OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/dev/ppb_file_chooser_dev.h" |
6 #include <stdio.h> // FIXME(brettw) erase me. | |
7 #ifndef _WIN32 | |
8 #include <sys/time.h> | |
9 #endif | |
10 #include <time.h> | |
11 | |
12 #include <algorithm> | |
13 | |
14 #include "ppapi/c/dev/ppp_printing_dev.h" | |
15 #include "ppapi/c/pp_errors.h" | |
16 #include "ppapi/c/pp_input_event.h" | 6 #include "ppapi/c/pp_input_event.h" |
17 #include "ppapi/c/pp_rect.h" | |
18 #include "ppapi/cpp/completion_callback.h" | 7 #include "ppapi/cpp/completion_callback.h" |
19 #include "ppapi/cpp/dev/scriptable_object_deprecated.h" | 8 #include "ppapi/cpp/dev/file_chooser_dev.h" |
20 #include "ppapi/cpp/graphics_2d.h" | 9 #include "ppapi/cpp/dev/file_ref_dev.h" |
21 #include "ppapi/cpp/image_data.h" | |
22 #include "ppapi/cpp/instance.h" | 10 #include "ppapi/cpp/instance.h" |
23 #include "ppapi/cpp/module.h" | 11 #include "ppapi/cpp/module.h" |
24 #include "ppapi/cpp/rect.h" | |
25 #include "ppapi/cpp/url_loader.h" | |
26 #include "ppapi/cpp/url_request_info.h" | |
27 #include "ppapi/cpp/var.h" | 12 #include "ppapi/cpp/var.h" |
28 | 13 |
29 static const int kStepsPerCircle = 800; | 14 class MyInstance : public pp::Instance { |
30 | |
31 void FlushCallback(void* data, int32_t result); | |
32 | |
33 void FillRect(pp::ImageData* image, int left, int top, int width, int height, | |
34 uint32_t color) { | |
35 for (int y = std::max(0, top); | |
36 y < std::min(image->size().height() - 1, top + height); | |
37 y++) { | |
38 for (int x = std::max(0, left); | |
39 x < std::min(image->size().width() - 1, left + width); | |
40 x++) | |
41 *image->GetAddr32(pp::Point(x, y)) = color; | |
42 } | |
43 } | |
44 | |
45 class MyScriptableObject : public pp::deprecated::ScriptableObject { | |
46 public: | |
47 explicit MyScriptableObject(pp::Instance* instance) : instance_(instance) {} | |
48 | |
49 virtual bool HasMethod(const pp::Var& method, pp::Var* exception) { | |
50 return method.AsString() == "toString"; | |
51 } | |
52 | |
53 virtual bool HasProperty(const pp::Var& name, pp::Var* exception) { | |
54 if (name.is_string() && name.AsString() == "blah") | |
55 return true; | |
56 return false; | |
57 } | |
58 | |
59 virtual pp::Var GetProperty(const pp::Var& name, pp::Var* exception) { | |
60 if (name.is_string() && name.AsString() == "blah") | |
61 return pp::Var(instance_, new MyScriptableObject(instance_)); | |
62 return pp::Var(); | |
63 } | |
64 | |
65 virtual void GetAllPropertyNames(std::vector<pp::Var>* names, | |
66 pp::Var* exception) { | |
67 names->push_back("blah"); | |
68 } | |
69 | |
70 virtual pp::Var Call(const pp::Var& method, | |
71 const std::vector<pp::Var>& args, | |
72 pp::Var* exception) { | |
73 if (method.AsString() == "toString") | |
74 return pp::Var("hello world"); | |
75 return pp::Var(); | |
76 } | |
77 | |
78 private: | |
79 pp::Instance* instance_; | |
80 }; | |
81 | |
82 class MyFetcherClient { | |
83 public: | |
84 virtual void DidFetch(bool success, const std::string& data) = 0; | |
85 }; | |
86 | |
87 class MyFetcher { | |
88 public: | |
89 MyFetcher() : client_(NULL) { | |
90 callback_factory_.Initialize(this); | |
91 } | |
92 | |
93 void Start(const pp::Instance& instance, | |
94 const pp::Var& url, | |
95 MyFetcherClient* client) { | |
96 pp::URLRequestInfo request; | |
97 request.SetURL(url); | |
98 request.SetMethod("GET"); | |
99 | |
100 loader_ = pp::URLLoader(instance); | |
101 client_ = client; | |
102 | |
103 pp::CompletionCallback callback = | |
104 callback_factory_.NewCallback(&MyFetcher::DidOpen); | |
105 int rv = loader_.Open(request, callback); | |
106 if (rv != PP_ERROR_WOULDBLOCK) | |
107 callback.Run(rv); | |
108 } | |
109 | |
110 void StartWithOpenedLoader(const pp::URLLoader& loader, | |
111 MyFetcherClient* client) { | |
112 loader_ = loader; | |
113 client_ = client; | |
114 | |
115 ReadMore(); | |
116 } | |
117 | |
118 private: | |
119 void ReadMore() { | |
120 pp::CompletionCallback callback = | |
121 callback_factory_.NewCallback(&MyFetcher::DidRead); | |
122 int rv = loader_.ReadResponseBody(buf_, sizeof(buf_), callback); | |
123 if (rv != PP_ERROR_WOULDBLOCK) | |
124 callback.Run(rv); | |
125 } | |
126 | |
127 void DidOpen(int32_t result) { | |
128 if (result == PP_OK) { | |
129 ReadMore(); | |
130 } else { | |
131 DidFinish(result); | |
132 } | |
133 } | |
134 | |
135 void DidRead(int32_t result) { | |
136 if (result > 0) { | |
137 data_.append(buf_, result); | |
138 ReadMore(); | |
139 } else { | |
140 DidFinish(result); | |
141 } | |
142 } | |
143 | |
144 void DidFinish(int32_t result) { | |
145 if (client_) | |
146 client_->DidFetch(result == PP_OK, data_); | |
147 } | |
148 | |
149 pp::CompletionCallbackFactory<MyFetcher> callback_factory_; | |
150 pp::URLLoader loader_; | |
151 MyFetcherClient* client_; | |
152 char buf_[4096]; | |
153 std::string data_; | |
154 }; | |
155 | |
156 class MyInstance : public pp::Instance, public MyFetcherClient { | |
157 public: | 15 public: |
158 MyInstance(PP_Instance instance) | 16 MyInstance(PP_Instance instance) |
159 : pp::Instance(instance), | 17 : pp::Instance(instance) { |
160 time_at_last_check_(0.0), | 18 callback_factory_.Initialize(this); |
161 fetcher_(NULL), | |
162 width_(0), | |
163 height_(0), | |
164 animation_counter_(0), | |
165 print_settings_valid_(false) {} | |
166 | |
167 virtual ~MyInstance() { | |
168 if (fetcher_) { | |
169 delete fetcher_; | |
170 fetcher_ = NULL; | |
171 } | |
172 } | |
173 | |
174 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | |
175 return true; | |
176 } | |
177 | |
178 virtual bool HandleDocumentLoad(const pp::URLLoader& loader) { | |
179 fetcher_ = new MyFetcher(); | |
180 fetcher_->StartWithOpenedLoader(loader, this); | |
181 return true; | |
182 } | 19 } |
183 | 20 |
184 virtual bool HandleInputEvent(const PP_InputEvent& event) { | 21 virtual bool HandleInputEvent(const PP_InputEvent& event) { |
185 switch (event.type) { | 22 switch (event.type) { |
186 case PP_INPUTEVENT_TYPE_MOUSEDOWN: | 23 case PP_INPUTEVENT_TYPE_MOUSEDOWN: { |
187 //SayHello(); | 24 const PP_InputEvent_Mouse& mouse_event = event.u.mouse; |
| 25 if (mouse_event.button == PP_INPUTEVENT_MOUSEBUTTON_LEFT) |
| 26 ShowFileChooser(false); |
| 27 else if (mouse_event.button == PP_INPUTEVENT_MOUSEBUTTON_RIGHT) |
| 28 ShowFileChooser(true); |
| 29 else |
| 30 return false; |
| 31 |
188 return true; | 32 return true; |
189 case PP_INPUTEVENT_TYPE_MOUSEMOVE: | 33 } |
190 return true; | |
191 case PP_INPUTEVENT_TYPE_KEYDOWN: | |
192 return true; | |
193 default: | 34 default: |
194 return false; | 35 return false; |
195 } | 36 } |
196 } | 37 } |
197 | 38 |
198 virtual pp::Var GetInstanceObject() { | 39 private: |
199 return pp::Var(this, new MyScriptableObject(this)); | 40 void ShowFileChooser(bool multi_select) { |
| 41 RecreateConsole(); |
| 42 |
| 43 PP_FileChooserOptions_Dev options; |
| 44 options.mode = (multi_select ? PP_FILECHOOSERMODE_OPENMULTIPLE : |
| 45 PP_FILECHOOSERMODE_OPEN); |
| 46 options.accept_mime_types = (multi_select ? "" : "plain/text"); |
| 47 |
| 48 // Deleted in ShowSelectedFileNames(). |
| 49 pp::FileChooser_Dev* file_chooser = new pp::FileChooser_Dev( |
| 50 *this, options); |
| 51 file_chooser->Show(callback_factory_.NewCallback( |
| 52 &MyInstance::ShowSelectedFileNames, file_chooser)); |
200 } | 53 } |
201 | 54 |
202 pp::ImageData PaintImage(int width, int height) { | 55 void ShowSelectedFileNames(int32_t, pp::FileChooser_Dev* file_chooser) { |
203 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, | 56 if (!file_chooser) |
204 pp::Size(width, height), false); | 57 return; |
205 if (image.is_null()) { | 58 |
206 printf("Couldn't allocate the image data: %d, %d\n", width, height); | 59 pp::FileRef_Dev file_ref = file_chooser->GetNextChosenFile(); |
207 return image; | 60 while (!file_ref.is_null()) { |
| 61 Log(file_ref.GetName()); |
| 62 file_ref = file_chooser->GetNextChosenFile(); |
208 } | 63 } |
209 | 64 |
210 // Fill with semitransparent gradient. | 65 delete file_chooser; |
211 for (int y = 0; y < image.size().height(); y++) { | |
212 char* row = &static_cast<char*>(image.data())[y * image.stride()]; | |
213 for (int x = 0; x < image.size().width(); x++) { | |
214 row[x * 4 + 0] = y; | |
215 row[x * 4 + 1] = y; | |
216 row[x * 4 + 2] = 0; | |
217 row[x * 4 + 3] = y; | |
218 } | |
219 } | |
220 | |
221 // Draw the orbiting box. | |
222 float radians = static_cast<float>(animation_counter_) / kStepsPerCircle * | |
223 2 * 3.14159265358979F; | |
224 | |
225 float radius = static_cast<float>(std::min(width, height)) / 2.0f - 3.0f; | |
226 int x = static_cast<int>(cos(radians) * radius + radius + 2); | |
227 int y = static_cast<int>(sin(radians) * radius + radius + 2); | |
228 | |
229 const uint32_t box_bgra = 0x80000000; // Alpha 50%. | |
230 FillRect(&image, x - 3, y - 3, 7, 7, box_bgra); | |
231 return image; | |
232 } | 66 } |
233 | 67 |
234 void Paint() { | 68 void RecreateConsole() { |
235 pp::ImageData image = PaintImage(width_, height_); | 69 pp::Var doc = GetWindowObject().GetProperty("document"); |
236 if (!image.is_null()) { | 70 pp::Var body = doc.GetProperty("body"); |
237 device_context_.ReplaceContents(&image); | 71 if (!console_.is_undefined()) |
238 device_context_.Flush(pp::CompletionCallback(&FlushCallback, this)); | 72 body.Call("removeChild", console_); |
239 } else { | 73 |
240 printf("NullImage: %d, %d\n", width_, height_); | 74 console_ = doc.Call("createElement", "pre"); |
241 } | 75 console_.SetProperty("id", "console"); |
| 76 console_.GetProperty("style").SetProperty("backgroundColor", "lightgray"); |
| 77 body.Call("appendChild", console_); |
242 } | 78 } |
243 | 79 |
244 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { | |
245 if (position.size().width() == width_ && | |
246 position.size().height() == height_) | |
247 return; // We don't care about the position, only the size. | |
248 | |
249 width_ = position.size().width(); | |
250 height_ = position.size().height(); | |
251 printf("DidChangeView relevant change: width=%d height:%d\n", | |
252 width_, height_); | |
253 | |
254 device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), false); | |
255 if (!BindGraphics(device_context_)) { | |
256 printf("Couldn't bind the device context\n"); | |
257 return; | |
258 } | |
259 | |
260 Paint(); | |
261 } | |
262 | |
263 void UpdateFps() { | |
264 // Time code doesn't currently compile on Windows, just skip FPS for now. | |
265 #ifndef _WIN32 | |
266 pp::Var window = GetWindowObject(); | |
267 pp::Var doc = window.GetProperty("document"); | |
268 pp::Var fps = doc.Call("getElementById", "fps"); | |
269 | |
270 struct timeval tv; | |
271 struct timezone tz = {0, 0}; | |
272 gettimeofday(&tv, &tz); | |
273 | |
274 double time_now = tv.tv_sec + tv.tv_usec / 1000000.0; | |
275 | |
276 if (animation_counter_ > 0) { | |
277 char fps_text[64]; | |
278 sprintf(fps_text, "%g fps", | |
279 kStepsPerCircle / (time_now - time_at_last_check_)); | |
280 fps.SetProperty("innerHTML", fps_text); | |
281 } | |
282 | |
283 time_at_last_check_ = time_now; | |
284 #endif | |
285 } | |
286 | |
287 // Print interfaces. | |
288 virtual PP_PrintOutputFormat_Dev* QuerySupportedPrintOutputFormats( | |
289 uint32_t* format_count) { | |
290 PP_PrintOutputFormat_Dev* format = | |
291 reinterpret_cast<PP_PrintOutputFormat_Dev*>( | |
292 pp::Module::Get()->core()->MemAlloc( | |
293 sizeof(PP_PrintOutputFormat_Dev))); | |
294 *format = PP_PRINTOUTPUTFORMAT_RASTER; | |
295 *format_count = 1; | |
296 return format; | |
297 } | |
298 | |
299 virtual int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) { | |
300 if (print_settings_.format != PP_PRINTOUTPUTFORMAT_RASTER) | |
301 return 0; | |
302 | |
303 print_settings_ = print_settings; | |
304 print_settings_valid_ = true; | |
305 return 1; | |
306 } | |
307 | |
308 virtual pp::Resource PrintPages( | |
309 const PP_PrintPageNumberRange_Dev* page_ranges, | |
310 uint32_t page_range_count) { | |
311 if (!print_settings_valid_) | |
312 return pp::Resource(); | |
313 | |
314 if (page_range_count != 1) | |
315 return pp::Resource(); | |
316 | |
317 // Check if the page numbers are valid. We returned 1 in PrintBegin so we | |
318 // only have 1 page to print. | |
319 if (page_ranges[0].first_page_number || page_ranges[0].last_page_number) { | |
320 return pp::Resource(); | |
321 } | |
322 | |
323 int width = static_cast<int>( | |
324 (print_settings_.printable_area.size.width / 72.0) * | |
325 print_settings_.dpi); | |
326 int height = static_cast<int>( | |
327 (print_settings_.printable_area.size.height / 72.0) * | |
328 print_settings_.dpi); | |
329 | |
330 return PaintImage(width, height); | |
331 } | |
332 | |
333 virtual void PrintEnd() { | |
334 print_settings_valid_ = false; | |
335 } | |
336 | |
337 void OnFlush() { | |
338 if (animation_counter_ % kStepsPerCircle == 0) | |
339 UpdateFps(); | |
340 animation_counter_++; | |
341 Paint(); | |
342 } | |
343 | |
344 private: | |
345 void Log(const pp::Var& var) { | 80 void Log(const pp::Var& var) { |
346 pp::Var doc = GetWindowObject().GetProperty("document"); | 81 pp::Var doc = GetWindowObject().GetProperty("document"); |
347 if (console_.is_undefined()) { | |
348 pp::Var body = doc.GetProperty("body"); | |
349 console_ = doc.Call("createElement", "pre"); | |
350 console_.GetProperty("style").SetProperty("backgroundColor", "lightgray"); | |
351 body.Call("appendChild", console_); | |
352 } | |
353 console_.Call("appendChild", doc.Call("createTextNode", var)); | 82 console_.Call("appendChild", doc.Call("createTextNode", var)); |
354 console_.Call("appendChild", doc.Call("createTextNode", "\n")); | 83 console_.Call("appendChild", doc.Call("createTextNode", "\n")); |
355 } | 84 } |
356 | 85 |
357 void SayHello() { | 86 pp::CompletionCallbackFactory<MyInstance> callback_factory_; |
358 pp::Var window = GetWindowObject(); | |
359 pp::Var doc = window.GetProperty("document"); | |
360 pp::Var body = doc.GetProperty("body"); | |
361 | |
362 pp::Var obj(this, new MyScriptableObject(this)); | |
363 | |
364 // Our object should have its toString method called. | |
365 Log("Testing MyScriptableObject::toString():"); | |
366 Log(obj); | |
367 | |
368 // body.appendChild(body) should throw an exception | |
369 Log("\nCalling body.appendChild(body):"); | |
370 pp::Var exception; | |
371 body.Call("appendChild", body, &exception); | |
372 Log(exception); | |
373 | |
374 Log("\nEnumeration of window properties:"); | |
375 std::vector<pp::Var> props; | |
376 window.GetAllPropertyNames(&props); | |
377 for (size_t i = 0; i < props.size(); ++i) | |
378 Log(props[i]); | |
379 | |
380 pp::Var location = window.GetProperty("location"); | |
381 pp::Var href = location.GetProperty("href"); | |
382 | |
383 if (!fetcher_) { | |
384 fetcher_ = new MyFetcher(); | |
385 fetcher_->Start(*this, href, this); | |
386 } | |
387 } | |
388 | |
389 void DidFetch(bool success, const std::string& data) { | |
390 Log("\nDownloaded location.href:"); | |
391 if (success) { | |
392 Log(data); | |
393 } else { | |
394 Log("Failed to download."); | |
395 } | |
396 delete fetcher_; | |
397 fetcher_ = NULL; | |
398 } | |
399 | |
400 pp::Var console_; | 87 pp::Var console_; |
401 pp::Graphics2D device_context_; | |
402 | |
403 double time_at_last_check_; | |
404 | |
405 MyFetcher* fetcher_; | |
406 | |
407 int width_; | |
408 int height_; | |
409 | |
410 // Incremented for each flush we get. | |
411 int animation_counter_; | |
412 bool print_settings_valid_; | |
413 PP_PrintSettings_Dev print_settings_; | |
414 }; | 88 }; |
415 | 89 |
416 void FlushCallback(void* data, int32_t result) { | |
417 static_cast<MyInstance*>(data)->OnFlush(); | |
418 } | |
419 | |
420 class MyModule : public pp::Module { | 90 class MyModule : public pp::Module { |
421 public: | 91 public: |
422 MyModule() : pp::Module() {} | 92 MyModule() : pp::Module() {} |
423 virtual ~MyModule() {} | 93 virtual ~MyModule() {} |
424 | 94 |
425 virtual pp::Instance* CreateInstance(PP_Instance instance) { | 95 virtual pp::Instance* CreateInstance(PP_Instance instance) { |
426 return new MyInstance(instance); | 96 return new MyInstance(instance); |
427 } | 97 } |
428 }; | 98 }; |
429 | 99 |
430 namespace pp { | 100 namespace pp { |
431 | 101 |
432 // Factory function for your specialization of the Module object. | 102 // Factory function for your specialization of the Module object. |
433 Module* CreateModule() { | 103 Module* CreateModule() { |
434 return new MyModule(); | 104 return new MyModule(); |
435 } | 105 } |
436 | 106 |
437 } // namespace pp | 107 } // namespace pp |
OLD | NEW |