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

Side by Side Diff: native_client_sdk/src/examples/api/var_array_buffer/file_histogram.cc

Issue 14607005: [NaCl SDK] Cleanup examples. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: feedback Created 7 years, 7 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698