Merge last green changeset on mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Sun, 18 Sep 2011 20:23:17 +0100
changeset 77120 5319b0100025f1a5bc7c30cabde3b9a3bcbf998d
parent 77112 bcde9f44b1495af9f5fb261975a20b8313f57c29 (current diff)
parent 77119 fbc0c5c938a97abf3d6745a00a842ef036fc1bfc (diff)
child 77131 75086668aebb002726a7e9dd27739bf5cd8b1177
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
milestone9.0a1
Merge last green changeset on mozilla-inbound to mozilla-central
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
layout/generic/nsObjectFrame.cpp
--- a/dom/plugins/base/Makefile.in
+++ b/dom/plugins/base/Makefile.in
@@ -94,16 +94,21 @@ CPPSRCS		= \
 		nsPluginHost.cpp \
 		nsPluginModule.cpp \
 		nsJSNPRuntime.cpp \
 		nsPluginTags.cpp \
 		PluginPRLibrary.cpp \
 		nsPluginInstanceOwner.cpp \
 		$(NULL)
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),android)
+DIRS += android
+LOCAL_INCLUDES += -I$(topsrcdir)/dom/plugins/base/android
+endif
+
 ifeq ($(OS_ARCH),WINNT)
 	CPPSRCS += nsPluginsDirWin.cpp
 	CPPSRCS += nsPluginNativeWindowWin.cpp
 	CPPSRCS += nsPluginDirServiceProvider.cpp
 	LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
 	CPPSRCS += nsPluginsDirOS2.cpp
@@ -122,17 +127,17 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
 else
 	CPPSRCS += nsPluginNativeWindow.cpp
 endif
 endif
 endif
 endif
 endif
 
-LOCAL_INCLUDES = \
+LOCAL_INCLUDES += \
   -I$(topsrcdir)/xpcom/base/ \
   $(MOZ_CAIRO_CFLAGS) \
   $(NULL)
 
 include $(topsrcdir)/dom/dom-config.mk
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/dom/plugins/base/PluginPRLibrary.cpp
+++ b/dom/plugins/base/PluginPRLibrary.cpp
@@ -32,34 +32,62 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/PluginPRLibrary.h"
-
 // Some plugins on Windows, notably Quake Live, implement NP_Initialize using
 // cdecl instead of the documented stdcall. In order to work around this,
 // we force the caller to use a frame pointer.
 #if defined(XP_WIN) && defined(_M_IX86)
 #include <malloc.h>
 
 // gNotOptimized exists so that the compiler will not optimize the alloca
 // below.
 static int gNotOptimized;
 #define CALLING_CONVENTION_HACK void* foo = _alloca(gNotOptimized);
 #else
 #define CALLING_CONVENTION_HACK
 #endif
 
