1// Copyright 2013 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_rect.h"
9#include "ppapi/c/pp_resource.h"
10#include "ppapi/c/pp_size.h"
11#include "ppapi/c/ppb_core.h"
12#include "ppapi/c/ppb_graphics_2d.h"
13#include "ppapi/c/ppb_image_data.h"
14#include "ppapi/c/ppb_instance.h"
15#include "ppapi/c/ppb_view.h"
16#include "ppapi/cpp/image_data.h"
17
18#include "ppapi_simple/ps.h"
19#include "ppapi_simple/ps_context_2d.h"
20#include "ppapi_simple/ps_event.h"
21#include "ppapi_simple/ps_instance.h"
22#include "ppapi_simple/ps_interface.h"
23
24PSContext2D_t* PSContext2DAllocate(PP_ImageDataFormat format) {
25  PSContext2D_t* ctx = (PSContext2D_t*) malloc(sizeof(PSContext2D_t));
26  memset(ctx, 0, sizeof(PSContext2D_t));
27
28  ctx->format = format;
29  return ctx;
30}
31
32void PSContext2DFree(PSContext2D_t* ctx) {
33  if (ctx->graphic_2d) {
34    PSInterfaceCore()->ReleaseResource(ctx->graphic_2d);
35    ctx->graphic_2d = 0;
36  }
37  if (ctx->image) {
38    PSInterfaceCore()->ReleaseResource(ctx->image);
39    ctx->image = 0;
40  }
41  free(ctx);
42}
43
44PP_ImageDataFormat PSContext2DGetNativeImageDataFormat() {
45  return PSInterfaceImageData()->GetNativeImageDataFormat();
46}
47
48// Update the 2D context if the message is appropriate, returning non-zero
49// if the event was consumed.
50int PSContext2DHandleEvent(PSContext2D_t* ctx, PSEvent* event) {
51  switch(event->type) {
52    case PSE_INSTANCE_DIDCHANGEVIEW: {
53      struct PP_Rect rect;
54
55      PSInterfaceView()->GetRect(event->as_resource, &rect);
56      PSInterfaceCore()->ReleaseResource(ctx->graphic_2d);
57      ctx->bound = 0;
58      ctx->width = rect.size.width;
59      ctx->height = rect.size.height;
60
61      // Create an opaque graphic context of the specified size.
62      ctx->graphic_2d =
63          PSInterfaceGraphics2D()->Create(PSGetInstanceId(), &rect.size,
64                                          PP_TRUE);
65
66      // Bind the context to so that draws will be visible.
67      if (ctx->graphic_2d) {
68        ctx->bound =
69            PSInterfaceInstance()->BindGraphics(PSGetInstanceId(),
70                                                ctx->graphic_2d);
71      }
72
73      // Typically this resource would not be allocated yet, but just in case
74      // throw it away, to force a new allocation when GetBuffer is called.
75      if (ctx->image) {
76        PSInterfaceCore()->ReleaseResource(ctx->image);
77        ctx->image = 0;
78      }
79
80      return 1;
81    }
82    default: break;
83  }
84
85  return 0;
86}
87
88
89// Allocates (if needed) a new image context which will be swapped in when
90// drawing is complete.  PSContextGetBuffer and PSContext2DSwapBuffer
91// implemented the suggested image/graphic_2d use specified in the
92// ppb_graphics_2d header.
93int PSContext2DGetBuffer(PSContext2D_t* ctx) {
94  if (!ctx->bound) return 0;
95
96  // Check if we are already holding an image
97  if (ctx->image) return 1;
98
99  PP_Size size;
100  size.width = ctx->width;
101  size.height = ctx->height;
102
103  // Allocate a new image resource with the specified size and format, but
104  // do not ZERO out the buffer first since we will fill it.
105  PP_Resource image =
106      PSInterfaceImageData()->Create(PSGetInstanceId(), ctx->format, &size,
107                                     PP_FALSE);
108
109  if (0 == image) {
110    PSInstance::GetInstance()->Error("Unable to create 2D image.\n");
111    return 0;
112  }
113
114  // Get the stride
115  struct PP_ImageDataDesc desc;
116  PSInterfaceImageData()->Describe(image, &desc);
117
118  ctx->image = image;
119  ctx->data = static_cast<uint32_t*>(PSInterfaceImageData()->Map(image));
120  ctx->stride = desc.stride;
121  return 1;
122}
123
124int PSContext2DSwapBuffer(PSContext2D_t* ctx) {
125  if (ctx->bound && ctx->image) {
126    PSInterfaceImageData()->Unmap(ctx->image);
127    PSInterfaceGraphics2D()->ReplaceContents(ctx->graphic_2d, ctx->image);
128    PSInterfaceGraphics2D()->Flush(ctx->graphic_2d, PP_BlockUntilComplete());
129    PSInterfaceCore()->ReleaseResource(ctx->image);
130
131    ctx->image = 0;
132    ctx->stride = 0;
133    ctx->data = NULL;
134    return 1;
135  }
136  return 0;
137}
138
139