PPAPI插件的绘图与输入事件处理

在PPAPI插件与浏览器的交互过程一文中学习了PPAPI插件与浏览器的交互流程、渲染逻辑、输入事件的处理逻辑,这次我们改造一下graphics_2d_example示例,加入处理鼠标事件的逻辑,演示一下PPAPI插件想要处理输入事件时的代码流程。

foruok原创,如需转载请关注foruok的微信订阅号“程序视界”联系foruok。

工程

新建一个Win32项目,类型选DLL,去掉预编译头文件stdafx.h和stdafx.cpp,并且在项目属性–>配置属性–>C/C++–>预编译头,把预编译头选项的值设置为不使用预编译头。

使用UNICODE字符集,运行库选择MT。

项目名就叫ppapi_simple吧,把ppapi的上一级目录添加到附加包含目录里。

把graphics_2d_example.c拷贝过来,改名为ppapi_simple.c。内容修改成下面的样子:

/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
* 
* 2016-1-10, edited by foruok.
* 如需转载,请关注微信订阅号“程序视界”,回复foruok获取其联系方式
*
*/
#include 
#include 
#include 
#include 
#include 

#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/pp_rect.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb.h"
#include "ppapi/c/ppb_core.h"
#include "ppapi/c/ppb_graphics_2d.h"
#include "ppapi/c/ppb_image_data.h"
#include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppb_view.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppb_input_event.h"
#include "ppapi/c/ppp_input_event.h"

PPB_GetInterface g_get_browser_interface = NULL;

const PPB_Core* g_core_interface;
const PPB_Graphics2D* g_graphics_2d_interface;
const PPB_ImageData* g_image_data_interface;
const PPB_Instance* g_instance_interface;
const PPB_View* g_view_interface;
// [1]
const PPB_InputEvent *g_input_interface;
const PPB_MouseInputEvent *g_mouse_interface;

/* PPP_Instance implementation -----------------------------------------------*/

struct InstanceInfo {
    PP_Instance pp_instance;
    struct PP_Size last_size;
    PP_Resource graphics;

    struct InstanceInfo* next;
};

/** Linked list of all live instances. */
struct InstanceInfo* all_instances = NULL;

/** Returns a refed resource corresponding to the created graphics 2d. */
PP_Resource MakeAndBindGraphics2D(PP_Instance instance,
    const struct PP_Size* size) {
    PP_Resource graphics;

    graphics = g_graphics_2d_interface->Create(instance, size, PP_FALSE);
    if (!graphics)
        return 0;

    if (!g_instance_interface->BindGraphics(instance, graphics)) {
        g_core_interface->ReleaseResource(graphics);
        return 0;
    }
    return graphics;
}

void FlushCompletionCallback(void* user_data, int32_t result) {
    /* Don't need to do anything here. */
}

unsigned int g_colors[4] = { 0xFF0000FF, 0xFFFF00FF, 0xFF00FFFF, 0xFFEA00FF };
unsigned int g_color_index = 0;

void Repaint(struct InstanceInfo* instance, const struct PP_Size* size) {
    PP_Resource image;
    struct PP_ImageDataDesc image_desc;
    uint32_t* image_data;
    int num_words, i;

    /* Ensure the graphics 2d is ready. */
    if (!instance->graphics) {
        instance->graphics = MakeAndBindGraphics2D(instance->pp_instance, size);
        if (!instance->graphics)
            return;
    }

    /* Create image data to paint into. */
    image = g_image_data_interface->Create(
        instance->pp_instance, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, PP_TRUE);
    if (!image)
        return;
    g_image_data_interface->Describe(image, &image_desc);

    /* Fill the image with blue. */
    image_data = (uint32_t*)g_image_data_interface->Map(image);
    if (!image_data) {
        g_core_interface->ReleaseResource(image);
        return;
    }
    num_words = image_desc.stride * size->height / 4;

    // [6]
    g_color_index++;
    if (g_color_index >= sizeof(g_colors) / sizeof(g_colors[0])) g_color_index = 0;

    for (i = 0; i < num_words; i++)
        image_data[i] = g_colors[g_color_index];

    /* Paint image to graphics 2d. */
    g_graphics_2d_interface->ReplaceContents(instance->graphics, image);
    g_graphics_2d_interface->Flush(instance->graphics,
        PP_MakeCompletionCallback(&FlushCompletionCallback, NULL));

    g_core_interface->ReleaseResource(image);
}