-namespace mozilla {
+#ifdef ANDROID
+#include "AndroidBridge.h"
+#include "android_npapi.h"
+#include <android/log.h>
+#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoJavaEnv", ## args)
+#endif
 
-#if defined(XP_UNIX) && !defined(XP_MACOSX)
+namespace mozilla {
+#ifdef ANDROID
+nsresult
+PluginPRLibrary::NP_Initialize(NPNetscapeFuncs* bFuncs,
+			       NPPluginFuncs* pFuncs, NPError* error)
+{
+  if (mNP_Initialize) {
+    *error = mNP_Initialize(bFuncs, pFuncs, GetJNIForThread());
+  } else {
+    NP_InitializeFunc pfNP_Initialize = (NP_InitializeFunc)
+      PR_FindFunctionSymbol(mLibrary, "NP_Initialize");
+    if (!pfNP_Initialize)
+      return NS_ERROR_FAILURE;
+    *error = pfNP_Initialize(bFuncs, pFuncs, GetJNIForThread());
+  }
+
+
+  // Save pointers to functions that get called through PluginLibrary itself.
+  mNPP_New = pFuncs->newp;
+  mNPP_GetValue = pFuncs->getvalue;
+  mNPP_ClearSiteData = pFuncs->clearsitedata;
+  mNPP_GetSitesWithData = pFuncs->getsiteswithdata;
+  return NS_OK;
+}
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
 nsresult
 PluginPRLibrary::NP_Initialize(NPNetscapeFuncs* bFuncs,
 			       NPPluginFuncs* pFuncs, NPError* error)
 {
   if (mNP_Initialize) {
     *error = mNP_Initialize(bFuncs, pFuncs);
   } else {
     NP_InitializeFunc pfNP_Initialize = (NP_InitializeFunc)
--- a/dom/plugins/base/PluginPRLibrary.h
+++ b/dom/plugins/base/PluginPRLibrary.h
@@ -58,19 +58,21 @@ public:
         mNP_GetMIMEDescription(nsnull),
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
         mNP_GetValue(nsnull),
 #endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
         mNP_GetEntryPoints(nsnull),
 #endif
         mNPP_New(nsnull),
+        mNPP_GetValue(nsnull),
         mNPP_ClearSiteData(nsnull),
         mNPP_GetSitesWithData(nsnull),
-        mLibrary(aLibrary)
+        mLibrary(aLibrary),
+        mFilePath(aFilePath)
     {
         NS_ASSERTION(mLibrary, "need non-null lib");
         // addref here??
     }
 
     virtual ~PluginPRLibrary()
     {
         // unref here??
@@ -154,28 +156,32 @@ public:
     NS_OVERRIDE
     virtual nsresult EndUpdateBackground(NPP instance,
                                          gfxContext* aCtx, const nsIntRect&);
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
     virtual nsresult HandleGUIEvent(NPP instance,
                                     const nsGUIEvent& anEvent, bool* handled);
 #endif
 
+    virtual void GetLibraryPath(nsACString& aPath) { aPath.Assign(mFilePath); }
+
 private:
     NP_InitializeFunc mNP_Initialize;
     NP_ShutdownFunc mNP_Shutdown;
     NP_GetMIMEDescriptionFunc mNP_GetMIMEDescription;
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
     NP_GetValueFunc mNP_GetValue;
 #endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
     NP_GetEntryPointsFunc mNP_GetEntryPoints;
 #endif
     NPP_NewProcPtr mNPP_New;
+    NPP_GetValueProcPtr mNPP_GetValue;
     NPP_ClearSiteDataPtr mNPP_ClearSiteData;
     NPP_GetSitesWithDataPtr mNPP_GetSitesWithData;
     PRLibrary* mLibrary;
+    nsCString mFilePath;
 };
 
 
 } // namespace mozilla
 
 #endif  // ifndef PluginPRLibrary_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPAudio.cpp
@@ -0,0 +1,361 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "base/basictypes.h"
+#include "AndroidBridge.h"
+
+#include <android/log.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "assert.h"
+#include "ANPBase.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPluginsAudio" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_audio_##name
+
+/* android.media.AudioTrack */
+struct AudioTrack {
+  jclass    at_class;
+  jmethodID constructor;
+  jmethodID flush;
+  jmethodID pause;
+  jmethodID play;
+  jmethodID setvol;
+  jmethodID stop;
+  jmethodID write;
+  jmethodID getpos;
+};
+
+enum AudioTrackMode {
+  MODE_STATIC = 0,
+  MODE_STREAM = 1
+};
+
+/* android.media.AudioManager */
+enum AudioManagerStream {
+  STREAM_VOICE_CALL = 0,
+  STREAM_SYSTEM = 1,
+  STREAM_RING = 2,
+  STREAM_MUSIC = 3,
+  STREAM_ALARM = 4,
+  STREAM_NOTIFICATION = 5,
+  STREAM_DTMF = 8
+};
+
+/* android.media.AudioFormat */
+enum AudioFormatChannel {
+  CHANNEL_OUT_MONO = 4,
+  CHANNEL_OUT_STEREO = 12
+};
+
+enum AudioFormatEncoding {
+  ENCODING_PCM_16BIT = 2,
+  ENCODING_PCM_8BIT = 3
+};
+
+static struct AudioTrack at;
+
+static jclass
+init_jni_bindings(JNIEnv *jenv) {
+  jclass jc = jenv->FindClass("android/media/AudioTrack");
+
+  at.constructor = jenv->GetMethodID(jc, "<init>", "(IIIIII)V");
+  at.flush       = jenv->GetMethodID(jc, "flush", "()V");
+  at.pause       = jenv->GetMethodID(jc, "pause", "()V");
+  at.play        = jenv->GetMethodID(jc, "play",  "()V");
+  at.setvol      = jenv->GetMethodID(jc, "setStereoVolume",  "(FF)I");
+  at.stop        = jenv->GetMethodID(jc, "stop",  "()V");
+  at.write       = jenv->GetMethodID(jc, "write", "([BII)I");
+  at.getpos      = jenv->GetMethodID(jc, "getPlaybackHeadPosition", "()I");
+
+  return jc;
+}
+
+struct ANPAudioTrack {
+  jobject output_unit;
+  jclass at_class;
+
+  unsigned int rate;
+  unsigned int channels;
+  unsigned int bufferSize;
+  unsigned int isStopped;
+  unsigned int keepGoing;
+
+  void* user;
+  ANPAudioCallbackProc proc;
+  ANPSampleFormat format;
+};
+
+class AudioRunnable : public nsRunnable
+{
+public:
+  NS_DECL_NSIRUNNABLE
+
+  AudioRunnable(ANPAudioTrack* aAudioTrack) {
+    mTrack = aAudioTrack;
+  }
+
+  ANPAudioTrack* mTrack;
+};
+
+NS_IMETHODIMP
+AudioRunnable::Run()
+{
+  JNIEnv* jenv = GetJNIForThread();
+
+  if (jenv->PushLocalFrame(128)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  jbyteArray bytearray = jenv->NewByteArray(mTrack->bufferSize);
+  if (!bytearray) {
+    LOG("AudioRunnable:: Run.  Could not create bytearray");
+    return NS_ERROR_FAILURE;
+  }
+
+  jbyte *byte = jenv->GetByteArrayElements(bytearray, NULL);
+  if (!byte) {
+    LOG("AudioRunnable:: Run.  Could not create bytearray");
+    return NS_ERROR_FAILURE;
+  }
+
+  ANPAudioBuffer buffer;
+  buffer.channelCount = mTrack->channels;
+  buffer.format = mTrack->format;
+  buffer.bufferData = (void*) byte;
+
+  while (mTrack->keepGoing)
+  {
+    // reset the buffer size
+    buffer.size = mTrack->bufferSize;
+
+    // Get data from the plugin
+    mTrack->proc(kMoreData_ANPAudioEvent, mTrack->user, &buffer);
+
+    if (buffer.size == 0) {
+      LOG("%p - kMoreData_ANPAudioEvent", mTrack);
+      continue;
+    }
+
+    size_t wroteSoFar = 0;
+    jint retval;
+    do {
+      retval = jenv->CallIntMethod(mTrack->output_unit,
+                                   at.write,
+                                   bytearray,
+                                   wroteSoFar,
+                                   buffer.size - wroteSoFar);
+      if (retval < 0) {
+        LOG("%p - Write failed %d", mTrack, retval);
+        break;
+      }
+
+      wroteSoFar += retval;
+
+    } while(wroteSoFar < buffer.size);
+  }
+
+  jenv->DeleteGlobalRef(mTrack->output_unit);
+  jenv->DeleteGlobalRef(mTrack->at_class);
+
+  free(mTrack);
+
+  jenv->ReleaseByteArrayElements(bytearray, byte, 0);
+  jenv->PopLocalFrame(NULL);
+
+  return NS_OK;
+}
+
+ANPAudioTrack*
+anp_audio_newTrack(uint32_t sampleRate,    // sampling rate in Hz
+                   ANPSampleFormat format,
+                   int channelCount,       // MONO=1, STEREO=2
+                   ANPAudioCallbackProc proc,
+                   void* user)
+{
+  ANPAudioTrack *s = (ANPAudioTrack*) malloc(sizeof(ANPAudioTrack));
+  if (s == NULL) {
+    return NULL;
+  }
+
+  JNIEnv *jenv = GetJNIForThread();
+  if (!jenv)
+    return NULL;
+
+  s->at_class = init_jni_bindings(jenv);
+  s->rate = sampleRate;
+  s->channels = channelCount;
+  s->bufferSize = s->rate * s->channels;
+  s->isStopped = true;
+  s->keepGoing = false;
+  s->user = user;
+  s->proc = proc;
+  s->format = format;
+
+  int jformat;
+  switch (format) {
+  case kPCM16Bit_ANPSampleFormat:
+    jformat = ENCODING_PCM_16BIT;
+    break;
+  case kPCM8Bit_ANPSampleFormat:
+    jformat = ENCODING_PCM_8BIT;
+    break;
+  default:
+    LOG("Unknown audio format.  defaulting to 16bit.");
+    jformat = ENCODING_PCM_16BIT;
+    break;
+  }
+
+  int jChannels;
+  switch (channelCount) {
+  case 1:
+    jChannels = CHANNEL_OUT_MONO;
+    break;
+  case 2:
+    jChannels = CHANNEL_OUT_STEREO;
+    break;
+  default:
+    LOG("Unknown channel count.  defaulting to mono.");
+    jChannels = CHANNEL_OUT_MONO;
+    break;
+  }
+
+  jobject obj = jenv->NewObject(s->at_class,
+                                at.constructor,
+                                STREAM_MUSIC,
+                                s->rate,
+                                jChannels,
+                                jformat,
+                                s->bufferSize,
+                                MODE_STREAM);
+
+  jthrowable exception = jenv->ExceptionOccurred();
+  if (exception) {
+    LOG("%s fAILED  ", __PRETTY_FUNCTION__);
+    jenv->ExceptionDescribe();
+    jenv->ExceptionClear();
+    jenv->DeleteGlobalRef(s->at_class);
+    free(s);
+    return NULL;
+  }
+
+  s->output_unit = jenv->NewGlobalRef(obj);
+  return s;
+}
+
+void
+anp_audio_deleteTrack(ANPAudioTrack* s)
+{
+  if (s == NULL) {
+    return;
+  }
+
+  s->keepGoing = false;
+
+  // deallocation happens in the AudioThread.  There is a
+  // potential leak if anp_audio_start is never called, but
+  // we do not see that from flash.
+}
+
+void
+anp_audio_start(ANPAudioTrack* s)
+{
+  if (s == NULL || s->output_unit == NULL) {
+    return;
+  }
+  
+  if (s->keepGoing) {
+    // we are already playing.  Ignore.
+    LOG("anp_audio_start called twice!");
+    return;
+  }
+
+  JNIEnv *jenv = GetJNIForThread();
+  jenv->CallVoidMethod(s->output_unit, at.play);
+
+  s->isStopped = false;
+  s->keepGoing = true;
+
+  // AudioRunnable now owns the ANPAudioTrack
+  nsRefPtr<AudioRunnable> runnable = new AudioRunnable(s);
+
+  nsCOMPtr<nsIThread> thread;
+  NS_NewThread(getter_AddRefs(thread), runnable);
+}
+
+void
+anp_audio_pause(ANPAudioTrack* s)
+{
+  if (s == NULL || s->output_unit == NULL) {
+    return;
+  }
+
+  JNIEnv *jenv = GetJNIForThread();
+  jenv->CallVoidMethod(s->output_unit, at.pause);
+}
+
+void
+anp_audio_stop(ANPAudioTrack* s)
+{
+  if (s == NULL || s->output_unit == NULL) {
+    return;
+  }
+
+  s->isStopped = true;
+  JNIEnv *jenv = GetJNIForThread();
+  jenv->CallVoidMethod(s->output_unit, at.stop);
+}
+
+bool
+anp_audio_isStopped(ANPAudioTrack* s)
+{
+  return s->isStopped;
+}
+
+void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, newTrack);
+  ASSIGN(i, deleteTrack);
+  ASSIGN(i, start);
+  ASSIGN(i, pause);
+  ASSIGN(i, stop);
+  ASSIGN(i, isStopped);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPBase.h
@@ -0,0 +1,90 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "android_npapi.h"
+#include <stdlib.h>
+#include "nsAutoPtr.h"
+#include "gfxFont.h"
+
+#define NOT_IMPLEMENTED_FATAL() do {                                    \
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoPlugins",              \
+                        "%s not implemented %s, %d",                    \
+                        __PRETTY_FUNCTION__, __FILE__, __LINE__);       \
+    abort();                                                            \
+  } while(0)
+
+#define NOT_IMPLEMENTED()                                               \
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoPlugins",              \
+                        "!!!!!!!!!!!!!!  %s not implemented %s, %d",    \
+                        __PRETTY_FUNCTION__, __FILE__, __LINE__);       \
+
+class gfxFont;
+
+void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i);
+void InitBitmapInterface(ANPBitmapInterfaceV0 *i);
+void InitCanvasInterface(ANPCanvasInterfaceV0 *i);
+void InitEventInterface(ANPEventInterfaceV0 *i);
+void InitLogInterface(ANPLogInterfaceV0 *i);
+void InitMatrixInterface(ANPMatrixInterfaceV0 *i);
+void InitPaintInterface(ANPPaintInterfaceV0 *i);
+void InitPathInterface(ANPPathInterfaceV0 *i);
+void InitSurfaceInterface(ANPSurfaceInterfaceV0 *i);
+void InitSystemInterface(ANPSystemInterfaceV0 *i);
+void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i);
+void InitWindowInterface(ANPWindowInterfaceV0 *i);
+
+struct ANPTypeface {
+  nsRefPtr<gfxFont> mFont;
+};
+
+
+typedef struct {
+  ANPMatrixFlag flags;
+  ANPColor color;
+  ANPPaintStyle style;
+  float strokeWidth;
+  float strokeMiter;
+  ANPPaintCap paintCap;
+  ANPPaintJoin paintJoin;
+  ANPTextEncoding textEncoding;
+  ANPPaintAlign paintAlign;
+  float textSize;
+  float textScaleX;
+  float textSkewX;
+  ANPTypeface typeface;
+} ANPPaintPrivate;
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPBitmap.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_bitmap_##name
+
+
+#define SK_A32_BITS     8
+#define SK_R32_BITS     8
+#define SK_G32_BITS     8
+#define SK_B32_BITS     8
+
+#ifdef IS_BIG_ENDIAN
+#define SK_R32_SHIFT    24
+#define SK_G32_SHIFT    16
+#define SK_B32_SHIFT    8
+#define SK_A32_SHIFT    0
+#else
+#define SK_R32_SHIFT    0
+#define SK_G32_SHIFT    8
+#define SK_B32_SHIFT    16
+#define SK_A32_SHIFT    24
+#endif
+
+#define SK_A32_MASK     ((1 << SK_A32_BITS) - 1)
+#define SK_R32_MASK     ((1 << SK_R32_BITS) - 1)
+#define SK_G32_MASK     ((1 << SK_G32_BITS) - 1)
+#define SK_B32_MASK     ((1 << SK_B32_BITS) - 1)
+
+#define SK_R16_BITS     5
+#define SK_G16_BITS     6
+#define SK_B16_BITS     5
+
+#define SK_R16_SHIFT    (SK_B16_BITS + SK_G16_BITS)
+#define SK_G16_SHIFT    (SK_B16_BITS)
+#define SK_B16_SHIFT    0
+
+#define SK_R16_MASK     ((1 << SK_R16_BITS) - 1)
+#define SK_G16_MASK     ((1 << SK_G16_BITS) - 1)
+#define SK_B16_MASK     ((1 << SK_B16_BITS) - 1)
+
+bool
+anp_bitmap_getPixelPacking(ANPBitmapFormat fmt, ANPPixelPacking* packing) {
+  LOG("%s", __PRETTY_FUNCTION__);
+  switch (fmt) {
+    case kRGBA_8888_ANPBitmapFormat:
+      if (packing) {
+        packing->AShift = SK_A32_SHIFT;
+        packing->ABits  = SK_A32_BITS;
+        packing->RShift = SK_R32_SHIFT;
+        packing->RBits  = SK_R32_BITS;
+        packing->GShift = SK_G32_SHIFT;
+        packing->GBits  = SK_G32_BITS;
+        packing->BShift = SK_B32_SHIFT;
+        packing->BBits  = SK_B32_BITS;
+      }
+      return true;
+    case kRGB_565_ANPBitmapFormat:
+      if (packing) {
+        packing->AShift = 0;
+        packing->ABits  = 0;
+        packing->RShift = SK_R16_SHIFT;
+        packing->RBits  = SK_R16_BITS;
+        packing->GShift = SK_G16_SHIFT;
+        packing->GBits  = SK_G16_BITS;
+        packing->BShift = SK_B16_SHIFT;
+        packing->BBits  = SK_B16_BITS;
+      }
+      return true;
+  default:
+    break;
+  }
+  return false;
+}
+
+void InitBitmapInterface(ANPBitmapInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, getPixelPacking);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPCanvas.cpp
@@ -0,0 +1,373 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+
+#include "cairo.h"
+#include "gfxPlatform.h"
+#include "gfxASurface.h"
+#include "gfxImageSurface.h"
+#include "gfxUtils.h"
+#include "gfxContext.h"
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_canvas_##name
+
+
+ANPCanvas*
+anp_canvas_newCanvas(const ANPBitmap* bitmap)
+{
+  PRUint32 stride;
+  gfxASurface::gfxImageFormat  format;
+
+  if (bitmap->format == ANPBitmapFormats::kRGBA_8888_ANPBitmapFormat) {
+    stride = bitmap->width * 4;
+    format = gfxImageSurface::ImageFormatARGB32;
+  }
+  else if (bitmap->format == ANPBitmapFormats::kRGB_565_ANPBitmapFormat) {
+    stride = bitmap->width * 2;
+    format = gfxImageSurface::ImageFormatRGB16_565;
+  }
+  else {
+    LOG("%s -- Unknown format", __PRETTY_FUNCTION__);
+    return nsnull;
+  }
+
+  gfxImageSurface* pluginSurface = new gfxImageSurface(static_cast<unsigned char*>(bitmap->baseAddr),
+                                                       gfxIntSize(bitmap->width,  bitmap->height), 
+                                                       stride,
+                                                       format);
+  if (pluginSurface->CairoStatus()) {
+    LOG("%s -- %d x %d FAILED to create gfxImageSurface", __PRETTY_FUNCTION__, bitmap->width, bitmap->height);
+    return nsnull;
+  }
+
+  gfxContext *pluginContext = new gfxContext(pluginSurface);
+  NS_ADDREF(pluginContext);
+  return (ANPCanvas*) pluginContext;
+}
+
+void
+anp_canvas_deleteCanvas(ANPCanvas* canvas)
+{
+  if (!canvas)
+    return;
+  gfxContext *ctx = (gfxContext*)canvas;
+  NS_RELEASE( ctx );
+}
+
+void
+anp_canvas_save(ANPCanvas* canvas)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->Save();
+}
+
+void
+anp_canvas_restore(ANPCanvas* canvas)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->Restore();
+}
+
+void
+anp_canvas_translate(ANPCanvas* canvas, float tx, float ty)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->Translate(gfxPoint(tx,ty));
+}
+
+void
+anp_canvas_scale(ANPCanvas* canvas, float sx, float sy)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->Scale(sx, sy);
+}
+
+void
+anp_canvas_rotate(ANPCanvas* canvas, float degrees)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->Rotate(degrees);
+}
+
+void
+anp_canvas_skew(ANPCanvas* canvas, float kx, float ky)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_concat(ANPCanvas* canvas, const ANPMatrix*)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_clipRect(ANPCanvas* canvas, const ANPRectF* r)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->Clip(gfxRect(r->left,
+                    r->top,
+                    r->right - r->left,
+                    r->bottom - r->top));
+}
+
+void
+anp_canvas_clipPath(ANPCanvas* canvas, const ANPPath*)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_getTotalMatrix(ANPCanvas* canvas, ANPMatrix*)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+bool
+anp_canvas_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* bounds, bool aa)
+{
+  if (!canvas)
+    return false;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+  return false;
+}
+
+bool
+anp_canvas_getDeviceClipBounds(ANPCanvas* canvas, ANPRectI* bounds)
+{
+  if (!canvas)
+    return false;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+  return false;
+}
+
+void
+anp_canvas_drawColor(ANPCanvas* canvas, ANPColor c)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->SetDeviceColor(gfxRGBA(c, gfxRGBA::PACKED_ARGB));
+  LOG("returning from %s", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_drawPaint(ANPCanvas* canvas, const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s", "                    **************   NOT IMPLEMENTED!!!");
+}
+
+void
+anp_canvas_drawLine(ANPCanvas* canvas, float x0, float y0, float x1, float y1,
+                    const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  ctx->NewPath();
+  ctx->SetColor(((ANPPaintPrivate*)paint)->color);
+  ctx->Line(gfxPoint(x0, y0), gfxPoint(x1, y1));
+  ctx->Fill();
+}
+
+void
+anp_canvas_drawRect(ANPCanvas* canvas, const ANPRectF* r, const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+
+  ctx->NewPath();
+  ctx->SetColor(((ANPPaintPrivate*)paint)->color);
+  ctx->Rectangle(gfxRect(r->left,
+                         r->top,
+                         r->right - r->left,
+                         r->bottom - r->top));
+  ctx->Fill();
+}
+
+void
+anp_canvas_drawOval(ANPCanvas* canvas, const ANPRectF* r, const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+   
+  ctx->NewPath();
+  ctx->SetColor(((ANPPaintPrivate*)paint)->color);
+
+  float sizeX = (r->right   - r->left);
+  float sizeY = (r->bottom  - r->top);
+
+  ctx->Ellipse(gfxPoint(r->left + ( sizeX / 2), r->top  + ( sizeY  / 2)),
+               gfxSize(sizeX, sizeY));
+  ctx->Fill();
+}
+
+void
+anp_canvas_drawPath(ANPCanvas* canvas, const ANPPath*, const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_drawText(ANPCanvas* canvas, const void* text, uint32_t byteLength,
+                                float x, float y, const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_drawPosText(ANPCanvas* canvas, const void* text, uint32_t byteLength,
+                       const float xy[], const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_drawBitmap(ANPCanvas* canvas, const ANPBitmap*, float x, float y,
+                      const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_canvas_drawBitmapRect(ANPCanvas* canvas, const ANPBitmap*,
+                          const ANPRectI* src, const ANPRectF* dst,
+                          const ANPPaint* paint)
+{
+  if (!canvas)
+    return;
+
+  gfxContext* ctx = (gfxContext*)canvas;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+void InitCanvasInterface(ANPCanvasInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, newCanvas);
+  ASSIGN(i, deleteCanvas);
+  ASSIGN(i, save);
+  ASSIGN(i, restore);
+  ASSIGN(i, translate);
+  ASSIGN(i, scale);
+  ASSIGN(i, rotate);
+  ASSIGN(i, skew);
+  ASSIGN(i, concat);
+  ASSIGN(i, clipRect);
+  ASSIGN(i, clipPath);
+  ASSIGN(i, getTotalMatrix);
+  ASSIGN(i, getLocalClipBounds);
+  ASSIGN(i, getDeviceClipBounds);
+  ASSIGN(i, drawColor);
+  ASSIGN(i, drawPaint);
+  ASSIGN(i, drawLine);
+  ASSIGN(i, drawRect);
+  ASSIGN(i, drawOval);
+  ASSIGN(i, drawPath);
+  ASSIGN(i, drawText);
+  ASSIGN(i, drawPosText);
+  ASSIGN(i, drawBitmap);
+  ASSIGN(i, drawBitmapRect);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPEvent.cpp
@@ -0,0 +1,84 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+#include "nsThreadUtils.h"
+#include "nsNPAPIPluginInstance.h"
+#include "AndroidBridge.h"
+#include "nsNPAPIPlugin.h"
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_event_##name
+
+class PluginEventRunnable : public nsRunnable
+{
+public:
+  PluginEventRunnable(NPP inst, ANPEvent* event, NPPluginFuncs* aFuncs)
+    : mInstance(inst), mEvent(*event), mFuncs(aFuncs) {}
+  virtual nsresult Run() {
+    (*mFuncs->event)(mInstance, &mEvent);
+    return NS_OK;
+  }
+private:
+  NPP mInstance;
+  ANPEvent mEvent;
+  NPPluginFuncs* mFuncs;
+};
+
+void
+anp_event_postEvent(NPP inst, const ANPEvent* event)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!mozilla::AndroidBridge::Bridge()) {
+    LOG("no bridge in %s!!!!", __PRETTY_FUNCTION__);
+    return;
+  }
+  nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(inst->ndata);
+  NPPluginFuncs* pluginFunctions = pinst->GetPlugin()->PluginFuncs();
+  mozilla::AndroidBridge::Bridge()->PostToJavaThread(
+    new PluginEventRunnable(inst, const_cast<ANPEvent*>(event), pluginFunctions), PR_TRUE);
+  LOG("returning from %s", __PRETTY_FUNCTION__);
+}
+
+
+void InitEventInterface(ANPEventInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, postEvent);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPKeyCodes.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANPKeyCodes_DEFINED
+#define ANPKeyCodes_DEFINED
+
+/*  List the key codes that are set to a plugin in the ANPKeyEvent.
+ 
+    These exactly match the values in android/view/KeyEvent.java and the
+    corresponding .h file android/keycodes.h.
+*/
+enum ANPKeyCodes {
+    kUnknown_ANPKeyCode = 0,
+
+    kSoftLeft_ANPKeyCode = 1,
+    kSoftRight_ANPKeyCode = 2,
+    kHome_ANPKeyCode = 3,
+    kBack_ANPKeyCode = 4,
+    kCall_ANPKeyCode = 5,
+    kEndCall_ANPKeyCode = 6,
+    k0_ANPKeyCode = 7,
+    k1_ANPKeyCode = 8,
+    k2_ANPKeyCode = 9,
+    k3_ANPKeyCode = 10,
+    k4_ANPKeyCode = 11,
+    k5_ANPKeyCode = 12,
+    k6_ANPKeyCode = 13,
+    k7_ANPKeyCode = 14,
+    k8_ANPKeyCode = 15,
+    k9_ANPKeyCode = 16,
+    kStar_ANPKeyCode = 17,
+    kPound_ANPKeyCode = 18,
+    kDpadUp_ANPKeyCode = 19,
+    kDpadDown_ANPKeyCode = 20,
+    kDpadLeft_ANPKeyCode = 21,
+    kDpadRight_ANPKeyCode = 22,
+    kDpadCenter_ANPKeyCode = 23,
+    kVolumeUp_ANPKeyCode = 24,
+    kVolumeDown_ANPKeyCode = 25,
+    kPower_ANPKeyCode = 26,
+    kCamera_ANPKeyCode = 27,
+    kClear_ANPKeyCode = 28,
+    kA_ANPKeyCode = 29,
+    kB_ANPKeyCode = 30,
+    kC_ANPKeyCode = 31,
+    kD_ANPKeyCode = 32,
+    kE_ANPKeyCode = 33,
+    kF_ANPKeyCode = 34,
+    kG_ANPKeyCode = 35,
+    kH_ANPKeyCode = 36,
+    kI_ANPKeyCode = 37,
+    kJ_ANPKeyCode = 38,
+    kK_ANPKeyCode = 39,
+    kL_ANPKeyCode = 40,
+    kM_ANPKeyCode = 41,
+    kN_ANPKeyCode = 42,
+    kO_ANPKeyCode = 43,
+    kP_ANPKeyCode = 44,
+    kQ_ANPKeyCode = 45,
+    kR_ANPKeyCode = 46,
+    kS_ANPKeyCode = 47,
+    kT_ANPKeyCode = 48,
+    kU_ANPKeyCode = 49,
+    kV_ANPKeyCode = 50,
+    kW_ANPKeyCode = 51,
+    kX_ANPKeyCode = 52,
+    kY_ANPKeyCode = 53,
+    kZ_ANPKeyCode = 54,
+    kComma_ANPKeyCode = 55,
+    kPeriod_ANPKeyCode = 56,
+    kAltLeft_ANPKeyCode = 57,
+    kAltRight_ANPKeyCode = 58,
+    kShiftLeft_ANPKeyCode = 59,
+    kShiftRight_ANPKeyCode = 60,
+    kTab_ANPKeyCode = 61,
+    kSpace_ANPKeyCode = 62,
+    kSym_ANPKeyCode = 63,
+    kExplorer_ANPKeyCode = 64,
+    kEnvelope_ANPKeyCode = 65,
+    kNewline_ANPKeyCode = 66,
+    kDel_ANPKeyCode = 67,
+    kGrave_ANPKeyCode = 68,
+    kMinus_ANPKeyCode = 69,
+    kEquals_ANPKeyCode = 70,
+    kLeftBracket_ANPKeyCode = 71,
+    kRightBracket_ANPKeyCode = 72,
+    kBackslash_ANPKeyCode = 73,
+    kSemicolon_ANPKeyCode = 74,
+    kApostrophe_ANPKeyCode = 75,
+    kSlash_ANPKeyCode = 76,
+    kAt_ANPKeyCode = 77,
+    kNum_ANPKeyCode = 78,
+    kHeadSetHook_ANPKeyCode = 79,
+    kFocus_ANPKeyCode = 80,
+    kPlus_ANPKeyCode = 81,
+    kMenu_ANPKeyCode = 82,
+    kNotification_ANPKeyCode = 83,
+    kSearch_ANPKeyCode = 84,
+    kMediaPlayPause_ANPKeyCode = 85,
+    kMediaStop_ANPKeyCode = 86,
+    kMediaNext_ANPKeyCode = 87,
+    kMediaPrevious_ANPKeyCode = 88,
+    kMediaRewind_ANPKeyCode = 89,
+    kMediaFastForward_ANPKeyCode = 90,
+    kMute_ANPKeyCode = 91,
+    kPageUp_ANPKeyCode = 92,
+    kPageDown_ANPKeyCode = 93,
+    kPictsymbols_ANPKeyCode = 94,
+    kSwitchCharset_ANPKeyCode = 95,
+    kButtonA_ANPKeyCode = 96,
+    kButtonB_ANPKeyCode = 97,
+    kButtonC_ANPKeyCode = 98,
+    kButtonX_ANPKeyCode = 99,
+    kButtonY_ANPKeyCode = 100,
+    kButtonZ_ANPKeyCode = 101,
+    kButtonL1_ANPKeyCode = 102,
+    kButtonR1_ANPKeyCode = 103,
+    kButtonL2_ANPKeyCode = 104,
+    kButtonR2_ANPKeyCode = 105,
+    kButtonThumbL_ANPKeyCode = 106,
+    kButtonThumbR_ANPKeyCode = 107,
+    kButtonStart_ANPKeyCode = 108,
+    kButtonSelect_ANPKeyCode = 109,
+    kButtonMode_ANPKeyCode = 110,
+
+    // NOTE: If you add a new keycode here you must also add it to several other files.
+    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPLog.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_log_##name
+
+void
+anp_log_log(ANPLogType type, const char format[], ...) {
+
+  va_list argp;
+  va_start(argp,format);
+  __android_log_vprint(type == kError_ANPLogType ? ANDROID_LOG_ERROR : type == kWarning_ANPLogType ?
+                       ANDROID_LOG_WARN : ANDROID_LOG_INFO, "GeckoPluginLog", format, argp);
+  va_end(argp);
+}
+
+void InitLogInterface(ANPLogInterfaceV0 *i) {
+      _assert(i->inSize == sizeof(*i));
+      ASSIGN(i, log);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPMatrix.cpp
@@ -0,0 +1,197 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_matrix_##name
+
+/** Return a new identity matrix
+ */
+ANPMatrix*
+anp_matrix_newMatrix()
+{
+  NOT_IMPLEMENTED();
+  return 0;
+}
+
+/** Delete a matrix previously allocated by newMatrix()
+ */
+void
+anp_matrix_deleteMatrix(ANPMatrix*)
+{
+  NOT_IMPLEMENTED();
+}
+
+
+ANPMatrixFlag
+anp_matrix_getFlags(const ANPMatrix*)
+{
+  NOT_IMPLEMENTED();
+  return 0;
+}
+
+
+void
+anp_matrix_copy(ANPMatrix* dst, const ANPMatrix* src)
+{
+  NOT_IMPLEMENTED();
+}
+
+
+void
+anp_matrix_get3x3(const ANPMatrix*, float[9])
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_set3x3(ANPMatrix*, const float[9])
+{
+  NOT_IMPLEMENTED();
+}
+
+
+void
+anp_matrix_setIdentity(ANPMatrix*)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_preTranslate(ANPMatrix*, float tx, float ty)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_postTranslate(ANPMatrix*, float tx, float ty)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_preScale(ANPMatrix*, float sx, float sy)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_postScale(ANPMatrix*, float sx, float sy)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_preSkew(ANPMatrix*, float kx, float ky)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_postSkew(ANPMatrix*, float kx, float ky)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_preRotate(ANPMatrix*, float degrees)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_postRotate(ANPMatrix*, float degrees)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_preConcat(ANPMatrix*, const ANPMatrix*)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_matrix_postConcat(ANPMatrix*, const ANPMatrix*)
+{
+  NOT_IMPLEMENTED();
+}
+
+
+bool
+anp_matrix_invert(ANPMatrix* dst, const ANPMatrix* src)
+{
+  NOT_IMPLEMENTED();
+  return false;
+}
+
+void
+anp_matrix_mapPoints(ANPMatrix*, float dst[], const float src[],
+                                 int32_t count)
+{
+  NOT_IMPLEMENTED();
+}
+
+
+void InitMatrixInterface(ANPMatrixInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, newMatrix);
+  ASSIGN(i, deleteMatrix);
+  ASSIGN(i, getFlags);
+  ASSIGN(i, copy);
+  ASSIGN(i, get3x3);
+  ASSIGN(i, set3x3);
+  ASSIGN(i, setIdentity);
+  ASSIGN(i, preTranslate);
+  ASSIGN(i, postTranslate);
+  ASSIGN(i, preScale);
+  ASSIGN(i, postScale);
+  ASSIGN(i, preSkew);
+  ASSIGN(i, postSkew);
+  ASSIGN(i, preRotate);
+  ASSIGN(i, postRotate);
+  ASSIGN(i, preConcat);
+  ASSIGN(i, postConcat);
+  ASSIGN(i, invert);
+  ASSIGN(i, mapPoints);
+}
+
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPPaint.cpp
@@ -0,0 +1,454 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <android/log.h>
+#include "ANPBase.h"
+
+#define LOG(args...)  
+//__android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_paint_##name
+
+ANPPaint*
+anp_paint_newPaint()
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) calloc(1, sizeof(ANPPaintPrivate));
+  return (ANPPaint*) p;
+}
+
+void
+anp_paint_deletePaint(ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  free((void*)p);
+}
+
+
+ANPPaintFlags
+anp_paint_getFlags(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return kAntiAlias_ANPPaintFlag;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->flags;
+}
+
+void
+anp_paint_setFlags(ANPPaint* paint, ANPPaintFlags flags)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;  
+  p->flags = flags;
+}
+
+
+ANPColor
+anp_paint_getColor(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return ANP_MAKE_COLOR(1, 255, 255, 255);
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->color;
+}
+
+void
+anp_paint_setColor(ANPPaint* paint, ANPColor color)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->color = color;
+}
+
+
+ANPPaintStyle
+anp_paint_getStyle(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return kFill_ANPPaintStyle;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->style;
+}
+
+void
+anp_paint_setStyle(ANPPaint* paint, ANPPaintStyle style)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->style = style;
+}
+
+float
+anp_paint_getStrokeWidth(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->strokeWidth;
+}
+
+float
+anp_paint_getStrokeMiter(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->strokeMiter;
+}
+
+ANPPaintCap
+anp_paint_getStrokeCap(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return kButt_ANPPaintCap;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->paintCap;
+}
+
+ANPPaintJoin
+anp_paint_getStrokeJoin(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return kMiter_ANPPaintJoin;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->paintJoin;
+}
+
+void
+anp_paint_setStrokeWidth(ANPPaint* paint, float width)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->strokeWidth = width;
+}
+
+void
+anp_paint_setStrokeMiter(ANPPaint* paint, float miter)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->strokeMiter = miter;
+}
+
+void
+anp_paint_setStrokeCap(ANPPaint* paint, ANPPaintCap cap)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->paintCap = cap;
+}
+
+void
+anp_paint_setStrokeJoin(ANPPaint* paint, ANPPaintJoin join)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->paintJoin = join;
+}
+
+
+ANPTextEncoding
+anp_paint_getTextEncoding(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return kUTF8_ANPTextEncoding;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->textEncoding;
+}
+
+ANPPaintAlign
+anp_paint_getTextAlign(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return kLeft_ANPPaintAlign;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->paintAlign;
+}
+
+float
+anp_paint_getTextSize(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->textSize;
+}
+
+float
+anp_paint_getTextScaleX(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->textScaleX;
+}
+
+float
+anp_paint_getTextSkewX(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return p->textSkewX;
+}
+
+void
+anp_paint_setTextEncoding(ANPPaint* paint, ANPTextEncoding encoding)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->textEncoding = encoding;
+}
+
+void
+anp_paint_setTextAlign(ANPPaint* paint, ANPPaintAlign align)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->paintAlign = align;  
+}
+
+void
+anp_paint_setTextSize(ANPPaint* paint, float size)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->textSize = size;
+}
+
+void
+anp_paint_setTextScaleX(ANPPaint* paint, float scale)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->textScaleX = scale;
+}
+
+void
+anp_paint_setTextSkewX(ANPPaint* paint, float skew)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  p->textSkewX = skew;
+}
+
+
+/** Return the typeface in paint, or null if there is none. This does not
+    modify the owner count of the returned typeface.
+*/
+ANPTypeface*
+anp_paint_getTypeface(const ANPPaint* paint)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return NULL;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  return &p->typeface;
+}
+
+
+/** Set the paint's typeface. If the paint already had a non-null typeface,
+    its owner count is decremented. If the new typeface is non-null, its
+    owner count is incremented.
+*/
+void
+anp_paint_setTypeface(ANPPaint* paint, ANPTypeface* typeface)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+}
+
+/** Return the width of the text. If bounds is not null, return the bounds
+    of the text in that rectangle.
+*/
+float
+anp_paint_measureText(ANPPaint* paint, const void* text, uint32_t byteLength,
+                      ANPRectF* bounds)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+  return 0;
+}
+
+
+/** Return the number of unichars specifed by the text.
+    If widths is not null, returns the array of advance widths for each
+    unichar.
+    If bounds is not null, returns the array of bounds for each unichar.
+*/
+int
+anp_paint_getTextWidths(ANPPaint* paint, const void* text, uint32_t byteLength,
+                        float widths[], ANPRectF bounds[])
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+  return 0;
+}
+
+
+/** Return in metrics the spacing values for text, respecting the paint's
+    typeface and pointsize, and return the spacing between lines
+    (descent - ascent + leading). If metrics is NULL, it will be ignored.
+*/
+float
+anp_paint_getFontMetrics(ANPPaint* paint, ANPFontMetrics* metrics)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!paint)
+    return 0;
+
+  ANPPaintPrivate* p = (ANPPaintPrivate*) paint;
+  LOG("%s is not impl.", __PRETTY_FUNCTION__);
+  return 0;
+}
+
+
+void InitPaintInterface(ANPPaintInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, newPaint);
+  ASSIGN(i, deletePaint);
+  ASSIGN(i, getFlags);
+  ASSIGN(i, setFlags);
+  ASSIGN(i, getColor);
+  ASSIGN(i, setColor);
+  ASSIGN(i, getStyle);
+  ASSIGN(i, setStyle);
+  ASSIGN(i, getStrokeWidth);
+  ASSIGN(i, getStrokeMiter);
+  ASSIGN(i, getStrokeCap);
+  ASSIGN(i, getStrokeJoin);
+  ASSIGN(i, setStrokeWidth);
+  ASSIGN(i, setStrokeMiter);
+  ASSIGN(i, setStrokeCap);
+  ASSIGN(i, setStrokeJoin);
+  ASSIGN(i, getTextEncoding);
+  ASSIGN(i, getTextAlign);
+  ASSIGN(i, getTextSize);
+  ASSIGN(i, getTextScaleX);
+  ASSIGN(i, getTextSkewX);
+  ASSIGN(i, setTextEncoding);
+  ASSIGN(i, setTextAlign);
+  ASSIGN(i, setTextSize);
+  ASSIGN(i, setTextScaleX);
+  ASSIGN(i, setTextSkewX);
+  ASSIGN(i, getTypeface);
+  ASSIGN(i, setTypeface);
+  ASSIGN(i, measureText);
+  ASSIGN(i, getTextWidths);
+  ASSIGN(i, getFontMetrics);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPPath.cpp
@@ -0,0 +1,171 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_path_##name
+
+
+// maybe this should store a list of actions (lineTo,
+// moveTo), and when canvas_drawPath() we apply all of these
+// actions to the gfxContext.
+
+ANPPath*
+anp_path_newPath()
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+  return 0;
+}
+
+
+void
+anp_path_deletePath(ANPPath* p)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+
+void
+anp_path_copy(ANPPath* dst, const ANPPath* src)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+
+bool
+anp_path_equal(const ANPPath* path0, const ANPPath* path1)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+  return false;
+}
+
+
+void
+anp_path_reset(ANPPath* p)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+
+bool
+anp_path_isEmpty(const ANPPath* p)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+  return false;
+}
+
+
+void
+anp_path_getBounds(const ANPPath* p, ANPRectF* bounds)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+
+  bounds->left = 0;
+  bounds->top = 0;
+  bounds->right = 1000;
+  bounds->left = 1000;
+}
+
+
+void
+anp_path_moveTo(ANPPath* p, float x, float y)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_path_lineTo(ANPPath* p, float x, float y)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_path_quadTo(ANPPath* p, float x0, float y0, float x1, float y1)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_path_cubicTo(ANPPath* p, float x0, float y0, float x1, float y1,
+                      float x2, float y2)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+void
+anp_path_close(ANPPath* p)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+
+void
+anp_path_offset(ANPPath* src, float dx, float dy, ANPPath* dst)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+
+void
+anp_path_transform(ANPPath* src, const ANPMatrix*, ANPPath* dst)
+{
+  LOG("%s - NOT IMPL.", __PRETTY_FUNCTION__);
+}
+
+
+
+void InitPathInterface(ANPPathInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, newPath);
+  ASSIGN(i, deletePath);
+  ASSIGN(i, copy);
+  ASSIGN(i, equal);
+  ASSIGN(i, reset);
+  ASSIGN(i, isEmpty);
+  ASSIGN(i, getBounds);
+  ASSIGN(i, moveTo);
+  ASSIGN(i, lineTo);
+  ASSIGN(i, quadTo);
+  ASSIGN(i, cubicTo);
+  ASSIGN(i, close);
+  ASSIGN(i, offset);
+  ASSIGN(i, transform);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPSurface.cpp
@@ -0,0 +1,189 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+#include "AndroidBridge.h"
+#include "gfxImageSurface.h"
+#include "gfxContext.h"
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_surface_##name
+
+
+// used to cache JNI method and field IDs for Surface Objects
+static struct ANPSurfaceInterfaceJavaGlue {
+  bool        initialized;
+  jclass geckoAppShellClass;
+  jclass lockInfoCls;
+  jmethodID lockSurfaceANP;
+  jmethodID jUnlockSurfaceANP;
+  jfieldID jDirtyTop;
+  jfieldID jDirtyLeft;
+  jfieldID jDirtyBottom;
+  jfieldID jDirtyRight;
+  jfieldID jFormat;
+  jfieldID jWidth ;
+  jfieldID jHeight;
+  jfieldID jBuffer;
+} gSurfaceJavaGlue;
+
+#define getClassGlobalRef(env, cname)                                    \
+     (jClass = jclass(env->NewGlobalRef(env->FindClass(cname))))
+
+static void init(JNIEnv* env) {
+  if (gSurfaceJavaGlue.initialized)
+    return;
+  
+  gSurfaceJavaGlue.geckoAppShellClass = mozilla::AndroidBridge::GetGeckoAppShellClass();
+  
+  jmethodID getClass = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, 
+                                              "getSurfaceLockInfoClass",
+                                              "()Ljava/lang/Class;");
+
+  gSurfaceJavaGlue.lockInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass));
+
+  gSurfaceJavaGlue.jDirtyTop = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyTop", "I");
+  gSurfaceJavaGlue.jDirtyLeft = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyLeft", "I");
+  gSurfaceJavaGlue.jDirtyBottom = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyBottom", "I");
+  gSurfaceJavaGlue.jDirtyRight = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyRight", "I");
+
+  gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "format", "I");
+  gSurfaceJavaGlue.jWidth = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "width", "I");
+  gSurfaceJavaGlue.jHeight = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "height", "I");
+
+  gSurfaceJavaGlue.jBuffer = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "buffer", "Ljava/nio/Buffer;");
+  gSurfaceJavaGlue.lockSurfaceANP = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "lockSurfaceANP", "(Landroid/view/SurfaceView;IIII)Lorg/mozilla/gecko/SurfaceLockInfo;");
+  gSurfaceJavaGlue.jUnlockSurfaceANP = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "unlockSurfaceANP", "(Landroid/view/SurfaceView;)V");
+  gSurfaceJavaGlue.initialized = true;
+}
+
+static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) {
+  LOG("%s", __PRETTY_FUNCTION__);
+  if (!bitmap || !surfaceView) {
+    LOG("%s, null bitmap or surface, exiting", __PRETTY_FUNCTION__);
+    return false;
+  }
+
+  init(env);
+
+  jvalue args[5];
+  args[0].l = surfaceView;
+  if (dirtyRect) {
+    args[1].i = dirtyRect->top;
+    args[2].i = dirtyRect->left;
+    args[3].i = dirtyRect->bottom;
+    args[4].i = dirtyRect->right;
+    LOG("dirty rect: %d, %d, %d, %d", dirtyRect->top, dirtyRect->left, dirtyRect->bottom, dirtyRect->right);
+  } else {
+    args[1].i = args[2].i = args[3].i = args[4].i = 0;
+  }
+  
+  jobject info = env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass,
+                                             gSurfaceJavaGlue.lockSurfaceANP, 
+                                             surfaceView, args[1].i, args[2].i, args[3].i, args[4].i);
+
+  LOG("info: %p", info);
+  if (!info)
+    return false;
+
+  // the surface may have expanded the dirty region so we must to pass that
+  // information back to the plugin.
+  if (dirtyRect) {
+    dirtyRect->left   = env->GetIntField(info, gSurfaceJavaGlue.jDirtyLeft);
+    dirtyRect->right  = env->GetIntField(info, gSurfaceJavaGlue.jDirtyRight);
+    dirtyRect->top    = env->GetIntField(info, gSurfaceJavaGlue.jDirtyTop);
+    dirtyRect->bottom = env->GetIntField(info, gSurfaceJavaGlue.jDirtyBottom);
+    LOG("dirty rect: %d, %d, %d, %d", dirtyRect->top, dirtyRect->left, dirtyRect->bottom, dirtyRect->right);
+  }
+
+  bitmap->width  = env->GetIntField(info, gSurfaceJavaGlue.jWidth);
+  bitmap->height = env->GetIntField(info, gSurfaceJavaGlue.jHeight);
+
+  int format = env->GetIntField(info, gSurfaceJavaGlue.jFormat);
+
+  // format is PixelFormat
+  if (format & 0x00000001) {
+    bitmap->format = kRGBA_8888_ANPBitmapFormat;
+    bitmap->rowBytes = bitmap->width * 4;
+  }
+  else if (format & 0x00000004) {
+    bitmap->format = kRGB_565_ANPBitmapFormat;
+    bitmap->rowBytes = bitmap->width * 2;
+  }
+  else {
+    LOG("format from glue is unknown %d\n", format);
+    return false;
+  }
+
+  jobject buf = env->GetObjectField(info, gSurfaceJavaGlue.jBuffer);
+  bitmap->baseAddr = env->GetDirectBufferAddress(buf);
+  
+  LOG("format: %d, width: %d, height: %d",  bitmap->format,  bitmap->width,  bitmap->height);
+  env->DeleteLocalRef(info);
+  env->DeleteLocalRef(buf);
+  return ( bitmap->width > 0 && bitmap->height > 0 );
+}
+
+static void anp_unlock(JNIEnv* env, jobject surfaceView) {
+  LOG("%s", __PRETTY_FUNCTION__);
+
+  if (!surfaceView) {
+    LOG("null surface, exiting %s", __PRETTY_FUNCTION__);
+    return;
+  }
+
+  init(env);
+  env->CallStaticVoidMethod(gSurfaceJavaGlue.geckoAppShellClass, gSurfaceJavaGlue.jUnlockSurfaceANP, surfaceView);
+  LOG("returning from %s", __PRETTY_FUNCTION__);
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ASSIGN(obj, name)   (obj)->name = anp_##name
+
+void InitSurfaceInterface(ANPSurfaceInterfaceV0 *i) {
+
+  ASSIGN(i, lock);
+  ASSIGN(i, unlock);
+
+  // setup the java glue struct
+  gSurfaceJavaGlue.initialized = false;
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPSystem.cpp
@@ -0,0 +1,86 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "base/basictypes.h"
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+#include "nsNPAPIPluginInstance.h"
+#include "AndroidBridge.h"
+#include "nsNPAPIPlugin.h"
+#include "PluginPRLibrary.h"
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_system_##name
+
+const char*
+anp_system_getApplicationDataDirectory()
+{
+  LOG("getApplicationDataDirectory return /data/data/org.mozilla.%s", MOZ_APP_NAME);
+  return "/data/data/org.mozilla." MOZ_APP_NAME;
+}
+
+jclass anp_system_loadJavaClass(NPP instance, const char* className)
+{
+  LOG("%s", __PRETTY_FUNCTION__);
+
+  JNIEnv* env = GetJNIForThread();
+  jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
+  jmethodID method = env->GetStaticMethodID(cls,
+                                            "loadPluginClass",
+                                            "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
+
+  // pass libname and classname, gotta create java strings
+  nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
+  mozilla::PluginPRLibrary* lib = static_cast<mozilla::PluginPRLibrary*>(pinst->GetPlugin()->GetLibrary());
+
+  nsCString libName;
+  lib->GetLibraryPath(libName);
+
+  jstring jclassName = env->NewStringUTF(className);
+  jstring jlibName = env->NewStringUTF(libName.get());
+  jobject obj = env->CallStaticObjectMethod(cls, method, jclassName, jlibName);
+  return reinterpret_cast<jclass>(obj);
+}
+
+void InitSystemInterface(ANPSystemInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, getApplicationDataDirectory);
+  ASSIGN(i, loadJavaClass);
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPTypeface.cpp
@@ -0,0 +1,151 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+#include "gfxAndroidPlatform.h"
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_typeface_##name
+
+ANPTypeface*
+anp_typeface_createFromName(const char name[], ANPTypefaceStyle aStyle)
+{
+  LOG("%s - %s\n", __PRETTY_FUNCTION__, name);
+
+  gfxFontStyle style (aStyle == kItalic_ANPTypefaceStyle ? FONT_STYLE_ITALIC :
+                      FONT_STYLE_NORMAL,
+                      NS_FONT_STRETCH_NORMAL,
+                      aStyle == kBold_ANPTypefaceStyle ? 700 : 400,
+                      16.0,
+                      NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
+                      0.0,
+                      PR_FALSE, PR_FALSE,
+                      NS_LITERAL_STRING(""),
+                      NS_LITERAL_STRING(""));
+  ANPTypeface* tf = new ANPTypeface;
+  gfxAndroidPlatform * p = (gfxAndroidPlatform*)gfxPlatform::GetPlatform();
+  tf->mFont = gfxFT2Font::GetOrMakeFont(NS_ConvertASCIItoUTF16(name), &style);
+  return tf;
+}
+
+ANPTypeface*
+anp_typeface_createFromTypeface(const ANPTypeface* family,
+                                ANPTypefaceStyle)
+{
+  NOT_IMPLEMENTED();
+  return 0;
+}
+
+int32_t
+anp_typeface_getRefCount(const ANPTypeface*)
+{
+  NOT_IMPLEMENTED();
+  return 0;
+}
+
+void
+anp_typeface_ref(ANPTypeface* tf)
+{
+  LOG("%s\n", __PRETTY_FUNCTION__);
+  if (tf->mFont)
+    tf->mFont->AddRef();
+
+}
+
+void
+anp_typeface_unref(ANPTypeface* tf)
+{
+  LOG("%s\n", __PRETTY_FUNCTION__);
+  if (tf->mFont)
+    tf->mFont->Release();
+}
+
+ANPTypefaceStyle
+anp_typeface_getStyle(const ANPTypeface* ft)
+{
+  LOG("%s\n", __PRETTY_FUNCTION__);
+  return kBold_ANPTypefaceStyle;
+}
+
+int32_t
+anp_typeface_getFontPath(const ANPTypeface*, char path[], int32_t length,
+                         int32_t* index)
+{
+  NOT_IMPLEMENTED();
+  return 0;
+}
+
+static const char* gFontDir;
+#define FONT_DIR_SUFFIX     "/fonts/"
+
+const char*
+anp_typeface_getFontDirectoryPath()
+{
+  LOG("%s\n", __PRETTY_FUNCTION__);
+  if (NULL == gFontDir) {
+    const char* root = getenv("ANDROID_ROOT");
+    size_t len = strlen(root);
+    char* storage = (char*)malloc(len + sizeof(FONT_DIR_SUFFIX));
+    if (NULL == storage) {
+      return NULL;
+    }
+    memcpy(storage, root, len);
+    memcpy(storage + len, FONT_DIR_SUFFIX, sizeof(FONT_DIR_SUFFIX));
+    // save this assignment for last, so that if multiple threads call us
+    // (which should never happen), we never return an incomplete global.
+    // At worst, we would allocate storage for the path twice.
+    gFontDir = storage;
+  }
+
+  return 0;
+}
+
+void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, createFromName);
+  ASSIGN(i, createFromTypeface);
+  ASSIGN(i, getRefCount);
+  ASSIGN(i, ref);
+  ASSIGN(i, unref);
+  ASSIGN(i, getStyle);
+  ASSIGN(i, getFontPath);
+  ASSIGN(i, getFontDirectoryPath);
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/ANPWindow.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Android NPAPI support code
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assert.h"
+#include "ANPBase.h"
+#include <android/log.h>
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#define ASSIGN(obj, name)   (obj)->name = anp_window_##name
+
+void
+anp_window_setVisibleRects(NPP instance, const ANPRectI rects[], int32_t count)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_window_clearVisibleRects(NPP instance)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_window_showKeyboard(NPP instance, bool value)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_window_requestFullScreen(NPP instance)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_window_exitFullScreen(NPP instance)
+{
+  NOT_IMPLEMENTED();
+}
+
+void
+anp_window_requestCenterFitZoom(NPP instance)
+{
+  NOT_IMPLEMENTED();
+}
+
+void InitWindowInterface(ANPWindowInterfaceV0 *i) {
+  _assert(i->inSize == sizeof(*i));
+  ASSIGN(i, setVisibleRects);
+  ASSIGN(i, clearVisibleRects);
+  ASSIGN(i, showKeyboard);
+  ASSIGN(i, requestFullScreen);
+  ASSIGN(i, exitFullScreen);
+  ASSIGN(i, requestCenterFitZoom);
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/Makefile.in
@@ -0,0 +1,81 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= plugin
+LIBRARY_NAME	= gkpluginandroid_s
+
+LIBXUL_LIBRARY   = 1
+FORCE_STATIC_LIB = 1
+EXPORT_LIBRARY = 1
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+
+EXPORTS = \
+  android_npapi.h \
+  $(NULL)
+
+CPPSRCS += ANPAudio.cpp    \
+           ANPCanvas.cpp   \
+           ANPEvent.cpp    \
+           ANPMatrix.cpp   \
+           ANPPath.cpp     \
+           ANPSystem.cpp   \
+           ANPWindow.cpp   \
+           ANPBitmap.cpp   \
+           ANPLog.cpp      \
+           ANPPaint.cpp    \
+           ANPSurface.cpp  \
+           ANPTypeface.cpp \
+           $(NULL)
+
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/dom/plugins/base \
+  $(MOZ_CAIRO_CFLAGS) \
+  $(NULL)
+
+DEFINES += -DMOZ_APP_NAME='"$(MOZ_APP_NAME)"'
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/base/android/android_npapi.h
@@ -0,0 +1,979 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*  Defines the android-specific types and functions as part of npapi
+
+    In particular, defines the window and event types that are passed to
+    NPN_GetValue, NPP_SetWindow and NPP_HandleEvent.
+
+    To minimize what native libraries the plugin links against, some
+    functionality is provided via function-ptrs (e.g. time, sound)
+ */
+
+#ifndef android_npapi_H
+#define android_npapi_H
+
+#include <stdint.h>
+#include "npapi.h"
+#include <jni.h>
+
+///////////////////////////////////////////////////////////////////////////////
+// General types
+
+enum ANPBitmapFormats {
+    kUnknown_ANPBitmapFormat    = 0,
+    kRGBA_8888_ANPBitmapFormat  = 1,
+    kRGB_565_ANPBitmapFormat    = 2
+};
+typedef int32_t ANPBitmapFormat;
+
+struct ANPPixelPacking {
+    uint8_t AShift;
+    uint8_t ABits;
+    uint8_t RShift;
+    uint8_t RBits;
+    uint8_t GShift;
+    uint8_t GBits;
+    uint8_t BShift;
+    uint8_t BBits;
+};
+
+struct ANPBitmap {
+    void*           baseAddr;
+    ANPBitmapFormat format;
+    int32_t         width;
+    int32_t         height;
+    int32_t         rowBytes;
+};
+
+struct ANPRectF {
+    float   left;
+    float   top;
+    float   right;
+    float   bottom;
+};
+
+struct ANPRectI {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+};
+
+struct ANPCanvas;
+struct ANPMatrix;
+struct ANPPaint;
+struct ANPPath;
+struct ANPRegion;
+struct ANPTypeface;
+
+enum ANPMatrixFlags {
+    kIdentity_ANPMatrixFlag     = 0,
+    kTranslate_ANPMatrixFlag    = 0x01,
+    kScale_ANPMatrixFlag        = 0x02,
+    kAffine_ANPMatrixFlag       = 0x04,
+    kPerspective_ANPMatrixFlag  = 0x08,
+};
+typedef uint32_t ANPMatrixFlag;
+
+///////////////////////////////////////////////////////////////////////////////
+// NPN_GetValue
+
+/** queries for a specific ANPInterface.
+
+    Maybe called with NULL for the NPP instance
+
+    NPN_GetValue(inst, interface_enum, ANPInterface*)
+ */
+#define kLogInterfaceV0_ANPGetValue         ((NPNVariable)1000)
+#define kAudioTrackInterfaceV0_ANPGetValue  ((NPNVariable)1001)
+#define kCanvasInterfaceV0_ANPGetValue      ((NPNVariable)1002)
+#define kMatrixInterfaceV0_ANPGetValue      ((NPNVariable)1003)
+#define kPaintInterfaceV0_ANPGetValue       ((NPNVariable)1004)
+#define kPathInterfaceV0_ANPGetValue        ((NPNVariable)1005)
+#define kTypefaceInterfaceV0_ANPGetValue    ((NPNVariable)1006)
+#define kWindowInterfaceV0_ANPGetValue      ((NPNVariable)1007)
+#define kBitmapInterfaceV0_ANPGetValue      ((NPNVariable)1008)
+#define kSurfaceInterfaceV0_ANPGetValue     ((NPNVariable)1009)
+#define kSystemInterfaceV0_ANPGetValue      ((NPNVariable)1010)
+#define kEventInterfaceV0_ANPGetValue       ((NPNVariable)1011)
+
+/** queries for the drawing models supported on this device.
+
+    NPN_GetValue(inst, kSupportedDrawingModel_ANPGetValue, uint32_t* bits)
+ */
+#define kSupportedDrawingModel_ANPGetValue  ((NPNVariable)2000)
+
+/** queries for the context (android.content.Context) of the plugin. If no
+    instance is specified the application's context is returned. If the instance
+    is given then the context returned is identical to the context used to
+    create the webview in which that instance resides.
+
+    NOTE: Holding onto a non-application context after your instance has been
+    destroyed will cause a memory leak.  Refer to the android documentation to
+    determine what context is best suited for your particular scenario.
+
+    NPN_GetValue(inst, kJavaContext_ANPGetValue, jobject context)
+ */
+#define kJavaContext_ANPGetValue            ((NPNVariable)2001)
+
+///////////////////////////////////////////////////////////////////////////////
+// NPN_SetValue
+
+/** Request to set the drawing model. SetValue will return false if the drawing
+    model is not supported or has insufficient information for configuration.
+
+    NPN_SetValue(inst, kRequestDrawingModel_ANPSetValue, (void*)foo_ANPDrawingModel)
+ */
+#define kRequestDrawingModel_ANPSetValue    ((NPPVariable)1000)
+
+/** These are used as bitfields in ANPSupportedDrawingModels_EnumValue,
+    and as-is in ANPRequestDrawingModel_EnumValue. The drawing model determines
+    how to interpret the ANPDrawingContext provided in the Draw event and how
+    to interpret the NPWindow->window field.
+ */
+enum ANPDrawingModels {
+    /** Draw into a bitmap from the browser thread in response to a Draw event.
+        NPWindow->window is reserved (ignore)
+     */
+    kBitmap_ANPDrawingModel  = 1 << 0,
+    /** Draw into a surface (e.g. raster, openGL, etc.) using the Java surface
+        interface. When this model is used the browser will invoke the Java
+        class specified in the plugin's apk manifest. From that class the browser
+        will invoke the appropriate method to return an an instance of a android
+        Java View. The instance is then embedded in the html. The plugin can then
+        manipulate the view as it would any normal Java View in android.
+
+        Unlike the bitmap model, a surface model is opaque so no html content
+        behind the plugin will be  visible. Unless the plugin needs to be
+        transparent the surface model should be chosen over the bitmap model as
+        it will have better performance.
+
+        Further, a plugin can manipulate some surfaces in native code using the
+        ANPSurfaceInterface.  This interface can be used to manipulate Java
+        objects that extend Surface.class by allowing them to access the
+        surface's underlying bitmap in native code.  For instance, if a raster
+        surface is used the plugin can lock, draw directly into the bitmap, and
+        unlock the surface in native code without making JNI calls to the Java
+        surface object.
+     */
+    kSurface_ANPDrawingModel = 1 << 1,
+};
+typedef int32_t ANPDrawingModel;
+
+/** Request to receive/disable events. If the pointer is NULL then all flags will
+    be disabled. Otherwise, the event type will be enabled iff its corresponding
+    bit in the EventFlags bit field is set.
+
+    NPN_SetValue(inst, ANPAcceptEvents, (void*)EventFlags)
+ */
+#define kAcceptEvents_ANPSetValue           ((NPPVariable)1001)
+
+/** The EventFlags are a set of bits used to determine which types of events the
+    plugin wishes to receive. For example, if the value is 0x03 then both key
+    and touch events will be provided to the plugin.
+ */
+enum ANPEventFlag {
+    kKey_ANPEventFlag               = 0x01,
+    kTouch_ANPEventFlag             = 0x02,
+};
+typedef uint32_t ANPEventFlags;
+
+///////////////////////////////////////////////////////////////////////////////
+// NPP_GetValue
+
+/** Requests that the plugin return a java surface to be displayed. This will
+    only be used if the plugin has choosen the kSurface_ANPDrawingModel.
+
+    NPP_GetValue(inst, kJavaSurface_ANPGetValue, jobject surface)
+ */
+#define kJavaSurface_ANPGetValue            ((NPPVariable)2000)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// ANDROID INTERFACE DEFINITIONS
+
+/** Interfaces provide additional functionality to the plugin via function ptrs.
+    Once an interface is retrieved, it is valid for the lifetime of the plugin
+    (just like browserfuncs).
+
+    All ANPInterfaces begin with an inSize field, which must be set by the
+    caller (plugin) with the number of bytes allocated for the interface.
+    e.g. SomeInterface si; si.inSize = sizeof(si); browser->getvalue(..., &si);
+ */
+struct ANPInterface {
+    uint32_t    inSize;     // size (in bytes) of this struct
+};
+
+enum ANPLogTypes {
+    kError_ANPLogType   = 0,    // error
+    kWarning_ANPLogType = 1,    // warning
+    kDebug_ANPLogType   = 2     // debug only (informational)
+};
+typedef int32_t ANPLogType;
+
+struct ANPLogInterfaceV0 : ANPInterface {
+    /** dumps printf messages to the log file
+        e.g. interface->log(instance, kWarning_ANPLogType, "value is %d", value);
+     */
+    void (*log)(ANPLogType, const char format[], ...);
+};
+
+struct ANPBitmapInterfaceV0 : ANPInterface {
+    /** Returns true if the specified bitmap format is supported, and if packing
+        is non-null, sets it to the packing info for that format.
+     */
+    bool (*getPixelPacking)(ANPBitmapFormat, ANPPixelPacking* packing);
+};
+
+struct ANPMatrixInterfaceV0 : ANPInterface {
+    /** Return a new identity matrix
+     */
+    ANPMatrix*  (*newMatrix)();
+    /** Delete a matrix previously allocated by newMatrix()
+     */
+    void        (*deleteMatrix)(ANPMatrix*);
+
+    ANPMatrixFlag (*getFlags)(const ANPMatrix*);
+
+    void        (*copy)(ANPMatrix* dst, const ANPMatrix* src);
+
+    /** Return the matrix values in a float array (allcoated by the caller),
+        where the values are treated as follows:
+        w  = x * [6] + y * [7] + [8];
+        x' = (x * [0] + y * [1] + [2]) / w;
+        y' = (x * [3] + y * [4] + [5]) / w;
+     */
+    void        (*get3x3)(const ANPMatrix*, float[9]);
+    /** Initialize the matrix from values in a float array,
+        where the values are treated as follows:
+         w  = x * [6] + y * [7] + [8];
+         x' = (x * [0] + y * [1] + [2]) / w;
+         y' = (x * [3] + y * [4] + [5]) / w;
+     */
+    void        (*set3x3)(ANPMatrix*, const float[9]);
+
+    void        (*setIdentity)(ANPMatrix*);
+    void        (*preTranslate)(ANPMatrix*, float tx, float ty);
+    void        (*postTranslate)(ANPMatrix*, float tx, float ty);
+    void        (*preScale)(ANPMatrix*, float sx, float sy);
+    void        (*postScale)(ANPMatrix*, float sx, float sy);
+    void        (*preSkew)(ANPMatrix*, float kx, float ky);
+    void        (*postSkew)(ANPMatrix*, float kx, float ky);
+    void        (*preRotate)(ANPMatrix*, float degrees);
+    void        (*postRotate)(ANPMatrix*, float degrees);
+    void        (*preConcat)(ANPMatrix*, const ANPMatrix*);
+    void        (*postConcat)(ANPMatrix*, const ANPMatrix*);
+
+    /** Return true if src is invertible, and if so, return its inverse in dst.
+        If src is not invertible, return false and ignore dst.
+     */
+    bool        (*invert)(ANPMatrix* dst, const ANPMatrix* src);
+
+    /** Transform the x,y pairs in src[] by this matrix, and store the results
+        in dst[]. The count parameter is treated as the number of pairs in the
+        array. It is legal for src and dst to point to the same memory, but
+        illegal for the two arrays to partially overlap.
+     */
+    void        (*mapPoints)(ANPMatrix*, float dst[], const float src[],
+                             int32_t count);
+};
+
+struct ANPPathInterfaceV0 : ANPInterface {
+    /** Return a new path */
+    ANPPath* (*newPath)();
+
+    /** Delete a path previously allocated by ANPPath() */
+    void (*deletePath)(ANPPath*);
+
+    /** Make a deep copy of the src path, into the dst path (already allocated
+        by the caller).
+     */
+    void (*copy)(ANPPath* dst, const ANPPath* src);
+
+    /** Returns true if the two paths are the same (i.e. have the same points)
+     */
+    bool (*equal)(const ANPPath* path0, const ANPPath* path1);
+
+    /** Remove any previous points, initializing the path back to empty. */
+    void (*reset)(ANPPath*);
+
+    /** Return true if the path is empty (has no lines, quads or cubics). */
+    bool (*isEmpty)(const ANPPath*);
+
+    /** Return the path's bounds in bounds. */
+    void (*getBounds)(const ANPPath*, ANPRectF* bounds);
+
+    void (*moveTo)(ANPPath*, float x, float y);
+    void (*lineTo)(ANPPath*, float x, float y);
+    void (*quadTo)(ANPPath*, float x0, float y0, float x1, float y1);
+    void (*cubicTo)(ANPPath*, float x0, float y0, float x1, float y1,
+                    float x2, float y2);
+    void (*close)(ANPPath*);
+
+    /** Offset the src path by [dx, dy]. If dst is null, apply the
+        change directly to the src path. If dst is not null, write the
+        changed path into dst, and leave the src path unchanged. In that case
+        dst must have been previously allocated by the caller.
+     */
+    void (*offset)(ANPPath* src, float dx, float dy, ANPPath* dst);
+
+    /** Transform the path by the matrix. If dst is null, apply the
+        change directly to the src path. If dst is not null, write the
+        changed path into dst, and leave the src path unchanged. In that case
+        dst must have been previously allocated by the caller.
+     */
+    void (*transform)(ANPPath* src, const ANPMatrix*, ANPPath* dst);
+};
+
+/** ANPColor is always defined to have the same packing on all platforms, and
+    it is always unpremultiplied.
+
+    This is in contrast to 32bit format(s) in bitmaps, which are premultiplied,
+    and their packing may vary depending on the platform, hence the need for
+    ANPBitmapInterface::getPixelPacking()
+ */
+typedef uint32_t ANPColor;
+#define ANPColor_ASHIFT     24
+#define ANPColor_RSHIFT     16
+#define ANPColor_GSHIFT     8
+#define ANPColor_BSHIFT     0
+#define ANP_MAKE_COLOR(a, r, g, b)  \
+                   (((a) << ANPColor_ASHIFT) |  \
+                    ((r) << ANPColor_RSHIFT) |  \
+                    ((g) << ANPColor_GSHIFT) |  \
+                    ((b) << ANPColor_BSHIFT))
+
+enum ANPPaintFlag {
+    kAntiAlias_ANPPaintFlag         = 1 << 0,
+    kFilterBitmap_ANPPaintFlag      = 1 << 1,
+    kDither_ANPPaintFlag            = 1 << 2,
+    kUnderlineText_ANPPaintFlag     = 1 << 3,
+    kStrikeThruText_ANPPaintFlag    = 1 << 4,
+    kFakeBoldText_ANPPaintFlag      = 1 << 5,
+};
+typedef uint32_t ANPPaintFlags;
+
+enum ANPPaintStyles {
+    kFill_ANPPaintStyle             = 0,
+    kStroke_ANPPaintStyle           = 1,
+    kFillAndStroke_ANPPaintStyle    = 2
+};
+typedef int32_t ANPPaintStyle;
+
+enum ANPPaintCaps {
+    kButt_ANPPaintCap   = 0,
+    kRound_ANPPaintCap  = 1,
+    kSquare_ANPPaintCap = 2
+};
+typedef int32_t ANPPaintCap;
+
+enum ANPPaintJoins {
+    kMiter_ANPPaintJoin = 0,
+    kRound_ANPPaintJoin = 1,
+    kBevel_ANPPaintJoin = 2
+};
+typedef int32_t ANPPaintJoin;
+
+enum ANPPaintAligns {
+    kLeft_ANPPaintAlign     = 0,
+    kCenter_ANPPaintAlign   = 1,
+    kRight_ANPPaintAlign    = 2
+};
+typedef int32_t ANPPaintAlign;
+
+enum ANPTextEncodings {
+    kUTF8_ANPTextEncoding   = 0,
+    kUTF16_ANPTextEncoding  = 1,
+};
+typedef int32_t ANPTextEncoding;
+
+enum ANPTypefaceStyles {
+    kBold_ANPTypefaceStyle      = 1 << 0,
+    kItalic_ANPTypefaceStyle    = 1 << 1
+};
+typedef uint32_t ANPTypefaceStyle;
+
+typedef uint32_t ANPFontTableTag;
+
+struct ANPFontMetrics {
+    /** The greatest distance above the baseline for any glyph (will be <= 0) */
+    float   fTop;
+    /** The recommended distance above the baseline (will be <= 0) */
+    float   fAscent;
+    /** The recommended distance below the baseline (will be >= 0) */
+    float   fDescent;
+    /** The greatest distance below the baseline for any glyph (will be >= 0) */
+    float   fBottom;
+    /** The recommended distance to add between lines of text (will be >= 0) */
+    float   fLeading;
+};
+
+struct ANPTypefaceInterfaceV0 : ANPInterface {
+    /** Return a new reference to the typeface that most closely matches the
+        requested name and style. Pass null as the name to return
+        the default font for the requested style. Will never return null
+
+        The 5 generic font names "serif", "sans-serif", "monospace", "cursive",
+        "fantasy" are recognized, and will be mapped to their logical font
+        automatically by this call.
+
+        @param name     May be NULL. The name of the font family.
+        @param style    The style (normal, bold, italic) of the typeface.
+        @return reference to the closest-matching typeface. Caller must call
+                unref() when they are done with the typeface.
+     */
+    ANPTypeface* (*createFromName)(const char name[], ANPTypefaceStyle);
+
+    /** Return a new reference to the typeface that most closely matches the
+        requested typeface and specified Style. Use this call if you want to
+        pick a new style from the same family of the existing typeface.
+        If family is NULL, this selects from the default font's family.
+
+        @param family  May be NULL. The name of the existing type face.
+        @param s       The style (normal, bold, italic) of the type face.
+        @return reference to the closest-matching typeface. Call must call
+                unref() when they are done.
+     */
+    ANPTypeface* (*createFromTypeface)(const ANPTypeface* family,
+                                       ANPTypefaceStyle);
+
+    /** Return the owner count of the typeface. A newly created typeface has an
+        owner count of 1. When the owner count is reaches 0, the typeface is
+        deleted.
+     */
+    int32_t (*getRefCount)(const ANPTypeface*);
+
+    /** Increment the owner count on the typeface
+     */
+    void (*ref)(ANPTypeface*);
+
+    /** Decrement the owner count on the typeface. When the count goes to 0,
+        the typeface is deleted.
+     */
+    void (*unref)(ANPTypeface*);
+
+    /** Return the style bits for the specified typeface
+     */
+    ANPTypefaceStyle (*getStyle)(const ANPTypeface*);
+
+    /** Some fonts are stored in files. If that is true for the fontID, then
+        this returns the byte length of the full file path. If path is not null,
+        then the full path is copied into path (allocated by the caller), up to
+        length bytes. If index is not null, then it is set to the truetype
+        collection index for this font, or 0 if the font is not in a collection.
+
+        Note: getFontPath does not assume that path is a null-terminated string,
+        so when it succeeds, it only copies the bytes of the file name and
+        nothing else (i.e. it copies exactly the number of bytes returned by the
+        function. If the caller wants to treat path[] as a C string, it must be
+        sure that it is allocated at least 1 byte larger than the returned size,
+        and it must copy in the terminating 0.
+
+        If the fontID does not correspond to a file, then the function returns
+        0, and the path and index parameters are ignored.
+
+        @param fontID  The font whose file name is being queried
+        @param path    Either NULL, or storage for receiving up to length bytes
+                       of the font's file name. Allocated by the caller.
+        @param length  The maximum space allocated in path (by the caller).
+                       Ignored if path is NULL.
+        @param index   Either NULL, or receives the TTC index for this font.
+                       If the font is not a TTC, then will be set to 0.
+        @return The byte length of th font's file name, or 0 if the font is not
+                baked by a file.
+     */
+    int32_t (*getFontPath)(const ANPTypeface*, char path[], int32_t length,
+                           int32_t* index);
+
+    /** Return a UTF8 encoded path name for the font directory, or NULL if not
+        supported. If returned, this string address will be valid for the life
+        of the plugin instance. It will always end with a '/' character.
+     */
+    const char* (*getFontDirectoryPath)();
+};
+
+struct ANPPaintInterfaceV0 : ANPInterface {
+    /** Return a new paint object, which holds all of the color and style
+        attributes that affect how things (geometry, text, bitmaps) are drawn
+        in a ANPCanvas.
+
+        The paint that is returned is not tied to any particular plugin
+        instance, but it must only be accessed from one thread at a time.
+     */
+    ANPPaint*   (*newPaint)();
+    void        (*deletePaint)(ANPPaint*);
+
+    ANPPaintFlags (*getFlags)(const ANPPaint*);
+    void        (*setFlags)(ANPPaint*, ANPPaintFlags);
+
+    ANPColor    (*getColor)(const ANPPaint*);
+    void        (*setColor)(ANPPaint*, ANPColor);
+
+    ANPPaintStyle (*getStyle)(const ANPPaint*);
+    void        (*setStyle)(ANPPaint*, ANPPaintStyle);
+
+    float       (*getStrokeWidth)(const ANPPaint*);
+    float       (*getStrokeMiter)(const ANPPaint*);
+    ANPPaintCap (*getStrokeCap)(const ANPPaint*);
+    ANPPaintJoin (*getStrokeJoin)(const ANPPaint*);
+    void        (*setStrokeWidth)(ANPPaint*, float);
+    void        (*setStrokeMiter)(ANPPaint*, float);
+    void        (*setStrokeCap)(ANPPaint*, ANPPaintCap);
+    void        (*setStrokeJoin)(ANPPaint*, ANPPaintJoin);
+
+    ANPTextEncoding (*getTextEncoding)(const ANPPaint*);
+    ANPPaintAlign (*getTextAlign)(const ANPPaint*);
+    float       (*getTextSize)(const ANPPaint*);
+    float       (*getTextScaleX)(const ANPPaint*);
+    float       (*getTextSkewX)(const ANPPaint*);
+    void        (*setTextEncoding)(ANPPaint*, ANPTextEncoding);
+    void        (*setTextAlign)(ANPPaint*, ANPPaintAlign);
+    void        (*setTextSize)(ANPPaint*, float);
+    void        (*setTextScaleX)(ANPPaint*, float);
+    void        (*setTextSkewX)(ANPPaint*, float);
+
+    /** Return the typeface ine paint, or null if there is none. This does not
+        modify the owner count of the returned typeface.
+     */
+    ANPTypeface* (*getTypeface)(const ANPPaint*);
+
+    /** Set the paint's typeface. If the paint already had a non-null typeface,
+        its owner count is decremented. If the new typeface is non-null, its
+        owner count is incremented.
+     */
+    void (*setTypeface)(ANPPaint*, ANPTypeface*);
+
+    /** Return the width of the text. If bounds is not null, return the bounds
+        of the text in that rectangle.
+     */
+    float (*measureText)(ANPPaint*, const void* text, uint32_t byteLength,
+                         ANPRectF* bounds);
+
+    /** Return the number of unichars specifed by the text.
+        If widths is not null, returns the array of advance widths for each
+            unichar.
+        If bounds is not null, returns the array of bounds for each unichar.
+     */
+    int (*getTextWidths)(ANPPaint*, const void* text, uint32_t byteLength,
+                         float widths[], ANPRectF bounds[]);
+
+    /** Return in metrics the spacing values for text, respecting the paint's
+        typeface and pointsize, and return the spacing between lines
+        (descent - ascent + leading). If metrics is NULL, it will be ignored.
+     */
+    float (*getFontMetrics)(ANPPaint*, ANPFontMetrics* metrics);
+};
+
+struct ANPCanvasInterfaceV0 : ANPInterface {
+    /** Return a canvas that will draw into the specified bitmap. Note: the
+        canvas copies the fields of the bitmap, so it need not persist after
+        this call, but the canvas DOES point to the same pixel memory that the
+        bitmap did, so the canvas should not be used after that pixel memory
+        goes out of scope. In the case of creating a canvas to draw into the
+        pixels provided by kDraw_ANPEventType, those pixels are only while
+        handling that event.
+
+        The canvas that is returned is not tied to any particular plugin
+        instance, but it must only be accessed from one thread at a time.
+     */
+    ANPCanvas*  (*newCanvas)(const ANPBitmap*);
+    void        (*deleteCanvas)(ANPCanvas*);
+
+    void        (*save)(ANPCanvas*);
+    void        (*restore)(ANPCanvas*);
+    void        (*translate)(ANPCanvas*, float tx, float ty);
+    void        (*scale)(ANPCanvas*, float sx, float sy);
+    void        (*rotate)(ANPCanvas*, float degrees);
+    void        (*skew)(ANPCanvas*, float kx, float ky);
+    void        (*concat)(ANPCanvas*, const ANPMatrix*);
+    void        (*clipRect)(ANPCanvas*, const ANPRectF*);
+    void        (*clipPath)(ANPCanvas*, const ANPPath*);
+
+    /** Return the current matrix on the canvas
+     */
+    void        (*getTotalMatrix)(ANPCanvas*, ANPMatrix*);
+    /** Return the current clip bounds in local coordinates, expanding it to
+        account for antialiasing edge effects if aa is true. If the
+        current clip is empty, return false and ignore the bounds argument.
+     */
+    bool        (*getLocalClipBounds)(ANPCanvas*, ANPRectF* bounds, bool aa);
+    /** Return the current clip bounds in device coordinates in bounds. If the
+        current clip is empty, return false and ignore the bounds argument.
+     */
+    bool        (*getDeviceClipBounds)(ANPCanvas*, ANPRectI* bounds);
+
+    void        (*drawColor)(ANPCanvas*, ANPColor);
+    void        (*drawPaint)(ANPCanvas*, const ANPPaint*);
+    void        (*drawLine)(ANPCanvas*, float x0, float y0, float x1, float y1,
+                            const ANPPaint*);
+    void        (*drawRect)(ANPCanvas*, const ANPRectF*, const ANPPaint*);
+    void        (*drawOval)(ANPCanvas*, const ANPRectF*, const ANPPaint*);
+    void        (*drawPath)(ANPCanvas*, const ANPPath*, const ANPPaint*);
+    void        (*drawText)(ANPCanvas*, const void* text, uint32_t byteLength,
+                            float x, float y, const ANPPaint*);
+    void       (*drawPosText)(ANPCanvas*, const void* text, uint32_t byteLength,
+                               const float xy[], const ANPPaint*);
+    void        (*drawBitmap)(ANPCanvas*, const ANPBitmap*, float x, float y,
+                              const ANPPaint*);
+    void        (*drawBitmapRect)(ANPCanvas*, const ANPBitmap*,
+                                  const ANPRectI* src, const ANPRectF* dst,
+                                  const ANPPaint*);
+};
+
+struct ANPWindowInterfaceV0 : ANPInterface {
+    /** Registers a set of rectangles that the plugin would like to keep on
+        screen. The rectangles are listed in order of priority with the highest
+        priority rectangle in location rects[0].  The browser will attempt to keep
+        as many of the rectangles on screen as possible and will scroll them into
+        view in response to the invocation of this method and other various events.
+        The count specifies how many rectangles are in the array. If the count is
+        zero it signals the browser that any existing rectangles should be cleared
+        and no rectangles will be tracked.
+     */
+    void (*setVisibleRects)(NPP instance, const ANPRectI rects[], int32_t count);
+    /** Clears any rectangles that are being tracked as a result of a call to
+        setVisibleRects. This call is equivalent to setVisibleRect(inst, NULL, 0).
+     */
+    void    (*clearVisibleRects)(NPP instance);
+    /** Given a boolean value of true the device will be requested to provide
+        a keyboard. A value of false will result in a request to hide the
+        keyboard. Further, the on-screen keyboard will not be displayed if a
+        physical keyboard is active.
+     */
+    void    (*showKeyboard)(NPP instance, bool value);
+    /** Called when a plugin wishes to enter into full screen mode. The plugin's
+        Java class (defined in the plugin's apk manifest) will be called
+        asynchronously to provide a View object to be displayed full screen.
+     */
+    void    (*requestFullScreen)(NPP instance);
+    /** Called when a plugin wishes to exit from full screen mode. As a result,
+        the plugin's full screen view will be discarded by the view system.
+     */
+    void    (*exitFullScreen)(NPP instance);
+    /** Called when a plugin wishes to be zoomed and centered in the current view.
+     */
+    void    (*requestCenterFitZoom)(NPP instance);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+enum ANPSampleFormats {
+    kUnknown_ANPSamleFormat     = 0,
+    kPCM16Bit_ANPSampleFormat   = 1,
+    kPCM8Bit_ANPSampleFormat    = 2
+};
+typedef int32_t ANPSampleFormat;
+
+/** The audio buffer is passed to the callback proc to request more samples.
+    It is owned by the system, and the callback may read it, but should not
+    maintain a pointer to it outside of the scope of the callback proc.
+ */
+struct ANPAudioBuffer {
+    // RO - repeat what was specified in newTrack()
+    int32_t     channelCount;
+    // RO - repeat what was specified in newTrack()
+    ANPSampleFormat  format;
+    /** This buffer is owned by the caller. Inside the callback proc, up to
+        "size" bytes of sample data should be written into this buffer. The
+        address is only valid for the scope of a single invocation of the
+        callback proc.
+     */
+    void*       bufferData;
+    /** On input, specifies the maximum number of bytes that can be written
+        to "bufferData". On output, specifies the actual number of bytes that
+        the callback proc wrote into "bufferData".
+     */
+    uint32_t    size;
+};
+
+enum ANPAudioEvents {
+    /** This event is passed to the callback proc when the audio-track needs
+        more sample data written to the provided buffer parameter.
+     */
+    kMoreData_ANPAudioEvent = 0,
+    /** This event is passed to the callback proc if the audio system runs out
+        of sample data. In this event, no buffer parameter will be specified
+        (i.e. NULL will be passed to the 3rd parameter).
+     */
+    kUnderRun_ANPAudioEvent = 1
+};
+typedef int32_t ANPAudioEvent;
+
+/** Called to feed sample data to the track. This will be called in a separate
+    thread. However, you may call trackStop() from the callback (but you
+    cannot delete the track).
+
+    For example, when you have written the last chunk of sample data, you can
+    immediately call trackStop(). This will take effect after the current
+    buffer has been played.
+
+    The "user" parameter is the same value that was passed to newTrack()
+ */
+typedef void (*ANPAudioCallbackProc)(ANPAudioEvent event, void* user,
+                                     ANPAudioBuffer* buffer);
+
+struct ANPAudioTrack;   // abstract type for audio tracks
+
+struct ANPAudioTrackInterfaceV0 : ANPInterface {
+    /** Create a new audio track, or NULL on failure. The track is initially in
+        the stopped state and therefore ANPAudioCallbackProc will not be called
+        until the track is started.
+     */
+    ANPAudioTrack*  (*newTrack)(uint32_t sampleRate,    // sampling rate in Hz
+                                ANPSampleFormat,
+                                int channelCount,       // MONO=1, STEREO=2
+                                ANPAudioCallbackProc,
+                                void* user);
+    /** Deletes a track that was created using newTrack.  The track can be
+        deleted in any state and it waits for the ANPAudioCallbackProc thread
+        to exit before returning.
+     */
+    void (*deleteTrack)(ANPAudioTrack*);
+
+    void (*start)(ANPAudioTrack*);
+    void (*pause)(ANPAudioTrack*);
+    void (*stop)(ANPAudioTrack*);
+    /** Returns true if the track is not playing (e.g. pause or stop was called,
+        or start was never called.
+     */
+    bool (*isStopped)(ANPAudioTrack*);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// DEFINITION OF VALUES PASSED THROUGH NPP_HandleEvent
+
+enum ANPEventTypes {
+    kNull_ANPEventType          = 0,
+    kKey_ANPEventType           = 1,
+    /** Mouse events are triggered by either clicking with the navigational pad
+        or by tapping the touchscreen (if the kDown_ANPTouchAction is handled by
+        the plugin then no mouse event is generated).  The kKey_ANPEventFlag has
+        to be set to true in order to receive these events.
+     */
+    kMouse_ANPEventType         = 2,
+    /** Touch events are generated when the user touches on the screen. The
+        kTouch_ANPEventFlag has to be set to true in order to receive these
+        events.
+     */
+    kTouch_ANPEventType         = 3,
+    /** Only triggered by a plugin using the kBitmap_ANPDrawingModel. This event
+        signals that the plugin needs to redraw itself into the provided bitmap.
+     */
+    kDraw_ANPEventType          = 4,
+    kLifecycle_ANPEventType     = 5,
+
+    /** This event type is completely defined by the plugin.
+        When creating an event, the caller must always set the first
+        two fields, the remaining data is optional.
+            ANPEvent evt;
+            evt.inSize = sizeof(ANPEvent);
+            evt.eventType = kCustom_ANPEventType
+            // other data slots are optional
+            evt.other[] = ...;
+        To post a copy of the event, call
+            eventInterface->postEvent(myNPPInstance, &evt);
+        That call makes a copy of the event struct, and post that on the event
+        queue for the plugin.
+     */
+    kCustom_ANPEventType   = 6,
+};
+typedef int32_t ANPEventType;
+
+enum ANPKeyActions {
+    kDown_ANPKeyAction  = 0,
+    kUp_ANPKeyAction    = 1,
+};
+typedef int32_t ANPKeyAction;
+
+#include "ANPKeyCodes.h"
+typedef int32_t ANPKeyCode;
+
+enum ANPKeyModifiers {
+    kAlt_ANPKeyModifier     = 1 << 0,
+    kShift_ANPKeyModifier   = 1 << 1,
+};
+// bit-field containing some number of ANPKeyModifier bits
+typedef uint32_t ANPKeyModifier;
+
+enum ANPMouseActions {
+    kDown_ANPMouseAction  = 0,
+    kUp_ANPMouseAction    = 1,
+};
+typedef int32_t ANPMouseAction;
+
+enum ANPTouchActions {
+    /** This occurs when the user first touches on the screen. As such, this
+        action will always occur prior to any of the other touch actions. If
+        the plugin chooses to not handle this action then no other events
+        related to that particular touch gesture will be generated.
+     */
+    kDown_ANPTouchAction        = 0,
+    kUp_ANPTouchAction          = 1,
+    kMove_ANPTouchAction        = 2,
+    kCancel_ANPTouchAction      = 3,
+    // The web view will ignore the return value from the following actions
+    kLongPress_ANPTouchAction   = 4,
+    kDoubleTap_ANPTouchAction   = 5,
+};
+typedef int32_t ANPTouchAction;
+
+enum ANPLifecycleActions {
+    /** The web view containing this plugin has been paused.  See documentation
+        on the android activity lifecycle for more information.
+     */
+    kPause_ANPLifecycleAction           = 0,
+    /** The web view containing this plugin has been resumed. See documentation
+        on the android activity lifecycle for more information.
+     */
+    kResume_ANPLifecycleAction          = 1,
+    /** The plugin has focus and is now the recipient of input events (e.g. key,
+        touch, etc.)
+     */
+    kGainFocus_ANPLifecycleAction       = 2,
+    /** The plugin has lost focus and will not receive any input events until it
+        regains focus. This event is always preceded by a GainFocus action.
+     */
+    kLoseFocus_ANPLifecycleAction       = 3,
+    /** The browser is running low on available memory and is requesting that
+        the plugin free any unused/inactive resources to prevent a performance
+        degradation.
+     */
+    kFreeMemory_ANPLifecycleAction      = 4,
+    /** The page has finished loading. This happens when the page's top level
+        frame reports that it has completed loading.
+     */
+    kOnLoad_ANPLifecycleAction          = 5,
+    /** The browser is honoring the plugin's request to go full screen. Upon
+        returning from this event the browser will resize the plugin's java
+        surface to full-screen coordinates.
+     */
+    kEnterFullScreen_ANPLifecycleAction = 6,
+    /** The browser has exited from full screen mode. Immediately prior to
+        sending this event the browser has resized the plugin's java surface to
+        its original coordinates.
+     */
+    kExitFullScreen_ANPLifecycleAction  = 7,
+    /** The plugin is visible to the user on the screen. This event will always
+        occur after a kOffScreen_ANPLifecycleAction event.
+     */
+    kOnScreen_ANPLifecycleAction        = 8,
+    /** The plugin is no longer visible to the user on the screen. This event
+        will always occur prior to an kOnScreen_ANPLifecycleAction event.
+     */
+    kOffScreen_ANPLifecycleAction       = 9,
+};
+typedef uint32_t ANPLifecycleAction;
+
+/* This is what is passed to NPP_HandleEvent() */
+struct ANPEvent {
+    uint32_t        inSize;  // size of this struct in bytes
+    ANPEventType    eventType;
+    // use based on the value in eventType
+    union {
+        struct {
+            ANPKeyAction    action;
+            ANPKeyCode      nativeCode;
+            int32_t         virtualCode;    // windows virtual key code
+            ANPKeyModifier  modifiers;
+            int32_t         repeatCount;    // 0 for initial down (or up)
+            int32_t         unichar;        // 0 if there is no value
+        } key;
+        struct {
+            ANPMouseAction  action;
+            int32_t         x;  // relative to your "window" (0...width)
+            int32_t         y;  // relative to your "window" (0...height)
+        } mouse;
+        struct {
+            ANPTouchAction  action;
+            ANPKeyModifier  modifiers;
+            int32_t         x;  // relative to your "window" (0...width)
+            int32_t         y;  // relative to your "window" (0...height)
+        } touch;
+        struct {
+            ANPLifecycleAction  action;
+        } lifecycle;
+        struct {
+            ANPDrawingModel model;
+            // relative to (0,0) in top-left of your plugin
+            ANPRectI        clip;
+            // use based on the value in model
+            union {
+                ANPBitmap   bitmap;
+            } data;
+        } draw;
+        int32_t     other[8];
+    } data;
+};
+
+struct ANPEventInterfaceV0 : ANPInterface {
+    /** Post a copy of the specified event to the plugin. The event will be
+        delivered to the plugin in its main thread (the thread that receives
+        other ANPEvents). If, after posting before delivery, the NPP instance
+        is torn down, the event will be discarded.
+     */
+    void (*postEvent)(NPP inst, const ANPEvent* event);
+};
+
+struct ANPSystemInterfaceV0 : ANPInterface {
+    /** Return the path name for the current Application's plugin data directory,
+        or NULL if not supported
+     */
+    const char* (*getApplicationDataDirectory)();
+
+    /** A helper function to load java classes from the plugin's apk.  The
+        function looks for a class given the fully qualified and null terminated
+        string representing the className. For example,
+
+        const char* className = "com.android.mypackage.MyClass";
+
+        If the class cannot be found or there is a problem loading the class
+        NULL will be returned.
+     */
+    jclass (*loadJavaClass)(NPP instance, const char* className);
+};
+
+struct ANPSurfaceInterfaceV0 : ANPInterface {
+  /** Locks the surface from manipulation by other threads and provides a bitmap
+        to be written to.  The dirtyRect param specifies which portion of the
+        bitmap will be written to.  If the dirtyRect is NULL then the entire
+        surface will be considered dirty.  If the lock was successful the function
+        will return true and the bitmap will be set to point to a valid bitmap.
+        If not the function will return false and the bitmap will be set to NULL.
+  */
+  bool (*lock)(JNIEnv* env, jobject surface, ANPBitmap* bitmap, ANPRectI* dirtyRect);
+  /** Given a locked surface handle (i.e. result of a successful call to lock)
+        the surface is unlocked and the contents of the bitmap, specifically
+        those inside the dirtyRect are written to the screen.
+  */
+  void (*unlock)(JNIEnv* env, jobject surface);
+};
+
+typedef int32_t   int32;
+typedef uint32_t uint32;
+typedef int16_t   int16;
+typedef uint16_t uint16;
+
+#endif
new file mode 100644
--- a/dom/plugins/base/npfunctions.h
+++ b/dom/plugins/base/npfunctions.h
@@ -43,16 +43,20 @@
 #define NP_LOADDS _System
 #else
 #define NP_LOADDS
 #endif
 
 #include "npapi.h"
 #include "npruntime.h"
 
+#ifdef ANDROID
+#include <jni.h>
+#endif
+
 typedef NPError      (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
 typedef NPError      (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save);
 typedef NPError      (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window);
 typedef NPError      (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype);
 typedef NPError      (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
 typedef int32_t      (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream);
 typedef int32_t      (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer);
 typedef void         (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname);
@@ -302,18 +306,23 @@ NP_EXPORT(char*)       NP_GetPluginVersi
 typedef const char*    (*NP_GetMIMEDescriptionFunc)(void);
 NP_EXPORT(const char*) NP_GetMIMEDescription(void);
 #ifdef XP_MACOSX
 typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*);
 NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs);
 typedef NPError        (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
 NP_EXPORT(NPError)     NP_GetEntryPoints(NPPluginFuncs* pFuncs);
 #else
-typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
-NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
+#ifdef ANDROID
+typedef NPError    (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*, JNIEnv* pEnv);
+NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, JNIEnv* pEnv);
+#else
+typedef NPError    (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
+NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
+#endif
 #endif
 typedef NPError        (*NP_ShutdownFunc)(void);
 NP_EXPORT(NPError)     NP_Shutdown(void);
 typedef NPError        (*NP_GetValueFunc)(void *, NPPVariable, void *);
 NP_EXPORT(NPError)     NP_GetValue(void *future, NPPVariable aVariable, void *aValue);
 #ifdef __cplusplus
 }
 #endif
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -122,16 +122,23 @@ using mozilla::plugins::PluginModulePare
 #ifdef MOZ_X11
 #include "mozilla/X11Util.h"
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
+#ifdef ANDROID
+#include "ANPBase.h"
+#include "AndroidBridge.h"
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#endif
+
 using namespace mozilla;
 using namespace mozilla::plugins::parent;
 
 // We should make this const...
 static NPNetscapeFuncs sBrowserFuncs = {
   sizeof(sBrowserFuncs),
   (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR,
   _geturl,
@@ -472,17 +479,17 @@ nsNPAPIPlugin::CreatePlugin(nsPluginTag 
   if (!plugin)
     return NS_ERROR_OUT_OF_MEMORY;
 
   PluginLibrary* pluginLib = GetNewPluginLibrary(aPluginTag);
   if (!pluginLib) {
     return NS_ERROR_FAILURE;
   }
 
-#ifdef XP_MACOSX
+#if defined(XP_MACOSX) || defined(ANDROID)
   if (!pluginLib->HasRequiredFunctions()) {
     NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
     return NS_ERROR_FAILURE;
   }
 #endif
 
   plugin->mLibrary = pluginLib;
   pluginLib->SetPlugin(plugin);
@@ -2259,27 +2266,134 @@ NPError NP_CALLBACK
   }
 
   case NPNVsupportsUpdatedCocoaTextInputBool: {
     *(NPBool*)result = true;
     return NPERR_NO_ERROR;
   }
 #endif
 
+#ifdef ANDROID
+    case kLogInterfaceV0_ANPGetValue: {
+      LOG("get log interface");
+      ANPLogInterfaceV0 *i = (ANPLogInterfaceV0 *) result;
+      InitLogInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kBitmapInterfaceV0_ANPGetValue: {
+      LOG("get bitmap interface");
+      ANPBitmapInterfaceV0 *i = (ANPBitmapInterfaceV0 *) result;
+      InitBitmapInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kMatrixInterfaceV0_ANPGetValue: {
+      LOG("get matrix interface");
+      ANPMatrixInterfaceV0 *i = (ANPMatrixInterfaceV0 *) result;
+      InitMatrixInterface(i);
+      return NPERR_NO_ERROR;
+    }
+      
+    case kPathInterfaceV0_ANPGetValue: {
+      LOG("get path interface");
+      ANPPathInterfaceV0 *i = (ANPPathInterfaceV0 *) result;
+      InitPathInterface(i);
+      return NPERR_NO_ERROR;
+    }
+      
+    case kTypefaceInterfaceV0_ANPGetValue: {
+      LOG("get typeface interface");
+      ANPTypefaceInterfaceV0 *i = (ANPTypefaceInterfaceV0 *) result;
+      InitTypeFaceInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kPaintInterfaceV0_ANPGetValue: {
+      LOG("get paint interface");
+      ANPPaintInterfaceV0 *i = (ANPPaintInterfaceV0 *) result;
+      InitPaintInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kCanvasInterfaceV0_ANPGetValue: {
+      LOG("get canvas interface");
+      ANPCanvasInterfaceV0 *i = (ANPCanvasInterfaceV0 *) result;
+      InitCanvasInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kWindowInterfaceV0_ANPGetValue: {
+      LOG("get window interface");
+      ANPWindowInterfaceV0 *i = (ANPWindowInterfaceV0 *) result;
+      InitWindowInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kAudioTrackInterfaceV0_ANPGetValue: {
+      LOG("get audio interface");
+      ANPAudioTrackInterfaceV0 *i = (ANPAudioTrackInterfaceV0 *) result;
+      InitAudioTrackInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kEventInterfaceV0_ANPGetValue: {
+      LOG("get event interface");
+      ANPEventInterfaceV0 *i = (ANPEventInterfaceV0 *) result;
+      InitEventInterface(i);
+      return NPERR_NO_ERROR;
+    }
+
+    case kSystemInterfaceV0_ANPGetValue: {
+      LOG("get system interface");
+      ANPSystemInterfaceV0* i = reinterpret_cast<ANPSystemInterfaceV0*>(result);
+      InitSystemInterface(i);
+      LOG("done system interface");
+      return NPERR_NO_ERROR;
+    }
+
+    case kSurfaceInterfaceV0_ANPGetValue: {
+      LOG("get surface interface");
+      ANPSurfaceInterfaceV0 *i = (ANPSurfaceInterfaceV0 *) result;
+      InitSurfaceInterface(i);
+      return NPERR_NO_ERROR;
+    }
+      
+    case kSupportedDrawingModel_ANPGetValue: {
+      LOG("get supported drawing model");
+      uint32_t* bits = reinterpret_cast<uint32_t*>(result);
+      *bits = kBitmap_ANPDrawingModel && kSurface_ANPDrawingModel;
+      return NPERR_NO_ERROR;
+    }  
+
+    case kJavaContext_ANPGetValue: {
+      LOG("get context");
+      JNIEnv* env    = GetJNIForThread();
+      jclass cls     = env->FindClass("org/mozilla/gecko/GeckoApp");
+      jfieldID field = env->GetStaticFieldID(cls, "mAppContext",
+                                             "Lorg/mozilla/gecko/GeckoApp;");
+      jobject ret = env->GetStaticObjectField(cls, field);
+      int32_t* i  = reinterpret_cast<int32_t*>(result);
+      *i = reinterpret_cast<int32_t>(ret);
+      return NPERR_NO_ERROR;
+    }
+#endif
+
   // we no longer hand out any XPCOM objects
   case NPNVDOMElement:
     // fall through
   case NPNVDOMWindow:
     // fall through
   case NPNVserviceManager:
     // old XPCOM objects, no longer supported, but null out the out
     // param to avoid crashing plugins that still try to use this.
     *(nsISupports**)result = nsnull;
     // fall through
   default:
+    NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_getvalue unhandled get value: %d\n", variable));
     return NPERR_GENERIC_ERROR;
   }
 }
 
 NPError NP_CALLBACK
 _setvalue(NPP npp, NPPVariable variable, void *result)
 {
   if (!NS_IsMainThread()) {
@@ -2369,17 +2483,24 @@ NPError NP_CALLBACK
         inst->SetEventModel((NPEventModel)NS_PTR_TO_INT32(result));
         return NPERR_NO_ERROR;
       }
       else {
         return NPERR_GENERIC_ERROR;
       }
     }
 #endif
-
+#ifdef ANDROID
+  case kRequestDrawingModel_ANPSetValue:
+    if (inst)
+      inst->SetDrawingModel(NS_PTR_TO_INT32(result));
+    return NPERR_NO_ERROR;
+  case kAcceptEvents_ANPSetValue:
+    return NPERR_NO_ERROR;
+#endif
     default:
       return NPERR_GENERIC_ERROR;
   }
 }
 
 NPError NP_CALLBACK
 _requestread(NPStream *pstream, NPByteRange *rangeList)
 {
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -56,33 +56,46 @@
 #include "nsIScriptContext.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsJSNPRuntime.h"
 #include "nsPluginStreamListenerPeer.h"
 #include "nsSize.h"
 #include "nsNetCID.h"
 #include "nsIContent.h"
 
+#ifdef ANDROID
+#include "ANPBase.h"
+#include <android/log.h>
+#include "android_npapi.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/CondVar.h"
+#include "AndroidBridge.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::plugins::parent;
 
 static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
 static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
 
-NS_IMPL_ISUPPORTS0(nsNPAPIPluginInstance)
+NS_IMPL_THREADSAFE_ISUPPORTS0(nsNPAPIPluginInstance)
 
 nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
   :
 #ifdef XP_MACOSX
 #ifdef NP_NO_QUICKDRAW
     mDrawingModel(NPDrawingModelCoreGraphics),
 #else
     mDrawingModel(NPDrawingModelQuickDraw),
 #endif
 #endif
+#ifdef ANDROID
+    mSurface(nsnull),
+    mDrawingModel(0),
+#endif
     mRunning(NOT_STARTED),
     mWindowless(PR_FALSE),
     mWindowlessLocal(PR_FALSE),
     mTransparent(PR_FALSE),
     mUsesDOMForCursor(PR_FALSE),
     mInPluginInitCall(PR_FALSE),
     mPlugin(plugin),
     mMIMEType(nsnull),
@@ -679,17 +692,17 @@ NPError nsNPAPIPluginInstance::SetUsesDO
 }
 
 PRBool
 nsNPAPIPluginInstance::UsesDOMForCursor()
 {
   return mUsesDOMForCursor;
 }
 
-#ifdef XP_MACOSX
+#if defined(XP_MACOSX)
 void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel)
 {
   mDrawingModel = aModel;
 }
 
 void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel)
 {
   // the event model needs to be set for the object frame immediately
@@ -697,22 +710,79 @@ void nsNPAPIPluginInstance::SetEventMode
   GetOwner(getter_AddRefs(owner));
   if (!owner) {
     NS_WARNING("Trying to set event model without a plugin instance owner!");
     return;
   }
 
   owner->SetEventModel(aModel);
 }
+#endif
+
+#if defined(ANDROID)
+void nsNPAPIPluginInstance::SetDrawingModel(PRUint32 aModel)
+{
+  mDrawingModel = aModel;
+}
+
+class SurfaceGetter : public nsRunnable {
+public:
+  SurfaceGetter(NPPluginFuncs* aPluginFunctions, NPP_t aNPP) : 
+    mHaveSurface(PR_FALSE), mPluginFunctions(aPluginFunctions), mNPP(aNPP) {
+    mLock = new Mutex("SurfaceGetter::Lock");
+    mCondVar = new CondVar(*mLock, "SurfaceGetter::CondVar");
+    
+  }
+  ~SurfaceGetter() {
+    delete mLock;
+    delete mCondVar;
+  }
+  nsresult Run() {
+    MutexAutoLock lock(*mLock);
+    (*mPluginFunctions->getvalue)(&mNPP, kJavaSurface_ANPGetValue, &mSurface);
+    mHaveSurface = PR_TRUE;
+    mCondVar->Notify();
+    return NS_OK;
+  }
+  void* GetSurface() {
+    MutexAutoLock lock(*mLock);
+    mHaveSurface = PR_FALSE;
+    AndroidBridge::Bridge()->PostToJavaThread(this);
+    while (!mHaveSurface)
+      mCondVar->Wait();
+    return mSurface;
+  }
+private:
+  NPP_t mNPP;
+  void* mSurface;
+  Mutex* mLock;
+  CondVar* mCondVar;
+  PRBool mHaveSurface;
+  NPPluginFuncs* mPluginFunctions;
+};
+
+
+void* nsNPAPIPluginInstance::GetJavaSurface()
+{
+  if (mDrawingModel != kSurface_ANPDrawingModel)
+    return nsnull;
+  
+  if (mSurface)
+    return mSurface;
+
+  nsCOMPtr<SurfaceGetter> sg = new SurfaceGetter(mPlugin->PluginFuncs(), mNPP);
+  mSurface = sg->GetSurface();
+  return mSurface;
+}
 
 #endif
 
 nsresult nsNPAPIPluginInstance::GetDrawingModel(PRInt32* aModel)
 {
-#ifdef XP_MACOSX
+#if defined(XP_MACOSX) || defined(ANDROID)
   *aModel = (PRInt32)mDrawingModel;
   return NS_OK;
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
 nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(PRBool* aDrawing)
@@ -801,17 +871,22 @@ nsNPAPIPluginInstance::DefineJavaPropert
     return NS_ERROR_FAILURE;
 
   return NS_OK;
 }
 
 nsresult
 nsNPAPIPluginInstance::IsWindowless(PRBool* isWindowless)
 {
+#ifdef ANDROID
+  // On android, pre-honeycomb, all plugins are treated as windowless.
+  *isWindowless = PR_TRUE;
+#else
   *isWindowless = mWindowless;
+#endif
   return NS_OK;
 }
 
 class NS_STACK_CLASS AutoPluginLibraryCall
 {
 public:
   AutoPluginLibraryCall(nsNPAPIPluginInstance* aThis)
     : mThis(aThis), mGuard(aThis), mLibrary(nsnull)
@@ -1061,24 +1136,50 @@ nsNPAPIPluginInstance::PrivateModeStateC
       NPBool value = static_cast<NPBool>(pme);
       NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVprivateModeBool, &value), this);
       return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
     }
   }
   return NS_ERROR_FAILURE;
 }
 
+class DelayUnscheduleEvent : public nsRunnable {
+public:
+  nsRefPtr<nsNPAPIPluginInstance> mInstance;
+  uint32_t mTimerID;
+  DelayUnscheduleEvent(nsNPAPIPluginInstance* aInstance, uint32_t aTimerId)
+    : mInstance(aInstance)
+    , mTimerID(aTimerId)
+  {}
+
+  ~DelayUnscheduleEvent() {}
+
+  NS_IMETHOD Run();
+};
+
+NS_IMETHODIMP
+DelayUnscheduleEvent::Run()
+{
+  mInstance->UnscheduleTimer(mTimerID);
+  return NS_OK;
+}
+
+
 static void
 PluginTimerCallback(nsITimer *aTimer, void *aClosure)
 {
   nsNPAPITimer* t = (nsNPAPITimer*)aClosure;
   NPP npp = t->npp;
   uint32_t id = t->id;
 
+  // Some plugins (Flash on Android) calls unscheduletimer
+  // from this callback.
+  t->inCallback = PR_TRUE;
   (*(t->callback))(npp, id);
+  t->inCallback = PR_FALSE;
 
   // Make sure we still have an instance and the timer is still alive
   // after the callback.
   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
   if (!inst || !inst->TimerWithID(id, NULL))
     return;
 
   // use UnscheduleTimer to clean up if this is a one-shot timer
@@ -1102,16 +1203,17 @@ nsNPAPIPluginInstance::TimerWithID(uint3
   return nsnull;
 }
 
 uint32_t
 nsNPAPIPluginInstance::ScheduleTimer(uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
 {
   nsNPAPITimer *newTimer = new nsNPAPITimer();
 
+  newTimer->inCallback = PR_FALSE;
   newTimer->npp = &mNPP;
 
   // generate ID that is unique to this instance
   uint32_t uniqueID = mTimers.Length();
   while ((uniqueID == 0) || TimerWithID(uniqueID, NULL))
     uniqueID++;
   newTimer->id = uniqueID;
 
@@ -1139,16 +1241,22 @@ void
 nsNPAPIPluginInstance::UnscheduleTimer(uint32_t timerID)
 {
   // find the timer struct by ID
   PRUint32 index;
   nsNPAPITimer* t = TimerWithID(timerID, &index);
   if (!t)
     return;
 
+  if (t->inCallback) {
+    nsCOMPtr<nsIRunnable> e = new DelayUnscheduleEvent(this, timerID);
+    NS_DispatchToCurrentThread(e);
+    return;
+  }
+
   // cancel the timer
   t->timer->Cancel();
 
   // remove timer struct from array
   mTimers.RemoveElementAt(index);
 
   // delete timer
   delete t;
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -63,16 +63,17 @@ class nsIOutputStream;
 
 class nsNPAPITimer
 {
 public:
   NPP npp;
   uint32_t id;
   nsCOMPtr<nsITimer> timer;
   void (*callback)(NPP npp, uint32_t timerID);
+  PRBool inCallback;
 };
 
 class nsNPAPIPluginInstance : public nsISupports
 {
 private:
   typedef mozilla::PluginLibrary PluginLibrary;
 
 public:
@@ -80,16 +81,19 @@ public:
 
   nsresult Initialize(nsIPluginInstanceOwner* aOwner, const char* aMIMEType);
   nsresult Start();
   nsresult Stop();
   nsresult SetWindow(NPWindow* window);
   nsresult NewStreamToPlugin(nsIPluginStreamListener** listener);
   nsresult NewStreamFromPlugin(const char* type, const char* target, nsIOutputStream* *result);
   nsresult Print(NPPrint* platformPrint);
+#ifdef ANDROID
+  nsresult PostEvent(void* event) { return 0; };
+#endif
   nsresult HandleEvent(void* event, PRInt16* result);
   nsresult GetValueFromPlugin(NPPVariable variable, void* value);
   nsresult GetDrawingModel(PRInt32* aModel);
   nsresult IsRemoteDrawingCoreAnimation(PRBool* aDrawing);
   nsresult GetJSObject(JSContext *cx, JSObject** outObject);
   nsresult DefineJavaProperties();
   nsresult IsWindowless(PRBool* isWindowless);
   nsresult AsyncSetWindow(NPWindow* window);
@@ -136,16 +140,21 @@ public:
   NPError SetUsesDOMForCursor(PRBool aUsesDOMForCursor);
   PRBool UsesDOMForCursor();
 
 #ifdef XP_MACOSX
   void SetDrawingModel(NPDrawingModel aModel);
   void SetEventModel(NPEventModel aModel);
 #endif
 
+#ifdef ANDROID
+  void SetDrawingModel(PRUint32 aModel);
+  void* GetJavaSurface();
+#endif
+
   nsresult NewStreamListener(const char* aURL, void* notifyData,
                              nsIPluginStreamListener** listener);
 
   nsNPAPIPluginInstance(nsNPAPIPlugin* plugin);
   virtual ~nsNPAPIPluginInstance();
 
   // To be called when an instance becomes orphaned, when
   // it's plugin is no longer guaranteed to be around.
@@ -202,16 +211,20 @@ protected:
   // The structure used to communicate between the plugin instance and
   // the browser.
   NPP_t mNPP;
 
 #ifdef XP_MACOSX
   NPDrawingModel mDrawingModel;
 #endif
 
+#ifdef ANDROID
+  PRUint32 mDrawingModel;
+#endif
+
   enum {
     NOT_STARTED,
     RUNNING,
     DESTROYING,
     DESTROYED
   } mRunning;
 
   // these are used to store the windowless properties
@@ -245,11 +258,14 @@ private:
   nsTArray<nsNPAPITimer*> mTimers;
 
   // non-null during a HandleEvent call
   void* mCurrentPluginEvent;
 
   nsCOMPtr<nsIURI> mURI;
 
   PRPackedBool mUsePluginLayersPref;
+#ifdef ANDROID
+  void* mSurface;
+#endif
 };
 
 #endif // nsNPAPIPluginInstance_h_
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -154,16 +154,21 @@
 
 #if defined(XP_WIN)
 #include "nsIWindowMediator.h"
 #include "nsIBaseWindow.h"
 #include "windows.h"
 #include "winbase.h"
 #endif
 
+#ifdef ANDROID
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#endif
+
 using namespace mozilla;
 using mozilla::TimeStamp;
 
 // Null out a strong ref to a linked list iteratively to avoid
 // exhausting the stack (bug 486349).
 #define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_)                \
   {                                                                  \
     while (list_) {                                                  \
@@ -2224,17 +2229,17 @@ nsresult nsPluginHost::ScanPluginsDirect
     while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
       nsCOMPtr<nsISupports> supports;
       nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
       if (NS_FAILED(rv))
         continue;
       nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
       if (NS_FAILED(rv))
         continue;
-
+      
       // don't pass aPluginsChanged directly to prevent it from been reset
       PRBool pluginschanged = PR_FALSE;
       ScanPluginsDirectory(nextDir, aCreatePluginList, &pluginschanged);
 
       if (pluginschanged)
         *aPluginsChanged = PR_TRUE;
 
       // if changes are detected and we are not creating the list, do not proceed
@@ -2319,16 +2324,20 @@ nsresult nsPluginHost::FindPlugins(PRBoo
 
     // if we are just looking for possible changes,
     // no need to proceed if changes are detected
     if (!aCreatePluginList && *aPluginsChanged) {
       NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
       NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
       return NS_OK;
     }
+  } else {
+#ifdef ANDROID
+    LOG("getting plugins dir failed");
+#endif
   }
 
   mPluginsLoaded = PR_TRUE; // at this point 'some' plugins have been loaded,
                             // the rest is optional
 
 #ifdef XP_WIN
   PRBool bScanPLIDs = PR_FALSE;
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -113,16 +113,26 @@ static NS_DEFINE_CID(kAppShellCID, NS_AP
 
 #ifdef MOZ_WIDGET_GTK2
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 #include "gfxXlibNativeRenderer.h"
 #endif
 
+#ifdef ANDROID
+#include "ANPBase.h"
+#include "android_npapi.h"
+#include "AndroidBridge.h"
+using namespace mozilla::dom;
+
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
+#endif
+
 using namespace mozilla;
 
 // special class for handeling DOM context menu events because for
 // some reason it starves other mouse events if implemented on the
 // same class
 class nsPluginDOMContextMenuListener : public nsIDOMEventListener
 {
 public:
@@ -1250,17 +1260,22 @@ nsresult nsPluginInstanceOwner::EnsureCa
   if (!data.IsEmpty()) {
     mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC"));
     mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data);
     nextAttrParamIndex++;
   }
 
   // Add PARAM and null separator.
   mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
+#ifdef ANDROID
+  // Flash expects an empty string on android
+  mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING(""));
+#else
   mCachedAttrParamValues[nextAttrParamIndex] = nsnull;
+#endif
   nextAttrParamIndex++;
 
   // Add PARAM name/value pairs.
   for (PRUint16 i = 0; i < mNumCachedParams; i++) {
     nsIDOMElement* param = ourParams.ObjectAt(i);
     if (!param) {
       continue;
     }
@@ -1635,18 +1650,58 @@ void nsPluginInstanceOwner::ScrollPositi
         mInstance->HandleEvent(&scrollEvent, nsnull);
       }
       pluginWidget->EndDrawPlugin();
     }
   }
 #endif
 }
 
+#ifdef ANDROID
+void nsPluginInstanceOwner::RemovePluginView()
+{
+  if (mInstance && mObjectFrame) {
+    void* surface = mInstance->GetJavaSurface();
+    if (surface) {
+      JNIEnv* env = GetJNIForThread();
+      if (env) {
+        jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
+        jmethodID method = env->GetStaticMethodID(cls,
+                                                  "removePluginView",
+                                                  "(Landroid/view/View;)V");
+        env->CallStaticVoidMethod(cls, method, surface);
+      }
+    }
+  }
+}
+#endif
+
 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
 {
+#ifdef ANDROID
+  {
+    ANPEvent event;
+    event.inSize = sizeof(ANPEvent);
+    event.eventType = kLifecycle_ANPEventType;
+
+    nsAutoString eventType;
+    aFocusEvent->GetType(eventType);
+    if (eventType.EqualsLiteral("focus")) {
+      event.data.lifecycle.action = kGainFocus_ANPLifecycleAction;
+    }
+    else if (eventType.EqualsLiteral("blur")) {
+      event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction;
+    }
+    else {
+      NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin, wierd eventType");   
+    }
+    mInstance->HandleEvent(&event, nsnull);
+  }
+#endif
+
 #ifndef XP_MACOSX
   if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
     // continue only for cases without child window
     return aFocusEvent->PreventDefault(); // consume event
   }
 #endif
 
   nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aFocusEvent));
@@ -1907,18 +1962,16 @@ static unsigned int XInputEventState(con
   if (anEvent.isAlt) state |= Mod1Mask;
   if (anEvent.isMeta) state |= Mod4Mask;
   return state;
 }
 #endif
 
 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
 {
-  // printf("nsGUIEvent.message: %d\n", anEvent.message);
-
   nsEventStatus rv = nsEventStatus_eIgnore;
 
   if (!mInstance || !mObjectFrame)   // if mInstance is null, we shouldn't be here
     return nsEventStatus_eIgnore;
 
 #ifdef XP_MACOSX
   if (!mWidget)
     return nsEventStatus_eIgnore;
@@ -2431,16 +2484,117 @@ nsEventStatus nsPluginInstanceOwner::Pro
   event.send_event = False;
 
   PRInt16 response = kNPEventNotHandled;
   mInstance->HandleEvent(&pluginEvent, &response);
   if (response == kNPEventHandled)
     rv = nsEventStatus_eConsumeNoDefault;
 #endif
 
+#ifdef ANDROID
+  // this code supports windowless plugins
+  {
+    // The plugin needs focus to receive keyboard and touch events
+    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+    if (fm) {
+      nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
+      fm->SetFocus(elem, 0);
+    }
+  }
+  switch(anEvent.eventStructType)
+    {
+    case NS_MOUSE_EVENT:
+      {
+        switch (anEvent.message)
+          {
+          case NS_MOUSE_CLICK:
+          case NS_MOUSE_DOUBLECLICK:
+            // Button up/down events sent instead.
+            return rv;
+          }
+
+        // Get reference point relative to plugin origin.
+        const nsPresContext* presContext = mObjectFrame->PresContext();
+        nsPoint appPoint =
+          nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
+          mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
+        nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
+                               presContext->AppUnitsToDevPixels(appPoint.y));
+
+        switch (anEvent.message)
+          {
+          case NS_MOUSE_MOVE:
+            {
+              // are these going to be touch events?
+              // pluginPoint.x;
+              // pluginPoint.y;
+            }
+            break;
+          case NS_MOUSE_BUTTON_DOWN:
+            {
+              ANPEvent event;
+              event.inSize = sizeof(ANPEvent);
+              event.eventType = kMouse_ANPEventType;
+              event.data.mouse.action = kDown_ANPMouseAction;
+              event.data.mouse.x = pluginPoint.x;
+              event.data.mouse.y = pluginPoint.y;
+              mInstance->HandleEvent(&event, nsnull);
+            }
+            break;
+          case NS_MOUSE_BUTTON_UP:
+            {
+              ANPEvent event;
+              event.inSize = sizeof(ANPEvent);
+              event.eventType = kMouse_ANPEventType;
+              event.data.mouse.action = kUp_ANPMouseAction;
+              event.data.mouse.x = pluginPoint.x;
+              event.data.mouse.y = pluginPoint.y;
+              mInstance->HandleEvent(&event, nsnull);
+            }
+            break;
+          }
+      }
+      break;
+
+    case NS_KEY_EVENT:
+     {
+       const nsKeyEvent& keyEvent = static_cast<const nsKeyEvent&>(anEvent);
+       LOG("Firing NS_KEY_EVENT %d %d\n", keyEvent.keyCode, keyEvent.charCode);
+       
+       int modifiers = 0;
+       if (keyEvent.isShift)
+         modifiers |= kShift_ANPKeyModifier;
+       if (keyEvent.isAlt)
+         modifiers |= kAlt_ANPKeyModifier;
+
+       ANPEvent event;
+       event.inSize = sizeof(ANPEvent);
+       event.eventType = kKey_ANPEventType;
+       event.data.key.nativeCode = keyEvent.keyCode;
+       event.data.key.virtualCode = keyEvent.charCode;
+       event.data.key.modifiers = modifiers;
+       event.data.key.repeatCount = 0;
+       event.data.key.unichar = 0;
+       switch (anEvent.message)
+         {
+         case NS_KEY_DOWN:
+           event.data.key.action = kDown_ANPKeyAction;
+           mInstance->HandleEvent(&event, nsnull);
+           break;
+           
+         case NS_KEY_UP:
+           event.data.key.action = kUp_ANPKeyAction;
+           mInstance->HandleEvent(&event, nsnull);
+           break;
+         }
+     }
+    }
+    rv = nsEventStatus_eConsumeNoDefault;
+#endif
+ 
   return rv;
 }
 
 nsresult
 nsPluginInstanceOwner::Destroy()
 {
 #ifdef MAC_CARBON_PLUGINS
   // stop the timer explicitly to reduce reference count.
@@ -2536,16 +2690,20 @@ nsPluginInstanceOwner::PrepareToStop(PRB
     // and plugin et al not holding any other references to its
     // parent.
     mWidget->SetParent(nsnull);
 
     mDestroyWidget = PR_TRUE;
   }
 #endif
 
+#ifdef ANDROID
+  RemovePluginView();
+#endif
+
   // Unregister scroll position listeners
   for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     nsIScrollableFrame* sf = do_QueryFrame(f);
     if (sf) {
       sf->RemoveScrollPositionListener(this);
     }
   }
 }
@@ -2632,16 +2790,148 @@ void nsPluginInstanceOwner::Paint(const 
   NPEvent pluginEvent;
   pluginEvent.event = WM_PAINT;
   pluginEvent.wParam = (uint32)aHPS;
   pluginEvent.lParam = (uint32)&rectl;
   mInstance->HandleEvent(&pluginEvent, nsnull);
 }
 #endif
 
+#ifdef ANDROID
+
+class AndroidPaintEventRunnable : public nsRunnable
+{
+public:
+  AndroidPaintEventRunnable(void* aSurface, nsNPAPIPluginInstance* inst, const gfxRect& aFrameRect)
+    : mSurface(aSurface), mInstance(inst), mFrameRect(aFrameRect) {
+  }
+
+  ~AndroidPaintEventRunnable() {
+  }
+
+  NS_IMETHOD Run()
+  {
+    LOG("%p - AndroidPaintEventRunnable::Run\n", this);
+
+    if (!mInstance || !mSurface)
+      return NS_OK;
+
+    // This needs to happen on the gecko main thread.
+    JNIEnv* env = GetJNIForThread();
+    jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
+    jmethodID method = env->GetStaticMethodID(cls,
+                                              "addPluginView",
+                                              "(Landroid/view/View;DDDD)V");
+    env->CallStaticVoidMethod(cls,
+                              method,
+                              mSurface,
+                              mFrameRect.x,
+                              mFrameRect.y,
+                              mFrameRect.width,
+                              mFrameRect.height);
+    return NS_OK;
+  }
+private:
+  void* mSurface;
+  nsCOMPtr<nsNPAPIPluginInstance> mInstance;
+  gfxRect mFrameRect;
+};
+
+
+void nsPluginInstanceOwner::Paint(gfxContext* aContext,
+                                  const gfxRect& aFrameRect,
+                                  const gfxRect& aDirtyRect)
+{
+  if (!mInstance || !mObjectFrame)
+    return;
+
+  PRInt32 model;
+  mInstance->GetDrawingModel(&model);
+
+  if (model == kSurface_ANPDrawingModel) {
+
+    {
+      ANPEvent event;
+      event.inSize = sizeof(ANPEvent);
+      event.eventType = kLifecycle_ANPEventType;
+      event.data.lifecycle.action = kOnScreen_ANPLifecycleAction;
+      mInstance->HandleEvent(&event, nsnull);
+    }
+
+    /*
+    gfxMatrix currentMatrix = aContext->CurrentMatrix();
+    gfxSize scale = currentMatrix.ScaleFactors(PR_TRUE);
+    printf_stderr("!!!!!!!! scale!!:  %f x %f\n", scale.width, scale.height);
+    */
+
+    JNIEnv* env = GetJNIForThread();
+    jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
+    jmethodID method = env->GetStaticMethodID(cls,
+                                              "addPluginView",
+                                              "(Landroid/view/View;DDDD)V");
+    env->CallStaticVoidMethod(cls,
+                              method,
+                              mInstance->GetJavaSurface(),
+                              aFrameRect.x,
+                              aFrameRect.y,
+                              aFrameRect.width,
+                              aFrameRect.height);
+    return;
+  }
+
+  if (model != kBitmap_ANPDrawingModel)
+    return;
+
+#ifdef ANP_BITMAP_DRAWING_MODEL
+  static nsRefPtr<gfxImageSurface> pluginSurface;
+
+  if (pluginSurface == nsnull ||
+      aFrameRect.width  != pluginSurface->Width() ||
+      aFrameRect.height != pluginSurface->Height()) {
+
+    pluginSurface = new gfxImageSurface(gfxIntSize(aFrameRect.width, aFrameRect.height), 
+                                        gfxImageSurface::ImageFormatARGB32);
+    if (!pluginSurface)
+      return;
+  }
+
+  // Clears buffer.  I think this is needed.
+  nsRefPtr<gfxContext> ctx = new gfxContext(pluginSurface);
+  ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
+  ctx->Paint();
+  
+  ANPEvent event;
+  event.inSize = sizeof(ANPEvent);
+  event.eventType = 4;
+  event.data.draw.model = 1;
+  
+  event.data.draw.clip.top     = 0;
+  event.data.draw.clip.left    = 0;
+  event.data.draw.clip.bottom  = aFrameRect.width;
+  event.data.draw.clip.right   = aFrameRect.height;
+  
+  event.data.draw.data.bitmap.format   = kRGBA_8888_ANPBitmapFormat;
+  event.data.draw.data.bitmap.width    = aFrameRect.width;
+  event.data.draw.data.bitmap.height   = aFrameRect.height;
+  event.data.draw.data.bitmap.baseAddr = pluginSurface->Data();
+  event.data.draw.data.bitmap.rowBytes = aFrameRect.width * 4;
+  
+  if (!mInstance)
+    return;
+    
+  mInstance->HandleEvent(&event, nsnull);
+
+  aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
+  aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
+  aContext->Clip(aFrameRect);
+  aContext->Paint();
+#endif
+}
+#endif
+
 #if defined(MOZ_X11)
 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
                                   const gfxRect& aFrameRect,
                                   const gfxRect& aDirtyRect)
 {
   if (!mInstance || !mObjectFrame)
     return;
 
@@ -3269,19 +3559,38 @@ void nsPluginInstanceOwner::UpdateWindow
   mPluginWindow->y = origin.y;
 
   mPluginWindow->clipRect.left = 0;
   mPluginWindow->clipRect.top = 0;
 
   if (mPluginWindowVisible && mPluginDocumentActiveState) {
     mPluginWindow->clipRect.right = mPluginWindow->width;
     mPluginWindow->clipRect.bottom = mPluginWindow->height;
+#ifdef ANDROID
+    if (mInstance) {
+      ANPEvent event;
+      event.inSize = sizeof(ANPEvent);
+      event.eventType = kLifecycle_ANPEventType;
+      event.data.lifecycle.action = kOnScreen_ANPLifecycleAction;
+      mInstance->HandleEvent(&event, nsnull);
+    }
+#endif
   } else {
     mPluginWindow->clipRect.right = 0;
     mPluginWindow->clipRect.bottom = 0;
+#ifdef ANDROID
+    if (mInstance) {
+      ANPEvent event;
+      event.inSize = sizeof(ANPEvent);
+      event.eventType = kLifecycle_ANPEventType;
+      event.data.lifecycle.action = kOffScreen_ANPLifecycleAction;
+      mInstance->HandleEvent(&event, nsnull);
+    }
+    RemovePluginView();
+#endif
   }
 
   if (!aSetWindow)
     return;
 
   if (mPluginWindow->x               != oldWindow.x               ||
       mPluginWindow->y               != oldWindow.y               ||
       mPluginWindow->clipRect.left   != oldWindow.clipRect.left   ||
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -139,17 +139,17 @@ public:
   void PrepareToStop(PRBool aDelayedStop);
   
 #ifdef XP_WIN
   void Paint(const RECT& aDirty, HDC aDC);
 #elif defined(XP_MACOSX)
   void Paint(const gfxRect& aDirtyRect, CGContextRef cgContext);  
   void RenderCoreAnimation(CGContextRef aCGContext, int aWidth, int aHeight);
   void DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext);
-#elif defined(MOZ_X11)
+#elif defined(MOZ_X11) || defined(ANDROID)
   void Paint(gfxContext* aContext,
              const gfxRect& aFrameRect,
              const gfxRect& aDirtyRect);
 #elif defined(XP_OS2)
   void Paint(const nsRect& aDirtyRect, HPS aHPS);
 #endif
   
 #ifdef MAC_CARBON_PLUGINS
@@ -303,17 +303,20 @@ private:
   PRBool IsUpToDate()
   {
     nsIntSize size;
     return NS_SUCCEEDED(mInstance->GetImageSize(&size)) &&
     size == nsIntSize(mPluginWindow->width, mPluginWindow->height);
   }
   
   void FixUpURLS(const nsString &name, nsAString &value);
-  
+#ifdef ANDROID
+  void RemovePluginView();
+#endif 
+ 
   nsPluginNativeWindow       *mPluginWindow;
   nsRefPtr<nsNPAPIPluginInstance> mInstance;
   nsObjectFrame              *mObjectFrame; // owns nsPluginInstanceOwner
   nsCOMPtr<nsIContent>        mContent;
   nsCString                   mDocumentBase;
   char                       *mTagText;
   nsCOMPtr<nsIWidget>         mWidget;
   nsRefPtr<nsPluginHost>      mPluginHost;
--- a/dom/plugins/base/nsPluginNativeWindowWin.cpp
+++ b/dom/plugins/base/nsPluginNativeWindowWin.cpp
@@ -179,18 +179,17 @@ static PRBool ProcessFlashMessageDelayed
                                          HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   NS_ENSURE_TRUE(aWin, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aInst, NS_ERROR_NULL_POINTER);
 
   if (msg == sWM_FLASHBOUNCEMSG) {
     // See PluginWindowEvent::Run() below.
     NS_ASSERTION((sWM_FLASHBOUNCEMSG != 0), "RegisterWindowMessage failed in flash plugin WM_USER message handling!");
-    NS_TRY_SAFE_CALL_VOID(::CallWindowProc((WNDPROC)aWin->GetWindowProc(), hWnd, WM_USER_FLASH, wParam, lParam),
-                                           aInst);
+    ::CallWindowProc((WNDPROC)aWin->GetWindowProc(), hWnd, WM_USER_FLASH, wParam, lParam);
     return TRUE;
   }
 
   if (msg != WM_USER_FLASH)
     return PR_FALSE; // no need to delay
 
   // do stuff
   nsCOMPtr<nsIRunnable> pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam);
@@ -572,22 +571,21 @@ NS_IMETHODIMP PluginWindowEvent::Run()
   if (GetMsg() == WM_USER_FLASH) {
     // XXX Unwind issues related to runnable event callback depth for this
     // event and destruction of the plugin. (Bug 493601)
     ::PostMessage(hWnd, sWM_FLASHBOUNCEMSG, GetWParam(), GetLParam());
   }
   else {
     // Currently not used, but added so that processing events here
     // is more generic.
-    NS_TRY_SAFE_CALL_VOID(::CallWindowProc(win->GetWindowProc(), 
-                          hWnd, 
-                          GetMsg(), 
-                          GetWParam(), 
-                          GetLParam()),
-                          inst);
+    ::CallWindowProc(win->GetWindowProc(), 
+                     hWnd, 
+                     GetMsg(), 
+                     GetWParam(), 
+                     GetLParam());
   }
 
   Clear();
   return NS_OK;
 }
 
 PluginWindowEvent * 
 nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam)
