| OLD | NEW |
| (Empty) |
| 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 /// @file file_histogram.cc | |
| 6 /// This example demonstrates loading, running and scripting a very simple NaCl | |
| 7 /// module. To load the NaCl module, the browser first looks for the | |
| 8 /// CreateModule() factory method (at the end of this file). It calls | |
| 9 /// CreateModule() once to load the module code from your .nexe. After the | |
| 10 /// .nexe code is loaded, CreateModule() is not called again. | |
| 11 /// | |
| 12 /// Once the .nexe code is loaded, the browser than calls the CreateInstance() | |
| 13 /// method on the object returned by CreateModule(). It calls CreateInstance() | |
| 14 /// each time it encounters an <embed> tag that references your NaCl module. | |
| 15 /// | |
| 16 /// The browser can talk to your NaCl module via the postMessage() Javascript | |
| 17 /// function. When you call postMessage() on your NaCl module from the browser, | |
| 18 /// this becomes a call to the HandleMessage() method of your pp::Instance | |
| 19 /// subclass. You can send messages back to the browser by calling the | |
| 20 /// PostMessage() method on your pp::Instance. Note that these two methods | |
| 21 /// (postMessage() in Javascript and PostMessage() in C++) are asynchronous. | |
| 22 /// This means they return immediately - there is no waiting for the message | |
| 23 /// to be handled. This has implications in your program design, particularly | |
| 24 /// when mutating property values that are exposed to both the browser and the | |
| 25 /// NaCl module. | |
| 26 | |
| 27 #include <algorithm> | |
| 28 #include <deque> | |
| 29 #include <string> | |
| 30 | |
| 31 #include "ppapi/cpp/graphics_2d.h" | |
| 32 #include "ppapi/cpp/image_data.h" | |
| 33 #include "ppapi/cpp/instance.h" | |
| 34 #include "ppapi/cpp/module.h" | |
| 35 #include "ppapi/cpp/var.h" | |
| 36 #include "ppapi/cpp/var_array_buffer.h" | |
| 37 #include "ppapi/utility/completion_callback_factory.h" | |
| 38 | |
| 39 #ifdef WIN32 | |
| 40 #undef min | |
| 41 #undef max | |
| 42 #undef PostMessage | |
| 43 | |
| 44 // Allow 'this' in initializer list | |
| 45 #pragma warning(disable : 4355) | |
| 46 // Disable warning about behaviour of array initialization. | |
| 47 #pragma warning(disable : 4351) | |
| 48 #endif | |
| 49 | |
| 50 namespace { | |
| 51 | |
| 52 const uint32_t kBlue = 0xff4040ffu; | |
| 53 const uint32_t kBlack = 0xff000000u; | |
| 54 const size_t kHistogramSize = 256u; | |
| 55 | |
| 56 } // namespace | |
| 57 | |
| 58 /// The Instance class. One of these exists for each instance of your NaCl | |
| 59 /// module on the web page. The browser will ask the Module object to create | |
| 60 /// a new Instance for each occurrence of the <embed> tag that has these | |
| 61 /// attributes: | |
| 62 /// type="application/x-nacl" | |
| 63 /// src="file_histogram.nmf" | |
| 64 class FileHistogramInstance : public pp::Instance { | |
| 65 public: | |
| 66 /// The constructor creates the plugin-side instance. | |
| 67 /// @param[in] instance the handle to the browser-side plugin instance. | |
| 68 explicit FileHistogramInstance(PP_Instance instance) | |
| 69 : pp::Instance(instance), | |
| 70 callback_factory_(this), | |
| 71 flushing_(false), | |
| 72 histogram_() {} | |
| 73 virtual ~FileHistogramInstance() {} | |
| 74 | |
| 75 private: | |
| 76 /// Handler for messages coming in from the browser via postMessage(). The | |
| 77 /// @a var_message can contain anything: a JSON string; a string that encodes | |
| 78 /// method names and arguments; etc. | |
| 79 /// | |
| 80 /// In this case, we only handle <code>pp::VarArrayBuffer</code>s. When we | |
| 81 /// receive one, we compute and display a histogram based on its contents. | |
| 82 /// | |
| 83 /// @param[in] var_message The message posted by the browser. | |
| 84 virtual void HandleMessage(const pp::Var& var_message) { | |
| 85 if (var_message.is_array_buffer()) { | |
| 86 pp::VarArrayBuffer buffer(var_message); | |
| 87 ComputeHistogram(buffer); | |
| 88 DrawHistogram(); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 /// Create and return a blank (all-black) <code>pp::ImageData</code> of the | |
| 93 /// given <code>size</code>. | |
| 94 pp::ImageData MakeBlankImageData(const pp::Size& size) { | |
| 95 const bool init_to_zero = false; | |
| 96 pp::ImageData image_data = | |
| 97 pp::ImageData(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, init_to_zero); | |
| 98 uint32_t* image_buffer = static_cast<uint32_t*>(image_data.data()); | |
| 99 for (int i = 0; i < size.GetArea(); ++i) | |
| 100 image_buffer[i] = kBlack; | |
| 101 return image_data; | |
| 102 } | |
| 103 | |
| 104 /// Draw a bar of the appropriate height based on <code>value</code> at | |
| 105 /// <code>column</code> in <code>image_data</code>. <code>value</code> must be | |
| 106 /// in the range [0, 1]. | |
| 107 void DrawBar(uint32_t column, double value, pp::ImageData* image_data) { | |
| 108 assert((value >= 0.0) && (value <= 1.0)); | |
| 109 uint32_t* image_buffer = static_cast<uint32_t*>(image_data->data()); | |
| 110 const uint32_t image_height = image_data->size().height(); | |
| 111 const uint32_t image_width = image_data->size().width(); | |
| 112 assert(column < image_width); | |
| 113 int bar_height = static_cast<int>(value * image_height); | |
| 114 for (int i = 0; i < bar_height; ++i) { | |
| 115 uint32_t row = image_height - 1 - i; | |
| 116 image_buffer[row * image_width + column] = kBlue; | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 void PaintAndFlush(pp::ImageData* image_data) { | |
| 121 assert(!flushing_); | |
| 122 graphics_2d_context_.ReplaceContents(image_data); | |
| 123 graphics_2d_context_.Flush( | |
| 124 callback_factory_.NewCallback(&FileHistogramInstance::DidFlush)); | |
| 125 flushing_ = true; | |
| 126 } | |
| 127 | |
| 128 /// The callback that gets invoked when a flush completes. This is bound to a | |
| 129 /// <code>CompletionCallback</code> and passed as a parameter to | |
| 130 /// <code>Flush</code>. | |
| 131 void DidFlush(int32_t error_code) { | |
| 132 flushing_ = false; | |
| 133 // If there are no images in the queue, we're done for now. | |
| 134 if (paint_queue_.empty()) | |
| 135 return; | |
| 136 // Otherwise, pop the next image off the queue and draw it. | |
| 137 pp::ImageData image_data = paint_queue_.front(); | |
| 138 paint_queue_.pop_front(); | |
| 139 PaintAndFlush(&image_data); | |
| 140 } | |
| 141 | |
| 142 virtual void DidChangeView(const pp::View& view) { | |
| 143 if (size_ != view.GetRect().size()) { | |
| 144 size_ = view.GetRect().size(); | |
| 145 const bool is_always_opaque = true; | |
| 146 graphics_2d_context_ = | |
| 147 pp::Graphics2D(this, view.GetRect().size(), is_always_opaque); | |
| 148 BindGraphics(graphics_2d_context_); | |
| 149 // The images in our queue are the wrong size, so we won't paint them. | |
| 150 // We'll only draw the most recently computed histogram. | |
| 151 paint_queue_.clear(); | |
| 152 DrawHistogram(); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 /// Compute and normalize a histogram based on the given VarArrayBuffer. | |
| 157 void ComputeHistogram(pp::VarArrayBuffer& buffer) { | |
| 158 std::fill_n(histogram_, kHistogramSize, 0.0); | |
| 159 uint32_t buffer_size = buffer.ByteLength(); | |
| 160 if (buffer_size == 0) | |
| 161 return; | |
| 162 uint8_t* buffer_data = static_cast<uint8_t*>(buffer.Map()); | |
| 163 for (uint32_t i = 0; i < buffer_size; ++i) | |
| 164 histogram_[buffer_data[i]] += 1.0; | |
| 165 // Normalize. | |
| 166 double max = *std::max_element(histogram_, histogram_ + kHistogramSize); | |
| 167 for (uint32_t i = 0; i < kHistogramSize; ++i) | |
| 168 histogram_[i] /= max; | |
| 169 } | |
| 170 | |
| 171 /// Draw the current histogram_ in to an pp::ImageData, then paint and flush | |
| 172 /// that image. If we're already waiting on a flush, push it on to | |
| 173 /// <code>paint_queue_</code> to paint later. | |
| 174 void DrawHistogram() { | |
| 175 pp::ImageData image_data = MakeBlankImageData(size_); | |
| 176 for (int i = 0; i < std::min(static_cast<int>(kHistogramSize), | |
| 177 image_data.size().width()); | |
| 178 ++i) { | |
| 179 DrawBar(i, histogram_[i], &image_data); | |
| 180 } | |
| 181 | |
| 182 if (!flushing_) | |
| 183 PaintAndFlush(&image_data); | |
| 184 else | |
| 185 paint_queue_.push_back(image_data); | |
| 186 } | |
| 187 | |
| 188 pp::Graphics2D graphics_2d_context_; | |
| 189 pp::CompletionCallbackFactory<FileHistogramInstance> callback_factory_; | |
| 190 | |
| 191 /// A queue of images to paint. We must maintain a queue because we can not | |
| 192 /// call pp::Graphics2D::Flush while a Flush is already pending. | |
| 193 std::deque<pp::ImageData> paint_queue_; | |
| 194 | |
| 195 /// The size of our rectangle in the DOM, as of the last time DidChangeView | |
| 196 /// was called. | |
| 197 pp::Size size_; | |
| 198 | |
| 199 /// true iff we are flushing. | |
| 200 bool flushing_; | |
| 201 | |
| 202 /// Stores the most recent histogram so that we can re-draw it if we get | |
| 203 /// resized. | |
| 204 double histogram_[kHistogramSize]; | |
| 205 }; | |
| 206 | |
| 207 /// The Module class. The browser calls the CreateInstance() method to create | |
| 208 /// an instance of your NaCl module on the web page. The browser creates a new | |
| 209 /// instance for each <embed> tag with type="application/x-nacl". | |
| 210 class FileHistogramModule : public pp::Module { | |
| 211 public: | |
| 212 FileHistogramModule() : pp::Module() {} | |
| 213 virtual ~FileHistogramModule() {} | |
| 214 | |
| 215 /// Create and return a FileHistogramInstance object. | |
| 216 /// @param[in] instance The browser-side instance. | |
| 217 /// @return the plugin-side instance. | |
| 218 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
| 219 return new FileHistogramInstance(instance); | |
| 220 } | |
| 221 }; | |
| 222 | |
| 223 namespace pp { | |
| 224 /// Factory function called by the browser when the module is first loaded. | |
| 225 /// The browser keeps a singleton of this module. It calls the | |
| 226 /// CreateInstance() method on the object you return to make instances. There | |
| 227 /// is one instance per <embed> tag on the page. This is the main binding | |
| 228 /// point for your NaCl module with the browser. | |
| 229 Module* CreateModule() { return new FileHistogramModule(); } | |
| 230 } // namespace pp | |
| OLD | NEW |