Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / native_client_sdk / src / gonacl_appengine / static / earth / example.js
blob629a321ac81035fcd454b74f57db4badcdc18725
1 // Copyright (c) 2013 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.
5 'use strict';
7 var naclModule = null;
9 /**
10 * A helper function to abbreviate getElementById.
12 * @param {string} elementId The id to get.
13 * @return {Element}
15 function $(elementId) {
16 return document.getElementById(elementId);
19 /**
20 * MIME type for PNaCl
22 * @return {string} MIME type
24 function PNaClmimeType() {
25 return 'application/x-pnacl';
28 /**
29 * Check if the browser supports PNaCl.
31 * @return {bool}
33 function browserSupportsPNaCl() {
34 var mimetype = PNaClmimeType();
35 return navigator.mimeTypes[mimetype] !== undefined;
38 /**
39 * Get the URL for Google Cloud Storage.
41 * @param {string} name The relative path to the file.
42 * @return {string}
44 function getDataURL(name) {
45 var revision = '236779';
46 var baseUrl = '//storage.googleapis.com/gonacl/demos/publish/';
47 return baseUrl + revision + '/earth/' + name;
50 /**
51 * Create the Native Client <embed> element as a child of the DOM element
52 * named "listener".
54 * @param {string} name The name of the example.
55 * @param {number} width The width to create the plugin.
56 * @param {number} height The height to create the plugin.
57 * @param {Object} attrs Dictionary of attributes to set on the module.
59 function createNaClModule(name, width, height, attrs) {
60 var moduleEl = document.createElement('embed');
61 moduleEl.setAttribute('name', 'nacl_module');
62 moduleEl.setAttribute('id', 'nacl_module');
63 moduleEl.setAttribute('width', width);
64 moduleEl.setAttribute('height', height);
65 moduleEl.setAttribute('path', '');
66 moduleEl.setAttribute('src', getDataURL(name + '.nmf'));
67 moduleEl.setAttribute('type', PNaClmimeType());
69 // Add any optional arguments
70 if (attrs) {
71 for (var key in attrs) {
72 moduleEl.setAttribute(key, attrs[key]);
76 // The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
77 // and a 'message' event listener attached. This wrapping method is used
78 // instead of attaching the event listeners directly to the <EMBED> element
79 // to ensure that the listeners are active before the NaCl module 'load'
80 // event fires.
81 var listenerDiv = $('listener');
82 listenerDiv.appendChild(moduleEl);
85 /**
86 * Add the default event listeners to the element with id "listener".
88 function attachDefaultListeners() {
89 var listenerDiv = $('listener');
90 listenerDiv.addEventListener('load', moduleDidLoad, true);
91 listenerDiv.addEventListener('error', moduleLoadError, true);
92 listenerDiv.addEventListener('progress', moduleLoadProgress, true);
93 listenerDiv.addEventListener('message', handleMessage, true);
94 listenerDiv.addEventListener('crash', handleCrash, true);
95 attachListeners();
98 /**
99 * Called when the Browser can not communicate with the Module
101 * This event listener is registered in attachDefaultListeners above.
103 * @param {Object} event
105 function handleCrash(event) {
106 if (naclModule.exitStatus == -1) {
107 updateStatus('CRASHED');
108 } else {
109 updateStatus('EXITED [' + naclModule.exitStatus + ']');
114 * Called when the NaCl module is loaded.
116 * This event listener is registered in attachDefaultListeners above.
118 function moduleDidLoad() {
119 var bar = $('progress-bar');
120 bar.style.width = 100;
121 naclModule = $('nacl_module');
122 hideStatus();
123 setThreadCount();
127 * Hide the status field and progress bar.
129 function hideStatus() {
130 $('loading-cover').style.display = 'none';
134 * Called when the plugin fails to load.
136 * @param {Object} event
138 function moduleLoadError(event) {
139 updateStatus('Load failed.');
143 * Called when the plugin reports progress events.
145 * @param {Object} event
147 function moduleLoadProgress(event) {
148 $('progress').style.display = 'block';
150 var loadPercent = 0.0;
151 var bar = $('progress-bar');
153 if (event.lengthComputable && event.total > 0) {
154 loadPercent = event.loaded / event.total * 100.0;
155 } else {
156 // The total length is not yet known.
157 loadPercent = 10;
159 bar.style.width = loadPercent + "%";
164 * If the element with id 'statusField' exists, then set its HTML to the status
165 * message as well.
167 * @param {string} opt_message The message to set.
169 function updateStatus(opt_message) {
170 var statusField = $('statusField');
171 if (statusField) {
172 statusField.style.display = 'block';
173 statusField.textContent = opt_message;
178 * Send the current value of the element threadCount to the NaCl module.
180 * @param {number} threads The number of threads to use to render.
182 function setThreadCount(threads) {
183 var value = parseInt($('threadCount').value);
184 naclModule.postMessage({'message': 'set_threads',
185 'value': value});
189 * Add event listeners after the NaCl module has loaded. These listeners will
190 * forward messages to the NaCl module via postMessage()
192 function attachListeners() {
193 $('threadCount').addEventListener('change', setThreadCount);
194 $('zoomRange').addEventListener('change',
195 function() {
196 var value = parseFloat($('zoomRange').value);
197 naclModule.postMessage({'message' : 'set_zoom',
198 'value' : value});
200 $('lightRange').addEventListener('change',
201 function() {
202 var value = parseFloat($('lightRange').value);
203 naclModule.postMessage({'message' : 'set_light',
204 'value' : value});
209 * Load a texture and send pixel data down to NaCl module.
210 * @param {string} name
212 function loadTexture(name) {
213 // Load image from jpg, decompress into canvas.
214 var img = new Image();
215 img.onload = function() {
216 var graph = document.createElement('canvas');
217 graph.width = img.width;
218 graph.height = img.height;
219 var context = graph.getContext('2d');
220 context.drawImage(img, 0, 0);
221 var imageData = context.getImageData(0, 0, img.width, img.height);
222 // Send NaCl module the raw image data obtained from canvas.
223 naclModule.postMessage({'message' : 'texture',
224 'name' : name,
225 'width' : img.width,
226 'height' : img.height,
227 'data' : imageData.data.buffer});
229 // A cross-origin request to an image is "tainted", and cannot be read into a
230 // canvas without specifying this. See
231 // https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image
232 img.crossOrigin = 'Anonymous';
233 img.src = getDataURL(name);
237 * Handle a message coming from the NaCl module.
238 * @param {Object} message_event
240 function handleMessage(message_event) {
241 var message = message_event.data.message;
242 var value = message_event.data.value;
243 if (message == 'set_zoom') {
244 // zoom slider
245 $('zoomRange').value = value;
246 } else if (message == 'set_light') {
247 // light slider
248 $('lightRange').value = value;
249 } else if (message == 'request_textures') {
250 // NaCl module is requesting a set of textures.
251 var names = message_event.data.names;
252 for (var i = 0; i < names.length; i++)
253 loadTexture(names[i]);
254 } else if (message == 'fps') {
255 // NaCl module notifying current FPS.
256 $('fps').textContent = message_event.data.value.toFixed(1);
261 * Listen for the DOM content to be loaded. This event is fired when parsing of
262 * the page's document has finished.
264 document.addEventListener('DOMContentLoaded', function() {
265 updateStatus('Loading...');
266 if (!browserSupportsPNaCl()) {
267 updateStatus('Browser does not support PNaCl or PNaCl is disabled');
268 } else if (naclModule == null) {
269 createNaClModule('earth', '100%', '100%');
270 attachDefaultListeners();
271 } else {
272 // It's possible that the Native Client module onload event fired
273 // before the page's onload event. In this case, the status message
274 // will reflect 'SUCCESS', but won't be displayed. This call will
275 // display the current message.
276 updateStatus('Waiting.');