--- a/dom/plugins/base/nsPluginsDirUnix.cpp
+++ b/dom/plugins/base/nsPluginsDirUnix.cpp
@@ -242,16 +242,26 @@ static void LoadExtraSharedLibs()
 /* nsPluginsDir implementation */
 
 PRBool nsPluginsDir::IsPluginFile(nsIFile* file)
 {
     nsCAutoString filename;
     if (NS_FAILED(file->GetNativeLeafName(filename)))
         return PR_FALSE;
 
+#ifdef ANDROID
+    // It appears that if you load
+    // 'libstagefright_honeycomb.so' on froyo, or
+    // 'libstagefright_froyo.so' on honeycomb, we will abort.
+    // Since these are just helper libs, we can ignore.
+    const char *cFile = filename.get();
+    if (strstr(cFile, "libstagefright") != NULL)
+        return PR_FALSE;
+#endif
+
     NS_NAMED_LITERAL_CSTRING(dllSuffix, LOCAL_PLUGIN_DLL_SUFFIX);
     if (filename.Length() > dllSuffix.Length() &&
         StringEndsWith(filename, dllSuffix))
         return PR_TRUE;
     
 #ifdef LOCAL_PLUGIN_DLL_ALT_SUFFIX
     NS_NAMED_LITERAL_CSTRING(dllAltSuffix, LOCAL_PLUGIN_DLL_ALT_SUFFIX);
     if (filename.Length() > dllAltSuffix.Length() &&
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -14,16 +14,23 @@
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
 
+    <uses-permission android:name="android.permission.READ_LOGS"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> 
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
+
     <uses-feature android:name="android.hardware.location" android:required="false"/>
     <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
     <uses-feature android:name="android.hardware.touchscreen"/>
 
     <application android:label="@MOZ_APP_DISPLAYNAME@"
 		 android:icon="@drawable/icon"
 #if MOZILLA_OFFICIAL
 		 android:debuggable="false">
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -40,16 +40,17 @@
 package org.mozilla.gecko;
 
 import java.io.*;
 import java.util.*;
 import java.util.zip.*;
 import java.nio.*;
 import java.nio.channels.FileChannel;
 import java.util.concurrent.*;
+import java.lang.reflect.*;
 
 import android.os.*;
 import android.app.*;
 import android.text.*;
 import android.view.*;
 import android.view.inputmethod.*;
 import android.content.*;
 import android.content.res.*;
@@ -57,29 +58,32 @@ import android.graphics.*;
 import android.widget.*;
 import android.hardware.*;
 
 import android.util.*;
 import android.net.*;
 import android.database.*;
 import android.provider.*;
 import android.telephony.*;
+import android.content.pm.*;
+import android.content.pm.PackageManager.*;
+import dalvik.system.*;
 
 abstract public class GeckoApp
     extends Activity
 {
     private static final String LOG_FILE_NAME     = "GeckoApp";
 
     public static final String ACTION_ALERT_CLICK = "org.mozilla.gecko.ACTION_ALERT_CLICK";
     public static final String ACTION_ALERT_CLEAR = "org.mozilla.gecko.ACTION_ALERT_CLEAR";
     public static final String ACTION_WEBAPP      = "org.mozilla.gecko.WEBAPP";
     public static final String ACTION_DEBUG       = "org.mozilla.gecko.DEBUG";
     public static final String ACTION_BOOKMARK    = "org.mozilla.gecko.BOOKMARK";
 
-    public static FrameLayout mainLayout;
+    public static AbsoluteLayout mainLayout;
     public static GeckoSurfaceView surfaceView;
     public static GeckoApp mAppContext;
     public static boolean mFullscreen = false;
     public static File sGREDir = null;
     static Thread mLibLoadThread = null;
     public Handler mMainHandler;
     private IntentFilter mConnectivityFilter;
     private BroadcastReceiver mConnectivityReceiver;
@@ -125,16 +129,161 @@ abstract public class GeckoApp
                                                        int id)
                                    {
                                        GeckoApp.this.finish();
                                        System.exit(0);
                                    }
                                }).show();
     }
 
