struct PP_Var ppb_url_util_dev_resolve_relative_to_url(struct PP_Var base_url, struct PP_Var relative_string, struct PP_URLComponents_Dev *components) { reset_components(components); struct PP_Var var = PP_MakeNull(); if (base_url.type != PP_VARTYPE_STRING) { trace_warning("%s, base_url is not a string\n", __func__); return PP_MakeNull(); } if (relative_string.type != PP_VARTYPE_STRING) { trace_warning("%s, relative_string is not a string\n", __func__); return PP_MakeNull(); } const char *s_base_url = ppb_var_var_to_utf8(base_url, NULL); const char *s_relative_string = ppb_var_var_to_utf8(relative_string, NULL); UriParserStateA ups; UriUriA uri_base, uri_rel, uri_result; ups.uri = &uri_base; if (uriParseUriA(&ups, s_base_url) != URI_SUCCESS) { trace_warning("%s, can't parse s_base_url\n", __func__); goto err_1; } ups.uri = &uri_rel; if (uriParseUriA(&ups, s_relative_string) != URI_SUCCESS) { trace_warning("%s, can't parse s_relative_string\n", __func__); goto err_2; } if (uriAddBaseUriA(&uri_result, &uri_rel, &uri_base) != URI_SUCCESS) { trace_warning("%s, can't merge base and rel\n", __func__); goto err_3; } int len; uriToStringCharsRequiredA(&uri_result, &len); len++; char *str = malloc(len); uriToStringA(str, &uri_result, len, NULL); var = ppb_var_var_from_utf8_z(str); free(str); if (components) parse_url_string(str, components); err_3: uriFreeUriMembersA(&uri_result); err_2: uriFreeUriMembersA(&uri_rel); err_1: uriFreeUriMembersA(&uri_base); return var; }
static void _execute_script_ptac(void *user_data) { struct execute_script_param_s *p = user_data; NPString np_script; NPVariant np_result; // no need to lock, this function is run only in browser thread if (!p->pp_i->npp) { trace_error("%s, plugin instance was destroyed\n", __func__); p->result = PP_MakeUndefined(); goto quit; } np_script.UTF8Characters = ppb_var_var_to_utf8(p->script, &np_script.UTF8Length); if (!npn.evaluate(p->pp_i->npp, p->pp_i->np_window_obj, &np_script, &np_result)) { trace_error("%s, NPN_Evaluate failed\n", __func__); p->result = PP_MakeUndefined(); goto quit; } // TODO: find out what exception is p->result = np_variant_to_pp_var(np_result); if (np_result.type == NPVariantType_Object) tables_add_npobj_npp_mapping(np_result.value.objectValue, p->pp_i->npp); else npn.releasevariantvalue(&np_result); quit: ppb_message_loop_post_quit_depth(p->m_loop, PP_FALSE, p->depth); }
TEST(ppb_net_address_private, ipv4_describe) { const uint8_t ip[4] = {192, 168, 1, 2}; const uint16_t port = 1234; struct PP_NetAddress_Private addr; struct PP_Var s; ppb_net_address_private_create_from_ipv4_address(ip, port, &addr); s = ppb_net_address_private_describe(0, &addr, PP_TRUE); ASSERT_STREQ(ppb_var_var_to_utf8(s, NULL), "192.168.1.2:1234"); ppb_var_release(s); s = ppb_net_address_private_describe(0, &addr, PP_FALSE); ASSERT_STREQ(ppb_var_var_to_utf8(s, NULL), "192.168.1.2"); ppb_var_release(s); }
TEST(ppb_net_address_private, ipv6_describe) { const uint8_t ip[16] = { 0x01, 0x23, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xef, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; const uint16_t port = 1234; struct PP_NetAddress_Private addr; struct PP_Var s; ppb_net_address_private_create_from_ipv6_address(ip, 0, port, &addr); s = ppb_net_address_private_describe(0, &addr, PP_TRUE); ASSERT_STREQ(ppb_var_var_to_utf8(s, NULL), "[123:3456:789a:bcde:ef11:2233:4455:6677]:1234"); ppb_var_release(s); s = ppb_net_address_private_describe(0, &addr, PP_FALSE); ASSERT_STREQ(ppb_var_var_to_utf8(s, NULL), "123:3456:789a:bcde:ef11:2233:4455:6677"); ppb_var_release(s); }
PP_Bool ppb_browser_font_trusted_draw_text_at(PP_Resource font, PP_Resource image_data, const struct PP_BrowserFont_Trusted_TextRun *text, const struct PP_Point *position, uint32_t color, const struct PP_Rect *clip, PP_Bool image_data_is_opaque) { (void)image_data_is_opaque; // TODO: is it worth implementing? struct pp_browser_font_s *bf = pp_resource_acquire(font, PP_RESOURCE_BROWSER_FONT); if (!bf) return PP_FALSE; struct pp_image_data_s *id = pp_resource_acquire(image_data, PP_RESOURCE_IMAGE_DATA); if (!id) { pp_resource_release(font); return PP_FALSE; } cairo_t *cr = cairo_create(id->cairo_surf); if (clip) { cairo_rectangle(cr, clip->point.x, clip->point.y, clip->size.width, clip->size.height); cairo_clip(cr); } PangoFontMetrics *m = pango_font_get_metrics(bf->font, NULL); int32_t ascent = pango_font_metrics_get_ascent(m) / PANGO_SCALE; cairo_surface_mark_dirty(id->cairo_surf); if (position) cairo_move_to(cr, position->x, position->y - ascent); else cairo_move_to(cr, 0, 0); pango_font_metrics_unref(m); cairo_set_source_rgba(cr, ((color >> 16) & 0xffu) / 255.0, ((color >> 8) & 0xffu) / 255.0, ((color >> 0) & 0xffu) / 255.0, ((color >> 24) & 0xffu) / 255.0); PangoLayout *layout = pango_cairo_create_layout(cr); uint32_t len = 0; const char *s = ""; if (text->text.type == PP_VARTYPE_STRING) s = ppb_var_var_to_utf8(text->text, &len); // TODO: factor into rtl direction pango_layout_set_font_description(layout, bf->font_desc); pango_layout_set_text(layout, s, len); pango_cairo_layout_path(cr, layout); cairo_fill(cr); g_object_unref(layout); cairo_surface_flush(id->cairo_surf); cairo_destroy(cr); pp_resource_release(font); pp_resource_release(image_data); return PP_FALSE; }
static void test_default_charset(void) { // silly test actually. Both test and implementation contains almost the same code setlocale(LC_ALL, ""); char *current_charset = nl_langinfo(CODESET); struct PP_Var cs = ppb_char_set_get_default_char_set(instance); assert(strcmp(ppb_var_var_to_utf8(cs, NULL), current_charset) == 0); printf("default charset = %s\n", current_charset); ppb_var_release(cs); }
struct PP_Var ppb_url_util_dev_get_plugin_instance_url(PP_Instance instance, struct PP_URLComponents_Dev *components) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); struct PP_Var var = PP_MakeString(pp_i->instance_url); if (components) parse_url_string(ppb_var_var_to_utf8(var, NULL), components); return var; }
static void n2p_has_property_ptac(void *param) { struct has_property_param_s *p = param; const char *s_name = ppb_var_var_to_utf8(p->name, NULL); NPIdentifier identifier = npn.getstringidentifier(s_name); NPP npp = tables_get_npobj_npp_mapping(p->object); if (npp) p->result = npn.hasproperty(npp, p->object, identifier); else p->result = false; ppb_message_loop_post_quit_depth(p->m_loop, PP_FALSE, p->depth); }
struct PP_Var ppb_url_util_dev_get_document_url(PP_Instance instance, struct PP_URLComponents_Dev *components) { struct pp_instance_s *pp_i = tables_get_pp_instance(instance); struct PP_Var result = PP_MakeString(""); NPIdentifier location_id = npn.getstringidentifier("location"); NPIdentifier href_id = npn.getstringidentifier("href"); NPObject *np_window_obj, *np_location_obj; NPVariant location_var, href_var; if (npn.getvalue(pp_i->npp, NPNVWindowNPObject, &np_window_obj) != NPERR_NO_ERROR) goto err_1; if (!npn.getproperty(pp_i->npp, np_window_obj, location_id, &location_var)) goto err_2; if (location_var.type != NPVariantType_Object) goto err_3; np_location_obj = location_var.value.objectValue; if (!npn.getproperty(pp_i->npp, np_location_obj, href_id, &href_var)) goto err_3; struct PP_Var var = np_variant_to_pp_var(href_var); if (var.type != PP_VARTYPE_STRING) { ppb_var_release(var); goto err_4; } ppb_var_release(result); result = var; if (components) parse_url_string(ppb_var_var_to_utf8(result, NULL), components); err_4: npn.releasevariantvalue(&href_var); err_3: npn.releasevariantvalue(&location_var); err_2: npn.releaseobject(np_window_obj); err_1: return result; }
struct PP_Var ppb_url_util_dev_get_plugin_instance_url(PP_Instance instance, struct PP_URLComponents_Dev *components) { reset_components(components); struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return PP_MakeUndefined(); } struct PP_Var var = ppb_var_var_from_utf8_z(pp_i->instance_url); if (components) parse_url_string(ppb_var_var_to_utf8(var, NULL), components); return var; }
bool p2n_enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count) { if (npobj->_class == &p2n_proxy_class) { struct enumerate_param_s *p = g_slice_alloc(sizeof(*p)); p->npobj = npobj; p->m_loop = ppb_message_loop_get_for_browser_thread(); p->depth = ppb_message_loop_get_depth(p->m_loop) + 1; ppb_message_loop_post_work_with_result(p->m_loop, PP_MakeCCB(p2n_enumerate_prepare_comt, p), 0, PP_OK, 0, __func__); ppb_message_loop_run_nested(p->m_loop); bool result = p->result; *count = p->count; *value = npn.memalloc(p->count * sizeof(NPIdentifier)); char *tmpbuf = malloc(1); for (uint32_t k = 0; k < p->count; k ++) { uint32_t len = 0; const char *s = ppb_var_var_to_utf8(p->values[k], &len); // make zero-terminated string char *ptr = realloc(tmpbuf, len + 1); if (!ptr) { result = false; goto err; } tmpbuf = ptr; memcpy(tmpbuf, s, len); tmpbuf[len] = 0; value[k] = npn.getstringidentifier(tmpbuf); } err: free(tmpbuf); g_slice_free1(sizeof(*p), p); return result; } else { return npobj->_class->enumerate(npobj, value, count); } }
int32_t ppb_browser_font_trusted_measure_text(PP_Resource font, const struct PP_BrowserFont_Trusted_TextRun *text) { struct pp_browser_font_s *bf = pp_resource_acquire(font, PP_RESOURCE_BROWSER_FONT); if (!bf) return -1; PangoLayout *layout = pango_layout_new(tables_get_pango_ctx()); uint32_t len = 0; const char *s = ""; if (text->text.type == PP_VARTYPE_STRING) s = ppb_var_var_to_utf8(text->text, &len); // TODO: factor into rtl direction pango_layout_set_font_description(layout, bf->font_desc); pango_layout_set_text(layout, s, len); int width, height; pango_layout_get_pixel_size(layout, &width, &height); g_object_unref(layout); pp_resource_release(font); return width; }
struct PP_Var ppb_url_util_dev_get_document_url(PP_Instance instance, struct PP_URLComponents_Dev *components) { reset_components(components); struct pp_instance_s *pp_i = tables_get_pp_instance(instance); if (!pp_i) { trace_error("%s, bad instance\n", __func__); return PP_MakeUndefined(); } struct get_document_url_param_s p; p.npp = pp_i->npp; p.m_loop = ppb_message_loop_get_current(); p.depth = ppb_message_loop_get_depth(p.m_loop) + 1; p.np_window_obj = pp_i->np_window_obj; ppb_message_loop_post_work(p.m_loop, PP_MakeCompletionCallback(_get_document_url_comt, &p), 0); ppb_message_loop_run_int(p.m_loop, 1); if (components) parse_url_string(ppb_var_var_to_utf8(p.result, NULL), components); return p.result; }
static void n2p_call_ptac(void *param) { struct call_param_s *p = param; const char *s_method_name = ppb_var_var_to_utf8(p->method_name, NULL); NPIdentifier np_method_name = npn.getstringidentifier(s_method_name); NPP npp = tables_get_npobj_npp_mapping(p->object); NPVariant *np_args = malloc(p->argc * sizeof(NPVariant)); for (uint32_t k = 0; k < p->argc; k ++) np_args[k] = pp_var_to_np_variant(p->argv[k]); NPVariant np_result; bool res = npp ? npn.invoke(npp, p->object, np_method_name, np_args, p->argc, &np_result) : FALSE; for (uint32_t k = 0; k < p->argc; k ++) npn.releasevariantvalue(&np_args[k]); free(np_args); if (res) { struct PP_Var var = np_variant_to_pp_var(np_result); if (np_result.type == NPVariantType_Object) tables_add_npobj_npp_mapping(np_result.value.objectValue, npp); else npn.releasevariantvalue(&np_result); p->result = var; } else { p->result = PP_MakeUndefined(); } ppb_message_loop_post_quit_depth(p->m_loop, PP_FALSE, p->depth); }
static void n2p_get_property_ptac(void *param) { struct get_property_param_s *p = param; const char *s_name = ppb_var_var_to_utf8(p->name, NULL); NPIdentifier identifier = npn.getstringidentifier(s_name); NPVariant np_value; NPP npp = tables_get_npobj_npp_mapping(p->object); if (npp && npn.getproperty(npp, p->object, identifier, &np_value)) { struct PP_Var var = np_variant_to_pp_var(np_value); if (np_value.type == NPVariantType_Object) tables_add_npobj_npp_mapping(np_value.value.objectValue, npp); else npn.releasevariantvalue(&np_value); p->result = var; } else { p->result = PP_MakeUndefined(); } ppb_message_loop_post_quit_depth(p->m_loop, PP_FALSE, p->depth); }
TEST(ppb_net_address, ipv6_compose_decompose) { PP_Instance instance = create_instance(); const struct PP_NetAddress_IPv6 ipv6 = { .addr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, .port = htons(3456) }; struct PP_NetAddress_IPv6 ipv6_a = {}; struct PP_NetAddress_IPv4 ipv4 = {}; PP_Resource addr = ppb_net_address_create_from_ipv6_address(instance, &ipv6); ASSERT_EQ(ppb_net_address_is_net_address(addr), PP_TRUE); ASSERT_EQ(ppb_net_address_get_family(addr), PP_NETADDRESS_FAMILY_IPV6); ASSERT_EQ(ppb_net_address_describe_as_ipv4_address(addr, &ipv4), PP_FALSE); ASSERT_EQ(ppb_net_address_describe_as_ipv6_address(addr, &ipv6_a), PP_TRUE); ASSERT_EQ(memcmp(&ipv6, &ipv6_a, sizeof(ipv6_a)), 0); struct PP_Var s = ppb_net_address_describe_as_string(addr, PP_TRUE); ASSERT_STREQ(ppb_var_var_to_utf8(s, NULL), "[102:304:506:708:90a:b0c:d0e:f10]:3456"); ppb_var_release(s); ppb_core_release_resource(addr); destroy_instance(instance); }
TEST(ppb_net_address, ipv4_compose_decompose) { PP_Instance instance = create_instance(); const struct PP_NetAddress_IPv4 ipv4 = { .addr = {192, 168, 1, 2}, .port = htons(3456) }; struct PP_NetAddress_IPv4 ipv4_a = {}; struct PP_NetAddress_IPv6 ipv6 = {}; PP_Resource addr = ppb_net_address_create_from_ipv4_address(instance, &ipv4); ASSERT_EQ(ppb_net_address_is_net_address(addr), PP_TRUE); ASSERT_EQ(ppb_net_address_get_family(addr), PP_NETADDRESS_FAMILY_IPV4); ASSERT_EQ(ppb_net_address_describe_as_ipv6_address(addr, &ipv6), PP_FALSE); ASSERT_EQ(ppb_net_address_describe_as_ipv4_address(addr, &ipv4_a), PP_TRUE); ASSERT_EQ(memcmp(&ipv4, &ipv4_a, sizeof(ipv4_a)), 0); struct PP_Var s = ppb_net_address_describe_as_string(addr, PP_TRUE); ASSERT_STREQ(ppb_var_var_to_utf8(s, NULL), "192.168.1.2:3456"); ppb_var_release(s); ppb_core_release_resource(addr); destroy_instance(instance); }
PP_Bool ppb_flash_draw_glyphs(PP_Instance instance, PP_Resource pp_image_data, const struct PP_BrowserFont_Trusted_Description *font_desc, uint32_t color, const struct PP_Point *position, const struct PP_Rect *clip, const float transformation[3][3], PP_Bool allow_subpixel_aa, uint32_t glyph_count, const uint16_t glyph_indices[], const struct PP_Point glyph_advances[]) { struct pp_image_data_s *id = pp_resource_acquire(pp_image_data, PP_RESOURCE_IMAGE_DATA); if (!id) { trace_error("%s, bad resource\n", __func__); return PP_FALSE; } cairo_t *cr = cairo_create(id->cairo_surf); const char *font_family; if (font_desc->face.type == PP_VARTYPE_STRING) { font_family = ppb_var_var_to_utf8(font_desc->face, NULL); } else { switch (font_desc->family) { case PP_BROWSERFONT_TRUSTED_FAMILY_SERIF: font_family = "serif"; break; case PP_BROWSERFONT_TRUSTED_FAMILY_SANSSERIF: font_family = "sans-serif"; break; case PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE: font_family = "monospace"; break; default: font_family = ""; break; } } cairo_select_font_face(cr, font_family, font_desc->italic ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL, font_desc->weight >= (int)PP_FONTWEIGHT_700 ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, font_desc->size); if (allow_subpixel_aa) { cairo_font_options_t *options = cairo_font_options_create(); cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL); cairo_set_font_options(cr, options); cairo_font_options_destroy(options); } if (clip) { cairo_rectangle(cr, clip->point.x, clip->point.y, clip->size.width, clip->size.height); cairo_clip(cr); } cairo_set_source_rgba(cr, ((color >> 16) & 0xffu) / 255.0, ((color >> 8) & 0xffu) / 255.0, ((color >> 0) & 0xffu) / 255.0, ((color >> 24) & 0xffu) / 255.0); cairo_matrix_t matrix; cairo_matrix_init(&matrix, transformation[0][0], transformation[0][1], transformation[1][0], transformation[1][1], transformation[0][2], transformation[1][2]); cairo_set_matrix(cr, &matrix); cairo_glyph_t *c_glyphs = malloc(glyph_count * sizeof(cairo_glyph_t)); struct PP_Point current = {.x = 0, .y = 0}; for (uint32_t k = 0; k < glyph_count; k ++) { c_glyphs[k].index = glyph_indices[k]; c_glyphs[k].x = current.x; c_glyphs[k].y = current.y; current.x += glyph_advances[k].x; current.y += glyph_advances[k].y; } cairo_show_glyphs(cr, c_glyphs, glyph_count); free(c_glyphs); cairo_surface_flush(id->cairo_surf); cairo_destroy(cr); pp_resource_release(pp_image_data); return PP_TRUE; } struct get_proxy_for_url_param_s { PP_Instance instance_id; const char *url; struct PP_Var result; PP_Resource m_loop; int depth; }; static void get_proxy_for_url_ptac(void *user_data) { struct get_proxy_for_url_param_s *p = user_data; struct pp_instance_s *pp_i = tables_get_pp_instance(p->instance_id); p->result = PP_MakeUndefined(); if (pp_i && pp_i->npp && npn.getvalueforurl) { char *value = NULL; uint32_t len = 0; NPError err; err = npn.getvalueforurl(pp_i->npp, NPNURLVProxy, p->url, &value, &len); if (err == NPERR_NO_ERROR) { p->result = ppb_var_var_from_utf8(value, len); } } ppb_message_loop_post_quit_depth(p->m_loop, PP_FALSE, p->depth); } static void get_proxy_for_url_comt(void *user_data, int32_t result) { ppb_core_call_on_browser_thread(0, get_proxy_for_url_ptac, user_data); }
PP_Bool ppb_url_request_info_set_property(PP_Resource request, PP_URLRequestProperty property, struct PP_Var value) { const char *tmp, *tmp2; PP_Bool retval = PP_TRUE; struct pp_url_request_info_s *ri = pp_resource_acquire(request, PP_RESOURCE_URL_REQUEST_INFO); if (!ri) { trace_error("%s, bad resource\n", __func__); return PP_FALSE; } #define ENSURE_TYPE(vartype) if (value.type != vartype) { retval = PP_FALSE; break; } switch (property) { case PP_URLREQUESTPROPERTY_URL: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->url); tmp = ppb_var_var_to_utf8(value, NULL); tmp2 = ltrim(tmp); ri->url = strdup(tmp2); ri->is_immediate_javascript = (strncasecmp(tmp2, "javascript:", strlen("javascript:"))==0); break; case PP_URLREQUESTPROPERTY_METHOD: ENSURE_TYPE(PP_VARTYPE_STRING); tmp = ppb_var_var_to_utf8(value, NULL); if (strcmp(tmp, "GET") == 0) { ri->method = PP_METHOD_GET; } else if (strcmp(tmp, "POST") == 0) { ri->method = PP_METHOD_POST; } else { trace_warning("%s, unknown method %s\n", __func__, tmp); ri->method = PP_METHOD_UNKNOWN; } break; case PP_URLREQUESTPROPERTY_HEADERS: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->headers); ri->headers = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_STREAMTOFILE: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->stream_to_file = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->follow_redirects = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->record_download_progress = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->record_upload_progress = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_CUSTOMREFERRERURL: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_referrer_url); ri->custom_referrer_url = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->allow_cross_origin_requests = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS: ENSURE_TYPE(PP_VARTYPE_BOOL); ri->allow_credentials = value.value.as_bool; break; case PP_URLREQUESTPROPERTY_CUSTOMCONTENTTRANSFERENCODING: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_content_transfer_encoding); ri->custom_content_transfer_encoding = strdup(ppb_var_var_to_utf8(value, NULL)); break; case PP_URLREQUESTPROPERTY_PREFETCHBUFFERUPPERTHRESHOLD: ENSURE_TYPE(PP_VARTYPE_INT32); ri->prefetch_buffer_upper_threshold = value.value.as_int; break; case PP_URLREQUESTPROPERTY_PREFETCHBUFFERLOWERTHRESHOLD: ENSURE_TYPE(PP_VARTYPE_INT32); ri->prefetch_buffer_lower_threshold = value.value.as_int; break; case PP_URLREQUESTPROPERTY_CUSTOMUSERAGENT: ENSURE_TYPE(PP_VARTYPE_STRING); free_and_nullify(ri->custom_user_agent); ri->custom_user_agent = strdup(ppb_var_var_to_utf8(value, NULL)); break; default: trace_error("%s, unknown url request property %d\n", __func__, property); retval = PP_FALSE; break; } pp_resource_release(request); return retval; }
int32_t ppb_url_loader_open_target(PP_Resource loader, PP_Resource request_info, struct PP_CompletionCallback callback, const char *target) { struct pp_url_loader_s *ul = pp_resource_acquire(loader, PP_RESOURCE_URL_LOADER); if (!ul) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } struct pp_url_request_info_s *ri = pp_resource_acquire(request_info, PP_RESOURCE_URL_REQUEST_INFO); if (!ri) { trace_error("%s, bad resource\n", __func__); pp_resource_release(loader); return PP_ERROR_BADRESOURCE; } struct PP_Var full_url; if (ri->is_immediate_javascript) { full_url = ppb_var_var_from_utf8_z(ri->url); } else { struct PP_Var rel_url = ppb_var_var_from_utf8_z(ri->url); full_url = ppb_url_util_dev_resolve_relative_to_document(ul->instance->id, rel_url, NULL); ppb_var_release(rel_url); } ul->url = nullsafe_strdup(ppb_var_var_to_utf8(full_url, NULL)); ul->method = ri->method; ul->read_pos = 0; ul->request_headers = nullsafe_strdup(ri->headers); ul->follow_redirects = ri->follow_redirects; ul->stream_to_file = ri->stream_to_file; ul->record_download_progress = ri->record_download_progress; ul->record_upload_progress = ri->record_upload_progress; ul->custom_referrer_url = nullsafe_strdup(ri->custom_referrer_url); ul->allow_cross_origin_requests = ri->allow_cross_origin_requests; ul->allow_credentials = ri->allow_credentials; ul->custom_content_transfer_encoding = nullsafe_strdup(ri->custom_content_transfer_encoding); ul->custom_user_agent = nullsafe_strdup(ri->custom_user_agent); ul->target = nullsafe_strdup(target); #define TRIM_NEWLINE(s) s = trim_nl(s) TRIM_NEWLINE(ul->request_headers); TRIM_NEWLINE(ul->custom_referrer_url); TRIM_NEWLINE(ul->custom_content_transfer_encoding); TRIM_NEWLINE(ul->custom_user_agent); ul->post_len = ri->post_len; if (ri->post_len > 0) { ul->post_data = malloc(ri->post_len); memcpy(ul->post_data, ri->post_data, ri->post_len); } ul->fd = open_temporary_file(); ul->ccb = callback; ppb_var_release(full_url); pp_resource_release(request_info); struct url_loader_open_param_s *p = g_slice_alloc(sizeof(*p)); p->url = ul->url; p->loader = loader; p->instance_id = ul->instance->id; p->method = ul->method; p->request_headers = ul->request_headers; p->custom_referrer_url = ul->custom_referrer_url; p->custom_content_transfer_encoding = ul->custom_content_transfer_encoding; p->custom_user_agent = ul->custom_user_agent; p->target = ul->target; p->post_len = ul->post_len; p->post_data = ul->post_data; p->m_loop = ppb_message_loop_get_current(); p->depth = ppb_message_loop_get_depth(p->m_loop) + 1; ppb_core_add_ref_resource(loader); // add ref to ensure data in ul remain accessible pp_resource_release(loader); ppb_message_loop_post_work(p->m_loop, PP_MakeCCB(_url_loader_open_comt, p), 0); ppb_message_loop_run_nested(p->m_loop); ppb_core_release_resource(loader); int retval = p->retval; g_slice_free1(sizeof(*p), p); if (retval != NPERR_NO_ERROR) return PP_ERROR_FAILED; if (callback.func == NULL) { int done = 0; while (!done) { ul = pp_resource_acquire(loader, PP_RESOURCE_URL_LOADER); if (ul) { done = ul->finished_loading; pp_resource_release(loader); } else { break; } printf("waitin'\n"); usleep(10000); } return PP_OK; } return PP_OK_COMPLETIONPENDING; }
int32_t ppb_video_capture_open(PP_Resource video_capture, PP_Resource device_ref, const struct PP_VideoCaptureDeviceInfo_Dev *requested_info, uint32_t buffer_count, struct PP_CompletionCallback callback) { int32_t result; struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } const char *capture_device = default_capture_device; struct PP_Var longname = ppb_device_ref_get_longname(device_ref); if (longname.type == PP_VARTYPE_STRING) capture_device = ppb_var_var_to_utf8(longname, NULL); vc->fd = v4l2_open(capture_device, O_RDWR); ppb_var_release(longname); if (vc->fd < 0) { result = PP_ERROR_NOACCESS; goto point_1; } struct v4l2_capability caps; if (v4l2_ioctl(vc->fd, VIDIOC_QUERYCAP, &caps) != 0) { result = PP_ERROR_FAILED; goto point_2; } #ifdef V4L2_CAP_DEVICE_CAPS const uint32_t device_caps = (caps.capabilities & V4L2_CAP_DEVICE_CAPS) ? caps.device_caps : caps.capabilities; #else const uint32_t device_caps = caps.capabilities; #endif // V4L2_CAP_DEVICE_CAPS if (!(device_caps & V4L2_CAP_VIDEO_CAPTURE)) { trace_error("%s, device can't capture\n", __func__); result = PP_ERROR_FAILED; goto point_2; } if (!(device_caps & V4L2_CAP_READWRITE)) { trace_error("%s, device doesn't support read/write interface\n", __func__); result = PP_ERROR_FAILED; goto point_2; } if (requested_info) { vc->width = requested_info->width; vc->height = requested_info->height; vc->fps = requested_info->frames_per_second; } else { vc->width = 640; vc->height = 480; vc->fps = 15; } struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .fmt.pix.width = vc->width, .fmt.pix.height = vc->height, .fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420, // PPAPI hardcodes format to YUV420 .fmt.pix.field = V4L2_FIELD_INTERLACED, }; if (v4l2_ioctl(vc->fd, VIDIOC_S_FMT, &fmt) != 0) { trace_error("%s, failed to set resolution\n", __func__); result = PP_ERROR_FAILED; goto point_2; } vc->width = fmt.fmt.pix.width; vc->height = fmt.fmt.pix.height; vc->buffer_size = fmt.fmt.pix.sizeimage; // buffer size in bytes vc->buffer_count = MAX(buffer_count, 5); // limit lowest number of buffers, just in case vc->buffers = calloc(sizeof(*vc->buffers), vc->buffer_count); if (!vc->buffers) { trace_error("%s, memory allocation failure (1)\n", __func__); result = PP_ERROR_FAILED; goto point_2; } vc->buffer_is_free = malloc(sizeof(*vc->buffer_is_free) * vc->buffer_count); if (!vc->buffer_is_free) { trace_error("%s, memory allocation failure (2)\n", __func__); result = PP_ERROR_FAILED; goto point_3; } for (unsigned int k = 0; k < vc->buffer_count; k ++) { vc->buffer_is_free[k] = 1; vc->buffers[k] = ppb_buffer_create(vc->instance->id, vc->buffer_size); if (vc->buffers[k] == 0) goto point_4; } struct PP_VideoCaptureDeviceInfo_Dev info = { .width = vc->width, .height = vc->height, .frames_per_second = vc->fps, }; vc->ppp_video_capture_dev->OnDeviceInfo(vc->instance->id, video_capture, &info, vc->buffer_count, vc->buffers); result = PP_OK; goto point_1; point_4: for (unsigned int k = 0; k < vc->buffer_count; k ++) ppb_core_release_resource(vc->buffers[k]); free_and_nullify(vc->buffer_is_free); point_3: free_and_nullify(vc->buffers); point_2: v4l2_close(vc->fd); vc->fd = -1; point_1: pp_resource_release(video_capture); ppb_core_call_on_main_thread2(0, callback, result, __func__); return PP_OK_COMPLETIONPENDING; } struct on_buffer_ready_param_s { PP_Instance instance; PP_Resource video_capture; uint32_t buf_idx; const struct PPP_VideoCapture_Dev_0_1 *ppp_video_capture_dev; }; static void on_buffer_ready_comt(void *user_data, int32_t result) { struct on_buffer_ready_param_s *p = user_data; struct pp_instance_s *pp_i = tables_get_pp_instance(p->instance); if (!pp_i) return; p->ppp_video_capture_dev->OnBufferReady(p->instance, p->video_capture, p->buf_idx); g_slice_free1(sizeof(*p), p); } static void * video_capture_thread(void *param) { struct pp_video_capture_s *vc = param; PP_Resource video_capture = vc->self_id; PP_Instance instance = vc->instance->id; const int fd = vc->fd; const size_t buffer_size = vc->buffer_size; vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) goto gone; while (!vc->terminate_thread) { // find free buffer uint32_t buf_idx = (uint32_t)-1; for (uint32_t k = 0; k < vc->buffer_count; k ++) { if (vc->buffer_is_free[k]) { buf_idx = k; vc->buffer_is_free[k] = 0; break; } } if (buf_idx == (uint32_t)-1) { // all buffers are busy, wait for some to free, with resource unlocked pp_resource_release(video_capture); usleep(10); vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) goto gone; continue; } PP_Resource buffer = vc->buffers[buf_idx]; pp_resource_release(video_capture); // wait on v4l2_read() with resource unlocked void *ptr = ppb_buffer_map(buffer); RETRY_ON_EINTR(v4l2_read(fd, ptr, buffer_size)); ppb_buffer_unmap(buffer); vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) goto gone; struct on_buffer_ready_param_s *p = g_slice_alloc(sizeof(*p)); p->instance = instance; p->video_capture = video_capture; p->buf_idx = buf_idx; p->ppp_video_capture_dev = vc->ppp_video_capture_dev; ppb_core_call_on_main_thread2(0, PP_MakeCCB(on_buffer_ready_comt, p), PP_OK, __func__); } pp_resource_release(video_capture); return NULL; gone: trace_error("%s, resource gone\n", __func__); return NULL; } int32_t ppb_video_capture_start_capture(PP_Resource video_capture) { struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (vc->thread_started) goto done; if (vc->fd < 0) { trace_error("%s, device is closed\n", __func__); pp_resource_release(video_capture); return PP_ERROR_FAILED; } vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STARTING); pp_resource_ref(video_capture); // prevents freeing while thread is still running pthread_create(&vc->thread, NULL, video_capture_thread, vc); vc->thread_started = 1; vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STARTED); done: pp_resource_release(video_capture); return PP_OK; } int32_t ppb_video_capture_reuse_buffer(PP_Resource video_capture, uint32_t buffer) { struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (buffer < vc->buffer_count) vc->buffer_is_free[buffer] = 1; pp_resource_release(video_capture); return PP_OK; } int32_t ppb_video_capture_stop_capture(PP_Resource video_capture) { struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return PP_ERROR_BADRESOURCE; } if (!vc->thread_started) goto done; vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STOPPING); vc->terminate_thread = 1; pthread_t thread = vc->thread; pp_resource_release(video_capture); pthread_join(thread, NULL); vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, resource gone\n", __func__); return PP_ERROR_BADRESOURCE; } vc->thread_started = 0; vc->terminate_thread = 0; vc->ppp_video_capture_dev->OnStatus(vc->instance->id, video_capture, PP_VIDEO_CAPTURE_STATUS_STOPPED); pp_resource_unref(video_capture); // remove reference made in start_capture() done: pp_resource_release(video_capture); return PP_OK; } void ppb_video_capture_close(PP_Resource video_capture) { ppb_video_capture_stop_capture(video_capture); struct pp_video_capture_s *vc = pp_resource_acquire(video_capture, PP_RESOURCE_VIDEO_CAPTURE); if (!vc) { trace_error("%s, bad resource\n", __func__); return; } ppb_video_capture_destroy(vc); pp_resource_release(video_capture); return; } // trace wrappers TRACE_WRAPPER PP_Resource trace_ppb_video_capture_create(PP_Instance instance) { trace_info("[PPB] {full} %s instance=%d\n", __func__+6, instance); return ppb_video_capture_create(instance); }