/** Returns the info for the given instance, or NULL if it's not found. */
struct InstanceInfo* FindInstance(PP_Instance instance) {
    struct InstanceInfo* cur = all_instances;
    while (cur) {
        if (cur->pp_instance == instance)
            return cur;
        cur = cur->next;
    }
    return NULL;
}

PP_Bool Instance_DidCreate(PP_Instance instance,
    uint32_t argc,
    const char* argn[],
    const char* argv[]) {
    struct InstanceInfo* info =
        (struct InstanceInfo*)malloc(sizeof(struct InstanceInfo));
    info->pp_instance = instance;
    info->last_size.width = 0;
    info->last_size.height = 0;
    info->graphics = 0;

    /* Insert into linked list of live instances. */
    info->next = all_instances;
    all_instances = info;

    // [5]
    g_input_interface->RequestInputEvents(instance, PP_INPUTEVENT_CLASS_MOUSE);
    g_input_interface->RequestFilteringInputEvents(instance, PP_INPUTEVENT_CLASS_MOUSE);
    OutputDebugString(_T("Instance_DidCreate\r\n"));

    return PP_TRUE;
}

void Instance_DidDestroy(PP_Instance instance) {
    /* Find the matching item in the linked list, delete it, and patch the
    * links.
    */
    struct InstanceInfo** prev_ptr = &all_instances;
    struct InstanceInfo* cur = all_instances;
    while (cur) {
        if (instance == cur->pp_instance) {
            *prev_ptr = cur->next;
            g_core_interface->ReleaseResource(cur->graphics);
            free(cur);
            return;
        }
        prev_ptr = &cur->next;
        cur = cur->next;
    }
}

void Instance_DidChangeView(PP_Instance pp_instance,
    PP_Resource view) {
    struct PP_Rect position;
    struct InstanceInfo* info = FindInstance(pp_instance);
    if (!info)
        return;

    if (g_view_interface->GetRect(view, &position) == PP_FALSE)
        return;

    if (info->last_size.width != position.size.width ||
        info->last_size.height != position.size.height) {
        /* Got a resize, repaint the plugin. */
        Repaint(info, &position.size);
        info->last_size.width = position.size.width;
        info->last_size.height = position.size.height;
    }

    OutputDebugString(_T("Instance_DidChangeView\r\n"));
}

void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
}

PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
    PP_Resource pp_url_loader) {
    return PP_FALSE;
}

static PPP_Instance instance_interface = {
    &Instance_DidCreate,
    &Instance_DidDestroy,
    &Instance_DidChangeView,
    &Instance_DidChangeFocus,
    &Instance_HandleDocumentLoad
};

// [3]
PP_Bool InputEvent_HandleInputEvent(PP_Instance instance, PP_Resource input_event)
{
    struct PP_Point pt;
    TCHAR szLog[512] = { 0 };
    switch (g_input_interface->GetType(input_event))
    {
    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
        pt = g_mouse_interface->GetPosition(input_event);
        _stprintf_s(szLog, 512, _T("InputEvent_HandleInputEvent, mouse down at [%d, %d]\r\n"), pt.x, pt.y);
        OutputDebugString(szLog);
        break;
        /*
    case PP_INPUTEVENT_TYPE_MOUSEUP:
        OutputDebugString(_T("InputEvent_HandleInputEvent, mouse up\r\n"));
        break;

    case PP_INPUTEVENT_TYPE_MOUSEMOVE:
        OutputDebugString(_T("InputEvent_HandleInputEvent, mouse move\r\n"));
        break;
    case PP_INPUTEVENT_TYPE_MOUSEENTER:
        OutputDebugString(_T("InputEvent_HandleInputEvent, mouse enter\r\n"));
        break;
    case PP_INPUTEVENT_TYPE_MOUSELEAVE:
        OutputDebugString(_T("InputEvent_HandleInputEvent, mouse leave\r\n"));
        break;
        */
    default:
        return PP_FALSE;
    }
    struct InstanceInfo* info = FindInstance(instance);
    if (info && info->last_size.width > 0)
    {
        Repaint(info, &info->last_size);
    }
    return PP_TRUE;
}

// [3]
static PPP_InputEvent input_interface = {
    &InputEvent_HandleInputEvent
};

/* Global entrypoints --------------------------------------------------------*/

