Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: examples/graphics/life/life.cc

Issue 6286025: Port the Life example to Pepper 2. (Closed) Base URL: http://naclports.googlecode.com/svn/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
1 // Copyright 2010 The Native Client SDK Authors. All rights reserved. 1 // Copyright 2011 The Native Client SDK Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can 2 // Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file. 3 // be found in the LICENSE file.
4 4
5 #include <assert.h> 5 #include "examples/graphics/life/life.h"
6 #include <math.h> 6
7 #include <stdlib.h> 7 #include <ppapi/cpp/completion_callback.h>
8 #include <string.h> 8 #include <ppapi/cpp/var.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <cassert>
12 #include <cmath>
13 #include <cstdio>
14 #include <cstring>
11 #include <string> 15 #include <string>
12 16
13 #include <nacl/nacl_npapi.h> 17 namespace {
14 #include <nacl/npapi_extensions.h> 18 // seed for rand_r() - we only call rand_r from main thread.
15 #include <nacl/npupp.h> 19 const uint32_t kInitialBrandSeed = 0xC0DE533D;
dmichael(do not use this one) 2011/02/02 23:03:59 I think 'Brand' is kind of confusing; brand is a
David Springer 2011/02/03 18:12:27 Done.
16 20
17 #define JS_LOG(msg) \ 21 const char* const kUpdateMethodId = "update";
18 const size_t line_number = __LINE__; \ 22 const char* const kAddCellAtPointMethodId = "addCellAtPoint";
19 size_t len = floor(line_number) + 1; \
20 len = std::string(msg).size() + strlen(__FILE__) + len + 5; \
21 char buffer[len]; \
22 memset(buffer, 0, len); \
23 snprintf(buffer, len, "%s:%i - ", __FILE__, line_number); \
24 strncat(buffer, std::string(msg).c_str(), len - strlen(buffer)); \
25 Log(npp_, buffer);
26
27 namespace {
28 // Log given message to javascript console.
29 bool Log(NPP npp, const char* msg, ...) {
30 bool rv = false;
31 NPObject* window = NULL;
32 if (NPERR_NO_ERROR == NPN_GetValue(npp, NPNVWindowNPObject, &window)) {
33 const char buffer[] = "top.console";
34 NPString console_stript = { 0 };
35 console_stript.UTF8Length = strlen(buffer);
36 console_stript.UTF8Characters = buffer;
37 NPVariant console;
38 if (NPN_Evaluate(npp, window, &console_stript, &console)) {
39 if (NPVARIANT_IS_OBJECT(console)) {
40 // Convert the message to NPString;
41 NPVariant text;
42 STRINGN_TO_NPVARIANT(msg, static_cast<uint32_t>(strlen(msg)),
43 text);
44 NPVariant result;
45 if (NPN_Invoke(npp, NPVARIANT_TO_OBJECT(console),
46 NPN_GetStringIdentifier("log"), &text, 1, &result)) {
47 NPN_ReleaseVariantValue(&result);
48 rv = true;
49 }
50 }
51 NPN_ReleaseVariantValue(&console);
52 }
53 }
54 return rv;
55 }
56
57 // seed for rand_r() - we only call rand_r from main thread.
58 static unsigned int gSeed = 0xC0DE533D;
59
60 // random number helper
61 // binary rand() returns 0 or 1
62 inline unsigned char brand() {
63 return static_cast<unsigned char>(rand_r(&gSeed) & 1);
64 }
65 23
66 inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { 24 inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
67 return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)); 25 return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
68 } 26 }
69 27
70 void FlushCallback(NPP instance, NPDeviceContext* context, 28 void FlushCallback(void* data, int32_t result) {
71 NPError err, void* user_data) { 29 static_cast<life::Life*>(data)->set_flush_pending(false);
72 } 30 }
31 } // namespace
73 32
74 void* life(void* data); 33 namespace life {
75 34 Life::Life(PP_Instance instance) : pp::Instance(instance),
76 // Life class holds information and functionality needed to render 35 graphics_2d_context_(NULL),
77 // life into an Pepper 2D surface. 36 pixel_buffer_(NULL),
78 class Life : public NPObject { 37 flush_pending_(false),
79 public: 38 brand_seed_(kInitialBrandSeed),
80 Life(NPP npp); 39 cell_in_(NULL),
81 ~Life(); 40 cell_out_(NULL) {
82 NPError SetWindow(NPWindow* window);
83 void Update();
84 void Plot(int x, int y);
85 void Stir();
86 void Draw();
87 void UpdateCells();
88 void Swap();
89 void HandleEvent(NPPepperEvent* event);
90
91 private:
92 void CreateContext();
93 void DestroyContext();
94 bool IsContextValid() {
95 return context2d_.region != NULL;
96 }
97 int width() const {
98 return width_;
99 }
100 int height() const {
101 return height_;
102 }
103 void* pixels() {
104 return context2d_.region;
105 }
106
107 NPP npp_;
108 NPExtensions* extensions_;
109 int width_, height_;
110 NPDevice* device2d_; // The PINPAPI 2D device.
111 NPDeviceContext2D context2d_; // The PINPAPI 2D drawing context.
112 bool scribble_;
113 bool quit_;
114 char *cell_in_;
115 char *cell_out_;
116 };
117
118 Life::Life(NPP npp) : npp_(npp), extensions_(NULL), width_(0), height_(0),
119 device2d_(NULL), cell_in_(NULL), cell_out_(NULL) {
120 memset(&context2d_, 0, sizeof(context2d_));
121 NPN_GetValue(npp_, NPNVPepperExtensions, &extensions_);
122 device2d_ = extensions_->acquireDevice(npp_, NPPepper2DDevice);
123 assert(extensions_);
124 } 41 }
125 42
126 Life::~Life() { 43 Life::~Life() {
127 delete[] cell_in_; 44 delete[] cell_in_;
128 delete[] cell_out_; 45 delete[] cell_out_;
129 DestroyContext(); 46 DestroyContext();
47 delete pixel_buffer_;
130 } 48 }
131 49
132 void Life::CreateContext() { 50 pp::Var Life::GetInstanceObject() {
133 if (IsContextValid()) 51 LifeScriptObject* script_object = new LifeScriptObject(this);
134 return; 52 return pp::Var(this, script_object);
135 device2d_ = extensions_->acquireDevice(npp_, NPPepper2DDevice);
136 assert(device2d_);
137 NPDeviceContext2DConfig config;
138 NPError init_err = device2d_->initializeContext(npp_, &config, &context2d_);
139 assert(NPERR_NO_ERROR == init_err);
140 } 53 }
141 54
142 void Life::HandleEvent(NPPepperEvent* event) { 55 bool Life::Init(uint32_t argc, const char* argn[], const char* argv[]) {
143 bool plot = false; 56 return true;
144 if (event->type == NPEventType_MouseDown) {
145 scribble_ = true;
146 plot = true;
147 }
148 if (event->type == NPEventType_MouseUp) {
149 JS_LOG("MouseUp event");
150 scribble_ = false;
151 }
152 if (event->type == NPEventType_MouseMove) {
153 plot = scribble_;
154 }
155 if (plot) {
156 // place a blob of life
157 Plot(event->u.mouse.x - 1, event->u.mouse.y - 1);
158 Plot(event->u.mouse.x + 0, event->u.mouse.y - 1);
159 Plot(event->u.mouse.x + 1, event->u.mouse.y - 1);
160 Plot(event->u.mouse.x - 1, event->u.mouse.y + 0);
161 Plot(event->u.mouse.x + 0, event->u.mouse.y + 0);
162 Plot(event->u.mouse.x + 1, event->u.mouse.y + 0);
163 Plot(event->u.mouse.x - 1, event->u.mouse.y + 1);
164 Plot(event->u.mouse.x + 0, event->u.mouse.y + 1);
165 Plot(event->u.mouse.x + 1, event->u.mouse.y + 1);
166 }
167 }
168
169 void Life::DestroyContext() {
170 if (!IsContextValid())
171 return;
172 device2d_->destroyContext(npp_, &context2d_);
173 } 57 }
174 58
175 void Life::Plot(int x, int y) { 59 void Life::Plot(int x, int y) {
60 if (cell_in_ == NULL)
61 return;
176 if (x < 0) return; 62 if (x < 0) return;
177 if (x >= width()) return; 63 if (x >= width()) return;
178 if (y < 0) return; 64 if (y < 0) return;
179 if (y >= height()) return; 65 if (y >= height()) return;
180 *(cell_in_ + x + y * width()) = 1; 66 *(cell_in_ + x + y * width()) = 1;
181 } 67 }
182 68
183 NPError Life::SetWindow(NPWindow* window) { 69 void Life::DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
184 if (!window) 70 if (position.size().width() == width() &&
185 return NPERR_NO_ERROR; 71 position.size().height() == height())
186 width_ = window->width; 72 return; // Size didn't change, no need to update anything.
187 height_ = window->height;
188 if (!IsContextValid())
189 CreateContext();
190 73
191 const size_t size = width() * height(); 74 // Create a new device context with the new size.
75 DestroyContext();
76 CreateContext(position.size());
77 // Delete the old pixel buffer and create a new one.
78 delete pixel_buffer_;
192 delete[] cell_in_; 79 delete[] cell_in_;
193 delete[] cell_out_; 80 delete[] cell_out_;
194 cell_in_ = new char[size]; 81 pixel_buffer_ = NULL;
195 cell_out_ = new char[size]; 82 cell_in_ = cell_out_ = NULL;
196 std::fill(cell_in_, cell_in_ + size, 0); 83 if (graphics_2d_context_ != NULL) {
197 std::fill(cell_out_, cell_out_ + size, 0); 84 pixel_buffer_ = new pp::ImageData(this,
198 85 PP_IMAGEDATAFORMAT_BGRA_PREMUL,
199 NPDeviceFlushContextCallbackPtr callback = 86 graphics_2d_context_->size(),
200 reinterpret_cast<NPDeviceFlushContextCallbackPtr>(&FlushCallback); 87 false);
201 device2d_->flushContext(npp_, &context2d_, callback, NULL); 88 const size_t size = width() * height();
202 return NPERR_NO_ERROR; 89 cell_in_ = new uint8_t[size];
90 cell_out_ = new uint8_t[size];
91 std::fill(cell_in_, cell_in_ + size, 0);
92 std::fill(cell_out_, cell_out_ + size, 0);
93 }
203 } 94 }
204 95
205 void Life::Update() { 96 void Life::Update() {
206 Stir(); 97 Stir();
207 UpdateCells(); 98 UpdateCells();
208 Swap(); 99 Swap();
209 NPDeviceFlushContextCallbackPtr callback = 100 FlushPixelBuffer();
210 reinterpret_cast<NPDeviceFlushContextCallbackPtr>(&FlushCallback); 101 }
211 device2d_->flushContext(npp_, &context2d_, callback, NULL); 102
103 void Life::AddCellAtPoint(const pp::Var& var_x, const pp::Var& var_y) {
104 if (!var_x.is_number() || !var_y.is_number())
105 return;
106 int32_t x, y;
107 x = var_x.is_int() ? var_x.AsInt() : static_cast<int32_t>(var_x.AsDouble());
108 y = var_y.is_int() ? var_y.AsInt() : static_cast<int32_t>(var_y.AsDouble());
109 Plot(x - 1, y - 1);
110 Plot(x + 0, y - 1);
111 Plot(x + 1, y - 1);
112 Plot(x - 1, y + 0);
113 Plot(x + 0, y + 0);
114 Plot(x + 1, y + 0);
115 Plot(x - 1, y + 1);
116 Plot(x + 0, y + 1);
117 Plot(x + 1, y + 1);
212 } 118 }
213 119
214 void Life::Stir() { 120 void Life::Stir() {
121 if (cell_in_ == NULL || cell_out_ == NULL)
122 return;
215 const int height = this->height(); 123 const int height = this->height();
216 const int width = this->width(); 124 const int width = this->width();
217 for (int i = 0; i < width; ++i) { 125 for (int i = 0; i < width; ++i) {
218 cell_in_[i] = brand(); 126 cell_in_[i] = brand();
dmichael(do not use this one) 2011/02/02 23:03:59 We're throwing away probably 30 bits of randomness
David Springer 2011/02/03 18:12:27 OK. How about we revisit this in another CL? Wan
219 cell_in_[i + (height - 1) * width] = brand(); 127 cell_in_[i + (height - 1) * width] = brand();
220 } 128 }
221 for (int i = 0; i < height; ++i) { 129 for (int i = 0; i < height; ++i) {
222 cell_in_[i * width] = brand(); 130 cell_in_[i * width] = brand();
223 cell_in_[i * width + (width - 2)] = brand(); 131 cell_in_[i * width + (width - 2)] = brand();
dmichael(do not use this one) 2011/02/02 23:03:59 I would've expected it to be width - 1... probabl
David Springer 2011/02/03 18:12:27 The right-most cells have to start 1 pixel in from
dmichael(do not use this one) 2011/02/03 20:08:44 I don't understand why the last column should be t
224 } 132 }
225 } 133 }
226 134
227 void Life::UpdateCells() { 135 void Life::UpdateCells() {
228 // map neighbor count to color 136 // Map neighbor count to color
229 static unsigned int colors[18] = { 137 static uint32_t colors[18] = {
230 MakeRGBA(0x00, 0x00, 0x00, 0xff), 138 MakeRGBA(0x00, 0x00, 0x00, 0xff),
231 MakeRGBA(0x00, 0x40, 0x00, 0xff), 139 MakeRGBA(0x00, 0x40, 0x00, 0xff),
232 MakeRGBA(0x00, 0x60, 0x00, 0xff), 140 MakeRGBA(0x00, 0x60, 0x00, 0xff),
233 MakeRGBA(0x00, 0x80, 0x00, 0xff), 141 MakeRGBA(0x00, 0x80, 0x00, 0xff),
234 MakeRGBA(0x00, 0xA0, 0x00, 0xff), 142 MakeRGBA(0x00, 0xA0, 0x00, 0xff),
235 MakeRGBA(0x00, 0xC0, 0x00, 0xff), 143 MakeRGBA(0x00, 0xC0, 0x00, 0xff),
236 MakeRGBA(0x00, 0xE0, 0x00, 0xff), 144 MakeRGBA(0x00, 0xE0, 0x00, 0xff),
237 MakeRGBA(0x00, 0x00, 0x00, 0xff), 145 MakeRGBA(0x00, 0x00, 0x00, 0xff),
238 MakeRGBA(0x00, 0x40, 0x00, 0xff), 146 MakeRGBA(0x00, 0x40, 0x00, 0xff),
239 MakeRGBA(0x00, 0x60, 0x00, 0xff), 147 MakeRGBA(0x00, 0x60, 0x00, 0xff),
240 MakeRGBA(0x00, 0x80, 0x00, 0xff), 148 MakeRGBA(0x00, 0x80, 0x00, 0xff),
241 MakeRGBA(0x00, 0xA0, 0x00, 0xff), 149 MakeRGBA(0x00, 0xA0, 0x00, 0xff),
242 MakeRGBA(0x00, 0xC0, 0x00, 0xff), 150 MakeRGBA(0x00, 0xC0, 0x00, 0xff),
243 MakeRGBA(0x00, 0xE0, 0x00, 0xff), 151 MakeRGBA(0x00, 0xE0, 0x00, 0xff),
244 MakeRGBA(0x00, 0xFF, 0x00, 0xff), 152 MakeRGBA(0x00, 0xFF, 0x00, 0xff),
245 MakeRGBA(0x00, 0xFF, 0x00, 0xff), 153 MakeRGBA(0x00, 0xFF, 0x00, 0xff),
246 MakeRGBA(0x00, 0xFF, 0x00, 0xff), 154 MakeRGBA(0x00, 0xFF, 0x00, 0xff),
247 MakeRGBA(0x00, 0xFF, 0x00, 0xff), 155 MakeRGBA(0x00, 0xFF, 0x00, 0xff),
dmichael(do not use this one) 2011/02/02 23:03:59 If we care about performance, we may want to avoid
David Springer 2011/02/03 18:12:27 Done.
248 }; 156 };
249 // map neighbor count to alive/dead 157 // Map neighbor count to alive/dead.
250 static char replace[18] = { 158 static uint8_t replace[18] = {
dmichael(do not use this one) 2011/02/02 23:03:59 Why 18? 17 should suffice, as written.
David Springer 2011/02/03 18:12:27 It turns out that |count| (below) has range [0..17
251 0, 0, 0, 1, 0, 0, 0, 0, // row for center cell dead 159 0, 0, 0, 1, 0, 0, 0, 0, // row for center cell dead
252 0, 0, 1, 1, 0, 0, 0, 0, // row for center cell alive 160 0, 0, 1, 1, 0, 0, 0, 0, // row for center cell alive
dmichael(do not use this one) 2011/02/02 23:03:59 The first 0 in this row could be dead center, all
David Springer 2011/02/03 18:12:27 Good catch. I ported this without trying to under
253 }; 161 };
162 if (cell_in_ == NULL || cell_out_ == NULL || pixels() == NULL)
163 return;
254 const int height = this->height(); 164 const int height = this->height();
255 const int width = this->width(); 165 const int width = this->width();
256 // do neighbor sumation; apply rules, output pixel color 166 // do neighbor sumation; apply rules, output pixel color
257 for (int y = 1; y < (height - 1); ++y) { 167 for (int y = 1; y < (height - 1); ++y) {
258 char *src0 = cell_in_ + (y - 1) * width; 168 uint8_t *src0 = cell_in_ + (y - 1) * width;
259 char *src1 = cell_in_ + (y) * width; 169 uint8_t *src1 = cell_in_ + (y) * width;
260 char *src2 = cell_in_ + (y + 1) * width; 170 uint8_t *src2 = cell_in_ + (y + 1) * width;
261 int count; 171 int count;
262 unsigned int color; 172 uint32_t color;
263 char *dst = cell_out_ + (y) * width; 173 uint8_t *dst = cell_out_ + (y) * width;
264 uint32_t *pixels = static_cast<uint32_t*>(this->pixels()) + y * width; 174 uint32_t *pixel_buffer = pixels() + y * width;
265 for (int x = 1; x < (width - 1); ++x) { 175 for (int x = 1; x < (width - 1); ++x) {
266 // build sum, weight center by 8x 176 // build sum, weight center by 8x
267 count = src0[-1] + src0[0] + src0[1] + 177 count = src0[-1] + src0[0] + src0[1] +
268 src1[-1] + src1[0] * 8 + src1[1] + 178 src1[-1] + src1[0] * 8 + src1[1] +
269 src2[-1] + src2[0] + src2[1]; 179 src2[-1] + src2[0] + src2[1];
dmichael(do not use this one) 2011/02/02 23:03:59 Seems like dead center with all neighbors alive is
David Springer 2011/02/03 18:12:27 Interesting observation. Comment added.
270 color = colors[count]; 180 color = colors[count];
271 *pixels++ = color; 181 *pixel_buffer++ = color;
272 *dst++ = replace[count]; 182 *dst++ = replace[count];
273 ++src0, ++src1, ++src2; 183 ++src0, ++src1, ++src2;
274 } 184 }
275 } 185 }
276 } 186 }
277 187
278 void Life::Swap() { 188 void Life::Swap() {
279 char* tmp = cell_in_; 189 uint8_t* tmp = cell_in_;
280 cell_in_ = cell_out_; 190 cell_in_ = cell_out_;
281 cell_out_ = tmp; 191 cell_out_ = tmp;
282 } 192 }
283 193
284 extern "C" { 194 void Life::CreateContext(const pp::Size& size) {
285 195 if (IsContextValid())
286 // The following functions implement functions to be used with npruntime. 196 return;
287 static NPObject* AllocateLife(NPP npp, NPClass* npclass) { 197 graphics_2d_context_ = new pp::Graphics2D(this, size, false);
288 Life* rv = new Life(npp); 198 if (!BindGraphics(*graphics_2d_context_)) {
289 return rv; 199 printf("Couldn't bind the device context\n");
200 }
290 } 201 }
291 202
292 static void Deallocate(NPObject* obj) { 203 void Life::DestroyContext() {
293 Life* const life = static_cast<Life*>(obj); 204 if (!IsContextValid())
294 delete life; 205 return;
206 delete graphics_2d_context_;
207 graphics_2d_context_ = NULL;
295 } 208 }
296 209
297 // These are for npruntime. 210 void Life::FlushPixelBuffer() {
298 static void Invalidate(NPObject*) { 211 if (!IsContextValid())
212 return;
213 graphics_2d_context_->PaintImageData(*pixel_buffer_, pp::Point());
214 if (flush_pending())
215 return;
216 set_flush_pending(true);
217 graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
299 } 218 }
300 219
301 static bool HasMethod(NPObject*, NPIdentifier name) { 220 bool Life::LifeScriptObject::HasMethod(
302 bool rv = false; 221 const pp::Var& method,
303 NPUTF8* method_name = NPN_UTF8FromIdentifier(name); 222 pp::Var* exception) {
304 if (0 == memcmp(method_name, "update", sizeof("update"))) { 223 if (!method.is_string()) {
305 rv = true; 224 return false;
306 } 225 }
307 NPN_MemFree(method_name); 226 std::string method_name = method.AsString();
308 return rv; 227 return method_name == kUpdateMethodId ||
228 method_name == kAddCellAtPointMethodId;
309 } 229 }
310 230
311 static bool Invoke(NPObject *obj, NPIdentifier name, const NPVariant *args, 231 pp::Var Life::LifeScriptObject::Call(
312 uint32_t argc, NPVariant *result) { 232 const pp::Var& method,
313 bool rv = false; 233 const std::vector<pp::Var>& args,
314 NPUTF8* method_name = NPN_UTF8FromIdentifier(name); 234 pp::Var* exception) {
315 if (0 == memcmp(method_name, "update", sizeof("update"))) { 235 if (!method.is_string()) {
316 rv = true; 236 return pp::Var(false);
317 Life* const life = static_cast<Life*>(obj);
318 life->Update();
319 } 237 }
320 NPN_MemFree(method_name); 238 std::string method_name = method.AsString();
321 return rv; 239 if (app_instance_ != NULL) {
240 if (method_name == kUpdateMethodId) {
241 app_instance_->Update();
242 } else if (method_name == kAddCellAtPointMethodId) {
243 // Pull off the first two params.
244 if (args.size() < 2)
245 return pp::Var(false);
246 app_instance_->AddCellAtPoint(args[0], args[1]);
247 }
248 }
249 return pp::Var();
322 } 250 }
323 251
324 static bool InvokeDefault(NPObject *npobj, const NPVariant *args, 252 } // namespace life
325 uint32_t argCount, NPVariant *result) {
326 return false;
327 }
328
329 static bool HasProperty(NPObject *npobj, NPIdentifier name) {
330 return false;
331 }
332
333 static bool GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) {
334 return false;
335 }
336
337 static bool SetProperty(NPObject *npobj, NPIdentifier name,
338 const NPVariant *value) {
339 return false;
340 }
341
342 static bool RemoveProperty(NPObject *npobj, NPIdentifier name) {
343 return false;
344 }
345
346 NPClass np_class = {
347 NP_CLASS_STRUCT_VERSION,
348 AllocateLife,
349 Deallocate,
350 Invalidate,
351 HasMethod,
352 Invoke,
353 InvokeDefault,
354 HasProperty,
355 GetProperty,
356 SetProperty,
357 RemoveProperty
358 };
359
360 // These functions are required by both the develop and publish versions,
361 // they are called when a module instance is first loaded, and when the module
362 // instance is finally deleted. They must use C-style linkage.
363 NPError NPP_Destroy(NPP instance, NPSavedData** save) {
364 if (instance == NULL) {
365 return NPERR_INVALID_INSTANCE_ERROR;
366 }
367
368 Life* life = static_cast<Life*>(instance->pdata);
369 if (life != NULL) {
370 NPN_ReleaseObject(life);
371 }
372 return NPERR_NO_ERROR;
373 }
374
375 // NPP_GetScriptableInstance retruns the NPObject pointer that corresponds to
376 // NPPVpluginScriptableNPObject queried by NPP_GetValue() from the browser.
377 NPObject* NPP_GetScriptableInstance(NPP instance) {
378 if (instance == NULL) {
379 return NULL;
380 }
381 Life* life = static_cast<Life*>(instance->pdata);
382 return life;
383 }
384
385 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
386 if (NPPVpluginScriptableNPObject == variable) {
387 NPObject* scriptable_object = NPP_GetScriptableInstance(instance);
388 if (scriptable_object == NULL)
389 return NPERR_INVALID_INSTANCE_ERROR;
390 *reinterpret_cast<NPObject**>(value) = scriptable_object;
391 return NPERR_NO_ERROR;
392 }
393 return NPERR_INVALID_PARAM;
394 }
395
396 int16_t NPP_HandleEvent(NPP instance, void* event) {
397 Life* life = static_cast<Life*>(instance->pdata);
398 if (NULL != life) {
399 NPPepperEvent* npevent = static_cast<NPPepperEvent*>(event);
400 life->HandleEvent(npevent);
401 }
402 return 0;
403 }
404
405 NPError NPP_New(NPMIMEType mime_type,
406 NPP instance,
407 uint16_t mode,
408 int16_t argc,
409 char* argn[],
410 char* argv[],
411 NPSavedData* saved) {
412 if (instance == NULL) {
413 return NPERR_INVALID_INSTANCE_ERROR;
414 }
415
416 Life* const life = static_cast<Life*>(NPN_CreateObject(instance, &np_class));
417 instance->pdata = life;
418 return NPERR_NO_ERROR;
419 }
420
421 NPError NPP_SetWindow(NPP instance, NPWindow* window) {
422 if (instance == NULL) {
423 return NPERR_INVALID_INSTANCE_ERROR;
424 }
425 if (window == NULL) {
426 return NPERR_GENERIC_ERROR;
427 }
428 Life* life = static_cast<Life*>(instance->pdata);
429 if (life != NULL) {
430 return life->SetWindow(window);
431 }
432 return NPERR_NO_ERROR;
433 }
434
435 NPError NP_GetEntryPoints(NPPluginFuncs* plugin_funcs) {
436 extern NPError InitializePluginFunctions(NPPluginFuncs* plugin_funcs);
437 return InitializePluginFunctions(plugin_funcs);
438 }
439
440 NPError InitializePluginFunctions(NPPluginFuncs* plugin_funcs) {
441 memset(plugin_funcs, 0, sizeof(*plugin_funcs));
442 plugin_funcs->version = NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL;
443 plugin_funcs->size = sizeof(*plugin_funcs);
444 plugin_funcs->newp = NPP_New;
445 plugin_funcs->destroy = NPP_Destroy;
446 plugin_funcs->setwindow = NPP_SetWindow;
447 plugin_funcs->event = NPP_HandleEvent;
448 plugin_funcs->getvalue = NPP_GetValue;
449 return NPERR_NO_ERROR;
450 }
451
452 NPError NP_Initialize(NPNetscapeFuncs* browser_functions,
453 NPPluginFuncs* plugin_functions) {
454 return NP_GetEntryPoints(plugin_functions);
455 }
456
457 NPError NP_Shutdown() {
458 return NPERR_NO_ERROR;
459 }
460
461 } // extern "C"
462 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698