+    public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
+
+    /**
+     * A plugin that wish to be loaded in the WebView must provide this permission
+     * in their AndroidManifest.xml.
+     */
+    public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
+
+    private static final String LOGTAG = "PluginManager";
+
+    private static final String PLUGIN_SYSTEM_LIB = "/system/lib/plugins/";
+
+    private static final String PLUGIN_TYPE = "type";
+    private static final String TYPE_NATIVE = "native";
+    public ArrayList<PackageInfo> mPackageInfoCache = new ArrayList<PackageInfo>();
+
+    String[] getPluginDirectories() {
+
+        ArrayList<String> directories = new ArrayList<String>();
+        PackageManager pm = this.mAppContext.getPackageManager();
+        List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+
+        synchronized(mPackageInfoCache) {
+
+            // clear the list of existing packageInfo objects
+            mPackageInfoCache.clear();
+
+
+            for (ResolveInfo info : plugins) {
+
+                // retrieve the plugin's service information
+                ServiceInfo serviceInfo = info.serviceInfo;
+                if (serviceInfo == null) {
+                    Log.w(LOGTAG, "Ignore bad plugin");
+                    continue;
+                }
+
+                Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName);
+
+
+                // retrieve information from the plugin's manifest
+                PackageInfo pkgInfo;
+                try {
+                    pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
+                                    PackageManager.GET_PERMISSIONS
+                                    | PackageManager.GET_SIGNATURES);
+                } catch (Exception e) {
+                    Log.w(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
+                    continue;
+                }
+                if (pkgInfo == null) {
+                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Could not load package information.");
+                    continue;
+                }
+
+                /*
+                 * find the location of the plugin's shared library. The default
+                 * is to assume the app is either a user installed app or an
+                 * updated system app. In both of these cases the library is
+                 * stored in the app's data directory.
+                 */
+                String directory = pkgInfo.applicationInfo.dataDir + "/lib";
+                final int appFlags = pkgInfo.applicationInfo.flags;
+                final int updatedSystemFlags = ApplicationInfo.FLAG_SYSTEM |
+                                               ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+                // preloaded system app with no user updates
+                if ((appFlags & updatedSystemFlags) == ApplicationInfo.FLAG_SYSTEM) {
+                    directory = PLUGIN_SYSTEM_LIB + pkgInfo.packageName;
+                }
+
+                // check if the plugin has the required permissions
+                String permissions[] = pkgInfo.requestedPermissions;
+                if (permissions == null) {
+                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Does not have required permission.");
+                    continue;
+                }
+                boolean permissionOk = false;
+                for (String permit : permissions) {
+                    if (PLUGIN_PERMISSION.equals(permit)) {
+                        permissionOk = true;
+                        break;
+                    }
+                }
+                if (!permissionOk) {
+                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Does not have required permission (2).");
+                    continue;
+                }
+
+                // check to ensure the plugin is properly signed
+                Signature signatures[] = pkgInfo.signatures;
+                if (signatures == null) {
+                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Not signed.");
+                    continue;
+                }
+
+                // determine the type of plugin from the manifest
+                if (serviceInfo.metaData == null) {
+                    Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no type defined");
+                    continue;
+                }
+
+                String pluginType = serviceInfo.metaData.getString(PLUGIN_TYPE);
+                if (!TYPE_NATIVE.equals(pluginType)) {
+                    Log.e(LOGTAG, "Unrecognized plugin type: " + pluginType);
+                    continue;
+                }
+
+                try {
+                    Class<?> cls = getPluginClass(serviceInfo.packageName, serviceInfo.name);
+
+                    //TODO implement any requirements of the plugin class here!
+                    boolean classFound = true;
+
+                    if (!classFound) {
+                        Log.e(LOGTAG, "The plugin's class' " + serviceInfo.name + "' does not extend the appropriate class.");
+                        continue;
+                    }
+
+                } catch (NameNotFoundException e) {
+                    Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
+                    continue;
+                } catch (ClassNotFoundException e) {
+                    Log.e(LOGTAG, "Can't find plugin's class: " + serviceInfo.name);
+                    continue;
+                }
+
+                // if all checks have passed then make the plugin available
+                mPackageInfoCache.add(pkgInfo);
+                directories.add(directory);
+            }
+        }
+
+        return directories.toArray(new String[directories.size()]);
+    }
+
+    Class<?> getPluginClass(String packageName, String className)
+            throws NameNotFoundException, ClassNotFoundException {
+        Context pluginContext = this.mAppContext.createPackageContext(packageName,
+                Context.CONTEXT_INCLUDE_CODE |
+                Context.CONTEXT_IGNORE_SECURITY);
+        ClassLoader pluginCL = pluginContext.getClassLoader();
+        return pluginCL.loadClass(className);
+    }
+
     // Returns true when the intent is going to be handled by gecko launch
     boolean launch(Intent intent)
     {
         if (!checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched))
             return false;
 
         if (intent == null)
             intent = getIntent();