PP_EXPORT int32_t PPP_InitializeModule(PP_Module module,
    PPB_GetInterface get_browser_interface) {
    g_get_browser_interface = get_browser_interface;

    g_core_interface = (const PPB_Core*)
        get_browser_interface(PPB_CORE_INTERFACE);
    g_instance_interface = (const PPB_Instance*)
        get_browser_interface(PPB_INSTANCE_INTERFACE);
    g_image_data_interface = (const PPB_ImageData*)
        get_browser_interface(PPB_IMAGEDATA_INTERFACE);
    g_graphics_2d_interface = (const PPB_Graphics2D*)
        get_browser_interface(PPB_GRAPHICS_2D_INTERFACE);
    g_view_interface = (const PPB_View*)
        get_browser_interface(PPB_VIEW_INTERFACE);
    // [2]
    g_input_interface = (const PPB_InputEvent*)get_browser_interface(PPB_INPUT_EVENT_INTERFACE);
    g_mouse_interface = (const PPB_MouseInputEvent*)get_browser_interface(PPB_MOUSE_INPUT_EVENT_INTERFACE);

    if (!g_core_interface || !g_instance_interface || !g_image_data_interface ||
        !g_graphics_2d_interface || !g_view_interface ||
        !g_input_interface || !g_mouse_interface)
        return -1;

    OutputDebugString(_T("PPP_InitializeModule\r\n"));
    return PP_OK;
}

PP_EXPORT void PPP_ShutdownModule() {
}

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
    if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
    {
        OutputDebugString(_T("PPP_GetInterface, instance_interface\r\n"));
        return &instance_interface;
    }
    // [4]
    else if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0)
    {
        OutputDebugString(_T("PPP_GetInterface, input_interface\r\n"));
        return &input_interface;
    }

    return NULL;
}

代码改动说明

ppapi_simple.c相对graphics_2d_example.c来讲,主要有6处改动,已在前面的源代码中使用[1]、[2]之类的符号标注出来了。大部分改动是为处理鼠标事件加入的代码,有两处是绘图相关的改动。

先说要处理鼠标事件需要添加的代码及流程。

[1] 这里声明了两个全局变量,g_input_interface和g_mouse_interface,它们将会在PPP_InitializeModule方法中被初始化(标号为[2]处的改动)。g_input_interface是浏览器暴露出来的输入事件接口,插件要请求处理某类事件就通过它。g_mouse_interface是鼠标事件,可以根据事件资源ID获取对应的详细信息,如位置、按下的鼠标按键等。

[3] 这处改动声明了插件测的输入处理接口。一个结构体,一个函数。

[4] 这里会被浏览器调用到,我们新添加的PPP_InputEvent就是在这里返回给浏览器。浏览器拿到PPP_InputEvent后就可以把事件传递给这个接口的HandleInputEvent方法,也就是我们实现的InputEvent_HandleInputEvent方法。在InputEvent_HandleInputEvent方法里,鼠标左键按下时我们调用Repaint()来重绘。

[5] 当插件对象实例创建时,我们向浏览器的输入事件接口请求处理鼠标事件。浏览器收到这个请求,才会派发事件给我们的插件实例对象。

[6] 渲染(绘图)函数。绘图过程,在PPAPI插件与浏览器的交互过程中已介绍过了,不多说了。这里添加的代码,主要是为了让示例随着鼠标点击有变化。通过一个颜色数组和索引,变换插件实例对象对应视图区域的颜色。

我还在关键处插入了一些日志代码,可以通过DbgView来查看。

下面是运行效果图:

PPAPI插件的绘图与输入事件处理_第1张图片

通过CEF运行时使用的命令参数如下:

–ppapi-out-of-process –register-pepper-plugins=”D:\projects\cef_binary_3.2357.1271.g8e0674e_windows32\Release\stub.dll;application/x-ppapi-simple” –url=file:///d:/projects/cef_binary_3.2357.1271.g8e0674e_windows32/Release/simple.html

simple.html和stub.html类似,改了下title和embed标签的type。


好啦,新的示例主要就这些内容了,处理输入事件的流程应该也清楚了。

相关文章参考:

  • CEF Windows开发环境搭建
  • CEF加载PPAPI插件
  • VS2013编译最简单的PPAPI插件
  • 理解PPAPI的设计
  • PPAPI插件与浏览器的交互过程
  • Windows下从源码编译CEF
  • 编译PPAPI的media_stream_video示例

你可能感兴趣的:(网络编程,CEF与PPAPI开发)