1/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5#include <stdlib.h>
6#include <string.h>
7
8#include "ppapi/c/pp_completion_callback.h"
9#include "ppapi/c/pp_errors.h"
10#include "ppapi/c/pp_instance.h"
11#include "ppapi/c/pp_module.h"
12#include "ppapi/c/pp_rect.h"
13#include "ppapi/c/pp_var.h"
14#include "ppapi/c/ppb.h"
15#include "ppapi/c/ppb_core.h"
16#include "ppapi/c/ppb_graphics_2d.h"
17#include "ppapi/c/ppb_image_data.h"
18#include "ppapi/c/ppb_instance.h"
19#include "ppapi/c/ppb_view.h"
20#include "ppapi/c/ppp.h"
21#include "ppapi/c/ppp_instance.h"
22
23PPB_GetInterface g_get_browser_interface = NULL;
24
25const PPB_Core* g_core_interface;
26const PPB_Graphics2D* g_graphics_2d_interface;
27const PPB_ImageData* g_image_data_interface;
28const PPB_Instance* g_instance_interface;
29const PPB_View* g_view_interface;
30
31/* PPP_Instance implementation -----------------------------------------------*/
32
33struct InstanceInfo {
34  PP_Instance pp_instance;
35  struct PP_Size last_size;
36
37  struct InstanceInfo* next;
38};
39
40/** Linked list of all live instances. */
41struct InstanceInfo* all_instances = NULL;
42
43/** Returns a refed resource corresponding to the created graphics 2d. */
44PP_Resource MakeAndBindGraphics2D(PP_Instance instance,
45                                  const struct PP_Size* size) {
46  PP_Resource graphics;
47
48  graphics = g_graphics_2d_interface->Create(instance, size, PP_FALSE);
49  if (!graphics)
50    return 0;
51
52  if (!g_instance_interface->BindGraphics(instance, graphics)) {
53    g_core_interface->ReleaseResource(graphics);
54    return 0;
55  }
56  return graphics;
57}
58
59void FlushCompletionCallback(void* user_data, int32_t result) {
60  /* Don't need to do anything here. */
61}
62
63void Repaint(struct InstanceInfo* instance, const struct PP_Size* size) {
64  PP_Resource image, graphics;
65  struct PP_ImageDataDesc image_desc;
66  uint32_t* image_data;
67  int num_words, i;
68
69  /* Create image data to paint into. */
70  image = g_image_data_interface->Create(
71      instance->pp_instance, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, PP_TRUE);
72  if (!image)
73    return;
74  g_image_data_interface->Describe(image, &image_desc);
75
76  /* Fill the image with blue. */
77  image_data = (uint32_t*)g_image_data_interface->Map(image);
78  if (!image_data) {
79    g_core_interface->ReleaseResource(image);
80    return;
81  }
82  num_words = image_desc.stride * size->height / 4;
83  for (i = 0; i < num_words; i++)
84    image_data[i] = 0xFF0000FF;
85
86  /* Create the graphics 2d and paint the image to it. */
87  graphics = MakeAndBindGraphics2D(instance->pp_instance, size);
88  if (!graphics) {
89    g_core_interface->ReleaseResource(image);
90    return;
91  }
92
93  g_graphics_2d_interface->ReplaceContents(graphics, image);
94  g_graphics_2d_interface->Flush(graphics,
95      PP_MakeCompletionCallback(&FlushCompletionCallback, NULL));
96
97  g_core_interface->ReleaseResource(graphics);
98  g_core_interface->ReleaseResource(image);
99}
100
101/** Returns the info for the given instance, or NULL if it's not found. */
102struct InstanceInfo* FindInstance(PP_Instance instance) {
103  struct InstanceInfo* cur = all_instances;
104  while (cur) {
105    if (cur->pp_instance == instance)
106      return cur;
107    cur = cur->next;
108  }
109  return NULL;
110}
111
112PP_Bool Instance_DidCreate(PP_Instance instance,
113                           uint32_t argc,
114                           const char* argn[],
115                           const char* argv[]) {
116  struct InstanceInfo* info =
117      (struct InstanceInfo*)malloc(sizeof(struct InstanceInfo));
118  info->pp_instance = instance;
119  info->last_size.width = 0;
120  info->last_size.height = 0;
121
122  /* Insert into linked list of live instances. */
123  info->next = all_instances;
124  all_instances = info;
125  return PP_TRUE;
126}
127
128void Instance_DidDestroy(PP_Instance instance) {
129  /* Find the matching item in the linked list, delete it, and patch the
130   * links.
131   */
132  struct InstanceInfo** prev_ptr = &all_instances;
133  struct InstanceInfo* cur = all_instances;
134  while (cur) {
135    if (instance == cur->pp_instance) {
136      *prev_ptr = cur->next;
137      free(cur);
138      return;
139    }
140    prev_ptr = &cur->next;
141    cur = cur->next;
142  }
143}
144
145void Instance_DidChangeView(PP_Instance pp_instance,
146                            PP_Resource view) {
147  struct PP_Rect position;
148  struct InstanceInfo* info = FindInstance(pp_instance);
149  if (!info)
150    return;
151
152  if (g_view_interface->GetRect(view, &position) == PP_FALSE)
153    return;
154
155  if (info->last_size.width != position.size.width ||
156      info->last_size.height != position.size.height) {
157    /* Got a resize, repaint the plugin. */
158    Repaint(info, &position.size);
159    info->last_size.width = position.size.width;
160    info->last_size.height = position.size.height;
161  }
162}
163
164void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
165}
166
167PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
168                                    PP_Resource pp_url_loader) {
169  return PP_FALSE;
170}
171
172static PPP_Instance instance_interface = {
173  &Instance_DidCreate,
174  &Instance_DidDestroy,
175  &Instance_DidChangeView,
176  &Instance_DidChangeFocus,
177  &Instance_HandleDocumentLoad
178};
179
180
181/* Global entrypoints --------------------------------------------------------*/
182
183PP_EXPORT int32_t PPP_InitializeModule(PP_Module module,
184                                       PPB_GetInterface get_browser_interface) {
185  g_get_browser_interface = get_browser_interface;
186
187  g_core_interface = (const PPB_Core*)
188      get_browser_interface(PPB_CORE_INTERFACE);
189  g_instance_interface = (const PPB_Instance*)
190      get_browser_interface(PPB_INSTANCE_INTERFACE);
191  g_image_data_interface = (const PPB_ImageData*)
192      get_browser_interface(PPB_IMAGEDATA_INTERFACE);
193  g_graphics_2d_interface = (const PPB_Graphics2D*)
194      get_browser_interface(PPB_GRAPHICS_2D_INTERFACE);
195  g_view_interface = (const PPB_View*)
196      get_browser_interface(PPB_VIEW_INTERFACE);
197  if (!g_core_interface || !g_instance_interface || !g_image_data_interface ||
198      !g_graphics_2d_interface || !g_view_interface)
199    return -1;
200
201  return PP_OK;
202}
203
204PP_EXPORT void PPP_ShutdownModule() {
205}
206
207PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
208  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
209    return &instance_interface;
210  return NULL;
211}
212