@@ -224,23 +373,24 @@ abstract public class GeckoApp
 
         getWindow().setFlags(mFullscreen ?
                              WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
                              WindowManager.LayoutParams.FLAG_FULLSCREEN);
 
         if (surfaceView == null)
             surfaceView = new GeckoSurfaceView(this);
         else
-            mainLayout.removeView(surfaceView);
+            mainLayout.removeAllViews();
 
-        mainLayout = new FrameLayout(this);
+        mainLayout = new AbsoluteLayout(this);
         mainLayout.addView(surfaceView,
-                           new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,
-                                                        FrameLayout.LayoutParams.FILL_PARENT));
-
+                           new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT, // level 8
+                                                           AbsoluteLayout.LayoutParams.MATCH_PARENT,
+                                                           0,
+                                                           0));
         setContentView(mainLayout,
                        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                                   ViewGroup.LayoutParams.FILL_PARENT));
 
         mConnectivityFilter = new IntentFilter();
         mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mConnectivityReceiver = new GeckoConnectivityReceiver();
 
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -303,16 +303,29 @@ public class GeckoAppShell
             if (oldHome.exists())
                 moveDir(oldHome, profileDir);
 
             File intHome =  geckoApp.getFilesDir();
             File intProf = new File(intHome, "mozilla");
             if (intHome != null && intProf != null && intProf.exists())
                 moveDir(intProf, profileDir);
         }
