tb_handle_t g2_pcache_init(tb_size_t maxn) { // check tb_assert_and_check_return_val(maxn, tb_null); // alloc g2_pcache_t* pcache = tb_malloc0(sizeof(g2_pcache_t)); tb_assert_and_check_return_val(pcache, tb_null); // init path cache pcache->maxn = maxn; pcache->cache = tb_stack_init(maxn, tb_item_func_ptr(tb_null, tb_null)); tb_assert_and_check_goto(pcache->cache, fail); while (maxn--) { // init tb_handle_t path = g2_path_init(); tb_assert_and_check_goto(path, fail); // put tb_stack_put(pcache->cache, path); } // init path hash pcache->hash = tb_hash_init(tb_isqrti(pcache->maxn), tb_item_func_ifm(sizeof(g2_shape_t), tb_null, tb_null), tb_item_func_ptr(g2_pcache_hash_item_free, pcache)); tb_assert_and_check_goto(pcache->hash, fail); // ok return pcache; fail: if (pcache) g2_pcache_exit(pcache); return tb_null; }
/* /////////////////////////////////////////////////////////////////////// * initializer */ g2_svg_element_t* g2_svg_element_init_polygon(tb_handle_t reader) { // alloc g2_svg_element_polygon_t* element = tb_malloc0(sizeof(g2_svg_element_polygon_t)); tb_assert_and_check_return_val(element, tb_null); // init element->base.exit = g2_svg_element_polygon_exit; element->base.writ = g2_svg_element_polygon_writ; element->base.fill = g2_svg_element_polygon_draw; element->base.stok = g2_svg_element_polygon_draw; element->base.clip = g2_svg_element_polygon_clip; element->base.style = &element->style; element->base.transform = &element->transform; // init style g2_svg_style_init(&element->style); // init transform g2_matrix_clear(&element->transform); // attributes tb_xml_node_t const* attr = tb_xml_reader_attributes(reader); for (; attr; attr = attr->next) { tb_char_t const* p = tb_pstring_cstr(&attr->data); if (!tb_pstring_cstricmp(&attr->name, "id")) tb_pstring_strcpy(&element->base.id, &attr->data); else if (!tb_pstring_cstricmp(&attr->name, "points")) g2_svg_element_polygon_points(element, p); else if (!tb_pstring_cstricmp(&attr->name, "style")) g2_svg_parser_style(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "fill")) g2_svg_parser_style_fill(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "fill-opacity")) g2_svg_parser_style_fill_opacity(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "stroke")) g2_svg_parser_style_stok(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "stroke-width")) g2_svg_parser_style_stok_width(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "stroke-linecap")) g2_svg_parser_style_stok_linecap(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "stroke-linejoin")) g2_svg_parser_style_stok_linejoin(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "stroke-opacity")) g2_svg_parser_style_stok_opacity(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "opacity")) g2_svg_parser_style_opacity(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "clip-path")) g2_svg_parser_style_clippath(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "transform")) g2_svg_parser_transform(p, &element->transform); } // ok return element; }
tb_handle_t g2_style_init() { // alloc g2_style_t* gstyle = tb_malloc0(sizeof(g2_style_t)); tb_assert_and_check_return_val(gstyle, tb_null); // init g2_style_clear(gstyle); // ok return gstyle; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_mutex_ref_t tb_mutex_init() { // make mutex pthread_mutex_t* pmutex = tb_malloc0(sizeof(pthread_mutex_t)); tb_assert_and_check_return_val(pmutex, tb_null); // init mutex if (pthread_mutex_init(pmutex, tb_null)) return tb_null; // ok return ((tb_mutex_ref_t)pmutex); }
/* /////////////////////////////////////////////////////////////////////// * initializer */ g2_svg_element_t* g2_svg_element_init_svg(tb_handle_t reader) { // alloc g2_svg_element_svg_t* element = tb_malloc0(sizeof(g2_svg_element_svg_t)); tb_assert_and_check_return_val(element, tb_null); // init element->base.writ = g2_svg_element_svg_writ; element->base.exit = g2_svg_element_svg_exit; // init painter element->painter.painter = tb_null; element->painter.hash = tb_null; element->painter.pool = tb_null; element->painter.load = tb_false; // attributes tb_size_t pw = 0; tb_size_t ph = 0; tb_xml_node_t const* attr = tb_xml_reader_attributes(reader); for (; attr; attr = attr->next) { tb_char_t const* p = tb_pstring_cstr(&attr->data); if (!tb_pstring_cstricmp(&attr->name, "x")) g2_svg_parser_float(p, &element->x); else if (!tb_pstring_cstricmp(&attr->name, "y")) g2_svg_parser_float(p, &element->y); else if (!tb_pstring_cstricmp(&attr->name, "width")) { p = g2_svg_parser_float(p, &element->width); if (*p == '%') pw = 1; } else if (!tb_pstring_cstricmp(&attr->name, "height")) { p = g2_svg_parser_float(p, &element->height); if (*p == '%') ph = 1; } else if (!tb_pstring_cstricmp(&attr->name, "viewBox")) { p = g2_svg_parser_float(p, &element->viewbox.x); p = g2_svg_parser_separator_skip(p); p = g2_svg_parser_float(p, &element->viewbox.y); p = g2_svg_parser_separator_skip(p); p = g2_svg_parser_float(p, &element->viewbox.w); p = g2_svg_parser_separator_skip(p); p = g2_svg_parser_float(p, &element->viewbox.h); } } if (pw && element->viewbox.w) element->width = g2_mul(element->viewbox.w, element->width / 100); if (pw && element->viewbox.h) element->height = g2_mul(element->viewbox.h, element->height / 100); // ok return element; }
/* /////////////////////////////////////////////////////////////////////// * initializer */ g2_svg_element_t* g2_svg_element_init_image(tb_handle_t reader) { // alloc g2_svg_element_image_t* element = tb_malloc0(sizeof(g2_svg_element_image_t)); tb_assert_and_check_return_val(element, tb_null); // init element->base.exit = g2_svg_element_image_exit; element->base.writ = g2_svg_element_image_writ; element->base.load = g2_svg_element_image_load; element->base.fill = g2_svg_element_image_draw; element->base.style = &element->style; element->base.transform = &element->transform; // init href tb_pstring_init(&element->href); // init style g2_svg_style_init(&element->style); // init transform g2_matrix_clear(&element->transform); // attributes tb_xml_node_t const* attr = tb_xml_reader_attributes(reader); for (; attr; attr = attr->next) { tb_char_t const* p = tb_pstring_cstr(&attr->data); if (!tb_pstring_cstricmp(&attr->name, "id")) tb_pstring_strcpy(&element->base.id, &attr->data); else if (!tb_pstring_cstricmp(&attr->name, "x")) g2_svg_parser_float(p, &element->rect.x); else if (!tb_pstring_cstricmp(&attr->name, "y")) g2_svg_parser_float(p, &element->rect.y); else if (!tb_pstring_cstricmp(&attr->name, "width")) g2_svg_parser_float(p, &element->rect.w); else if (!tb_pstring_cstricmp(&attr->name, "height")) g2_svg_parser_float(p, &element->rect.h); else if (!tb_pstring_cstricmp(&attr->name, "opacity")) g2_svg_parser_style_opacity(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "clip-path")) g2_svg_parser_style_clippath(p, &element->style); else if (!tb_pstring_cstricmp(&attr->name, "transform")) g2_svg_parser_transform(p, &element->transform); else if (!tb_pstring_cstricmp(&attr->name, "xlink:href")) tb_pstring_strcpy(&element->href, &attr->data); } // ok return element; }
static tb_bool_t tb_environment_set_impl(tb_char_t const* name, tb_char_t const* value) { // check tb_assert_and_check_return_val(name, tb_false); // done tb_bool_t ok = tb_false; tb_size_t size = 0; tb_wchar_t* value_w = tb_null; tb_size_t value_n = 0; do { // make name tb_wchar_t name_w[512] = {0}; tb_size_t name_n = tb_atow(name_w, name, tb_arrayn(name_w)); tb_assert_and_check_break(name_n); // exists value? if (value) { // make value value_n = tb_strlen(value); value_w = (tb_wchar_t*)tb_malloc0(sizeof(tb_wchar_t) * (value_n + 1)); tb_assert_and_check_break(value_w); // init value if (!tb_atow(value_w, value, value_n + 1)) break; // set it if (!tb_kernel32()->SetEnvironmentVariableW(name_w, value_w)) break; } // remove this variable else { // remove it if (!tb_kernel32()->SetEnvironmentVariableW(name_w, tb_null)) break; } // ok ok = tb_true; } while (0); // exit data if (value_w) tb_free(value_w); value_w = tb_null; // ok? return ok; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ gb_bitmap_ref_t gb_bitmap_init(tb_pointer_t data, tb_size_t pixfmt, tb_size_t width, tb_size_t height, tb_size_t row_bytes, tb_bool_t has_alpha) { // done tb_bool_t ok = tb_false; gb_bitmap_impl_t* impl = tb_null; do { // check tb_assert_and_check_break(GB_PIXFMT_OK(pixfmt)); tb_assert_and_check_break(width && width <= GB_WIDTH_MAXN && height && height <= GB_HEIGHT_MAXN); // make bitmap impl = tb_malloc0_type(gb_bitmap_impl_t); tb_assert_and_check_break(impl); // the pixmap, only using btp gb_pixmap_ref_t pixmap = gb_pixmap(pixfmt, 0xff); tb_assert_and_check_break(pixmap); // the row bytes if (!row_bytes) row_bytes = width * pixmap->btp; tb_assert_and_check_break(row_bytes && row_bytes >= width * pixmap->btp); // init bitmap impl->pixfmt = (tb_uint16_t)pixfmt; impl->width = (tb_uint16_t)width; impl->height = (tb_uint16_t)height; impl->row_bytes = (tb_uint16_t)row_bytes; impl->size = row_bytes * height; impl->data = data? data : tb_malloc0(impl->size); impl->has_alpha = !!has_alpha; impl->is_owner = !data; tb_assert_and_check_break(impl->data); // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (impl) gb_bitmap_exit((gb_bitmap_ref_t)impl); impl = tb_null; } // ok? return (gb_bitmap_ref_t)impl; }
static tb_aiop_rtor_impl_t* tb_aiop_rtor_kqueue_init(tb_aiop_impl_t* aiop) { // check tb_assert_and_check_return_val(aiop && aiop->maxn, tb_null); // done tb_bool_t ok = tb_false; tb_aiop_rtor_kqueue_impl_t* impl = tb_null; do { // make impl impl = tb_malloc0(sizeof(tb_aiop_rtor_kqueue_impl_t)); tb_assert_and_check_break(impl); // init base impl->base.aiop = aiop; impl->base.code = TB_AIOE_CODE_EALL | TB_AIOE_CODE_CLEAR | TB_AIOE_CODE_ONESHOT; impl->base.exit = tb_aiop_rtor_kqueue_exit; impl->base.cler = tb_aiop_rtor_kqueue_cler; impl->base.addo = tb_aiop_rtor_kqueue_addo; impl->base.delo = tb_aiop_rtor_kqueue_delo; impl->base.post = tb_aiop_rtor_kqueue_post; impl->base.wait = tb_aiop_rtor_kqueue_wait; // init kqueue impl->kqfd = kqueue(); tb_assert_and_check_break(impl->kqfd >= 0); // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit it if (impl) tb_aiop_rtor_kqueue_exit((tb_aiop_rtor_impl_t*)impl); impl = tb_null; } // ok? return (tb_aiop_rtor_impl_t*)impl; }
/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_char_t* tb_environment_get_impl(tb_char_t const* name, tb_size_t* psize) { // check tb_assert_and_check_return_val(name, 0); // done tb_bool_t ok = tb_false; tb_size_t size = 0; tb_size_t maxn = 256; tb_char_t* value = tb_null; tb_wchar_t* value_w = tb_null; do { // make value_w value_w = (tb_wchar_t*)tb_malloc0(sizeof(tb_wchar_t) * maxn); tb_assert_and_check_break(value_w); // make name tb_wchar_t name_w[512]; tb_size_t name_n = tb_atow(name_w, name, tb_arrayn(name_w)); tb_assert_and_check_break(name_n != -1); // get it size = (tb_size_t)tb_kernel32()->GetEnvironmentVariableW(name_w, value_w, (DWORD)maxn); if (!size) { // error? if (ERROR_ENVVAR_NOT_FOUND == GetLastError()) { // trace tb_trace_d("environment variable(%s) does not exist", name); } break; } else if (size > maxn) { // grow space value_w = (tb_wchar_t*)tb_ralloc(value_w, sizeof(tb_wchar_t) * (size + 1)); tb_assert_and_check_break(value_w); // get it size = (tb_size_t)tb_kernel32()->GetEnvironmentVariableW(name_w, value_w, (DWORD)size + 1); tb_assert_and_check_break(size); } // make value value = (tb_char_t*)tb_malloc0(sizeof(tb_char_t) * (size + 1)); tb_assert_and_check_break(value); // save value if ((size = tb_wtoa(value, value_w, size)) == -1) break; // save size if (psize) *psize = size; // ok ok = tb_true; } while (0); // failed? if (!ok) { // exit value if (value) tb_free(value); value = tb_null; } // exit value_w if (value_w) tb_free(value_w); value_w = tb_null; // ok? return value; }
tb_size_t tb_hash_map_insert(tb_hash_map_ref_t hash_map, tb_cpointer_t name, tb_cpointer_t data) { // check tb_hash_map_impl_t* impl = (tb_hash_map_impl_t*)hash_map; tb_assert_and_check_return_val(impl, 0); // the step tb_size_t step = impl->element_name.size + impl->element_data.size; tb_assert_and_check_return_val(step, 0); // find it tb_size_t buck = 0; tb_size_t item = 0; if (tb_hash_map_item_find(impl, name, &buck, &item)) { // check tb_assert_and_check_return_val(buck < impl->hash_size, 0); // get list tb_hash_map_item_list_t* list = impl->hash_list[buck]; tb_assert_and_check_return_val(list && list->size && item < list->size, 0); // replace data impl->element_data.repl(&impl->element_data, ((tb_byte_t*)&list[1]) + item * step + impl->element_name.size, data); } else { // check tb_assert_and_check_return_val(buck < impl->hash_size, 0); // get list tb_hash_map_item_list_t* list = impl->hash_list[buck]; // insert item if (list) { // grow? if (list->size >= list->maxn) { // check tb_assert_and_check_return_val(impl->item_grow, 0); // resize maxn tb_size_t maxn = tb_align_pow2(list->maxn + impl->item_grow); tb_assert_and_check_return_val(maxn > list->maxn, 0); // realloc it list = (tb_hash_map_item_list_t*)tb_ralloc(list, sizeof(tb_hash_map_item_list_t) + maxn * step); tb_assert_and_check_return_val(list, 0); // update the impl item maxn impl->item_maxn += maxn - list->maxn; // update maxn list->maxn = maxn; // reattach list impl->hash_list[buck] = list; } tb_assert_and_check_return_val(item <= list->size && list->size < list->maxn, 0); // move items if (item != list->size) tb_memmov(((tb_byte_t*)&list[1]) + (item + 1) * step, ((tb_byte_t*)&list[1]) + item * step, (list->size - item) * step); // dupl item list->size++; impl->element_name.dupl(&impl->element_name, ((tb_byte_t*)&list[1]) + item * step, name); impl->element_data.dupl(&impl->element_data, ((tb_byte_t*)&list[1]) + item * step + impl->element_name.size, data); } // create list for adding item else { // check tb_assert_and_check_return_val(impl->item_grow, 0); // make list list = (tb_hash_map_item_list_t*)tb_malloc0(sizeof(tb_hash_map_item_list_t) + impl->item_grow * step); tb_assert_and_check_return_val(list, 0); // init list list->size = 1; list->maxn = impl->item_grow; impl->element_name.dupl(&impl->element_name, ((tb_byte_t*)&list[1]), name); impl->element_data.dupl(&impl->element_data, ((tb_byte_t*)&list[1]) + impl->element_name.size, data); // attach list impl->hash_list[buck] = list; // update the impl item maxn impl->item_maxn += list->maxn; } // update the impl item size impl->item_size++; } // ok? return tb_hash_map_index_make(buck + 1, item + 1); }
static tb_object_ref_t tb_object_bplist_reader_done(tb_stream_ref_t stream) { // check tb_assert_and_check_return_val(stream, tb_null); // init root tb_object_ref_t root = tb_null; // init reader tb_object_bplist_reader_t reader = {0}; reader.stream = stream; // init size tb_hize_t size = tb_stream_size(stream); tb_assert_and_check_return_val(size, tb_null); // init data tb_byte_t data[32] = {0}; // read magic & version if (!tb_stream_bread(stream, data, 8)) return tb_null; // check magic & version if (tb_strncmp((tb_char_t const*)data, "bplist00", 8)) return tb_null; // seek to tail if (!tb_stream_seek(stream, size - 26)) return tb_null; // read offset size tb_size_t offset_size = tb_stream_bread_u8(stream); tb_trace_d("offset_size: %lu", offset_size); // read item size for array and dictionary tb_size_t item_size = tb_stream_bread_u8(stream); tb_trace_d("item_size: %lu", item_size); // read object count tb_size_t object_count = (tb_size_t)tb_stream_bread_u64_be(stream); tb_trace_d("object_count: %lu", object_count); // read root object tb_size_t root_object = (tb_size_t)tb_stream_bread_u64_be(stream); tb_trace_d("root_object: %lu", root_object); // read offset table index tb_size_t offset_table_index = (tb_size_t)tb_stream_bread_u64_be(stream); tb_trace_d("offset_table_index: %lu", offset_table_index); // check tb_assert_and_check_return_val(item_size && offset_size && object_count, tb_null); // init object hash tb_object_ref_t* object_hash = (tb_object_ref_t*)tb_malloc0(sizeof(tb_object_ref_t) * object_count); tb_assert_and_check_return_val(object_hash, tb_null); // done tb_bool_t failed = tb_false; do { // walk tb_size_t i = 0; for (i = 0; i < object_count; i++) { // seek to the offset entry if (!tb_stream_seek(stream, offset_table_index + i * offset_size)) { failed = tb_true; break; } // read the object offset tb_hize_t offset = 0; switch (offset_size) { case 1: offset = tb_stream_bread_u8(stream); break; case 2: offset = tb_stream_bread_u16_be(stream); break; case 4: offset = tb_stream_bread_u32_be(stream); break; case 8: offset = tb_stream_bread_u64_be(stream); break; default: return tb_null; break; } // seek to the object offset if (!tb_stream_seek(stream, offset)) { failed = tb_true; break; } // read object object_hash[i] = tb_object_bplist_reader_func_object(&reader, item_size); // if (object_hash[i]) tb_object_dump(object_hash[i]); } // failed? tb_check_break(!failed); // build array & dictionary items for (i = 0; i < object_count; i++) { tb_object_ref_t object = object_hash[i]; if (object) { switch (tb_object_type(object)) { case TB_OBJECT_TYPE_ARRAY: { // the priv data tb_byte_t* priv = (tb_byte_t*)tb_object_getp(object); if (priv) { // count tb_size_t count = (tb_size_t)tb_bits_get_u32_ne(priv); if (count) { // goto item data tb_byte_t const* p = priv + sizeof(tb_uint32_t); // walk items tb_size_t j = 0; for (i = 0; j < count; j++) { // the item index tb_size_t item = tb_object_bplist_bits_get(p + j * item_size, item_size); tb_assert(item < object_count && object_hash[item]); // tb_trace_d("item: %d", item); // append item if (item < object_count && object_hash[item]) { tb_object_inc(object_hash[item]); tb_object_array_append(object, object_hash[item]); } } } // exit priv tb_free(priv); tb_object_setp(object, tb_null); // tb_object_dump(object); } } break; case TB_OBJECT_TYPE_DICTIONARY: { // the priv data tb_byte_t* priv = (tb_byte_t*)tb_object_getp(object); if (priv) { // count tb_size_t count = (tb_size_t)tb_bits_get_u32_ne(priv); if (count) { // goto item data tb_byte_t const* p = priv + sizeof(tb_uint32_t); // walk items tb_size_t j = 0; for (i = 0; j < count; j++) { // the key & val tb_size_t key = tb_object_bplist_bits_get(p + j * item_size, item_size); tb_size_t val = tb_object_bplist_bits_get(p + (count + j) * item_size, item_size); tb_assert(key < object_count && object_hash[key]); tb_assert(val < object_count && object_hash[val]); // tb_trace_d("key_val: %u => %lu", key, val); // append the key & val if (key < object_count && val < object_count && object_hash[key] && object_hash[val]) { // key must be string now. tb_assert(tb_object_type(object_hash[key]) == TB_OBJECT_TYPE_STRING); if (tb_object_type(object_hash[key]) == TB_OBJECT_TYPE_STRING) { // set key => val tb_char_t const* skey = tb_object_string_cstr(object_hash[key]); if (skey) { tb_object_inc(object_hash[val]); tb_object_dictionary_set(object, skey, object_hash[val]); } tb_assert(skey); } } } } // exit priv tb_free(priv); tb_object_setp(object, tb_null); // tb_object_dump(object); } } break; default: break; } } } } while (0); // exit object hash if (object_hash) { // root if (root_object < object_count) root = object_hash[root_object]; // refn-- tb_size_t i; for (i = 0; i < object_count; i++) { if (object_hash[i] && i != root_object) tb_object_dec(object_hash[i]); } // exit object hash tb_free(object_hash); object_hash = tb_null; } // ok? return root; }