Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 7
0
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);
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 13
0
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);
}
Exemplo n.º 18
0
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;
}
Exemplo n.º 20
0
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);
}