+        try {
+            String[] dirs = GeckoApp.mAppContext.getPluginDirectories();
+            StringBuffer pluginSearchPath = new StringBuffer();
+            for (int i = 0; i < dirs.length; i++) {
+                Log.i("GeckoPlugins", "dir: " + dirs[i]);
+                pluginSearchPath.append(dirs[i]);
+                pluginSearchPath.append(":");
+            }
+            GeckoAppShell.putenv("MOZ_PLUGIN_PATH="+pluginSearchPath);
+        } catch (Exception ex) {
+            Log.i("GeckoPlugins", "exception getting plugin dirs", ex);
+        }
+
         GeckoAppShell.putenv("HOME=" + homeDir);
         GeckoAppShell.putenv("GRE_HOME=" + GeckoApp.sGREDir.getPath());
         Intent i = geckoApp.getIntent();
         String env = i.getStringExtra("env0");
         Log.i(LOG_FILE_NAME, "env0: "+ env);
         for (int c = 1; env != null; c++) {
             GeckoAppShell.putenv(env);
             env = i.getStringExtra("env" + c);
@@ -390,16 +403,17 @@ public class GeckoAppShell
         GeckoAppShell.setSurfaceView(GeckoApp.surfaceView);
 
         // First argument is the .apk path
         String combinedArgs = apkPath + " -greomni " + apkPath;
         if (args != null)
             combinedArgs += " " + args;
         if (url != null)
             combinedArgs += " " + url;
+
         // and go
         GeckoAppShell.nativeRun(combinedArgs);
     }
 
     private static GeckoEvent mLastDrawEvent;
 
     private static void sendPendingEventsToGecko() {
         try {
@@ -1380,9 +1394,192 @@ public class GeckoAppShell
                 Settings.System.getInt(GeckoApp.mAppContext.getContentResolver(),
                                        Settings.System.TEXT_SHOW_PASSWORD);
             return (showPassword > 0);
         }
         catch (Exception e) {
             return false;
         }
     }
