OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <math.h> | 5 #include "ppapi/c/pp_errors.h" |
6 #include <stdio.h> // FIXME(brettw) erase me. | 6 #include "ppapi/cpp/input_event.h" |
7 #ifndef _WIN32 | 7 #include "ppapi/cpp/instance.h" |
8 #include <sys/time.h> | 8 #include "ppapi/cpp/module.h" |
9 #else | 9 #include "ppapi/utility/completion_callback_factory.h" |
10 #include <windows.h> | 10 #include "ppapi/utility/threading/simple_thread.h" |
11 #endif | |
12 #include <time.h> | |
13 | 11 |
14 #include <algorithm> | 12 class MyInstance : public pp::Instance { |
15 | |
16 #include "ppapi/c/dev/ppb_console_dev.h" | |
17 #include "ppapi/c/dev/ppb_cursor_control_dev.h" | |
18 #include "ppapi/c/dev/ppp_printing_dev.h" | |
19 #include "ppapi/c/pp_errors.h" | |
20 #include "ppapi/c/pp_rect.h" | |
21 #include "ppapi/cpp/completion_callback.h" | |
22 #include "ppapi/cpp/dev/memory_dev.h" | |
23 #include "ppapi/cpp/dev/scriptable_object_deprecated.h" | |
24 #include "ppapi/cpp/graphics_2d.h" | |
25 #include "ppapi/cpp/image_data.h" | |
26 #include "ppapi/cpp/input_event.h" | |
27 #include "ppapi/cpp/private/instance_private.h" | |
28 #include "ppapi/cpp/module.h" | |
29 #include "ppapi/cpp/private/var_private.h" | |
30 #include "ppapi/cpp/rect.h" | |
31 #include "ppapi/cpp/url_loader.h" | |
32 #include "ppapi/cpp/url_request_info.h" | |
33 #include "ppapi/cpp/var.h" | |
34 #include "ppapi/utility/completion_callback_factory.h" | |
35 | |
36 static const int kStepsPerCircle = 800; | |
37 | |
38 void FlushCallback(void* data, int32_t result); | |
39 | |
40 void FillRect(pp::ImageData* image, int left, int top, int width, int height, | |
41 uint32_t color) { | |
42 for (int y = std::max(0, top); | |
43 y < std::min(image->size().height() - 1, top + height); | |
44 y++) { | |
45 for (int x = std::max(0, left); | |
46 x < std::min(image->size().width() - 1, left + width); | |
47 x++) | |
48 *image->GetAddr32(pp::Point(x, y)) = color; | |
49 } | |
50 } | |
51 | |
52 class MyScriptableObject : public pp::deprecated::ScriptableObject { | |
53 public: | 13 public: |
54 explicit MyScriptableObject(pp::InstancePrivate* instance) | 14 MyInstance(PP_Instance instance) : pp::Instance(instance) { |
55 : instance_(instance) {} | 15 thread_ = new pp::SimpleThread(this); |
56 | 16 factory_.Initialize(this); |
57 virtual bool HasMethod(const pp::Var& method, pp::Var* exception) { | |
58 return method.AsString() == "toString"; | |
59 } | 17 } |
60 | 18 |
61 virtual bool HasProperty(const pp::Var& name, pp::Var* exception) { | 19 virtual ~MyInstance() { |
62 if (name.is_string() && name.AsString() == "blah") | 20 delete thread_; |
63 return true; | |
64 return false; | |
65 } | 21 } |
66 | 22 |
67 virtual pp::Var GetProperty(const pp::Var& name, pp::Var* exception) { | 23 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { |
68 if (name.is_string() && name.AsString() == "blah") | 24 thread_->Start(); |
69 return pp::VarPrivate(instance_, new MyScriptableObject(instance_)); | 25 thread_->message_loop().PostWork( |
70 return pp::Var(); | 26 factory_.NewCallback(&MyInstance::CallOnBackground)); |
27 return true; | |
71 } | 28 } |
72 | 29 |
73 virtual void GetAllPropertyNames(std::vector<pp::Var>* names, | 30 virtual void DidChangeView(const pp::View& view) { |
74 pp::Var* exception) { | |
75 names->push_back("blah"); | |
76 } | |
77 | |
78 virtual pp::Var Call(const pp::Var& method, | |
79 const std::vector<pp::Var>& args, | |
80 pp::Var* exception) { | |
81 if (method.AsString() == "toString") | |
82 return pp::Var("hello world"); | |
83 return pp::Var(); | |
84 } | 31 } |
85 | 32 |
86 private: | 33 private: |
87 pp::InstancePrivate* instance_; | 34 void CallOnBackground(int32_t result) { |
35 } | |
36 | |
37 pp::CompletionCallbackFactory<MyInstance> factory_; | |
38 | |
39 pp::SimpleThread* thread_; | |
dmichael (off chromium)
2012/02/21 23:38:02
I'm guessing the changes in this file weren't mean
| |
88 }; | 40 }; |
89 | 41 |
90 class MyFetcherClient { | |
91 public: | |
92 virtual void DidFetch(bool success, const std::string& data) = 0; | |
93 }; | |
94 | |
95 class MyFetcher { | |
96 public: | |
97 MyFetcher() : client_(NULL) { | |
98 callback_factory_.Initialize(this); | |
99 } | |
100 | |
101 void Start(const pp::InstancePrivate& instance, | |
102 const pp::Var& url, | |
103 MyFetcherClient* client) { | |
104 pp::URLRequestInfo request; | |
105 request.SetURL(url); | |
106 request.SetMethod("GET"); | |
107 | |
108 loader_ = pp::URLLoader(instance); | |
109 client_ = client; | |
110 | |
111 pp::CompletionCallback callback = | |
112 callback_factory_.NewOptionalCallback(&MyFetcher::DidOpen); | |
113 int rv = loader_.Open(request, callback); | |
114 if (rv != PP_OK_COMPLETIONPENDING) | |
115 callback.Run(rv); | |
116 } | |
117 | |
118 void StartWithOpenedLoader(const pp::URLLoader& loader, | |
119 MyFetcherClient* client) { | |
120 loader_ = loader; | |
121 client_ = client; | |
122 | |
123 ReadMore(); | |
124 } | |
125 | |
126 private: | |
127 void ReadMore() { | |
128 pp::CompletionCallback callback = | |
129 callback_factory_.NewOptionalCallback(&MyFetcher::DidRead); | |
130 int rv = loader_.ReadResponseBody(buf_, sizeof(buf_), callback); | |
131 if (rv != PP_OK_COMPLETIONPENDING) | |
132 callback.Run(rv); | |
133 } | |
134 | |
135 void DidOpen(int32_t result) { | |
136 if (result == PP_OK) { | |
137 ReadMore(); | |
138 } else { | |
139 DidFinish(result); | |
140 } | |
141 } | |
142 | |
143 void DidRead(int32_t result) { | |
144 if (result > 0) { | |
145 data_.append(buf_, result); | |
146 ReadMore(); | |
147 } else { | |
148 DidFinish(result); | |
149 } | |
150 } | |
151 | |
152 void DidFinish(int32_t result) { | |
153 if (client_) | |
154 client_->DidFetch(result == PP_OK, data_); | |
155 } | |
156 | |
157 pp::CompletionCallbackFactory<MyFetcher> callback_factory_; | |
158 pp::URLLoader loader_; | |
159 MyFetcherClient* client_; | |
160 char buf_[4096]; | |
161 std::string data_; | |
162 }; | |
163 | |
164 class MyInstance : public pp::InstancePrivate, public MyFetcherClient { | |
165 public: | |
166 MyInstance(PP_Instance instance) | |
167 : pp::InstancePrivate(instance), | |
168 time_at_last_check_(0.0), | |
169 fetcher_(NULL), | |
170 width_(0), | |
171 height_(0), | |
172 animation_counter_(0), | |
173 print_settings_valid_(false), | |
174 showing_custom_cursor_(false) { | |
175 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); | |
176 } | |
177 | |
178 virtual ~MyInstance() { | |
179 if (fetcher_) { | |
180 delete fetcher_; | |
181 fetcher_ = NULL; | |
182 } | |
183 } | |
184 | |
185 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | |
186 return true; | |
187 } | |
188 | |
189 void Log(PP_LogLevel_Dev level, const pp::Var& value) { | |
190 const PPB_Console_Dev* console = reinterpret_cast<const PPB_Console_Dev*>( | |
191 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_DEV_INTERFACE)); | |
192 if (!console) | |
193 return; | |
194 console->Log(pp_instance(), level, value.pp_var()); | |
195 } | |
196 | |
197 virtual bool HandleDocumentLoad(const pp::URLLoader& loader) { | |
198 fetcher_ = new MyFetcher(); | |
199 fetcher_->StartWithOpenedLoader(loader, this); | |
200 return true; | |
201 } | |
202 | |
203 virtual bool HandleInputEvent(const pp::InputEvent& event) { | |
204 switch (event.GetType()) { | |
205 case PP_INPUTEVENT_TYPE_MOUSEDOWN: | |
206 SayHello(); | |
207 ToggleCursor(); | |
208 return true; | |
209 case PP_INPUTEVENT_TYPE_MOUSEMOVE: | |
210 return true; | |
211 case PP_INPUTEVENT_TYPE_KEYDOWN: | |
212 return true; | |
213 default: | |
214 return false; | |
215 } | |
216 } | |
217 | |
218 virtual pp::Var GetInstanceObject() { | |
219 return pp::VarPrivate(this, new MyScriptableObject(this)); | |
220 } | |
221 | |
222 pp::ImageData PaintImage(int width, int height) { | |
223 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, | |
224 pp::Size(width, height), false); | |
225 if (image.is_null()) { | |
226 printf("Couldn't allocate the image data: %d, %d\n", width, height); | |
227 return image; | |
228 } | |
229 | |
230 // Fill with semitransparent gradient. | |
231 for (int y = 0; y < image.size().height(); y++) { | |
232 char* row = &static_cast<char*>(image.data())[y * image.stride()]; | |
233 for (int x = 0; x < image.size().width(); x++) { | |
234 row[x * 4 + 0] = y; | |
235 row[x * 4 + 1] = y; | |
236 row[x * 4 + 2] = 0; | |
237 row[x * 4 + 3] = y; | |
238 } | |
239 } | |
240 | |
241 // Draw the orbiting box. | |
242 float radians = static_cast<float>(animation_counter_) / kStepsPerCircle * | |
243 2 * 3.14159265358979F; | |
244 | |
245 float radius = static_cast<float>(std::min(width, height)) / 2.0f - 3.0f; | |
246 int x = static_cast<int>(cos(radians) * radius + radius + 2); | |
247 int y = static_cast<int>(sin(radians) * radius + radius + 2); | |
248 | |
249 const uint32_t box_bgra = 0x80000000; // Alpha 50%. | |
250 FillRect(&image, x - 3, y - 3, 7, 7, box_bgra); | |
251 return image; | |
252 } | |
253 | |
254 void Paint() { | |
255 pp::ImageData image = PaintImage(width_, height_); | |
256 if (!image.is_null()) { | |
257 device_context_.ReplaceContents(&image); | |
258 device_context_.Flush(pp::CompletionCallback(&FlushCallback, this)); | |
259 } else { | |
260 printf("NullImage: %d, %d\n", width_, height_); | |
261 } | |
262 } | |
263 | |
264 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { | |
265 Log(PP_LOGLEVEL_LOG, "DidChangeView"); | |
266 if (position.size().width() == width_ && | |
267 position.size().height() == height_) | |
268 return; // We don't care about the position, only the size. | |
269 | |
270 width_ = position.size().width(); | |
271 height_ = position.size().height(); | |
272 printf("DidChangeView relevant change: width=%d height:%d\n", | |
273 width_, height_); | |
274 | |
275 device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), false); | |
276 if (!BindGraphics(device_context_)) { | |
277 printf("Couldn't bind the device context\n"); | |
278 return; | |
279 } | |
280 | |
281 Paint(); | |
282 } | |
283 | |
284 #if defined(_WIN32) | |
285 struct timeval { | |
286 long tv_sec; | |
287 long tv_usec; | |
288 }; | |
289 | |
290 struct timezone { | |
291 long x; | |
292 long y; | |
293 }; | |
294 | |
295 #define EPOCHFILETIME (116444736000000000i64) | |
296 | |
297 int gettimeofday(struct timeval *tv, struct timezone*) { | |
298 FILETIME ft; | |
299 ::GetSystemTimeAsFileTime(&ft); | |
300 LARGE_INTEGER li = {ft.dwLowDateTime, ft.dwHighDateTime}; | |
301 __int64 t = li.QuadPart - EPOCHFILETIME; | |
302 tv->tv_sec = static_cast<long>(t / 10000000); | |
303 tv->tv_usec = static_cast<long>(t % 10000000); | |
304 return 0; | |
305 } | |
306 #endif // if defined(_WIN32) | |
307 | |
308 void UpdateFps() { | |
309 pp::VarPrivate window = GetWindowObject(); | |
310 if (window.is_undefined()) | |
311 return; | |
312 pp::VarPrivate doc = window.GetProperty("document"); | |
313 pp::VarPrivate fps = doc.Call("getElementById", "fps"); | |
314 | |
315 struct timeval tv; | |
316 struct timezone tz = {0, 0}; | |
317 gettimeofday(&tv, &tz); | |
318 | |
319 double time_now = tv.tv_sec + tv.tv_usec / 1000000.0; | |
320 | |
321 if (animation_counter_ > 0) { | |
322 char fps_text[64]; | |
323 sprintf(fps_text, "%g fps", | |
324 kStepsPerCircle / (time_now - time_at_last_check_)); | |
325 fps.SetProperty("innerHTML", fps_text); | |
326 } | |
327 | |
328 time_at_last_check_ = time_now; | |
329 } | |
330 | |
331 // Print interfaces. | |
332 // TODO(mball,dmichael) Replace this with the PPP_PRINTING_DEV_USE_0_4 version | |
333 virtual PP_PrintOutputFormat_Dev* QuerySupportedPrintOutputFormats( | |
334 uint32_t* format_count) { | |
335 pp::Memory_Dev memory; | |
336 PP_PrintOutputFormat_Dev* format = | |
337 static_cast<PP_PrintOutputFormat_Dev*>( | |
338 memory.MemAlloc(sizeof(PP_PrintOutputFormat_Dev))); | |
339 *format = PP_PRINTOUTPUTFORMAT_RASTER; | |
340 *format_count = 1; | |
341 return format; | |
342 } | |
343 | |
344 virtual int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) { | |
345 if (print_settings_.format != PP_PRINTOUTPUTFORMAT_RASTER) | |
346 return 0; | |
347 | |
348 print_settings_ = print_settings; | |
349 print_settings_valid_ = true; | |
350 return 1; | |
351 } | |
352 | |
353 virtual pp::Resource PrintPages( | |
354 const PP_PrintPageNumberRange_Dev* page_ranges, | |
355 uint32_t page_range_count) { | |
356 if (!print_settings_valid_) | |
357 return pp::Resource(); | |
358 | |
359 if (page_range_count != 1) | |
360 return pp::Resource(); | |
361 | |
362 // Check if the page numbers are valid. We returned 1 in PrintBegin so we | |
363 // only have 1 page to print. | |
364 if (page_ranges[0].first_page_number || page_ranges[0].last_page_number) { | |
365 return pp::Resource(); | |
366 } | |
367 | |
368 int width = static_cast<int>( | |
369 (print_settings_.printable_area.size.width / 72.0) * | |
370 print_settings_.dpi); | |
371 int height = static_cast<int>( | |
372 (print_settings_.printable_area.size.height / 72.0) * | |
373 print_settings_.dpi); | |
374 | |
375 return PaintImage(width, height); | |
376 } | |
377 | |
378 virtual void PrintEnd() { | |
379 print_settings_valid_ = false; | |
380 } | |
381 | |
382 void OnFlush() { | |
383 if (animation_counter_ % kStepsPerCircle == 0) | |
384 UpdateFps(); | |
385 animation_counter_++; | |
386 Paint(); | |
387 } | |
388 | |
389 private: | |
390 void SayHello() { | |
391 pp::VarPrivate window = GetWindowObject(); | |
392 pp::VarPrivate doc = window.GetProperty("document"); | |
393 pp::VarPrivate body = doc.GetProperty("body"); | |
394 | |
395 pp::VarPrivate obj(this, new MyScriptableObject(this)); | |
396 | |
397 // Our object should have its toString method called. | |
398 Log(PP_LOGLEVEL_LOG, "Testing MyScriptableObject::toString():"); | |
399 Log(PP_LOGLEVEL_LOG, obj); | |
400 | |
401 // body.appendChild(body) should throw an exception | |
402 Log(PP_LOGLEVEL_LOG, "Calling body.appendChild(body):"); | |
403 pp::Var exception; | |
404 body.Call("appendChild", body, &exception); | |
405 Log(PP_LOGLEVEL_LOG, exception); | |
406 | |
407 Log(PP_LOGLEVEL_LOG, "Enumeration of window properties:"); | |
408 std::vector<pp::Var> props; | |
409 window.GetAllPropertyNames(&props); | |
410 for (size_t i = 0; i < props.size(); ++i) | |
411 Log(PP_LOGLEVEL_LOG, props[i]); | |
412 | |
413 pp::VarPrivate location = window.GetProperty("location"); | |
414 pp::VarPrivate href = location.GetProperty("href"); | |
415 | |
416 if (!fetcher_) { | |
417 fetcher_ = new MyFetcher(); | |
418 fetcher_->Start(*this, href, this); | |
419 } | |
420 } | |
421 | |
422 void DidFetch(bool success, const std::string& data) { | |
423 Log(PP_LOGLEVEL_LOG, "Downloaded location.href:"); | |
424 if (success) { | |
425 Log(PP_LOGLEVEL_LOG, data); | |
426 } else { | |
427 Log(PP_LOGLEVEL_ERROR, "Failed to download."); | |
428 } | |
429 delete fetcher_; | |
430 fetcher_ = NULL; | |
431 } | |
432 | |
433 void ToggleCursor() { | |
434 const PPB_CursorControl_Dev* cursor_control = | |
435 reinterpret_cast<const PPB_CursorControl_Dev*>( | |
436 pp::Module::Get()->GetBrowserInterface( | |
437 PPB_CURSOR_CONTROL_DEV_INTERFACE)); | |
438 if (!cursor_control) | |
439 return; | |
440 | |
441 if (showing_custom_cursor_) { | |
442 cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_POINTER, 0, NULL); | |
443 } else { | |
444 pp::ImageData image_data(this, pp::ImageData::GetNativeImageDataFormat(), | |
445 pp::Size(50, 50), false); | |
446 FillRect(&image_data, 0, 0, 50, 50, | |
447 image_data.format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL ? | |
448 0x80800000 : 0x80000080); | |
449 pp::Point hot_spot(0, 0); | |
450 cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_CUSTOM, | |
451 image_data.pp_resource(), &hot_spot.pp_point()); | |
452 } | |
453 | |
454 showing_custom_cursor_ = !showing_custom_cursor_; | |
455 } | |
456 | |
457 pp::Var console_; | |
458 pp::Graphics2D device_context_; | |
459 | |
460 double time_at_last_check_; | |
461 | |
462 MyFetcher* fetcher_; | |
463 | |
464 int width_; | |
465 int height_; | |
466 | |
467 // Incremented for each flush we get. | |
468 int animation_counter_; | |
469 bool print_settings_valid_; | |
470 PP_PrintSettings_Dev print_settings_; | |
471 | |
472 bool showing_custom_cursor_; | |
473 }; | |
474 | |
475 void FlushCallback(void* data, int32_t result) { | |
476 static_cast<MyInstance*>(data)->OnFlush(); | |
477 } | |
478 | 42 |
479 class MyModule : public pp::Module { | 43 class MyModule : public pp::Module { |
480 public: | 44 public: |
481 MyModule() : pp::Module() {} | 45 MyModule() : pp::Module() {} |
482 virtual ~MyModule() {} | 46 virtual ~MyModule() {} |
483 | 47 |
484 virtual pp::Instance* CreateInstance(PP_Instance instance) { | 48 virtual pp::Instance* CreateInstance(PP_Instance instance) { |
485 return new MyInstance(instance); | 49 return new MyInstance(instance); |
486 } | 50 } |
487 }; | 51 }; |
488 | 52 |
489 namespace pp { | 53 namespace pp { |
490 | 54 |
491 // Factory function for your specialization of the Module object. | 55 // Factory function for your specialization of the Module object. |
492 Module* CreateModule() { | 56 Module* CreateModule() { |
493 return new MyModule(); | 57 return new MyModule(); |
494 } | 58 } |
495 | 59 |
496 } // namespace pp | 60 } // namespace pp |
OLD | NEW |