diff --git a/Osmand-kernel/Makefile.vars b/Osmand-kernel/Makefile.vars index fe7c07bbf3..45d6f888de 100644 --- a/Osmand-kernel/Makefile.vars +++ b/Osmand-kernel/Makefile.vars @@ -1,6 +1,7 @@ -ifeq ($(ARCH),) +ifndef $(ARCH) ARCH := x86 endif + ############################################ ############# NACL ### TARGET ifeq ($(TARGET),nacl) @@ -26,10 +27,10 @@ CC:=$(TC_PATH)/bin/i686-nacl-gcc STATICLIB_EXT := a DYNAMICLIB_EXT := nexe LIBRARY_PREFIX := lib -LDFLAGS := -lppapi +LDFLAGS := -lppapi_cpp -lppapi GLOBAL_INCLUDES=-I../zlib/zlib_library -I$(TC_PATH)/i686-nacl/usr/include -RT_NOT_SUPPORTED := -ZLIB_BUILD := +RT_NOT_SUPPORTED := defined +ZLIB_BUILD := defined ifeq ($(ARCH),x86) CFLAGS += -m32 @@ -83,7 +84,9 @@ RANLIB := i586-mingw32msvc-ranlib WINDRES := i586-mingw32msvc-windres AR := i586-mingw32msvc-ar GLOBAL_INCLUDES := -I../pthread/pthreads_library -I../zlib/zlib_library -RT_NOT_SUPPORTED := 1 +RT_NOT_SUPPORTED := defined +ZLIB_BUILD := defined +PTHREAD_BUILD := defined COMMONFLAGS := -D_Windows -DXMD_H -DHAVE_BOOLEAN -DRT_NOT_SUPPORTED CPP_FLAGS := $(COMMONFLAGS) CFLAGS := -D_JNI_IMPLEMENTATION $(COMMONFLAGS) diff --git a/Osmand-kernel/osmand/Android.mk b/Osmand-kernel/osmand/Android.mk index 26209e3b5f..336d8a2e81 100644 --- a/Osmand-kernel/osmand/Android.mk +++ b/Osmand-kernel/osmand/Android.mk @@ -11,6 +11,8 @@ LOCAL_MODULE := osmand_neon LOCAL_ARM_NEON := true endif +LOCAL_SRC_FILES += src/java_wrap.cpp + LOCAL_CFLAGS := \ -DGOOGLE_PROTOBUF_NO_RTTI \ -DANDROID_BUILD \ diff --git a/Osmand-kernel/osmand/nacl/.gitignore b/Osmand-kernel/osmand/nacl/.gitignore index e951f656a9..42c9587409 100644 --- a/Osmand-kernel/osmand/nacl/.gitignore +++ b/Osmand-kernel/osmand/nacl/.gitignore @@ -1 +1,2 @@ -*.nexe +osmand-*.nexe + diff --git a/Osmand-kernel/osmand/nacl/index.html b/Osmand-kernel/osmand/nacl/index.html index 6a9139a2ad..47f75e2cd5 100644 --- a/Osmand-kernel/osmand/nacl/index.html +++ b/Osmand-kernel/osmand/nacl/index.html @@ -69,11 +69,19 @@ appendToEventLog('abort'); } - // When the NaCl module has loaded indicate success. + var piGenerator = null; + var paintInterval = null; + + // Start up the paint timer when the NaCl module has loaded. function moduleDidLoad() { loadProgressModule = document.getElementById('load_progress'); appendToEventLog('load'); updateStatus('SUCCESS'); + piGenerator = document.getElementById('load_progress'); + paintInterval = setInterval('load_progress.postMessage("paint")', 50); + } + function pageDidUnload() { + clearInterval(paintInterval); } // Handler that gets called when the NaCl module loading has completed. @@ -94,7 +102,8 @@ // Handle a message coming from the NaCl module. function handleMessage(message_event) { - alert(message_event.data); + // alert(message_event.data); + //document.form.pi.value = message_event.data; } // Set the global status message. Updates the 'status_field' element with @@ -195,7 +204,7 @@ --> diff --git a/Osmand-kernel/osmand/nacl/osmand-x64.nexe b/Osmand-kernel/osmand/nacl/osmand-x64.nexe deleted file mode 100755 index fc46fabfd7..0000000000 Binary files a/Osmand-kernel/osmand/nacl/osmand-x64.nexe and /dev/null differ diff --git a/Osmand-kernel/osmand/nacl/osmand-x86.nexe b/Osmand-kernel/osmand/nacl/osmand-x86.nexe deleted file mode 100755 index b3afd9b836..0000000000 Binary files a/Osmand-kernel/osmand/nacl/osmand-x86.nexe and /dev/null differ diff --git a/Osmand-kernel/osmand/src/osmand_nacl.cpp b/Osmand-kernel/osmand/src/osmand_nacl.cpp index e6a2627cf1..ea379979c1 100644 --- a/Osmand-kernel/osmand/src/osmand_nacl.cpp +++ b/Osmand-kernel/osmand/src/osmand_nacl.cpp @@ -1,182 +1,266 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -/** @file hello_world.c - * This example demonstrates loading, running and scripting a very simple - * NaCl module. - */ #include #include -#include +#include +#include +#include +#include +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/var.h" +#include -#include "ppapi/c/pp_errors.h" -#include "ppapi/c/pp_module.h" -#include "ppapi/c/pp_var.h" -#include "ppapi/c/ppb.h" -#include "ppapi/c/ppb_instance.h" -#include "ppapi/c/ppb_messaging.h" -#include "ppapi/c/ppb_var.h" -#include "ppapi/c/ppp.h" -#include "ppapi/c/ppp_instance.h" -#include "ppapi/c/ppp_messaging.h" +#include "osmand_nacl.h" -static PPB_Messaging* ppb_messaging_interface = NULL; -static PPB_Var* ppb_var_interface = NULL; +namespace { +const int kPthreadMutexSuccess = 0; +const char* const kPaintMethodId = "paint"; +const double kInvalidPiValue = -1.0; +const int kMaxPointCount = 1000000000; // The total number of points to draw. +const uint32_t kOpaqueColorMask = 0xff000000; // Opaque pixels. +const uint32_t kRedMask = 0xff0000; +const uint32_t kBlueMask = 0xff; +const uint32_t kRedShift = 16; +const uint32_t kBlueShift = 0; +// This is called by the browser when the 2D context has been flushed to the +// browser window. +void FlushCallback(void* data, int32_t result) { + static_cast(data)->set_flush_pending(false); +} +} // namespace -/** - * Creates new string PP_Var from C string. The resulting object will be a - * refcounted string object. It will be AddRef()ed for the caller. When the - * caller is done with it, it should be Release()d. - * @param[in] str C string to be converted to PP_Var - * @return PP_Var containing string. - */ -static struct PP_Var CStrToVar(const char* str) { - if (ppb_var_interface != NULL) { - return ppb_var_interface->VarFromUtf8(str, strlen(str)); +namespace osmand { + +// A small helper RAII class that implementes a scoped pthread_mutex lock. +class ScopedMutexLock { + public: + explicit ScopedMutexLock(pthread_mutex_t* mutex) : mutex_(mutex) { + if (pthread_mutex_lock(mutex_) != kPthreadMutexSuccess) { + mutex_ = NULL; + } } - return PP_MakeUndefined(); -} - - -/** - * Called when the NaCl module is instantiated on the web page. The identifier - * of the new instance will be passed in as the first argument (this value is - * generated by the browser and is an opaque handle). This is called for each - * instantiation of the NaCl module, which is each time the tag for - * this module is encountered. - * - * If this function reports a failure (by returning @a PP_FALSE), the NaCl - * module will be deleted and DidDestroy will be called. - * @param[in] instance The identifier of the new instance representing this - * NaCl module. - * @param[in] argc The number of arguments contained in @a argn and @a argv. - * @param[in] argn An array of argument names. These argument names are - * supplied in the tag, for example: - * - * will produce two arguments, one named "id" and one named "dimensions". - * @param[in] argv An array of argument values. These are the values of the - * arguments listed in the tag. In the above example, there will - * be two elements in this array, "nacl_module" and "2". The indices of - * these values match the indices of the corresponding names in @a argn. - * @return @a PP_TRUE on success. - */ -static PP_Bool Instance_DidCreate(PP_Instance instance, - uint32_t argc, - const char* argn[], - const char* argv[]) { - ppb_messaging_interface->PostMessage(instance, - CStrToVar("Osmand application")); - return PP_TRUE; -} - - -/** - * Called when the NaCl module is destroyed. This will always be called, - * even if DidCreate returned failure. This routine should deallocate any data - * associated with the instance. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - */ -static void Instance_DidDestroy(PP_Instance instance) { -} - -/** - * Called when the position, the size, or the clip rect of the element in the - * browser that corresponds to this NaCl module has changed. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - * @param[in] position The location on the page of this NaCl module. This is - * relative to the top left corner of the viewport, which changes as the - * page is scrolled. - * @param[in] clip The visible region of the NaCl module. This is relative to - * the top left of the plugin's coordinate system (not the page). If the - * plugin is invisible, @a clip will be (0, 0, 0, 0). - */ -static void Instance_DidChangeView(PP_Instance instance, - PP_Resource view_resource) { -} - -/** - * Notification that the given NaCl module has gained or lost focus. - * Having focus means that keyboard events will be sent to the NaCl module - * represented by @a instance. A NaCl module's default condition is that it - * will not have focus. - * - * Note: clicks on NaCl modules will give focus only if you handle the - * click event. You signal if you handled it by returning @a true from - * HandleInputEvent. Otherwise the browser will bubble the event and give - * focus to the element on the page that actually did end up consuming it. - * If you're not getting focus, check to make sure you're returning true from - * the mouse click in HandleInputEvent. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - * @param[in] has_focus Indicates whether this NaCl module gained or lost - * event focus. - */ -static void Instance_DidChangeFocus(PP_Instance instance, - PP_Bool has_focus) { -} - -/** - * Handler that gets called after a full-frame module is instantiated based on - * registered MIME types. This function is not called on NaCl modules. This - * function is essentially a place-holder for the required function pointer in - * the PPP_Instance structure. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - * @param[in] url_loader A PP_Resource an open PPB_URLLoader instance. - * @return PP_FALSE. - */ -static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, - PP_Resource url_loader) { - /* NaCl modules do not need to handle the document load function. */ - return PP_FALSE; -} - - - -/** - * Entry points for the module. - * Initialize needed interfaces: PPB_Core, PPB_Messaging and PPB_Var. - * @param[in] a_module_id module ID - * @param[in] get_browser pointer to PPB_GetInterface - * @return PP_OK on success, any other value on failure. - */ -PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, - PPB_GetInterface get_browser) { - ppb_messaging_interface = - (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE)); - ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE)); - return PP_OK; -} - - -/** - * Returns an interface pointer for the interface of the given name, or NULL - * if the interface is not supported. - * @param[in] interface_name name of the interface - * @return pointer to the interface - */ -PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { - if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { - static PPP_Instance instance_interface = { - &Instance_DidCreate, - &Instance_DidDestroy, - &Instance_DidChangeView, - &Instance_DidChangeFocus, - &Instance_HandleDocumentLoad, - }; - return &instance_interface; + ~ScopedMutexLock() { + if (mutex_) + pthread_mutex_unlock(mutex_); } - return NULL; + bool is_valid() const { + return mutex_ != NULL; + } + private: + pthread_mutex_t* mutex_; // Weak reference. +}; + +// A small helper RAII class used to acquire and release the pixel lock. +class ScopedPixelLock { + public: + explicit ScopedPixelLock(PiGenerator* image_owner) + : image_owner_(image_owner), pixels_(image_owner->LockPixels()) {} + + ~ScopedPixelLock() { + pixels_ = NULL; + image_owner_->UnlockPixels(); + } + + uint32_t* pixels() const { + return pixels_; + } + private: + PiGenerator* image_owner_; // Weak reference. + uint32_t* pixels_; // Weak reference. + + ScopedPixelLock(); // Not implemented, do not use. +}; + +PiGenerator::PiGenerator(PP_Instance instance) + : pp::Instance(instance), + graphics_2d_context_(NULL), + pixel_buffer_(NULL), + flush_pending_(false), + quit_(false), + compute_pi_thread_(0), + pi_(0.0) { + pthread_mutex_init(&pixel_buffer_mutex_, NULL); +} + +PiGenerator::~PiGenerator() { + quit_ = true; + if (compute_pi_thread_) { + pthread_join(compute_pi_thread_, NULL); + } + DestroyContext(); + // The ComputePi() thread should be gone by now, so there is no need to + // acquire the mutex for |pixel_buffer_|. + delete pixel_buffer_; + pthread_mutex_destroy(&pixel_buffer_mutex_); +} + +void PiGenerator::DidChangeView(const pp::Rect& position, + const pp::Rect& clip) { + if (position.size().width() == width() && + position.size().height() == height()) + return; // Size didn't change, no need to update anything. + + // Create a new device context with the new size. + DestroyContext(); + CreateContext(position.size()); + // Delete the old pixel buffer and create a new one. + ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_); + delete pixel_buffer_; + pixel_buffer_ = NULL; + if (graphics_2d_context_ != NULL) { + pixel_buffer_ = new pp::ImageData(this, + PP_IMAGEDATAFORMAT_BGRA_PREMUL, + graphics_2d_context_->size(), + false); + } +} + +bool PiGenerator::Init(uint32_t argc, const char* argn[], const char* argv[]) { + pthread_create(&compute_pi_thread_, NULL, ComputePi, this); + return true; +} + +uint32_t* PiGenerator::LockPixels() { + void* pixels = NULL; + // Do not use a ScopedMutexLock here, since the lock needs to be held until + // the matching UnlockPixels() call. + if (pthread_mutex_lock(&pixel_buffer_mutex_) == kPthreadMutexSuccess) { + if (pixel_buffer_ != NULL && !pixel_buffer_->is_null()) { + pixels = pixel_buffer_->data(); + } + } + return reinterpret_cast(pixels); +} + +void PiGenerator::HandleMessage(const pp::Var& var_message) { + if (!var_message.is_string()) { + PostMessage(pp::Var(kInvalidPiValue)); + } + std::string message = var_message.AsString(); + if (message == kPaintMethodId) { + Paint(); + } else { + PostMessage(pp::Var(kInvalidPiValue)); + } +} + +void PiGenerator::UnlockPixels() const { + pthread_mutex_unlock(&pixel_buffer_mutex_); +} + +void PiGenerator::Paint() { + ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_); + if (!scoped_mutex.is_valid()) { + return; + } + FlushPixelBuffer(); + // Post the current estimate of Pi back to the browser. + pp::Var pi_estimate(pi()); + // Paint() is called on the main thread, so no need for CallOnMainThread() + // here. It's OK to just post the message. + PostMessage(pi_estimate); +} + +void PiGenerator::CreateContext(const pp::Size& size) { + ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_); + if (!scoped_mutex.is_valid()) { + return; + } + if (IsContextValid()) + return; + graphics_2d_context_ = new pp::Graphics2D(this, size, false); + if (!BindGraphics(*graphics_2d_context_)) { + printf("Couldn't bind the device context\n"); + } +} + +void PiGenerator::DestroyContext() { + ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_); + if (!scoped_mutex.is_valid()) { + return; + } + if (!IsContextValid()) + return; + delete graphics_2d_context_; + graphics_2d_context_ = NULL; +} + +void PiGenerator::FlushPixelBuffer() { + if (!IsContextValid()) + return; + // Note that the pixel lock is held while the buffer is copied into the + // device context and then flushed. + graphics_2d_context_->PaintImageData(*pixel_buffer_, pp::Point()); + if (flush_pending()) + return; + set_flush_pending(true); + graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this)); +} + +void* PiGenerator::ComputePi(void* param) { + int count = 0; // The number of points put inside the inscribed quadrant. + unsigned int seed = 1; + PiGenerator* pi_generator = static_cast(param); + srand(seed); + for (int i = 1; i <= kMaxPointCount && !pi_generator->quit(); ++i) { + ScopedPixelLock scoped_pixel_lock(pi_generator); + uint32_t* pixel_bits = scoped_pixel_lock.pixels(); + if (pixel_bits == NULL) { + // Note that if the pixel buffer never gets initialized, this won't ever + // paint anything. Which is probably the right thing to do. Also, this + // clause means that the image will not get the very first few Pi dots, + // since it's possible that this thread starts before the pixel buffer is + // initialized. + continue; + } + double x = static_cast(rand_r(&seed)) / RAND_MAX; + double y = static_cast(rand_r(&seed)) / RAND_MAX; + double distance = sqrt(x * x + y * y); + int px = x * pi_generator->width(); + int py = (1.0 - y) * pi_generator->height(); + uint32_t color = pixel_bits[pi_generator->width() * py + px]; + if (distance < 1.0) { + // Set color to blue. + ++count; + pi_generator->pi_ = 4.0 * count / i; + color += 4 << kBlueShift; + color &= kBlueMask; + } else { + // Set color to red. + color += 4 << kRedShift; + color &= kRedMask; + } + pixel_bits[pi_generator->width() * py + px] = color | kOpaqueColorMask; + } + return 0; } -/** - * Called before the plugin module is unloaded. - */ -PP_EXPORT void PPP_ShutdownModule() { +// The Module class. The browser calls the CreateInstance() method to create +// an instance of your NaCl module on the web page. The browser creates a new +// instance for each tag with type="application/x-nacl". +class OsmandModule : public pp::Module { + public: + OsmandModule() : pp::Module() {} + virtual ~OsmandModule() {} + + // Create and return a PiGeneratorInstance object. + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new PiGenerator(instance); + } +}; +} // namespace osmand + +// Factory function called by the browser when the module is first loaded. +// The browser keeps a singleton of this module. It calls the +// CreateInstance() method on the object you return to make instances. There +// is one instance per tag on the page. This is the main binding +// point for your NaCl module with the browser. +namespace pp { +Module* CreateModule() { + return new osmand::OsmandModule(); } +} // namespace pp diff --git a/Osmand-kernel/osmand/src/osmand_nacl.h b/Osmand-kernel/osmand/src/osmand_nacl.h new file mode 100644 index 0000000000..3eda6b387f --- /dev/null +++ b/Osmand-kernel/osmand/src/osmand_nacl.h @@ -0,0 +1,116 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef OSMAND_NACL_H_ +#define OSMAND_NACL_H_ + +#include +#include +#include +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/rect.h" +#include "ppapi/cpp/size.h" + +namespace osmand { + +// The Instance class. One of these exists for each instance of your NaCl +// module on the web page. The browser will ask the Module object to create +// a new Instance for each occurrence of the tag that has these +// attributes: +// type="application/x-nacl" +// nacl="pi_generator.nmf" +class PiGenerator : public pp::Instance { + public: + explicit PiGenerator(PP_Instance instance); + virtual ~PiGenerator(); + + // Start up the ComputePi() thread. + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); + + // Update the graphics context to the new size, and regenerate |pixel_buffer_| + // to fit the new size as well. + virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip); + + // Called by the browser to handle the postMessage() call in Javascript. + // The message in this case is expected to contain the string 'paint', and + // if so this invokes the Paint() function. If |var_message| is not a string + // type, or contains something other than 'paint', this method posts an + // invalid value for Pi (-1.0) back to the browser. + virtual void HandleMessage(const pp::Var& var_message); + + // Return a pointer to the pixels represented by |pixel_buffer_|. When this + // method returns, the underlying |pixel_buffer_| object is locked. This + // call must have a matching UnlockPixels() or various threading errors + // (e.g. deadlock) will occur. + uint32_t* LockPixels(); + // Release the image lock acquired by LockPixels(). + void UnlockPixels() const; + + // Flushes its contents of |pixel_buffer_| to the 2D graphics context. The + // ComputePi() thread fills in |pixel_buffer_| pixels as it computes Pi. + // This method is called by HandleMessage when a message containing 'paint' + // is received. Echos the current value of pi as computed by the Monte Carlo + // method by posting the value back to the browser. + void Paint(); + + bool quit() const { + return quit_; + } + + // |pi_| is computed in the ComputePi() thread. + double pi() const { + return pi_; + } + + int width() const { + return pixel_buffer_ ? pixel_buffer_->size().width() : 0; + } + int height() const { + return pixel_buffer_ ? pixel_buffer_->size().height() : 0; + } + + // Indicate whether a flush is pending. This can only be called from the + // main thread; it is not thread safe. + bool flush_pending() const { + return flush_pending_; + } + void set_flush_pending(bool flag) { + flush_pending_ = flag; + } + + private: + // Create and initialize the 2D context used for drawing. + void CreateContext(const pp::Size& size); + // Destroy the 2D drawing context. + void DestroyContext(); + // Push the pixels to the browser, then attempt to flush the 2D context. If + // there is a pending flush on the 2D context, then update the pixels only + // and do not flush. + void FlushPixelBuffer(); + + bool IsContextValid() const { + return graphics_2d_context_ != NULL; + } + + mutable pthread_mutex_t pixel_buffer_mutex_; + pp::Graphics2D* graphics_2d_context_; + pp::ImageData* pixel_buffer_; + bool flush_pending_; + bool quit_; + pthread_t compute_pi_thread_; + double pi_; + + // ComputePi() estimates Pi using Monte Carlo method and it is executed by a + // separate thread created in SetWindow(). ComputePi() puts kMaxPointCount + // points inside the square whose length of each side is 1.0, and calculates + // the ratio of the number of points put inside the inscribed quadrant divided + // by the total number of random points to get Pi/4. + static void* ComputePi(void* param); +}; + +} // namespace osmand + +#endif // OSMAND_NACL_H