+    public static void addPluginView(final View view,
+                                     final double x, final double y,
+                                     final double w, final double h) {
+
+        Log.i("GeckoAppShell", "addPluginView:" + view + " @ x:" + x + " y:" + y + " w:" + w + " h:" + h ) ;
+
+        getMainHandler().post(new Runnable() { 
+                public void run() {
+                    AbsoluteLayout.LayoutParams lp = new AbsoluteLayout.LayoutParams((int)w,
+                                                                                     (int)h,
+                                                                                     (int)x,
+                                                                                     (int)y);
+
+                    if (GeckoApp.mainLayout.indexOfChild(view) == -1) {
+                        view.setWillNotDraw(false);
+                        if(view instanceof SurfaceView)
+                            ((SurfaceView)view).setZOrderOnTop(true);
+
+                        GeckoApp.mainLayout.addView(view, lp);
+                    }
+                    else
+                    {
+                        try {
+                            GeckoApp.mainLayout.updateViewLayout(view, lp);
+                        } catch (IllegalArgumentException e) {
+                            Log.i("updateViewLayout - IllegalArgumentException", "e:" + e);
+                            // it can be the case where we
+                            // get an update before the view
+                            // is actually attached.
+                        }
+                    }
+                }
+            });
+    }
+
+    public static void removePluginView(final View view) {
+        Log.i("GeckoAppShell", "remove view:" + view);
+        getMainHandler().post(new Runnable() { 
+                public void run() {
+                    try {
+                        GeckoApp.mainLayout.removeView(view);
+                    } catch (Exception e) {}
+                }
+            });
+    }
+
+    public static Class<?> loadPluginClass(String className, String libName) {
+        Log.i("GeckoAppShell", "in loadPluginClass... attempting to access className, then libName.....");
+        Log.i("GeckoAppShell", "className: " + className);
+        Log.i("GeckoAppShell", "libName: " + libName);
+
+        try {
+            String[] split = libName.split("/");
+            String packageName = split[split.length - 3];
+            Log.i("GeckoAppShell", "load \"" + className + "\" from \"" + packageName + 
+                  "\" for \"" + libName + "\"");
+            Context pluginContext = 
+                GeckoApp.mAppContext.createPackageContext(packageName,
+                                                          Context.CONTEXT_INCLUDE_CODE |
+                                                      Context.CONTEXT_IGNORE_SECURITY);
+            ClassLoader pluginCL = pluginContext.getClassLoader();
+            return pluginCL.loadClass(className);
+        } catch (java.lang.ClassNotFoundException cnfe) {
+            Log.i("GeckoAppShell", "class not found", cnfe);
+        } catch (android.content.pm.PackageManager.NameNotFoundException nnfe) {
+            Log.i("GeckoAppShell", "package not found", nnfe);
+        }
+        Log.e("GeckoAppShell", "couldn't find class");
+        return null;
+    }
+
+    static HashMap<SurfaceView, SurfaceLockInfo> sSufaceMap = new HashMap<SurfaceView, SurfaceLockInfo>();
+
+    public static void lockSurfaceANP()
+    {
+         Log.i("GeckoAppShell", "other lockSurfaceANP");
+    }
+
+    public static org.mozilla.gecko.SurfaceLockInfo lockSurfaceANP(android.view.SurfaceView sview, int top, int left, int bottom, int right)
+    {
+        Log.i("GeckoAppShell", "real lockSurfaceANP " + sview + ", " + top + ",  " + left + ", " + bottom + ", " + right);
+        if (sview == null)
+            return null;
+
+        int format = -1;
+        try {
+            Field privateFormatField = SurfaceView.class.getDeclaredField("mFormat");
+            privateFormatField.setAccessible(true);
+            format = privateFormatField.getInt(sview);
+        } catch (Exception e) {
+            Log.i("GeckoAppShell", "mFormat is not a field of sview: ", e);
+        }
+
+        int n = 0;
+        if (format == PixelFormat.RGB_565)
+            n = 2;
+        else if (format == PixelFormat.RGBA_8888)
+            n = 4;
+
+        if (n == 0)
+            return null;
+
+        SurfaceLockInfo info = sSufaceMap.get(sview);
+        if (info == null) {
+            info = new SurfaceLockInfo();
+            sSufaceMap.put(sview, info);
+        }
+
+        Rect r = new Rect(left, top, right, bottom);
+
+        info.canvas = sview.getHolder().lockCanvas(r);
+        int bufSizeRequired = info.canvas.getWidth() * info.canvas.getHeight() * n;
+        Log.i("GeckoAppShell", "lockSurfaceANP - bufSizeRequired: " + n + " " + info.canvas.getHeight() + " " + info.canvas.getWidth());
+
+        if (info.width != info.canvas.getWidth() || info.height != info.canvas.getHeight() || info.buffer == null || info.buffer.capacity() < bufSizeRequired) {
+            info.width = info.canvas.getWidth();
+            info.height = info.canvas.getHeight();
+
+            // XXX Bitmaps instead of ByteBuffer
+            info.buffer = ByteBuffer.allocateDirect(bufSizeRequired);  //leak
+            Log.i("GeckoAppShell", "!!!!!!!!!!!  lockSurfaceANP - Allocating buffer! " + bufSizeRequired);
+
+        }
+
+        info.canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
+
+        info.format = format;
+        info.dirtyTop = top;
+        info.dirtyBottom = bottom;
+        info.dirtyLeft = left;
+        info.dirtyRight = right;
+
+        return info;
+    }
+
+    public static void unlockSurfaceANP(SurfaceView sview) {
+        SurfaceLockInfo info = sSufaceMap.get(sview);
+
+        int n = 0;
+        Bitmap.Config config;
+        if (info.format == PixelFormat.RGB_565) {
+            n = 2;
+            config = Bitmap.Config.RGB_565;
+        } else {
+            n = 4;
+            config = Bitmap.Config.ARGB_8888;
+        }
+
+        Log.i("GeckoAppShell", "unlockSurfaceANP: " + (info.width * info.height * n));
+
+        Bitmap bm = Bitmap.createBitmap(info.width, info.height, config);
+        bm.copyPixelsFromBuffer(info.buffer);
+        info.canvas.drawBitmap(bm, 0, 0, null);
+        sview.getHolder().unlockCanvasAndPost(info.canvas);
+    }
+
+    public static Class getSurfaceLockInfoClass() {
+        Log.i("GeckoAppShell", "class name: " + SurfaceLockInfo.class.getName());
+        return SurfaceLockInfo.class;
+    }
+
+    public static Method getSurfaceLockMethod() {
+        Method[] m = GeckoAppShell.class.getMethods();
+        for (int i = 0; i < m.length; i++) {
+            if (m[i].getName().equals("lockSurfaceANP"))
+                return m[i];
+        }
+        return null;
+    }
+
+    static native void executeNextRunnable();
+
+    static class GeckoRunnableCallback implements Runnable {
+        public void run() {
+            Log.i("GeckoShell", "run GeckoRunnableCallback");
+            GeckoAppShell.executeNextRunnable();
+        }
+    }
+
+    public static void postToJavaThread(boolean mainThread) {
+        Log.i("GeckoShell", "post to " + (mainThread ? "main " : "") + "java thread");
+        getMainHandler().post(new GeckoRunnableCallback());
+    }
 }
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -49,16 +49,17 @@ JAVAFILES = \
   GeckoApp.java \
   GeckoAppShell.java \
   GeckoConnectivityReceiver.java \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   GeckoPhoneStateListener.java \
   AlertNotification.java \
+  SurfaceLockInfo.java \
   $(NULL)
 
 PROCESSEDJAVAFILES = \
   App.java \
   Restarter.java \
   NotificationHandler.java \
   LauncherShortcuts.java \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/embedding/android/SurfaceLockInfo.java
@@ -0,0 +1,18 @@
+package org.mozilla.gecko;
+
+import android.graphics.Canvas;
+import java.nio.Buffer;
+
+public class SurfaceLockInfo {
+    public int dirtyTop;
+    public int dirtyLeft;
+    public int dirtyRight;
+    public int dirtyBottom;
+
+    public int bpr;
+    public int format;
+    public int width;
+    public int height;
+    public Buffer buffer;
+    public Canvas canvas;
+}
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -130,16 +130,17 @@ SHARED_LIBRARY_LIBS += \
 	$(DEPTH)/dom/system/cocoa/$(LIB_PREFIX)domsystemcocoa_s.$(LIB_SUFFIX) \
 	$(NULL)
 LOCAL_INCLUDES	+= \
 	-I$(topsrcdir)/dom/system/cocoa \
 	$(NULL)
 else ifneq (,$(filter android,$(MOZ_WIDGET_TOOLKIT)))
 SHARED_LIBRARY_LIBS += \
 	$(DEPTH)/dom/system/android/$(LIB_PREFIX)domsystemandroid_s.$(LIB_SUFFIX) \
+	$(DEPTH)/dom/plugins/base/android/$(LIB_PREFIX)gkpluginandroid_s.$(LIB_SUFFIX) \
 	$(NULL)
 LOCAL_INCLUDES	+= \
 	-I$(topsrcdir)/dom/system/android \
 	$(NULL)
 endif
 
 ifdef MOZ_VORBIS
 SHARED_LIBRARY_LIBS 	+= \
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -1678,16 +1678,32 @@ nsObjectFrame::BuildLayer(nsDisplayListB
   return layer.forget();
 }
 
 void
 nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
                            nsRenderingContext& aRenderingContext,
                            const nsRect& aDirtyRect, const nsRect& aPluginRect)
 {
+#if defined(ANDROID)
+  if (mInstanceOwner) {
+    NPWindow *window;
+    mInstanceOwner->GetWindow(window);
+
+    gfxRect frameGfxRect =
+      PresContext()->AppUnitsToGfxUnits(aPluginRect);
+    gfxRect dirtyGfxRect =
+      PresContext()->AppUnitsToGfxUnits(aDirtyRect);
+    gfxContext* ctx = aRenderingContext.ThebesContext();
+
+    mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect);
+    return;
+  }
+#endif
+
   // Screen painting code
 #if defined(XP_MACOSX)
   // delegate all painting to the plugin instance.
   if (mInstanceOwner) {
     if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics ||
         mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation ||
         mInstanceOwner->GetDrawingModel() == 
                                   NPDrawingModelInvalidatingCoreAnimation) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filter-bounds-01.svg
@@ -0,0 +1,24 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
+     xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <title>Testcase for checking that filter bounds include stroke width</title>
+
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=647687 -->
+
+  <defs>
+    <filter id="f1" filterUnits="userSpaceOnUse" x="150" y="150" width="200" height="200">
+      <feOffset in="SourceGraphic"/>
+    </filter>
+  </defs>
+
+  <rect height="100%" width="100%" fill="lime"/>
+
+  <rect x="150" y="150" height="200" width="200" fill="red"/>
+
+  <rect x="200" y="200" height="100" width="100" stroke-width="100"
+            fill="none" stroke="lime" filter="url(#f1)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filter-bounds-02.svg
@@ -0,0 +1,25 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
+     xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <title>Testcase for checking that filter bounds include stroke width</title>
+
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=647687 -->
+
+  <defs>
+    <filter id="f1" filterUnits="objectBoundingBox">
+      <feFlood flood-color="red"/>
+    </filter>
+  </defs>
+
+  <rect height="100%" width="100%" fill="lime"/>
+
+  <polygon points="200,200 300,200 300,300 200,300" stroke-width="100"
+            fill="none" stroke="lime" filter="url(#f1)"/>
+
+  <rect x="150" y="150" height="200" width="200" fill="lime"/>
+
+</svg>
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -106,16 +106,18 @@ random == dynamic-use-nested-01.svg dyna
 == fallback-color-01a.svg pass.svg
 == fallback-color-01b.svg pass.svg
 == fallback-color-02a.svg fallback-color-02-ref.svg
 == fallback-color-02b.svg fallback-color-02-ref.svg
 == fallback-color-03.svg pass.svg
 == filter-basic-01.svg pass.svg
 == filter-basic-02.svg pass.svg
 == filter-basic-03.svg pass.svg
+== filter-bounds-01.svg pass.svg
+== filter-bounds-02.svg pass.svg
 == filter-foreignObject-01.svg pass.svg
 == filter-invalidation-01.svg pass.svg
 == filter-scaled-01.svg pass.svg
 == filter-translated-01.svg filter-translated-01-ref.svg
 == filters-and-group-opacity-01.svg filters-and-group-opacity-01-ref.svg
 == foreignObject-01.svg pass.svg
 == foreignObject-02.svg foreignObject-02-ref.svg
 == foreignObject-ancestor-style-change-01.svg foreignObject-ancestor-style-change-01-ref.svg
