From 67b8fad33d4ac428d70c8150f1af6e339568a2ca Mon Sep 17 00:00:00 2001 From: Pranav Ravichandran Date: Wed, 21 Dec 2011 01:42:00 -0500 Subject: [PATCH 01/44] Bug 710997 - Fix incorrect assignment in PuppetWidget::DispatchPaintEvent(). r=cjones --- widget/src/xpwidgets/PuppetWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/src/xpwidgets/PuppetWidget.cpp b/widget/src/xpwidgets/PuppetWidget.cpp index e80ea688aca1..ce00eb0b4bb5 100644 --- a/widget/src/xpwidgets/PuppetWidget.cpp +++ b/widget/src/xpwidgets/PuppetWidget.cpp @@ -529,7 +529,7 @@ PuppetWidget::DispatchPaintEvent() nsIntRect dirtyRect = mDirtyRegion.GetBounds(); nsPaintEvent event(true, NS_PAINT, this); event.refPoint.x = dirtyRect.x; - event.refPoint.x = dirtyRect.y; + event.refPoint.y = dirtyRect.y; event.region = mDirtyRegion; event.willSendDidPaint = true; From 4710b375264366788e43a13629fe22610e295c0a Mon Sep 17 00:00:00 2001 From: Steffen Wilberg Date: Wed, 21 Dec 2011 19:43:29 +0100 Subject: [PATCH 02/44] Bug 712614: extensions.js never stops observing extensions.update.enabled. r=mossop --- toolkit/mozapps/extensions/content/extensions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index a8cce2c8ae84..b78a353e227a 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -377,7 +377,8 @@ var gEventManager = { shutdown: function() { Services.prefs.removeObserver(PREF_CHECK_COMPATIBILITY, this); Services.prefs.removeObserver(PREF_CHECK_UPDATE_SECURITY, this); - Services.prefs.removeObserver(PREF_AUTOUPDATE_DEFAULT, this, false); + Services.prefs.removeObserver(PREF_UPDATE_ENABLED, this); + Services.prefs.removeObserver(PREF_AUTOUPDATE_DEFAULT, this); AddonManager.removeInstallListener(this); AddonManager.removeAddonListener(this); From 4db16a76a90bf500b3f23edcd326cac157314510 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Wed, 21 Dec 2011 14:03:26 -0500 Subject: [PATCH 03/44] Bug 670930 - Add Android direct texture implementation --- widget/src/android/AndroidDirectTexture.cpp | 149 +++++++ widget/src/android/AndroidDirectTexture.h | 90 ++++ widget/src/android/AndroidGraphicBuffer.cpp | 450 ++++++++++++++++++++ widget/src/android/AndroidGraphicBuffer.h | 99 +++++ 4 files changed, 788 insertions(+) create mode 100644 widget/src/android/AndroidDirectTexture.cpp create mode 100644 widget/src/android/AndroidDirectTexture.h create mode 100644 widget/src/android/AndroidGraphicBuffer.cpp create mode 100644 widget/src/android/AndroidGraphicBuffer.h diff --git a/widget/src/android/AndroidDirectTexture.cpp b/widget/src/android/AndroidDirectTexture.cpp new file mode 100644 index 000000000000..5a118e4bf4c8 --- /dev/null +++ b/widget/src/android/AndroidDirectTexture.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * 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 "AndroidDirectTexture.h" + +typedef gfxASurface::gfxImageFormat gfxImageFormat; + +namespace mozilla { + +AndroidDirectTexture::AndroidDirectTexture(PRUint32 width, PRUint32 height, PRUint32 usage, + gfxImageFormat format) : + mLock("AndroidDirectTexture.mLock") + , mNeedFlip(false) + , mWidth(width) + , mHeight(height) + , mFormat(format) + , mPendingReallocBuffer(NULL) +{ + mFrontBuffer = new AndroidGraphicBuffer(width, height, usage, format); + mBackBuffer = new AndroidGraphicBuffer(width, height, usage, format); +} + +AndroidDirectTexture::~AndroidDirectTexture() +{ + if (mFrontBuffer) { + delete mFrontBuffer; + mFrontBuffer = NULL; + } + + if (mBackBuffer) { + delete mBackBuffer; + mBackBuffer = NULL; + } +} + +void +AndroidDirectTexture::ReallocPendingBuffer() +{ + // We may have reallocated while the current back buffer was being + // used as the front buffer. If we have such a reallocation pending + // and the current back buffer is the target buffer, do it now. + // + // It is assumed that mLock is already acquired + if (mPendingReallocBuffer == mBackBuffer) { + mBackBuffer->Reallocate(mWidth, mHeight, mFormat); + mPendingReallocBuffer = NULL; + } +} + +bool +AndroidDirectTexture::Lock(PRUint32 aUsage, unsigned char **bits) +{ + mLock.Lock(); + ReallocPendingBuffer(); + return mBackBuffer->Lock(aUsage, bits); +} + +bool +AndroidDirectTexture::Lock(PRUint32 aUsage, const nsIntRect& aRect, unsigned char **bits) +{ + mLock.Lock(); + ReallocPendingBuffer(); + return mBackBuffer->Lock(aUsage, aRect, bits); +} + +bool +AndroidDirectTexture::Unlock(bool aFlip) +{ + if (aFlip) { + mNeedFlip = true; + } + + bool result = mBackBuffer->Unlock(); + mLock.Unlock(); + + return result; +} + +bool +AndroidDirectTexture::Reallocate(PRUint32 aWidth, PRUint32 aHeight) { + return Reallocate(aWidth, aHeight, mFormat); +} + +bool +AndroidDirectTexture::Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat) +{ + MutexAutoLock lock(mLock); + + // We only reallocate the current back buffer. The front buffer is likely + // in use, so we'll reallocate it on the first Lock() after it is rotated + // to the back. + bool result = mBackBuffer->Reallocate(aWidth, aHeight, aFormat); + if (result) { + mPendingReallocBuffer = mFrontBuffer; + } + + return result; +} + +bool +AndroidDirectTexture::Bind() +{ + MutexAutoLock lock(mLock); + + if (mNeedFlip) { + AndroidGraphicBuffer* tmp = mBackBuffer; + mBackBuffer = mFrontBuffer; + mFrontBuffer = tmp; + mNeedFlip = false; + } + + return mFrontBuffer->Bind(); +} + +} /* mozilla */ diff --git a/widget/src/android/AndroidDirectTexture.h b/widget/src/android/AndroidDirectTexture.h new file mode 100644 index 000000000000..f4914e1aae66 --- /dev/null +++ b/widget/src/android/AndroidDirectTexture.h @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * 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 ***** */ + +#ifndef AndroidDirectTexture_h_ +#define AndroidDirectTexture_h_ + +#include "gfxASurface.h" +#include "nsRect.h" +#include "mozilla/Mutex.h" +#include "AndroidGraphicBuffer.h" + +namespace mozilla { + +/** + * This is a thread safe wrapper around AndroidGraphicBuffer that handles + * double buffering. Each call to Bind() flips the buffer when necessary. + * + * You need to be careful when destroying an instance of this class. If either + * buffer is locked by the application of the driver/hardware, bad things will + * happen. Be sure that the OpenGL texture is no longer on the screen. + */ +class AndroidDirectTexture +{ +public: + AndroidDirectTexture(PRUint32 width, PRUint32 height, PRUint32 usage, gfxASurface::gfxImageFormat format); + virtual ~AndroidDirectTexture(); + + bool Lock(PRUint32 usage, unsigned char **bits); + bool Lock(PRUint32 usage, const nsIntRect& rect, unsigned char **bits); + bool Unlock(bool aFlip = true); + + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight); + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat); + + PRUint32 Width() { return mWidth; } + PRUint32 Height() { return mHeight; } + + bool Bind(); + +private: + mozilla::Mutex mLock; + bool mNeedFlip; + + PRUint32 mWidth; + PRUint32 mHeight; + gfxASurface::gfxImageFormat mFormat; + + AndroidGraphicBuffer* mFrontBuffer; + AndroidGraphicBuffer* mBackBuffer; + + AndroidGraphicBuffer* mPendingReallocBuffer; + void ReallocPendingBuffer(); +}; + +} /* mozilla */ +#endif /* AndroidDirectTexture_h_ */ diff --git a/widget/src/android/AndroidGraphicBuffer.cpp b/widget/src/android/AndroidGraphicBuffer.cpp new file mode 100644 index 000000000000..97ab7b806a55 --- /dev/null +++ b/widget/src/android/AndroidGraphicBuffer.cpp @@ -0,0 +1,450 @@ +/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * 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 +#include +#include +#include "AndroidGraphicBuffer.h" + +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AndroidGraphicBuffer" , ## args) + +#define EGL_NATIVE_BUFFER_ANDROID 0x3140 +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 + +typedef void* EGLContext; +typedef void* EGLImageKHR; +typedef void* EGLClientBuffer; +typedef void* EGLDisplay; + +typedef PRUint32 EGLenum; +typedef PRInt32 EGLint; +typedef PRUint32 EGLBoolean; + +typedef gfxASurface::gfxImageFormat gfxImageFormat; + +#define EGL_TRUE 1 +#define EGL_FALSE 0 +#define EGL_NONE 0x3038 +#define EGL_NO_CONTEXT (EGLContext)0 +#define EGL_DEFAULT_DISPLAY (void*)0 + +#define ANDROID_LIBUI_PATH "/system/lib/libui.so" +#define ANDROID_GLES_PATH "/system/lib/libGLESv2.so" +#define ANDROID_EGL_PATH "/system/lib/libEGL.so" + +// Really I have no idea, but this should be big enough +#define GRAPHIC_BUFFER_SIZE 1024 + +enum { + /* buffer is never read in software */ + GRALLOC_USAGE_SW_READ_NEVER = 0x00000000, + /* buffer is rarely read in software */ + GRALLOC_USAGE_SW_READ_RARELY = 0x00000002, + /* buffer is often read in software */ + GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003, + /* mask for the software read values */ + GRALLOC_USAGE_SW_READ_MASK = 0x0000000F, + + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_NEVER = 0x00000000, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_RARELY = 0x00000020, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_OFTEN = 0x00000030, + /* mask for the software write values */ + GRALLOC_USAGE_SW_WRITE_MASK = 0x000000F0, + + /* buffer will be used as an OpenGL ES texture */ + GRALLOC_USAGE_HW_TEXTURE = 0x00000100, + /* buffer will be used as an OpenGL ES render target */ + GRALLOC_USAGE_HW_RENDER = 0x00000200, + /* buffer will be used by the 2D hardware blitter */ + GRALLOC_USAGE_HW_2D = 0x00000400, + /* buffer will be used with the framebuffer device */ + GRALLOC_USAGE_HW_FB = 0x00001000, + /* mask for the software usage bit-mask */ + GRALLOC_USAGE_HW_MASK = 0x00001F00, +}; + +enum { + HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, + HAL_PIXEL_FORMAT_RGB_565 = 4, + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + HAL_PIXEL_FORMAT_RGBA_5551 = 6, + HAL_PIXEL_FORMAT_RGBA_4444 = 7, +}; + +typedef struct AndroidRect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} AndroidRect; + +static bool gTryRealloc = true; + +static class GLFunctions +{ +public: + GLFunctions() : mInitialized(false) + { + } + + typedef EGLDisplay (* pfnGetDisplay)(void *display_id); + pfnGetDisplay fGetDisplay; + typedef EGLint (* pfnEGLGetError)(void); + pfnEGLGetError fEGLGetError; + + typedef EGLImageKHR (* pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); + pfnCreateImageKHR fCreateImageKHR; + typedef EGLBoolean (* pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image); + pfnDestroyImageKHR fDestroyImageKHR; + + typedef void (* pfnImageTargetTexture2DOES)(GLenum target, EGLImageKHR image); + pfnImageTargetTexture2DOES fImageTargetTexture2DOES; + + typedef void (* pfnBindTexture)(GLenum target, GLuint texture); + pfnBindTexture fBindTexture; + + typedef GLenum (* pfnGLGetError)(); + pfnGLGetError fGLGetError; + + typedef void (*pfnGraphicBufferCtor)(void*, PRUint32 w, PRUint32 h, PRUint32 format, PRUint32 usage); + pfnGraphicBufferCtor fGraphicBufferCtor; + + typedef void (*pfnGraphicBufferDtor)(void*); + pfnGraphicBufferDtor fGraphicBufferDtor; + + typedef int (*pfnGraphicBufferLock)(void*, PRUint32 usage, unsigned char **addr); + pfnGraphicBufferLock fGraphicBufferLock; + + typedef int (*pfnGraphicBufferLockRect)(void*, PRUint32 usage, const AndroidRect&, unsigned char **addr); + pfnGraphicBufferLockRect fGraphicBufferLockRect; + + typedef int (*pfnGraphicBufferUnlock)(void*); + pfnGraphicBufferUnlock fGraphicBufferUnlock; + + typedef void* (*pfnGraphicBufferGetNativeBuffer)(void*); + pfnGraphicBufferGetNativeBuffer fGraphicBufferGetNativeBuffer; + + typedef int (*pfnGraphicBufferReallocate)(void*, PRUint32 w, PRUint32 h, PRUint32 format); + pfnGraphicBufferReallocate fGraphicBufferReallocate; + + bool EnsureInitialized() + { + if (mInitialized) { + return true; + } + + void *handle = dlopen(ANDROID_EGL_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load EGL library"); + return false; + } + + fGetDisplay = (pfnGetDisplay)dlsym(handle, "eglGetDisplay"); + fEGLGetError = (pfnEGLGetError)dlsym(handle, "eglGetError"); + fCreateImageKHR = (pfnCreateImageKHR)dlsym(handle, "eglCreateImageKHR"); + fDestroyImageKHR = (pfnDestroyImageKHR)dlsym(handle, "eglDestroyImageKHR"); + + if (!fGetDisplay || !fEGLGetError || !fCreateImageKHR || !fDestroyImageKHR) { + LOG("Failed to find some EGL functions"); + return false; + } + + handle = dlopen(ANDROID_GLES_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load GL library"); + return false; + } + + fImageTargetTexture2DOES = (pfnImageTargetTexture2DOES)dlsym(handle, "glEGLImageTargetTexture2DOES"); + fBindTexture = (pfnBindTexture)dlsym(handle, "glBindTexture"); + fGLGetError = (pfnGLGetError)dlsym(handle, "glGetError"); + + if (!fImageTargetTexture2DOES || !fBindTexture || !fGLGetError) { + LOG("Failed to find some GL functions"); + return false; + } + + handle = dlopen(ANDROID_LIBUI_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load libui.so"); + return false; + } + + fGraphicBufferCtor = (pfnGraphicBufferCtor)dlsym(handle, "_ZN7android13GraphicBufferC1Ejjij"); + fGraphicBufferDtor = (pfnGraphicBufferDtor)dlsym(handle, "_ZN7android13GraphicBufferD1Ev"); + fGraphicBufferLock = (pfnGraphicBufferLock)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjPPv"); + fGraphicBufferLockRect = (pfnGraphicBufferLockRect)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjRKNS_4RectEPPv"); + fGraphicBufferUnlock = (pfnGraphicBufferUnlock)dlsym(handle, "_ZN7android13GraphicBuffer6unlockEv"); + fGraphicBufferGetNativeBuffer = (pfnGraphicBufferGetNativeBuffer)dlsym(handle, "_ZNK7android13GraphicBuffer15getNativeBufferEv"); + fGraphicBufferReallocate = (pfnGraphicBufferReallocate)dlsym(handle, "_ZN7android13GraphicBuffer10reallocateEjjij"); + + if (!fGraphicBufferCtor || !fGraphicBufferDtor || !fGraphicBufferLock || + !fGraphicBufferUnlock || !fGraphicBufferGetNativeBuffer) { + LOG("Failed to lookup some GraphicBuffer functions"); + return false; + } + + mInitialized = true; + return true; + } + +private: + bool mInitialized; + +} sGLFunctions; + +namespace mozilla { + +static bool ensureNoGLError(const char* name) +{ + bool result = true; + GLuint error; + + while ((error = glGetError()) != GL_NO_ERROR) { + LOG("GL error [%s]: %40x\n", name, error); + result = false; + } + + return result; +} + +AndroidGraphicBuffer::AndroidGraphicBuffer(PRUint32 width, PRUint32 height, PRUint32 usage, + gfxImageFormat format) : + mWidth(width) + , mHeight(height) + , mUsage(usage) + , mFormat(format) + , mHandle(0) + , mEGLImage(0) +{ +} + +AndroidGraphicBuffer::~AndroidGraphicBuffer() +{ + DestroyBuffer(); +} + +void +AndroidGraphicBuffer::DestroyBuffer() +{ + /** + * XXX: eglDestroyImageKHR crashes sometimes due to refcount badness (I think) + * + * If you look at egl.cpp (https://github.com/android/platform_frameworks_base/blob/master/opengl/libagl/egl.cpp#L2002) + * you can see that eglCreateImageKHR just refs the native buffer, and eglDestroyImageKHR + * just unrefs it. Somehow the ref count gets messed up and things are already destroyed + * by the time eglDestroyImageKHR gets called. For now, at least, just not calling + * eglDestroyImageKHR should be fine since we do free the GraphicBuffer below. + * + * Bug 712716 + */ +#if 0 + if (mEGLImage) { + if (sGLFunctions.EnsureInitialized()) { + sGLFunctions.fDestroyImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), mEGLImage); + mEGLImage = NULL; + } + } +#endif + mEGLImage = NULL; + + if (mHandle) { + if (sGLFunctions.EnsureInitialized()) { + sGLFunctions.fGraphicBufferDtor(mHandle); + } + free(mHandle); + mHandle = NULL; + } + +} + +bool +AndroidGraphicBuffer::EnsureBufferCreated(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aUsage, gfxImageFormat aFormat) +{ + if (!mHandle) { + mHandle = malloc(GRAPHIC_BUFFER_SIZE); + sGLFunctions.fGraphicBufferCtor(mHandle, mWidth, mHeight, GetAndroidFormat(aFormat), GetAndroidUsage(aUsage)); + } + + return true; +} + +bool +AndroidGraphicBuffer::EnsureInitialized() +{ + if (!sGLFunctions.EnsureInitialized()) { + return false; + } + + EnsureBufferCreated(mWidth, mHeight, mUsage, mFormat); + return true; +} + +bool +AndroidGraphicBuffer::Lock(PRUint32 aUsage, unsigned char **bits) +{ + if (!EnsureInitialized()) + return true; + + return sGLFunctions.fGraphicBufferLock(mHandle, GetAndroidUsage(aUsage), bits) == 0; +} + +bool +AndroidGraphicBuffer::Lock(PRUint32 aUsage, const nsIntRect& aRect, unsigned char **bits) +{ + if (!EnsureInitialized()) + return false; + + AndroidRect rect; + rect.left = aRect.x; + rect.top = aRect.y; + rect.right = aRect.x + aRect.width; + rect.bottom = aRect.y + aRect.height; + + return sGLFunctions.fGraphicBufferLockRect(mHandle, GetAndroidUsage(aUsage), rect, bits) == 0; +} + +bool +AndroidGraphicBuffer::Unlock() +{ + if (!EnsureInitialized()) + return false; + + return sGLFunctions.fGraphicBufferUnlock(mHandle) == 0; +} + +bool +AndroidGraphicBuffer::Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxImageFormat aFormat) +{ + if (!EnsureInitialized()) + return false; + + // Sometimes GraphicBuffer::reallocate just doesn't work. In those cases we'll just allocate a brand + // new buffer. If reallocate fails once, never try it again. + if (!gTryRealloc || sGLFunctions.fGraphicBufferReallocate(mHandle, aWidth, aHeight, GetAndroidFormat(aFormat)) != 0) { + DestroyBuffer(); + EnsureBufferCreated(aWidth, aHeight, mUsage, aFormat); + + gTryRealloc = false; + } + + mWidth = aWidth; + mHeight = aHeight; + mFormat = aFormat; + + return true; +} + +PRUint32 +AndroidGraphicBuffer::GetAndroidUsage(PRUint32 aUsage) +{ + PRUint32 flags = 0; + + if (aUsage & UsageSoftwareRead) { + flags |= GRALLOC_USAGE_SW_READ_OFTEN; + } + + if (aUsage & UsageSoftwareWrite) { + flags |= GRALLOC_USAGE_SW_WRITE_OFTEN; + } + + if (aUsage & UsageTexture) { + flags |= GRALLOC_USAGE_HW_TEXTURE; + } + + if (aUsage & UsageTarget) { + flags |= GRALLOC_USAGE_HW_RENDER; + } + + if (aUsage & Usage2D) { + flags |= GRALLOC_USAGE_HW_2D; + } + + return flags; +} + +PRUint32 +AndroidGraphicBuffer::GetAndroidFormat(gfxImageFormat aFormat) +{ + switch (aFormat) { + case gfxImageFormat::ImageFormatRGB24: + return HAL_PIXEL_FORMAT_RGBX_8888; + case gfxImageFormat::ImageFormatRGB16_565: + return HAL_PIXEL_FORMAT_RGB_565; + default: + return 0; + } +} + +bool +AndroidGraphicBuffer::EnsureEGLImage() +{ + if (mEGLImage) + return true; + + + if (!EnsureInitialized()) + return false; + + EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE }; + void* nativeBuffer = sGLFunctions.fGraphicBufferGetNativeBuffer(mHandle); + + mEGLImage = sGLFunctions.fCreateImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)nativeBuffer, eglImgAttrs); + return mEGLImage != NULL; +} + +bool +AndroidGraphicBuffer::Bind() +{ + if (!EnsureInitialized()) + return false; + + if (!EnsureEGLImage()) { + LOG("No valid EGLImage!"); + return false; + } + + sGLFunctions.fImageTargetTexture2DOES(GL_TEXTURE_2D, mEGLImage); + return ensureNoGLError("glEGLImageTargetTexture2DOES"); +} + +} /* mozilla */ diff --git a/widget/src/android/AndroidGraphicBuffer.h b/widget/src/android/AndroidGraphicBuffer.h new file mode 100644 index 000000000000..961c7e29d3bf --- /dev/null +++ b/widget/src/android/AndroidGraphicBuffer.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * 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 ***** */ + +#ifndef AndroidGraphicBuffer_h_ +#define AndroidGraphicBuffer_h_ + +#include "gfxASurface.h" +#include "nsRect.h" + +namespace mozilla { + +/** + * This class allows access to Android's direct texturing mechanism. Locking + * the buffer gives you a pointer you can read/write to directly. It is fully + * threadsafe, but you probably really want to use the AndroidDirectTexture + * class which will handle double buffering. + * + * In order to use the buffer in OpenGL, just call Bind() and it will attach + * to whatever texture is bound to GL_TEXTURE_2D. + */ +class AndroidGraphicBuffer +{ +public: + enum { + UsageSoftwareRead = 1, + UsageSoftwareWrite = 1 << 1, + UsageTexture = 1 << 2, + UsageTarget = 1 << 3, + Usage2D = 1 << 4 + }; + + AndroidGraphicBuffer(PRUint32 width, PRUint32 height, PRUint32 usage, gfxASurface::gfxImageFormat format); + virtual ~AndroidGraphicBuffer(); + + bool Lock(PRUint32 usage, unsigned char **bits); + bool Lock(PRUint32 usage, const nsIntRect& rect, unsigned char **bits); + bool Unlock(); + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat); + + PRUint32 Width() { return mWidth; } + PRUint32 Height() { return mHeight; } + + bool Bind(); + +private: + PRUint32 mWidth; + PRUint32 mHeight; + PRUint32 mUsage; + gfxASurface::gfxImageFormat mFormat; + + bool EnsureInitialized(); + bool EnsureEGLImage(); + + void DestroyBuffer(); + bool EnsureBufferCreated(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aUsage, gfxASurface::gfxImageFormat aFormat); + + PRUint32 GetAndroidUsage(PRUint32 aUsage); + PRUint32 GetAndroidFormat(gfxASurface::gfxImageFormat aFormat); + + void *mHandle; + void *mEGLImage; +}; + +} /* mozilla */ +#endif /* AndroidGraphicBuffer_h_ */ From de4b11c5d18c7b24355174bf66c8871c042daef8 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Wed, 21 Dec 2011 14:05:23 -0500 Subject: [PATCH 04/44] Bug 670930 - Use asynchronous direct texturing on Android when available --- mobile/android/base/GeckoAppShell.java | 10 ++ mobile/android/base/Makefile.in | 1 + .../base/gfx/GeckoSoftwareLayerClient.java | 11 +- mobile/android/base/gfx/LayerClient.java | 12 +- mobile/android/base/gfx/WidgetTileLayer.java | 116 ++++++++++++++++++ other-licenses/android/APKOpen.cpp | 6 +- widget/src/android/AndroidJNI.cpp | 22 ++++ widget/src/android/Makefile.in | 2 + widget/src/android/nsWindow.cpp | 94 +++++++++++++- widget/src/android/nsWindow.h | 5 + 10 files changed, 267 insertions(+), 12 deletions(-) create mode 100644 mobile/android/base/gfx/WidgetTileLayer.java diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 4fa06a5ab513..e11c538d0c44 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -140,6 +140,8 @@ public class GeckoAppShell public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp); public static native ByteBuffer allocateDirectBuffer(long size); public static native void freeDirectBuffer(ByteBuffer buf); + public static native void bindWidgetTexture(); + public static native boolean testDirectTexture(); // A looper thread, accessed by GeckoAppShell.getHandler private static class LooperThread extends Thread { @@ -427,6 +429,14 @@ public class GeckoAppShell Log.i(LOGTAG, "post native init"); + // If we have direct texture available, use it + if (GeckoAppShell.testDirectTexture()) { + Log.i(LOGTAG, "Using direct texture for widget layer"); + GeckoApp.mAppContext.getSoftwareLayerClient().installWidgetLayer(); + } else { + Log.i(LOGTAG, "Falling back to traditional texture upload"); + } + // Tell Gecko where the target byte buffer is for rendering GeckoAppShell.setSoftwareLayerClient(GeckoApp.mAppContext.getSoftwareLayerClient()); diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 337eefb866de..155bd37a83c2 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -108,6 +108,7 @@ JAVAFILES = \ gfx/TextureReaper.java \ gfx/TileLayer.java \ gfx/ViewportMetrics.java \ + gfx/WidgetTileLayer.java \ ui/PanZoomController.java \ $(NULL) diff --git a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java index ef58d9f131ec..9a51e996f511 100644 --- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java +++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java @@ -45,6 +45,7 @@ import org.mozilla.gecko.gfx.LayerController; import org.mozilla.gecko.gfx.LayerRenderer; import org.mozilla.gecko.gfx.PointUtils; import org.mozilla.gecko.gfx.SingleTileLayer; +import org.mozilla.gecko.gfx.WidgetTileLayer; import org.mozilla.gecko.FloatUtils; import org.mozilla.gecko.GeckoApp; import org.mozilla.gecko.GeckoAppShell; @@ -76,7 +77,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL private IntSize mScreenSize, mViewportSize; private IntSize mBufferSize; private ByteBuffer mBuffer; - private final SingleTileLayer mTileLayer; + private Layer mTileLayer; /* The viewport rect that Gecko is currently displaying. */ private ViewportMetrics mGeckoViewport; @@ -125,6 +126,10 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL } } + public void installWidgetLayer() { + mTileLayer = new WidgetTileLayer(mCairoImage); + } + /** Attaches the root layer to the layer controller so that Gecko appears. */ @Override public void setLayerController(LayerController layerController) { @@ -188,7 +193,9 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL updateViewport(metadata, !mUpdateViewportOnEndDraw); mUpdateViewportOnEndDraw = false; Rect rect = new Rect(x, y, x + width, y + height); - mTileLayer.invalidate(rect); + + if (mTileLayer instanceof SingleTileLayer) + ((SingleTileLayer)mTileLayer).invalidate(rect); } finally { endTransaction(mTileLayer); } diff --git a/mobile/android/base/gfx/LayerClient.java b/mobile/android/base/gfx/LayerClient.java index f7263021ce91..1afaca3799ea 100644 --- a/mobile/android/base/gfx/LayerClient.java +++ b/mobile/android/base/gfx/LayerClient.java @@ -53,24 +53,24 @@ public abstract class LayerClient { } /** - * A utility function for calling TileLayer.beginTransaction with the + * A utility function for calling Layer.beginTransaction with the * appropriate LayerView. */ - public void beginTransaction(TileLayer aTileLayer) { + public void beginTransaction(Layer aLayer) { if (mLayerController != null) { LayerView view = mLayerController.getView(); if (view != null) { - aTileLayer.beginTransaction(view); + aLayer.beginTransaction(view); return; } } - aTileLayer.beginTransaction(); + aLayer.beginTransaction(); } // Included for symmetry. - public void endTransaction(TileLayer aTileLayer) { - aTileLayer.endTransaction(); + public void endTransaction(Layer aLayer) { + aLayer.endTransaction(); } } diff --git a/mobile/android/base/gfx/WidgetTileLayer.java b/mobile/android/base/gfx/WidgetTileLayer.java new file mode 100644 index 000000000000..f77fda204239 --- /dev/null +++ b/mobile/android/base/gfx/WidgetTileLayer.java @@ -0,0 +1,116 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * ***** 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 Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009-2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * 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 ***** */ + +package org.mozilla.gecko.gfx; + +import org.mozilla.gecko.gfx.LayerController; +import org.mozilla.gecko.gfx.SingleTileLayer; +import org.mozilla.gecko.GeckoAppShell; +import android.opengl.GLES11; +import android.opengl.GLES11Ext; +import android.graphics.RectF; +import android.util.Log; +import javax.microedition.khronos.opengles.GL10; + +/** + * Encapsulates the logic needed to draw the single-tiled Gecko texture + */ +public class WidgetTileLayer extends Layer { + + private int[] mTextureIDs; + private CairoImage mImage; + + public WidgetTileLayer(CairoImage image) { + mImage = image; + } + + protected boolean initialized() { return mTextureIDs != null; } + + @Override + public IntSize getSize() { return mImage.getSize(); } + + protected void bindAndSetGLParameters() { + GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]); + GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); + GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); + } + + @Override + protected void finalize() throws Throwable { + if (mTextureIDs != null) + TextureReaper.get().add(mTextureIDs); + } + + @Override + protected void performUpdates(GL10 gl) { + super.performUpdates(gl); + + if (mTextureIDs == null) { + mTextureIDs = new int[1]; + GLES11.glGenTextures(1, mTextureIDs, 0); + } + + bindAndSetGLParameters(); + GeckoAppShell.bindWidgetTexture(); + } + + @Override + public void draw(RenderContext context) { + // mTextureIDs may be null here during startup if Layer.java's draw method + // failed to acquire the transaction lock and call performUpdates. + if (!initialized()) + return; + + GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]); + + RectF bounds; + int[] cropRect; + IntSize size = getSize(); + RectF viewport = context.viewport; + + bounds = getBounds(context, new FloatSize(size)); + cropRect = new int[] { 0, size.height, size.width, -size.height }; + bounds.offset(-viewport.left, -viewport.top); + + GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, + 0); + + float top = viewport.height() - (bounds.top + bounds.height()); + GLES11Ext.glDrawTexfOES(bounds.left, top, 0.0f, bounds.width(), bounds.height()); + } +} + diff --git a/other-licenses/android/APKOpen.cpp b/other-licenses/android/APKOpen.cpp index 6cc23c016df8..bb1a69800948 100644 --- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -299,6 +299,8 @@ SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray) SHELL_WRAPPER1(notifyUriVisited, jstring) SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble); SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong); +SHELL_WRAPPER0(bindWidgetTexture); +SHELL_WRAPPER0_WITH_RETURN(testDirectTexture, bool); static void * xul_handle = NULL; static time_t apk_mtime = 0; @@ -638,7 +640,7 @@ loadLibs(const char *apkName) gettimeofday(&t0, 0); struct rusage usage1; getrusage(RUSAGE_THREAD, &usage1); - + void *zip = map_file(apkName); struct cdir_end *dirend = (struct cdir_end *)((char *)zip + zip_size - sizeof(*dirend)); while ((void *)dirend > zip && @@ -704,6 +706,8 @@ loadLibs(const char *apkName) GETFUNC(notifyUriVisited); GETFUNC(notifyBatteryChange); GETFUNC(notifySmsReceived); + GETFUNC(bindWidgetTexture); + GETFUNC(testDirectTexture); #undef GETFUNC sStartupTimeline = (uint64_t *)__wrap_dlsym(xul_handle, "_ZN7mozilla15StartupTimeline16sStartupTimelineE"); gettimeofday(&t1, 0); diff --git a/widget/src/android/AndroidJNI.cpp b/widget/src/android/AndroidJNI.cpp index 3a1762eb128a..4e30f13b43fb 100644 --- a/widget/src/android/AndroidJNI.cpp +++ b/widget/src/android/AndroidJNI.cpp @@ -40,6 +40,7 @@ #include "nsString.h" #include "AndroidBridge.h" +#include "AndroidGraphicBuffer.h" #include #include @@ -88,6 +89,11 @@ extern "C" { NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(JNIEnv *, jclass, jstring uri); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass, jdouble, jboolean, jdouble); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass, jstring, jstring, jlong); + +#ifdef MOZ_JAVA_COMPOSITOR + NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass); + NS_EXPORT bool JNICALL Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass); +#endif } @@ -278,3 +284,19 @@ Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass, nsCOMPtr runnable = new NotifySmsReceivedRunnable(message); NS_DispatchToMainThread(runnable); } + +#ifdef MOZ_JAVA_COMPOSITOR + +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass) +{ + nsWindow::BindToTexture(); +} + +NS_EXPORT bool JNICALL +Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass) +{ + return nsWindow::HasDirectTexture(); +} + +#endif diff --git a/widget/src/android/Makefile.in b/widget/src/android/Makefile.in index 865142727ab2..91e345e92011 100644 --- a/widget/src/android/Makefile.in +++ b/widget/src/android/Makefile.in @@ -61,6 +61,8 @@ CPPSRCS = \ nsAppShell.cpp \ AndroidJavaWrappers.cpp \ AndroidBridge.cpp \ + AndroidDirectTexture.cpp \ + AndroidGraphicBuffer.cpp \ AndroidJNI.cpp \ nsWindow.cpp \ nsLookAndFeel.cpp \ diff --git a/widget/src/android/nsWindow.cpp b/widget/src/android/nsWindow.cpp index d5b1fc5abd30..a67be5635794 100644 --- a/widget/src/android/nsWindow.cpp +++ b/widget/src/android/nsWindow.cpp @@ -39,6 +39,7 @@ #include #include +#include #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentChild.h" @@ -92,6 +93,20 @@ static gfxIntSize gAndroidScreenBounds; bool nsWindow::sAccessibilityEnabled = false; #endif +#ifdef MOZ_JAVA_COMPOSITOR +#include "mozilla/Mutex.h" +#include "nsThreadUtils.h" +#include "AndroidDirectTexture.h" + +static AndroidDirectTexture* sDirectTexture = new AndroidDirectTexture(2048, 2048, + AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture, + gfxASurface::ImageFormatRGB16_565); + +static bool sHasDirectTexture = true; + +#endif + + class ContentCreationNotifier; static nsCOMPtr gContentCreationNotifier; // A helper class to send updates when content processes @@ -808,6 +823,53 @@ nsWindow::GetThebesSurface() return new gfxImageSurface(gfxIntSize(5,5), gfxImageSurface::ImageFormatRGB24); } +#ifdef MOZ_JAVA_COMPOSITOR + +void +nsWindow::BindToTexture() +{ + sDirectTexture->Bind(); +} + +bool +nsWindow::HasDirectTexture() +{ + // If we already tested, return early + if (!sHasDirectTexture) + return false; + + AndroidGraphicBuffer* buffer = new AndroidGraphicBuffer(512, 512, + AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture, + gfxASurface::ImageFormatRGB16_565); + + unsigned char* bits = NULL; + if (!buffer->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits) || !bits) { + ALOG("failed to lock graphic buffer"); + buffer->Unlock(); + sHasDirectTexture = false; + goto cleanup; + } + + if (!buffer->Unlock()) { + ALOG("failed to unlock graphic buffer"); + sHasDirectTexture = false; + goto cleanup; + } + + if (!buffer->Reallocate(1024, 1024, gfxASurface::ImageFormatRGB16_565)) { + ALOG("failed to reallocate graphic buffer"); + sHasDirectTexture = false; + goto cleanup; + } + +cleanup: + delete buffer; + + return sHasDirectTexture; +} + +#endif + void nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) { @@ -1111,9 +1173,26 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) client.BeginDrawing(); nsAutoString metadata; - unsigned char *bits = client.LockBufferBits(); + unsigned char *bits = NULL; + if (sHasDirectTexture) { + if ((sDirectTexture->Width() != gAndroidBounds.width || + sDirectTexture->Height() != gAndroidBounds.height) && + gAndroidBounds.width != 0 && gAndroidBounds.height != 0) { + sDirectTexture->Reallocate(gAndroidBounds.width, gAndroidBounds.height); + } + + sDirectTexture->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits); + } else { + bits = client.LockBufferBits(); + } if (!bits) { ALOG("### Failed to lock buffer"); + + if (sHasDirectTexture) { + sDirectTexture->Unlock(); + } else { + client.UnlockBuffer(); + } } else { nsRefPtr targetSurface = new gfxImageSurface(bits, gfxIntSize(gAndroidBounds.width, gAndroidBounds.height), gAndroidBounds.width * 2, @@ -1121,7 +1200,12 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) if (targetSurface->CairoStatus()) { ALOG("### Failed to create a valid surface from the bitmap"); } else { - DrawTo(targetSurface, ae->Rect()); + if (sHasDirectTexture) { + // XXX: lock only the dirty rect above and pass it in here + DrawTo(targetSurface); + } else { + DrawTo(targetSurface, ae->Rect()); + } { nsCOMPtr metadataProvider = @@ -1130,7 +1214,11 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) metadataProvider->GetDrawMetadata(metadata); } } - client.UnlockBuffer(); + if (sHasDirectTexture) { + sDirectTexture->Unlock(); + } else { + client.UnlockBuffer(); + } } client.EndDrawing(ae->Rect(), metadata); return; diff --git a/widget/src/android/nsWindow.h b/widget/src/android/nsWindow.h index fb557ac63a25..0a3d5f688443 100644 --- a/widget/src/android/nsWindow.h +++ b/widget/src/android/nsWindow.h @@ -177,6 +177,11 @@ public: static bool sAccessibilityEnabled; #endif +#ifdef MOZ_JAVA_COMPOSITOR + static void BindToTexture(); + static bool HasDirectTexture(); +#endif + protected: void BringToFront(); nsWindow *FindTopLevel(); From 26bb91936c21fa1a60e934e3b7d8289232967311 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 21 Dec 2011 11:20:06 -0800 Subject: [PATCH 05/44] Bug 709921 - (followup) Update strings about:config to say "Settings" instead of "Preferences" [r=mfinkle] --- mobile/android/chrome/content/config.xhtml | 4 ++-- mobile/android/locales/en-US/chrome/config.dtd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mobile/android/chrome/content/config.xhtml b/mobile/android/chrome/content/config.xhtml index f9d14b26bc37..43f51fc6bf02 100644 --- a/mobile/android/chrome/content/config.xhtml +++ b/mobile/android/chrome/content/config.xhtml @@ -53,7 +53,7 @@
-
- +
diff --git a/mobile/android/locales/en-US/chrome/config.dtd b/mobile/android/locales/en-US/chrome/config.dtd index c6402f532269..8dd28e4083a4 100644 --- a/mobile/android/locales/en-US/chrome/config.dtd +++ b/mobile/android/locales/en-US/chrome/config.dtd @@ -1,3 +1,3 @@ - + - + From 8cdb5ddd6201611597106eabb7bc8f48c56a15d5 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 21 Dec 2011 11:22:43 -0800 Subject: [PATCH 06/44] Bug 710960 - Make runtests.py work out of the box with MOZ_BUILD_APP=mobile/xul [r=ctalbert] --- build/binary-location.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/binary-location.mk b/build/binary-location.mk index d19634dd137d..f2579e2bf98e 100644 --- a/build/binary-location.mk +++ b/build/binary-location.mk @@ -40,7 +40,7 @@ ifneq (,$(filter OS2 WINNT,$(OS_ARCH))) PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX) else -ifeq ($(MOZ_BUILD_APP),mobile) +ifeq ($(MOZ_BUILD_APP),mobile/xul) PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX) else PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX) From 31e220b6954192620f376b28a6c42cf1b15aeda2 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Wed, 21 Dec 2011 11:28:24 -0800 Subject: [PATCH 07/44] Bug 710961 - Carry over syncGUID generated when install is staged; r=Mossop --- toolkit/mozapps/extensions/XPIProvider.jsm | 7 ++++--- toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js | 7 +++++-- toolkit/mozapps/extensions/test/xpcshell/test_install.js | 7 +++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index a2f2e0d9630e..0288121449d1 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -7283,9 +7283,10 @@ AddonInternal.prototype = { * A JS object containing the cached metadata */ importMetadata: function(aObj) { - ["targetApplications", "userDisabled", "softDisabled", "existingAddonID", - "sourceURI", "releaseNotesURI", "installDate", "updateDate", - "applyBackgroundUpdates", "compatibilityOverrides"].forEach(function(aProp) { + ["syncGUID", "targetApplications", "userDisabled", "softDisabled", + "existingAddonID", "sourceURI", "releaseNotesURI", "installDate", + "updateDate", "applyBackgroundUpdates", "compatibilityOverrides"] + .forEach(function(aProp) { if (!(aProp in aObj)) return; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js b/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js index 8e7c7bc92144..3d6282ac3b3a 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js @@ -149,6 +149,7 @@ function run_test_1() { do_check_eq(install.version, "1.0"); do_check_eq(install.name, "Test Bootstrap 1"); do_check_eq(install.state, AddonManager.STATE_DOWNLOADED); + do_check_neq(install.addon.syncGUID, null); do_check_true(install.addon.hasResource("install.rdf")); do_check_true(install.addon.hasResource("bootstrap.js")); do_check_false(install.addon.hasResource("foo.bar")); @@ -167,13 +168,13 @@ function run_test_1() { "onInstallEnded", ], function() { do_check_true(addon.hasResource("install.rdf")); - check_test_1(); + check_test_1(addon.syncGUID); }); install.install(); }); } -function check_test_1() { +function check_test_1(installSyncGUID) { let file = gProfD.clone(); file.append("extensions.sqlite"); do_check_true(file.exists()); @@ -189,6 +190,8 @@ function check_test_1() { AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) { do_check_neq(b1, null); do_check_eq(b1.version, "1.0"); + do_check_neq(b1.syncGUID, null); + do_check_eq(b1.syncGUID, installSyncGUID); do_check_false(b1.appDisabled); do_check_false(b1.userDisabled); do_check_true(b1.isActive); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_install.js b/toolkit/mozapps/extensions/test/xpcshell/test_install.js index bd12e8f11453..21283692f8f4 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_install.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_install.js @@ -105,7 +105,9 @@ function run_test_1() { }, [ "onInstallStarted", "onInstallEnded", - ], check_test_1); + ], function() { + check_test_1(install.addon.syncGUID); + }); install.install(); }); }); @@ -113,7 +115,7 @@ function run_test_1() { }); } -function check_test_1() { +function check_test_1(installSyncGUID) { ensure_test_completed(); AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) { do_check_eq(olda1, null); @@ -160,6 +162,7 @@ function check_test_1() { do_check_neq(a1, null); do_check_neq(a1.syncGUID, null); do_check_true(a1.syncGUID.length >= 9); + do_check_eq(a1.syncGUID, installSyncGUID); do_check_eq(a1.type, "extension"); do_check_eq(a1.version, "1.0"); do_check_eq(a1.name, "Test 1"); From 3d288c6d3a47ec6bd487bca7e0883c82ab40e5fb Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Wed, 21 Dec 2011 12:30:53 -0800 Subject: [PATCH 08/44] backout 243520b7d8c3 because it broke the autocomplete popup text --- mobile/android/base/AutoCompletePopup.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/mobile/android/base/AutoCompletePopup.java b/mobile/android/base/AutoCompletePopup.java index f28170cb93ea..9f0778f9a223 100644 --- a/mobile/android/base/AutoCompletePopup.java +++ b/mobile/android/base/AutoCompletePopup.java @@ -68,8 +68,6 @@ public class AutoCompletePopup extends ListView { private static final String LOGTAG = "AutoCompletePopup"; - private static int sMinWidth = 0; - public AutoCompletePopup(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; @@ -134,18 +132,7 @@ public class AutoCompletePopup extends ListView { // If the textbox is smaller than the screen-width, // shrink the list's width if ((left + width) < viewport.width) - listWidth = left < 0 ? left + width : width; - - // Late initializing variable to allow DisplayMetrics not to be null and avoid NPE - if (sMinWidth == 0) - sMinWidth = 100 * GeckoAppShell.getDpi(); - - if (listWidth < sMinWidth) { - listWidth = sMinWidth; - - if ((listLeft + listWidth) > viewport.width) - listLeft = (int)viewport.width - listWidth; - } + listWidth = left + width; // If the list is extending outside of the viewport // try moving above From 37e18a65988002397884f0662db96e0834ad0be3 Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Wed, 21 Dec 2011 13:08:01 -0800 Subject: [PATCH 09/44] Bug 700527 - Master password support for native fennec. r=mfinkle --- mobile/android/base/GeckoPreferences.java | 133 ++++++++++++++++++ .../base/locales/en-US/android_strings.dtd | 13 +- .../base/resources/xml/preferences.xml | 5 + mobile/android/base/strings.xml.in | 9 ++ mobile/android/chrome/content/browser.js | 89 ++++++++++++ mobile/android/components/PromptService.js | 2 +- .../locales/en-US/chrome/browser.properties | 2 + 7 files changed, 250 insertions(+), 3 deletions(-) diff --git a/mobile/android/base/GeckoPreferences.java b/mobile/android/base/GeckoPreferences.java index a30cfdec6c79..6f815a60e45c 100644 --- a/mobile/android/base/GeckoPreferences.java +++ b/mobile/android/base/GeckoPreferences.java @@ -41,16 +41,24 @@ package org.mozilla.gecko; import java.lang.CharSequence; import java.util.ArrayList; +import android.app.Dialog; +import android.text.Editable; +import android.app.AlertDialog; import android.os.Build; import android.os.Bundle; import android.content.res.Resources; import android.content.Context; import android.preference.*; import android.preference.Preference.*; +import android.text.InputType; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.text.TextWatcher; +import android.content.DialogInterface; import org.json.JSONArray; import org.json.JSONException; @@ -128,9 +136,17 @@ public class GeckoPreferences return super.onOptionsItemSelected(item); } + final private int DIALOG_CREATE_MASTER_PASSWORD = 0; + final private int DIALOG_REMOVE_MASTER_PASSWORD = 1; + @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String prefName = preference.getKey(); + if (prefName.equals("privacy.masterpassword.enabled")) { + showDialog((Boolean)newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD); + return false; + } + setPreference(prefName, newValue); if (preference instanceof ListPreference) { // We need to find the entry for the new value @@ -143,6 +159,123 @@ public class GeckoPreferences return true; } + private EditText getTextBox(int aHintText) { + EditText input = new EditText(GeckoApp.mAppContext); + int inputtype = InputType.TYPE_CLASS_TEXT; + inputtype |= InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; + input.setInputType(inputtype); + + String hint = getResources().getString(aHintText); + input.setHint(aHintText); + return input; + } + + private AlertDialog mDialog = null; + + private class PasswordTextWatcher implements TextWatcher { + EditText input1 = null; + EditText input2 = null; + + PasswordTextWatcher(EditText aInput1, EditText aInput2) { + input1 = aInput1; + input2 = aInput2; + } + + public void afterTextChanged(Editable s) { + if (mDialog == null) + return; + + String text1 = input1.getText().toString(); + String text2 = input2.getText().toString(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(text1.equals(text2)); + } + + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } + public void onTextChanged(CharSequence s, int start, int before, int count) { } + } + + protected Dialog onCreateDialog(int id) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + LinearLayout linearLayout = new LinearLayout(this); + linearLayout.setOrientation(LinearLayout.VERTICAL); + switch(id) { + case DIALOG_CREATE_MASTER_PASSWORD: + final EditText input1 = getTextBox(R.string.masterpassword_password); + final EditText input2 = getTextBox(R.string.masterpassword_confirm); + PasswordTextWatcher watcher = new PasswordTextWatcher(input1, input2); + input1.addTextChangedListener((TextWatcher)watcher); + input2.addTextChangedListener((TextWatcher)watcher); + linearLayout.addView(input1); + linearLayout.addView(input2); + + builder.setTitle(R.string.masterpassword_create_title) + .setView((View)linearLayout) + .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + JSONObject jsonPref = new JSONObject(); + try { + jsonPref.put("name", "privacy.masterpassword.enabled"); + jsonPref.put("type", "string"); + jsonPref.put("value", input1.getText().toString()); + + GeckoEvent event = new GeckoEvent("Preferences:Set", jsonPref.toString()); + GeckoAppShell.sendEventToGecko(event); + } catch(Exception ex) { + Log.e(LOGTAG, "Error setting masterpassword", ex); + } + mDialog = null; + input1.setText(""); + input2.setText(""); + return; + } + }) + .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mDialog = null; + input1.setText(""); + input2.setText(""); + return; + } + }); + break; + case DIALOG_REMOVE_MASTER_PASSWORD: + final EditText input = getTextBox(R.string.masterpassword_password); + linearLayout.addView(input); + + builder.setTitle(R.string.masterpassword_remove_title) + .setView((View)linearLayout) + .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + try { + JSONObject jsonPref = new JSONObject(); + jsonPref.put("name", "privacy.masterpassword.enabled"); + jsonPref.put("type", "string"); + jsonPref.put("value", input.getText().toString()); + + GeckoEvent event = new GeckoEvent("Preferences:Set", jsonPref.toString()); + GeckoAppShell.sendEventToGecko(event); + } catch(Exception ex) { + Log.e(LOGTAG, "Error setting masterpassword", ex); + } + input.setText(""); + mDialog = null; + return; + } + }) + .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mDialog = null; + input.setText(""); + return; + } + }); + break; + default: + return null; + } + return mDialog = builder.create(); + } + private void refresh(JSONArray jsonPrefs) { // enable all preferences once we have them from gecko GeckoAppShell.getMainHandler().post(new Runnable() { diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index b6e40a57707e..e31f96ad7530 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -62,15 +62,16 @@ - + - + + @@ -89,3 +90,11 @@ + + + + + + + + diff --git a/mobile/android/base/resources/xml/preferences.xml b/mobile/android/base/resources/xml/preferences.xml index e9a3643159ce..f0634507689b 100644 --- a/mobile/android/base/resources/xml/preferences.xml +++ b/mobile/android/base/resources/xml/preferences.xml @@ -65,6 +65,11 @@ android:title="@string/pref_telemetry" android:persistent="false" /> + + diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in index cfe798bd5931..8b43cc53418f 100644 --- a/mobile/android/base/strings.xml.in +++ b/mobile/android/base/strings.xml.in @@ -93,4 +93,13 @@ &contextmenu_open_new_tab; &contextmenu_add_to_launcher; &contextmenu_share; + + &pref_use_master_password; + &masterpassword_create_title; + &masterpassword_remove_title; + &masterpassword_password; + &masterpassword_confirm; + + &button_ok; + &button_cancel; diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index d9350e983b98..42191164ce5e 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -490,6 +490,12 @@ var BrowserApp = { pref.value = PluginHelper.getPluginPreference(); prefs.push(pref); continue; + } else if (prefName == MasterPassword.pref) { + // Master password is not a "real" pref + pref.type = "bool"; + pref.value = MasterPassword.enabled; + prefs.push(pref); + continue; } try { @@ -552,6 +558,11 @@ var BrowserApp = { if (json.name == "plugin.enable") { PluginHelper.setPluginPreference(json.value); return; + } else if(json.name == MasterPassword.pref) { + if (MasterPassword.enabled) + MasterPassword.removePassword(json.value); + else + MasterPassword.setPassword(json.value); } // when sending to java, we normalized special preferences that use @@ -3483,3 +3494,81 @@ var PermissionsHelper = { } } } + +var MasterPassword = { + pref: "privacy.masterpassword.enabled", + get _secModuleDB() { + delete this._secModuleDB; + return this._secModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(Ci.nsIPKCS11ModuleDB); + }, + + get _pk11DB() { + delete this._pk11DB; + return this._pk11DB = Cc["@mozilla.org/security/pk11tokendb;1"].getService(Ci.nsIPK11TokenDB); + }, + + get enabled() { + let slot = this._secModuleDB.findSlotByName(this._tokenName); + if (slot) { + let status = slot.status; + return status != Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED && status != Ci.nsIPKCS11Slot.SLOT_READY; + } + return false; + }, + + setPassword: function setPassword(aPassword) { + try { + let status; + let slot = this._secModuleDB.findSlotByName(this._tokenName); + if (slot) + status = slot.status; + else + return false; + + let token = this._pk11DB.findTokenByName(this._tokenName); + + if (status == Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED) + token.initPassword(aPassword); + else if (status == Ci.nsIPKCS11Slot.SLOT_READY) + token.changePassword("", aPassword); + + this.updatePref(); + return true; + } catch(e) { + dump("MasterPassword.setPassword: " + e); + } + return false; + }, + + removePassword: function removePassword(aOldPassword) { + try { + let token = this._pk11DB.getInternalKeyToken(); + if (token.checkPassword(aOldPassword)) { + token.changePassword(aOldPassword, ""); + this.updatePref(); + return true; + } + } catch(e) { + dump("MasterPassword.removePassword: " + e + "\n"); + } + NativeWindow.toast.show(Strings.browser.GetStringFromName("masterPassword.incorrect"), "short"); + return false; + }, + + updatePref: function() { + var prefs = []; + let pref = { + name: this.pref, + type: "bool", + value: this.enabled + }; + prefs.push(pref); + + sendMessageToJava({ + gecko: { + type: "Preferences:Data", + preferences: prefs + } + }); + } +} diff --git a/mobile/android/components/PromptService.js b/mobile/android/components/PromptService.js index 6f261f272843..a61de8c680e9 100644 --- a/mobile/android/components/PromptService.js +++ b/mobile/android/components/PromptService.js @@ -328,7 +328,7 @@ Prompt.prototype = { nsIPrompt_promptPassword: function nsIPrompt_promptPassword( aTitle, aText, aPassword, aCheckMsg, aCheckState) { - let inputs = [{ type: "password", hint: "Password", value: aPassword.value }]; + let inputs = [{ type: "password", hint: "Password", value: aPassword.value || "" }]; let data = this.commonPrompt(aTitle, aText, null, aCheckMsg, aCheckState, inputs); if (aCheckMsg) diff --git a/mobile/android/locales/en-US/chrome/browser.properties b/mobile/android/locales/en-US/chrome/browser.properties index 90f0ca671cc8..6cb6d3321aac 100644 --- a/mobile/android/locales/en-US/chrome/browser.properties +++ b/mobile/android/locales/en-US/chrome/browser.properties @@ -214,3 +214,5 @@ clickToPlayPlugins.no=No # dislay a list of current permissions settings for a site. # Example: "Store Offline Data: Allow" siteSettings.labelToValue=%S: %S + +masterPassword.incorrect=Incorrect password From 0aa0ecf02f3bd9af5a806253fa8e6d5b720a63e2 Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Wed, 21 Dec 2011 16:34:02 -0500 Subject: [PATCH 10/44] Bug 712414 - Throbber does not stop after running on pages that use document.write without document.close [r=mbrubeck] --- mobile/android/base/GeckoApp.java | 2 +- mobile/android/base/GeckoAppShell.java | 1 + mobile/android/chrome/content/browser.js | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 9a0e80118e93..0b5f9279a703 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -902,7 +902,7 @@ abstract public class GeckoApp final int tabId = message.getInt("tabID"); int state = message.getInt("state"); Log.i(LOGTAG, "State - " + state); - if ((state & GeckoAppShell.WPL_STATE_IS_DOCUMENT) != 0) { + if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) { if ((state & GeckoAppShell.WPL_STATE_START) != 0) { Log.i(LOGTAG, "Got a document start"); handleDocumentStart(tabId); diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index e11c538d0c44..f2c045445532 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -106,6 +106,7 @@ public class GeckoAppShell static public final int WPL_STATE_START = 0x00000001; static public final int WPL_STATE_STOP = 0x00000010; static public final int WPL_STATE_IS_DOCUMENT = 0x00020000; + static public final int WPL_STATE_IS_NETWORK = 0x00040000; static private File sCacheFile = null; static private int sFreeSpace = -1; diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 42191164ce5e..6278f22cc996 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1526,8 +1526,8 @@ Tab.prototype = { }, onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) { - if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT) { - // Filter optimization: Only really send DOCUMENT state changes to Java listener + if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) { + // Filter optimization: Only really send NETWORK state changes to Java listener let browser = BrowserApp.getBrowserForWindow(aWebProgress.DOMWindow); let uri = ""; if (browser) From 9d243d11ea3d736b68b3943e7501c033418dd375 Mon Sep 17 00:00:00 2001 From: Sriram Ramasubramanian Date: Wed, 21 Dec 2011 00:03:34 -0800 Subject: [PATCH 11/44] Bug 712477: Landscape specific resources should be used in Android [r=mfinkle] --- mobile/android/base/GeckoApp.java | 18 ++++++++++++++---- .../drawable-land-v14/address_bar_texture.png | Bin 7602 -> 0 bytes .../address_bar_url_bg.9.png | Bin 1591 -> 0 bytes .../address_bar_url_outline.9.png | Bin 1034 -> 0 bytes .../drawable-land-v14/tabs_normal.png | Bin 16600 -> 0 bytes .../drawable-land-v14/tabs_pressed.png | Bin 16667 -> 0 bytes .../drawable-port-v14/address_bar_texture.png | Bin 10633 -> 0 bytes .../address_bar_url_bg.9.png | Bin 2007 -> 0 bytes .../address_bar_url_outline.9.png | Bin 1050 -> 0 bytes .../drawable-port-v14/tabs_normal.png | Bin 22359 -> 0 bytes .../drawable-port-v14/tabs_pressed.png | Bin 22572 -> 0 bytes 11 files changed, 14 insertions(+), 4 deletions(-) delete mode 100644 mobile/android/base/resources/drawable-land-v14/address_bar_texture.png delete mode 100644 mobile/android/base/resources/drawable-land-v14/address_bar_url_bg.9.png delete mode 100644 mobile/android/base/resources/drawable-land-v14/address_bar_url_outline.9.png delete mode 100644 mobile/android/base/resources/drawable-land-v14/tabs_normal.png delete mode 100644 mobile/android/base/resources/drawable-land-v14/tabs_pressed.png delete mode 100644 mobile/android/base/resources/drawable-port-v14/address_bar_texture.png delete mode 100644 mobile/android/base/resources/drawable-port-v14/address_bar_url_bg.9.png delete mode 100644 mobile/android/base/resources/drawable-port-v14/address_bar_url_outline.9.png delete mode 100644 mobile/android/base/resources/drawable-port-v14/tabs_normal.png delete mode 100644 mobile/android/base/resources/drawable-port-v14/tabs_pressed.png diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 0b5f9279a703..3e2db6ee1d0c 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -111,6 +111,7 @@ abstract public class GeckoApp public Handler mMainHandler; private File mProfileDir; private static boolean sIsGeckoReady = false; + private static int mOrientation; private IntentFilter mConnectivityFilter; private IntentFilter mBatteryFilter; @@ -1594,6 +1595,8 @@ abstract public class GeckoApp checkMigrateProfile(); } }, 50); + + mOrientation = getResources().getConfiguration().orientation; } /** @@ -1802,14 +1805,21 @@ abstract public class GeckoApp @Override - public void onConfigurationChanged(android.content.res.Configuration newConfig) + public void onConfigurationChanged(Configuration newConfig) { Log.i(LOGTAG, "configuration changed"); - // hide the autocomplete list on rotation - mAutoCompletePopup.hide(); - super.onConfigurationChanged(newConfig); + + if (mOrientation != newConfig.orientation) { + mOrientation = newConfig.orientation; + mAutoCompletePopup.hide(); + + if (Build.VERSION.SDK_INT >= 11) { + mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.gecko_app_actionbar, null); + GeckoActionBar.setCustomView(mAppContext, mBrowserToolbar); + } + } } @Override diff --git a/mobile/android/base/resources/drawable-land-v14/address_bar_texture.png b/mobile/android/base/resources/drawable-land-v14/address_bar_texture.png deleted file mode 100644 index c7d33833dda75cdce701592385cb544a13c0885d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7602 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 diff --git a/mobile/android/base/resources/drawable-land-v14/address_bar_url_outline.9.png b/mobile/android/base/resources/drawable-land-v14/address_bar_url_outline.9.png deleted file mode 100644 index 6fe1742d135ddc725a71c988a831f5615f5672e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1034 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 diff --git a/mobile/android/base/resources/drawable-land-v14/tabs_pressed.png b/mobile/android/base/resources/drawable-land-v14/tabs_pressed.png deleted file mode 100644 index 4d64e035c95d668d959f4516978a751ecb4eba11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16667 zcmV({K+?a7P)E9BR0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBVdy-7qtRCwBSefhIo$93M_XWj!zfFwu& z1O$R0NRU_vfV*Uhl&GkzCAJo8DN9jQP9-YG+9Ert{9SfcQu!g3vVTfkj#ZIF?U6`| zq{LmMi1%jhp7VWQ_nCeJ2K6|cxzo4ro!i}K`ObGv=Rf(yuZMn^rs0h@-+b$>xBp=O z-hKDCzx!R07iCp0mpfTDFL!pcd0s4+MN#B=K8;gR7Q-;wCp(g5+0ge@RcE=q&FtH} z$nqQw=6R~?dKiYPEbUNeS=U+e58qbR<|Di6hdxL9ysApOy{fL#Q?l8<$#nefx8Cf! zuJ8NTUw`fOS6_Yay+6GAyWjrm|NhcWFUxYC=bZm^A>HjXO* t$_}zrCzgx|8!8N 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�USV(3X)gbm4@wh}u%|>7Mo_CyXu)VcWrZ&P# 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 diff --git a/mobile/android/base/resources/drawable-port-v14/address_bar_url_bg.9.png b/mobile/android/base/resources/drawable-port-v14/address_bar_url_bg.9.png deleted file mode 100644 index dc647b8c3eebd373c902546e12fbee0b31d375a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2007 zcmV;|2PpW7P)ac$w1|Rl(G|tl7@{$mAYu`fLMiVel)~NrxG(Lr#Y!tm+k29K`h7soJ@?0V&pr3@ zal3SRb;it;)mm4`0eTmD4;pB1Z|`hpXXk2;$Orine7-BR(bZBRb)!yn@7{gjNFN`s z)jx+Uh}gDc`wr2rw7A55Hxu@V(&z-%z>6}3riryR;)h$V+&qSz?L z&cMo!hCpcemX*IJ?Z1BdY!>_HRz8!<<()zVk7A4n5SXo(Frxe9TG46~@JP@>G`4k5ShhFHyYcDOKJ32ZJ+_?3(kV6?KYHt@7vGVeA zi%{X6B9@kMQnh*e&d|Pn`@Y}d6T_fEgY2E1orgrl?25gbbM0{u3WdVr^w-~cEIKYR zj`~7<>JV7{`t^GQ4Y(%lOOX^7-DMRO6&9^KMKZQ~|ADl@g9i`o)2Gjy9Rdq8)* zQ>9XA6_O*r9Xyh8j-d7G)yv_94MR6KH`hby$4->vajvYav??hS6)gSu>8znJvxldz zuWvU`Pfyo_hmT6=H&RtqWtAduhcb>!sIOjLUZzh3{{H^X`^1vy3c#wauC{6^m6c5V zM{1m(pWg>2l^h`5Gd4acM1cfZQ&VFTqQ1r@?hWFVY?)qG?Fj@47iBDKawCn5Z zZBhg+K4I@lV`t$mtMT^{xl@SiR_wHZN(9poR8d$Pe zvT*$P@ojGl1qTPa-z_f5YHVy|T#YmVTnY&Z8Qx}*I&R!JH~gT6!_p}@c%3h?(E}D5 z8ruJAPHtFJQxoIT>Du)hTO%SO2Iv8cjEo$C;w?w5Rx>W0Fk|LKM@M@-ox8dQ1O&J> zH#ch_#`T0W#D*AYfq|f7X6B!P8jXf=>Fb42fi=fI5E(xpo|Fq47B#Kdr5Mr_rpRUDYfz~bZMIWQx(cI{dn zuswVBa9~Dk!-fqUn90DzVlfA1#89hpU?u}gO-<#%j2IT*I$-JP=^U656Ny9|SUcs;Vhk zU@Dbrf?O`2!OK`hVj?d48hmY2tyV9_^cl!e{bzM`bwQ}X7PWoy24mi3 zWo7<6`9FTTE|r#+eu>M^pZV%JmPpHqEKl|g3&G+?Kg;bZOtw zON@Pw_0wd4+ipXNKB}gshKAyt_McV7SXVrj>rk7GhNEN~fF(xF<%K?nQ{PQH;ES<$ z;2;X62JQK$St~5`?F97^ecgduC-Y84W6YVLVb*Ym<0DoG>nQaNecamay!8xdAHiWX zRskR5(`tq%`a1u%a=kdE+wcFnODG!qu@>}H#R@Sm!R;2P=gT`Hld)M) zGNxntr>=>eIk!=+qWwN-4#f-wnp`@V39UD@0@{mUX#F{hW}VJdE+D4a6dP`LLqAc> zul!s;A-8RWVrh30Ibtk+tF+yHiPo|&v;L$u(e@^afnvdZj1Zekm(FH1+du^BFfHJr zNtht$FD`-T1g%TO5dDSyCRAhwm?FVP4*3*(2cj+7Vy9%jQivh!g_jE*I5A9veuYjz zR6(zS=0ddP>rdNAkgJLMT<|eL@VQ24(a;rg$~hCY pTksJn_?#lN(aqA%hqhK}?O!>BlESvA$Xx&c002ovPDHLkV1j~*>mmRE diff --git a/mobile/android/base/resources/drawable-port-v14/address_bar_url_outline.9.png b/mobile/android/base/resources/drawable-port-v14/address_bar_url_outline.9.png deleted file mode 100644 index 1a611c71807e61435cdb804f5e309044f8f39d71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1050 zcmV+#1m*jQP)gghPLD4`tTI7&H6pUQEBQpyoZDWy+&Dydc~gtAX1gb=Pm zNR^PMJe5*PY4xdua)j-C?R>j)`|aKB-sbl9cIVGX_Hw!V_P4w9&Cbp@0K=8tr=?nB zXe($B(KgWz(N54lM*wz8pV35njkbz*E2aZH5M4uS&<_2H04A*cM%zWJqvb{cSP5+p z?cB2?>a2Q0XM%c95p6NT_Y~+e%5>(wMLYI(Q;VE$5x%-fExM!U8K$Flv*-&x-D{Kztz#up|287GzJ` zT`o;uVE0(gDT~UnOS2jT*eU(tF=ST_VsO$6Se0Hp0+G(IRk{JwVMIfC{maHE7W`g5Xyd{QrisTn1@H#2C*Wo$MeTP04L@Kyl(-|DI{I`6*dz;7CxnxuDR3XCOmbiq z+Gq+RLrpeYI>6RwV_oQfWo=EwwCK(#RvU;<2l2`~XBz(fK}fC(@GCcp%k z0P7*1*O&B802%2WC7m403m-#90#Qj))SYFdsFn2cm%8vVR0p?KP9C!bkndwQd63&# zABasEq*NeONHGagjM7uO80C-!u#TkM$yC>JCn>0FSI>evr32_**q@@BfEMfLU^pTb@Ysn({kie8mkp4CdLApRmqYrX9L0e`? zD;XGID;Yi!jAFB*B^W}pBJcf{w;k4W0zs*@2SaU#S`) zgOI;s%>V!Z diff --git a/mobile/android/base/resources/drawable-port-v14/tabs_normal.png b/mobile/android/base/resources/drawable-port-v14/tabs_normal.png deleted file mode 100644 index 50cd8e69f40869e3394f1c9180c9efac478b198e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22359 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 Tl}{V>00000NkvXXu0mjf1adAp From 5052055361f1b14b63055f9f19483825f4da1201 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 21 Dec 2011 16:50:29 -0500 Subject: [PATCH 12/44] Bug 710917. Moving hover from a button to text in the label containing the button should keep the button's hover state. r=dbaron --- content/events/src/nsEventStateManager.cpp | 25 ++++++++++++++++ content/events/test/test_bug656379-2.html | 35 +++++++++++++++++----- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 8b0f8cf0e306..667c3e80e0b5 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -4508,6 +4508,31 @@ nsEventStateManager::UpdateAncestorState(nsIContent* aStartNode, DoStateChange(labelTarget, aState, aAddState); } } + + if (aAddState) { + // We might be in a situation where a node was in hover both + // because it was hovered and because the label for it was + // hovered, and while we stopped hovering the node the label is + // still hovered. Or we might have had two nested labels for the + // same node, and while one is no longer hovered the other still + // is. In that situation, the label that's still hovered will be + // aStopBefore or some ancestor of it, and the call we just made + // to UpdateAncestorState with aAddState = false would have + // removed the hover state from the node. But the node should + // still be in hover state. To handle this situation we need to + // keep walking up the tree and any time we find a label mark its + // corresponding node as still in our state. + for ( ; aStartNode; aStartNode = aStartNode->GetParent()) { + if (!aStartNode->IsElement()) { + continue; + } + + Element* labelTarget = GetLabelTarget(aStartNode->AsElement()); + if (labelTarget && !labelTarget->State().HasState(aState)) { + DoStateChange(labelTarget, aState, true); + } + } + } } bool diff --git a/content/events/test/test_bug656379-2.html b/content/events/test/test_bug656379-2.html index 54a2df545328..597bee66394c 100644 --- a/content/events/test/test_bug656379-2.html +++ b/content/events/test/test_bug656379-2.html @@ -9,15 +9,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=656379 Mozilla Bug 656379

- - + +