--- a/layout/svg/base/src/nsSVGFilterFrame.cpp
+++ b/layout/svg/base/src/nsSVGFilterFrame.cpp
@@ -201,21 +201,29 @@ nsAutoFilterInstance::nsAutoFilterInstan
   // filterToDeviceSpace is always invertible
   gfxMatrix deviceToFilterSpace = filterToDeviceSpace;
   deviceToFilterSpace.Invert();
 
   nsIntRect dirtyOutputRect =
     MapDeviceRectToFilterSpace(deviceToFilterSpace, filterRes, aDirtyOutputRect);
   nsIntRect dirtyInputRect =
     MapDeviceRectToFilterSpace(deviceToFilterSpace, filterRes, aDirtyInputRect);
+  nsIntRect targetBoundsDeviceSpace;
+  nsISVGChildFrame* svgTarget = do_QueryFrame(aTarget);
+  if (svgTarget) {
+    targetBoundsDeviceSpace.UnionRect(targetBoundsDeviceSpace,
+      svgTarget->GetCoveredRegion().ToOutsidePixels(aTarget->PresContext()->AppUnitsPerDevPixel()));
+  }
+  nsIntRect targetBoundsFilterSpace =
+    MapDeviceRectToFilterSpace(deviceToFilterSpace, filterRes, &targetBoundsDeviceSpace);
 
   // Setup instance data
   mInstance = new nsSVGFilterInstance(aTarget, aPaint, filter, bbox, filterRegion,
                                       nsIntSize(filterRes.width, filterRes.height),
-                                      filterToDeviceSpace,
+                                      filterToDeviceSpace, targetBoundsFilterSpace,
                                       dirtyOutputRect, dirtyInputRect,
                                       primitiveUnits);
 }
 
 nsAutoFilterInstance::~nsAutoFilterInstance()
 {
 }
 
--- a/layout/svg/base/src/nsSVGFilterInstance.cpp
+++ b/layout/svg/base/src/nsSVGFilterInstance.cpp
@@ -184,16 +184,17 @@ nsSVGFilterInstance::BuildSources()
   mSourceAlpha.mImage.mFilterPrimitiveSubregion = filterRegion;
 
   nsIntRect sourceBoundsInt;
   gfxRect sourceBounds = UserSpaceToFilterSpace(mTargetBBox);
   sourceBounds.RoundOut();
   // Detect possible float->int overflow
   if (!gfxUtils::GfxRectToIntRect(sourceBounds, &sourceBoundsInt))
     return NS_ERROR_FAILURE;
+  sourceBoundsInt.UnionRect(sourceBoundsInt, mTargetBounds);
 
   mSourceColorAlpha.mResultBoundingBox = sourceBoundsInt;
   mSourceAlpha.mResultBoundingBox = sourceBoundsInt;
   return NS_OK;
 }
 
 nsresult
 nsSVGFilterInstance::BuildPrimitives()
--- a/layout/svg/base/src/nsSVGFilterInstance.h
+++ b/layout/svg/base/src/nsSVGFilterInstance.h
@@ -65,26 +65,28 @@ class NS_STACK_CLASS nsSVGFilterInstance
 public:
   nsSVGFilterInstance(nsIFrame *aTargetFrame,
                       nsSVGFilterPaintCallback *aPaintCallback,
                       nsSVGFilterElement *aFilterElement,
                       const gfxRect &aTargetBBox,
                       const gfxRect& aFilterRect,
                       const nsIntSize& aFilterSpaceSize,
                       const gfxMatrix &aFilterSpaceToDeviceSpaceTransform,
+                      const nsIntRect& aTargetBounds,
                       const nsIntRect& aDirtyOutputRect,
                       const nsIntRect& aDirtyInputRect,
                       PRUint16 aPrimitiveUnits) :
     mTargetFrame(aTargetFrame),
     mPaintCallback(aPaintCallback),
     mFilterElement(aFilterElement),
     mTargetBBox(aTargetBBox),
     mFilterSpaceToDeviceSpaceTransform(aFilterSpaceToDeviceSpaceTransform),
     mFilterRect(aFilterRect),
     mFilterSpaceSize(aFilterSpaceSize),
+    mTargetBounds(aTargetBounds),
     mDirtyOutputRect(aDirtyOutputRect),
     mDirtyInputRect(aDirtyInputRect),
     mSurfaceRect(nsIntPoint(0, 0), aFilterSpaceSize),
     mPrimitiveUnits(aPrimitiveUnits) {
   }
   
   // The area covered by temporary images, in filter space
   void SetSurfaceRect(const nsIntRect& aRect) { mSurfaceRect = aRect; }
@@ -204,16 +206,18 @@ private:
   nsIFrame*               mTargetFrame;
   nsSVGFilterPaintCallback* mPaintCallback;
   nsSVGFilterElement*     mFilterElement;
   // Bounding box of the target element, in user space
   gfxRect                 mTargetBBox;
   gfxMatrix               mFilterSpaceToDeviceSpaceTransform;
   gfxRect                 mFilterRect;
   nsIntSize               mFilterSpaceSize;
+  // Filter-space bounds of the target image (SourceAlpha/SourceGraphic)
+  nsIntRect               mTargetBounds;
   nsIntRect               mDirtyOutputRect;
   nsIntRect               mDirtyInputRect;
   nsIntRect               mSurfaceRect;
   PRUint16                mPrimitiveUnits;
 
   PrimitiveInfo           mSourceColorAlpha;
   PrimitiveInfo           mSourceAlpha;
   nsTArray<PrimitiveInfo> mPrimitives;
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -61,16 +61,17 @@
 #include "nsEscape.h"
 #include "nsStreamUtils.h"
 #include "nsIOService.h"
 #include "nsICacheService.h"
 #include "nsDNSPrefetch.h"
 #include "nsChannelClassifier.h"
 #include "nsIRedirectResultListener.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/Telemetry.h"
 
 // True if the local cache should be bypassed when processing a request.
 #define BYPASS_LOCAL_CACHE(loadFlags) \
         (loadFlags & (nsIRequest::LOAD_BYPASS_CACHE | \
                       nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE))
 
 static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
 
@@ -123,16 +124,17 @@ nsHttpChannel::nsHttpChannel()
     , mInitedCacheEntry(PR_FALSE)
     , mCacheForOfflineUse(PR_FALSE)
     , mCachingOpportunistically(PR_FALSE)
     , mFallbackChannel(PR_FALSE)
     , mCustomConditionalRequest(PR_FALSE)
     , mFallingBack(PR_FALSE)
     , mWaitingForRedirectCallback(PR_FALSE)
     , mRequestTimeInitialized(PR_FALSE)
+    , mDidReval(false)
 {
     LOG(("Creating nsHttpChannel [this=%p]\n", this));
     mChannelCreationTime = PR_Now();
     mChannelCreationTimestamp = mozilla::TimeStamp::Now();
 }
 
 nsHttpChannel::~nsHttpChannel()
 {
@@ -262,16 +264,18 @@ nsHttpChannel::Connect(PRBool firstTime)
             nsRunnableMethod<nsHttpChannel> *event = nsnull;
             if (!mCachedContentIsPartial) {
                 AsyncCall(&nsHttpChannel::AsyncOnExamineCachedResponse, &event);
             }
             rv = ReadFromCache();
             if (NS_FAILED(rv) && event) {
                 event->Revoke();
             }
+            mozilla::Telemetry::Accumulate(
+                    mozilla::Telemetry::HTTP_CACHE_DISPOSITION, kCacheHit);
             return rv;
         }
         else if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
             // the cache contains the requested resource, but it must be 
             // validated before we can reuse it.  since we are not allowed
             // to hit the net, there's nothing more to do.  the document
             // is effectively not in the cache.
             return NS_ERROR_DOCUMENT_NOT_CACHED;
@@ -969,16 +973,18 @@ nsHttpChannel::ProcessResponse()
 
         // reset the authentication's current continuation state because our
         // last authentication attempt has been completed successfully
         mAuthProvider->Disconnect(NS_ERROR_ABORT);
         mAuthProvider = nsnull;
         LOG(("  continuation state has been reset"));
     }
 
+    bool successfulReval = false;
+
     // handle different server response categories.  Note that we handle
     // caching or not caching of error pages in
     // nsHttpResponseHead::MustValidate; if you change this switch, update that
     // one
     switch (httpStatus) {
     case 200:
     case 203:
         // Per RFC 2616, 14.35.2, "A server MAY ignore the Range header".
@@ -1020,16 +1026,19 @@ nsHttpChannel::ProcessResponse()
         }
         break;
     case 304:
         rv = ProcessNotModified();
         if (NS_FAILED(rv)) {
             LOG(("ProcessNotModified failed [rv=%x]\n", rv));
             rv = ProcessNormal();
         }
+        else {
+            successfulReval = true;
+        }
         break;
     case 401:
     case 407:
         rv = mAuthProvider->ProcessAuthentication(
             httpStatus, mConnectionInfo->UsingSSL() &&
                         mTransaction->SSLConnectFailed());
         if (rv == NS_ERROR_IN_PROGRESS)  {
             // authentication prompt has been invoked and result
@@ -1055,16 +1064,27 @@ nsHttpChannel::ProcessResponse()
             mAuthRetryPending = PR_TRUE; // see DoAuthRetry
         break;
     default:
         rv = ProcessNormal();
         MaybeInvalidateCacheEntryForSubsequentGet();
         break;
     }
 
+    if (!mDidReval)
+        mozilla::Telemetry::Accumulate(
+                mozilla::Telemetry::HTTP_CACHE_DISPOSITION, kCacheMissed);
+    else if (successfulReval)
+        mozilla::Telemetry::Accumulate(
+                mozilla::Telemetry::HTTP_CACHE_DISPOSITION, kCacheHitViaReval);
+    else
+        mozilla::Telemetry::Accumulate(
+                mozilla::Telemetry::HTTP_CACHE_DISPOSITION,
+                kCacheMissedViaReval);
+
     return rv;
 }
 
 nsresult
 nsHttpChannel::ContinueProcessResponse(nsresult rv)
 {
     if (NS_SUCCEEDED(rv)) {
         InitCacheEntry();
@@ -2661,16 +2681,17 @@ nsHttpChannel::CheckCache()
                     mRequestHead.SetHeader(nsHttp::If_Modified_Since,
                                            nsDependentCString(val));
             }
             // Add If-None-Match header if an ETag was given in the response
             val = mCachedResponseHead->PeekHeader(nsHttp::ETag);
             if (val)
                 mRequestHead.SetHeader(nsHttp::If_None_Match,
                                        nsDependentCString(val));
+            mDidReval = true;
         }
     }
 
     LOG(("nsHTTPChannel::CheckCache exit [this=%p doValidation=%d]\n", this, doValidation));
     return NS_OK;
 }
 
 PRBool
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -361,11 +361,20 @@ private:
     nsRefPtr<nsDNSPrefetch>           mDNSPrefetch;
 
     nsresult WaitForRedirectCallback();
     void PushRedirectAsyncFunc(nsContinueRedirectionFunc func);
     void PopRedirectAsyncFunc(nsContinueRedirectionFunc func);
 
 protected:
     virtual void DoNotifyListenerCleanup();
+
+private: // cache telemetry
+    enum {
+        kCacheHit = 1,
+        kCacheHitViaReval = 2,
+        kCacheMissedViaReval = 3,
+        kCacheMissed = 4
+    };
+    bool mDidReval;
 };
 
 #endif // nsHttpChannel_h__
--- a/other-licenses/android/APKOpen.cpp
+++ b/other-licenses/android/APKOpen.cpp
@@ -236,16 +236,17 @@ SHELL_WRAPPER1(notifyGeckoOfEvent, jobje
 SHELL_WRAPPER0(processNextNativeEvent)
 SHELL_WRAPPER1(setSurfaceView, jobject)
 SHELL_WRAPPER0(onResume)
 SHELL_WRAPPER0(onLowMemory)
 SHELL_WRAPPER3(callObserver, jstring, jstring, jstring)
 SHELL_WRAPPER1(removeObserver, jstring)
 SHELL_WRAPPER2(onChangeNetworkLinkStatus, jstring, jstring)
 SHELL_WRAPPER1(reportJavaCrash, jstring)
+SHELL_WRAPPER0(executeNextRunnable)
 
 static void * xul_handle = NULL;
 static time_t apk_mtime = 0;
 #ifdef DEBUG
 extern "C" int extractLibs = 1;
 #else
 extern "C" int extractLibs = 0;
 #endif
@@ -662,16 +663,17 @@ loadLibs(const char *apkName)
   GETFUNC(processNextNativeEvent);
   GETFUNC(setSurfaceView);
   GETFUNC(onResume);
   GETFUNC(onLowMemory);
   GETFUNC(callObserver);
   GETFUNC(removeObserver);
   GETFUNC(onChangeNetworkLinkStatus);
   GETFUNC(reportJavaCrash);
+  GETFUNC(executeNextRunnable);
 #undef GETFUNC
   gettimeofday(&t1, 0);
   struct rusage usage2;
   getrusage(RUSAGE_SELF, &usage2);
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %dms total, %dms user, %dms system, %d faults",
                       (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000, 
                       (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000,
                       (usage2.ru_stime.tv_sec - usage1.ru_stime.tv_sec)*1000 + (usage2.ru_stime.tv_usec - usage1.ru_stime.tv_usec)/1000,
--- a/toolkit/components/telemetry/TelemetryHistograms.h
+++ b/toolkit/components/telemetry/TelemetryHistograms.h
@@ -127,16 +127,19 @@ HISTOGRAM(HTTP_REQUEST_PER_PAGE_FROM_CAC
   _HTTP_HIST(HTTP_##prefix##_COMPLETE_LOAD_CACHED, labelprefix "Overall load time - cache hits (ms)") \
   _HTTP_HIST(HTTP_##prefix##_COMPLETE_LOAD_NET, labelprefix "Overall load time - network (ms)") \
 
 HTTP_HISTOGRAMS(PAGE, "page: ")
 HTTP_HISTOGRAMS(SUB, "subitem: ")
 
 #undef _HTTP_HIST
 #undef HTTP_HISTOGRAMS
+
+HISTOGRAM(HTTP_CACHE_DISPOSITION, 1, 5, 5, LINEAR, "HTTP Cache Hit, Reval, Failed-Reval, Miss")
+
 HISTOGRAM(FIND_PLUGINS, 1, 3000, 10, EXPONENTIAL, "Time spent scanning filesystem for plugins (ms)")
 HISTOGRAM(CHECK_JAVA_ENABLED, 1, 3000, 10, EXPONENTIAL, "Time spent checking if Java is enabled (ms)")
 
 /* Define 2 histograms: MOZ_SQLITE_(NAME)_MS and
  * MOZ_SQLITE_(NAME)_MAIN_THREAD_MS. These are meant to be used by
  * IOThreadAutoTimer which relies on _MAIN_THREAD_MS histogram being
  * "+ 1" away from MOZ_SQLITE_(NAME)_MS.
  */
--- a/widget/src/android/AndroidBridge.cpp
+++ b/widget/src/android/AndroidBridge.cpp
@@ -144,16 +144,17 @@ AndroidBridge::Init(JNIEnv *jEnv,
     jIsNetworkLinkKnown = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "isNetworkLinkKnown", "()Z");
     jGetNetworkLinkType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNetworkLinkType", "()I");
     jSetSelectedLocale = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setSelectedLocale", "(Ljava/lang/String;)V");
     jScanMedia = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V");
     jGetSystemColors = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getSystemColors", "()[I");
     jGetIconForExtension = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getIconForExtension", "(Ljava/lang/String;I)[B");
     jCreateShortcut = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
     jGetShowPasswordSetting = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getShowPasswordSetting", "()Z");
+    jPostToJavaThread = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "postToJavaThread", "(Z)V");
 
     jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
     jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
     jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
     jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
     jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
     jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
 
@@ -164,18 +165,24 @@ AndroidBridge::Init(JNIEnv *jEnv,
     // at SetMainThread time.
 
     return PR_TRUE;
 }
 
 JNIEnv *
 AndroidBridge::AttachThread(PRBool asDaemon)
 {
+    // If we already have a env, return it
+    JNIEnv *jEnv = NULL;
+    mJavaVM->GetEnv((void**) &jEnv, JNI_VERSION_1_2);
+    if (jEnv)
+        return jEnv;
+
     ALOG_BRIDGE("AndroidBridge::AttachThread");
-    JNIEnv *jEnv = (JNIEnv*) PR_GetThreadPrivate(sJavaEnvThreadIndex);
+    jEnv = (JNIEnv*) PR_GetThreadPrivate(sJavaEnvThreadIndex);
     if (jEnv)
         return jEnv;
 
     JavaVMAttachArgs args = {
         JNI_VERSION_1_2,
         "GeckoThread",
         NULL
     };
@@ -190,16 +197,18 @@ AndroidBridge::AttachThread(PRBool asDae
 
     if (res != 0) {
         ALOG_BRIDGE("AttachCurrentThread failed!");
         return nsnull;
     }
 
     PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
 
+    PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
+
     return jEnv;
 }
 
 PRBool
 AndroidBridge::SetMainThread(void *thr)
 {
     ALOG_BRIDGE("AndroidBridge::SetMainThread");
     if (thr) {
@@ -921,16 +930,55 @@ AndroidBridge::CreateShortcut(const nsAS
   jstring jstrIntent = mJNIEnv->NewString(nsPromiseFlatString(aIntent).get(), aIntent.Length());
   
   if (!jstrURI || !jstrTitle || !jstrIconData)
     return;
     
   mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jCreateShortcut, jstrTitle, jstrURI, jstrIconData, jstrIntent);
 }
 
+void
+AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, PRBool aMainThread)
+{
+    __android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
+    JNIEnv* env = AndroidBridge::AttachThread(false);
+    if (!env) {
+        __android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
+        return;
+    }
+    mRunnableQueue.AppendObject(aRunnable);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jPostToJavaThread, (jboolean)aMainThread);
+
+    jthrowable ex = env->ExceptionOccurred();
+    if (ex) {
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+    __android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
+}
+
+void
+AndroidBridge::ExecuteNextRunnable()
+{
+    __android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
+
+    JNIEnv* env = AndroidBridge::AttachThread(false);
+    if (!env) {
+        __android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
+        return;
+    }
+
+    if (mRunnableQueue.Count() > 0) {
+        nsIRunnable* r = mRunnableQueue[0];
+        __android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "going to run %p", r);
+        r->Run();
+        mRunnableQueue.RemoveObjectAt(0);
+    }
+    __android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
+}
 bool
 AndroidBridge::HasNativeBitmapAccess()
 {
     if (!mOpenedBitmapLibrary) {
         // Try to dlopen libjnigraphics.so for direct bitmap access on
         // Android 2.2+ (API level 8)
         mOpenedBitmapLibrary = true;
 
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -37,16 +37,17 @@
 
 #ifndef AndroidBridge_h__
 #define AndroidBridge_h__
 
 #include <jni.h>
 #include <android/log.h>
 
 #include "nsCOMPtr.h"
+#include "nsCOMArray.h"
 #include "nsIRunnable.h"
 #include "nsIObserver.h"
 
 #include "AndroidJavaWrappers.h"
 
 #include "nsIMutableArray.h"
 #include "nsIMIMEInfo.h"
 #include "nsColor.h"
@@ -257,16 +258,20 @@ public:
     bool HasNativeBitmapAccess();
 
     bool ValidateBitmap(jobject bitmap, int width, int height);
 
     void *LockBitmap(jobject bitmap);
 
     void UnlockBitmap(jobject bitmap);
 
+    void PostToJavaThread(nsIRunnable* aRunnable, PRBool aMainThread = PR_FALSE);
+
+    void ExecuteNextRunnable();
+
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
@@ -281,16 +286,18 @@ protected:
     AndroidBridge() { }
     PRBool Init(JNIEnv *jEnv, jclass jGeckoApp);
 
     void EnsureJNIThread();
 
     bool mOpenedBitmapLibrary;
     bool mHasNativeBitmapAccess;
 
+    nsCOMArray<nsIRunnable> mRunnableQueue;
+
     // other things
     jmethodID jNotifyIME;
     jmethodID jNotifyIMEEnabled;
     jmethodID jNotifyIMEChange;
     jmethodID jAcknowledgeEventSync;
     jmethodID jEnableDeviceMotion;
     jmethodID jEnableLocation;
     jmethodID jReturnIMEQueryResult;
@@ -320,16 +327,17 @@ protected:
     jmethodID jIsNetworkLinkKnown;
     jmethodID jGetNetworkLinkType;
     jmethodID jSetSelectedLocale;
     jmethodID jScanMedia;
     jmethodID jGetSystemColors;
     jmethodID jGetIconForExtension;
     jmethodID jCreateShortcut;
     jmethodID jGetShowPasswordSetting;
+    jmethodID jPostToJavaThread;
 
     // stuff we need for CallEglCreateWindowSurface
     jclass jEGLSurfaceImplClass;
     jclass jEGLContextImplClass;
     jclass jEGLConfigImplClass;
     jclass jEGLDisplayImplClass;
     jclass jEGLContextClass;
     jclass jEGL10Class;
--- a/widget/src/android/AndroidJNI.cpp
+++ b/widget/src/android/AndroidJNI.cpp
@@ -67,16 +67,17 @@ extern "C" {
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_processNextNativeEvent(JNIEnv *, jclass);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject sv);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *, jclass);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *, jclass);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_callObserver(JNIEnv *, jclass, jstring observerKey, jstring topic, jstring data);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_removeObserver(JNIEnv *jenv, jclass, jstring jObserverKey);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onChangeNetworkLinkStatus(JNIEnv *, jclass, jstring status, jstring type);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *, jclass, jstring stack);
+    NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_executeNextRunnable(JNIEnv *, jclass);
 }
 
 
 /*
  * Incoming JNI methods
  */
 
 NS_EXPORT void JNICALL
@@ -174,8 +175,20 @@ NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *jenv, jclass, jstring stack)
 {
 #ifdef MOZ_CRASHREPORTER
     nsJNIString javaStack(stack, jenv);
     CrashReporter::AppendAppNotesToCrashReport(NS_ConvertUTF16toUTF8(javaStack));
 #endif
     abort();
 }
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_executeNextRunnable(JNIEnv *, jclass)
+{
+    __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", "%s", __PRETTY_FUNCTION__);
+    if (!AndroidBridge::Bridge()) {
+        __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", "no bridge in %s!!!!", __PRETTY_FUNCTION__);
+        return;
+    }
+    AndroidBridge::Bridge()->ExecuteNextRunnable();
+    __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", "leaving %s", __PRETTY_FUNCTION__);
+}
--- a/widget/src/xpwidgets/PuppetWidget.cpp
+++ b/widget/src/xpwidgets/PuppetWidget.cpp
@@ -553,17 +553,16 @@ PuppetWidget::DispatchPaintEvent()
 
   nsEventStatus status;
   {
 #ifdef DEBUG
     debug_DumpPaintEvent(stderr, this, &event,
                          nsCAutoString("PuppetWidget"), nsnull);
 #endif
 
-    LayerManager* lm = GetLayerManager();
     if (LayerManager::LAYERS_D3D10 == mLayerManager->GetBackendType()) {
       DispatchEvent(&event, status);
     } else {
       nsRefPtr<gfxContext> ctx = new gfxContext(mSurface);
       AutoLayerManagerSetup setupLayerManager(this, ctx,
                                               BasicLayerManager::BUFFER_NONE);
       DispatchEvent(&event, status);  
     }