mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team.
This commit is contained in:
commit
aa1c106fad
1
.hgtags
1
.hgtags
@ -105,3 +105,4 @@ ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE-m
|
||||
0000000000000000000000000000000000000000 FIREFOX_AURORA_29_BASE-m
|
||||
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE
|
||||
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||
83c9853e136451474dfa6d1aaa60a7fca7d2d83a FIREFOX_AURORA_30_BASE
|
||||
|
@ -676,6 +676,19 @@ pref("hal.processPriorityManager.gonk.BACKGROUND.Nice", 18);
|
||||
// Processes get this niceness when they have low CPU priority.
|
||||
pref("hal.processPriorityManager.gonk.LowCPUNice", 18);
|
||||
|
||||
// By default the compositor thread on gonk runs without real-time priority. RT
|
||||
// priority can be enabled by setting this pref to a value between 1 and 99.
|
||||
// Note that audio processing currently runs at RT priority 2 or 3 at most.
|
||||
//
|
||||
// If RT priority is disabled, then the compositor nice value is used. The
|
||||
// code will default to ANDROID_PRIORITY_URGENT_DISPLAY which is -8. Per gfx
|
||||
// request we are keeping the compositor at nice level 0 until we can complete
|
||||
// the investigation in bug 982972.
|
||||
//
|
||||
// Do not change these values without gfx team review.
|
||||
pref("hal.gonk.compositor.rt_priority", 0);
|
||||
pref("hal.gonk.compositor.nice", 0);
|
||||
|
||||
// Fire a memory pressure event when the system has less than Xmb of memory
|
||||
// remaining. You should probably set this just above Y.KillUnderKB for
|
||||
// the highest priority class Y that you want to make an effort to keep alive.
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"branch": "",
|
||||
"revision": ""
|
||||
},
|
||||
"revision": "fb54fbd4849b9adfdb4fc236c2cf8161545d736d",
|
||||
"revision": "f5280df8a66c88c8bafc0062e19a4770ce18e08d",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0701e08a025787481a5d23443c75be7473c866f5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c03a6af9028c4b74a84b5a98085bbb0c07261175"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -5,7 +5,7 @@
|
||||
MOZ_APP_BASENAME=B2G
|
||||
MOZ_APP_VENDOR=Mozilla
|
||||
|
||||
MOZ_APP_VERSION=30.0a1
|
||||
MOZ_APP_VERSION=31.0a1
|
||||
MOZ_APP_UA_NAME=Firefox
|
||||
|
||||
MOZ_UA_OS_AGNOSTIC=1
|
||||
|
@ -1 +1 @@
|
||||
30.0a1
|
||||
31.0a1
|
||||
|
@ -44,8 +44,12 @@ endif
|
||||
# by GDB when we debug executables there.
|
||||
# NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
|
||||
GDBINIT_FILES := $(topsrcdir)/.gdbinit
|
||||
GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit
|
||||
GDBINIT_DEST = $(FINAL_TARGET)
|
||||
INSTALL_TARGETS += GDBINIT
|
||||
|
||||
# needs to be absolute to be distinct from $(topsrcdir)/.gdbinit
|
||||
GDBINIT_OBJDIR_DEST = $(abspath $(DEPTH))
|
||||
INSTALL_TARGETS += GDBINIT GDBINIT_OBJDIR
|
||||
|
||||
# Put a .lldbinit in the bin directory and the objdir, to be picked up
|
||||
# automatically by LLDB when we debug executables using either of those two
|
||||
|
@ -10,4 +10,4 @@
|
||||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
30.0a1
|
||||
31.0a1
|
||||
|
11
configure.in
11
configure.in
@ -7888,7 +7888,13 @@ dnl ========================================================
|
||||
dnl Check for pixman and cairo
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_TREE_CAIRO=1
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = "gtk3" ; then
|
||||
# cairo-gtk3 can be build with system-cairo only
|
||||
MOZ_TREE_CAIRO=
|
||||
else
|
||||
MOZ_TREE_CAIRO=1
|
||||
fi
|
||||
|
||||
MOZ_ARG_ENABLE_BOOL(system-cairo,
|
||||
[ --enable-system-cairo Use system cairo (located with pkgconfig)],
|
||||
MOZ_TREE_CAIRO=,
|
||||
@ -7978,6 +7984,9 @@ if test "$MOZ_TREE_CAIRO"; then
|
||||
MOZ_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
|
||||
fi
|
||||
;;
|
||||
gtk3)
|
||||
AC_MSG_ERROR([cairo-gtk3 toolkit is incompatible with in-tree cairo. Please add --enable-system-cairo to your build config.])
|
||||
;;
|
||||
esac
|
||||
if test "$USE_FC_FREETYPE"; then
|
||||
FC_FONT_FEATURE="#define CAIRO_HAS_FC_FONT 1"
|
||||
|
@ -4,9 +4,11 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLContext.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLElementArrayCache.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -55,6 +57,22 @@ WebGLBuffer::ElementArrayCacheBufferSubData(size_t pos, const void* ptr, size_t
|
||||
mCache->BufferSubData(pos, ptr, update_size_in_bytes);
|
||||
}
|
||||
|
||||
size_t
|
||||
WebGLBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t sizeOfCache = mCache ? mCache->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
return aMallocSizeOf(this) + sizeOfCache;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLBuffer::Validate(GLenum type, uint32_t max_allowed,
|
||||
size_t first, size_t count,
|
||||
uint32_t* out_upperBound)
|
||||
{
|
||||
return mCache->Validate(type, max_allowed, first, count, out_upperBound);
|
||||
}
|
||||
|
||||
|
||||
JSObject*
|
||||
WebGLBuffer::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) {
|
||||
return dom::WebGLBufferBinding::Wrap(cx, scope, this);
|
||||
|
@ -6,14 +6,12 @@
|
||||
#ifndef WEBGLBUFFER_H_
|
||||
#define WEBGLBUFFER_H_
|
||||
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLElementArrayCache.h"
|
||||
#include "GLDefs.h"
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -32,10 +30,7 @@ public:
|
||||
|
||||
void Delete();
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
size_t sizeOfCache = mCache ? mCache->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
return aMallocSizeOf(this) + sizeOfCache;
|
||||
}
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
bool HasEverBeenBound() { return mHasEverBeenBound; }
|
||||
void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
|
||||
@ -51,9 +46,8 @@ public:
|
||||
|
||||
void ElementArrayCacheBufferSubData(size_t pos, const void* ptr, size_t update_size_in_bytes);
|
||||
|
||||
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count) {
|
||||
return mCache->Validate(type, max_allowed, first, count);
|
||||
}
|
||||
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
|
||||
uint32_t* out_upperBound);
|
||||
|
||||
WebGLContext *GetParentObject() const {
|
||||
return Context();
|
||||
|
@ -787,7 +787,8 @@ private:
|
||||
|
||||
bool DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info);
|
||||
bool DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset,
|
||||
GLsizei primcount, const char* info);
|
||||
GLsizei primcount, const char* info,
|
||||
GLuint* out_upperBound = nullptr);
|
||||
bool DrawInstanced_check(const char* info);
|
||||
void Draw_cleanup();
|
||||
|
||||
|
@ -4,16 +4,18 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLUniformInfo.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLProgram.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLUniformInfo.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace dom;
|
||||
@ -554,7 +556,9 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset, GLsizei primcount, const char* info)
|
||||
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount,
|
||||
const char* info, GLuint* out_upperBound)
|
||||
{
|
||||
if (count < 0 || byteOffset < 0) {
|
||||
ErrorInvalidValue("%s: negative count or offset", info);
|
||||
@ -620,7 +624,9 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOff
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mBoundVertexArray->mBoundElementArrayBuffer->ByteLength()) {
|
||||
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mBoundElementArrayBuffer;
|
||||
|
||||
if (!elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
|
||||
return false;
|
||||
}
|
||||
@ -632,7 +638,7 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOff
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(checked_neededByteCount.value()) > mBoundVertexArray->mBoundElementArrayBuffer->ByteLength()) {
|
||||
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
|
||||
return false;
|
||||
}
|
||||
@ -641,7 +647,7 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOff
|
||||
return false;
|
||||
|
||||
if (!mMaxFetchedVertices ||
|
||||
!mBoundVertexArray->mBoundElementArrayBuffer->Validate(type, mMaxFetchedVertices - 1, first, count))
|
||||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
|
||||
{
|
||||
ErrorInvalidOperation(
|
||||
"%s: bound vertex attribute buffers do not have sufficient "
|
||||
@ -673,7 +679,7 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOff
|
||||
|
||||
void
|
||||
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset)
|
||||
WebGLintptr byteOffset)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
@ -681,18 +687,28 @@ WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
|
||||
return;
|
||||
|
||||
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements"))
|
||||
GLuint upperBound = UINT_MAX;
|
||||
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
|
||||
&upperBound))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetupContextLossTimer();
|
||||
gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
|
||||
gl->fDrawRangeElements(mode, 0, upperBound,
|
||||
count, type, reinterpret_cast<GLvoid*>(byteOffset));
|
||||
} else {
|
||||
gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
|
||||
}
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount)
|
||||
WebGLintptr byteOffset, GLsizei primcount)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
@ -16,6 +16,24 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static void
|
||||
SetUpperBound(uint32_t* out_upperBound, uint32_t newBound)
|
||||
{
|
||||
if (!out_upperBound)
|
||||
return;
|
||||
|
||||
*out_upperBound = newBound;
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateUpperBound(uint32_t* out_upperBound, uint32_t newBound)
|
||||
{
|
||||
if (!out_upperBound)
|
||||
return;
|
||||
|
||||
*out_upperBound = std::max(*out_upperBound, newBound);
|
||||
}
|
||||
|
||||
/*
|
||||
* WebGLElementArrayCacheTree contains most of the implementation of WebGLElementArrayCache,
|
||||
* which performs WebGL element array buffer validation for drawElements.
|
||||
@ -227,7 +245,9 @@ public:
|
||||
return ((numElements - 1) | sElementsPerLeafMask) + 1;
|
||||
}
|
||||
|
||||
bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf) {
|
||||
bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf,
|
||||
uint32_t* out_upperBound)
|
||||
{
|
||||
MOZ_ASSERT(!mInvalidated);
|
||||
|
||||
size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
|
||||
@ -240,13 +260,17 @@ public:
|
||||
|
||||
// final case where there is only 1 node to validate at the current tree level
|
||||
if (lastTreeIndex == firstTreeIndex) {
|
||||
return mTreeData[firstTreeIndex] <= maxAllowed;
|
||||
const T& curData = mTreeData[firstTreeIndex];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
return curData <= maxAllowed;
|
||||
}
|
||||
|
||||
// if the first node at current tree level is a right node, handle it individually
|
||||
// and replace it with its right neighbor, which is a left node
|
||||
if (IsRightNode(firstTreeIndex)) {
|
||||
if (mTreeData[firstTreeIndex] > maxAllowed)
|
||||
const T& curData = mTreeData[firstTreeIndex];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowed)
|
||||
return false;
|
||||
firstTreeIndex = RightNeighborNode(firstTreeIndex);
|
||||
}
|
||||
@ -254,7 +278,9 @@ public:
|
||||
// if the last node at current tree level is a left node, handle it individually
|
||||
// and replace it with its left neighbor, which is a right node
|
||||
if (IsLeftNode(lastTreeIndex)) {
|
||||
if (mTreeData[lastTreeIndex] > maxAllowed)
|
||||
const T& curData = mTreeData[lastTreeIndex];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowed)
|
||||
return false;
|
||||
lastTreeIndex = LeftNeighborNode(lastTreeIndex);
|
||||
}
|
||||
@ -490,10 +516,18 @@ void WebGLElementArrayCache::InvalidateTrees(size_t firstByte, size_t lastByte)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement, size_t countElements) {
|
||||
bool
|
||||
WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
size_t countElements, uint32_t* out_upperBound)
|
||||
{
|
||||
SetUpperBound(out_upperBound, 0);
|
||||
|
||||
// if maxAllowed is >= the max T value, then there is no way that a T index could be invalid
|
||||
if (maxAllowed >= std::numeric_limits<T>::max())
|
||||
uint32_t maxTSize = std::numeric_limits<T>::max();
|
||||
if (maxAllowed >= maxTSize) {
|
||||
SetUpperBound(out_upperBound, maxTSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
T maxAllowedT(maxAllowed);
|
||||
|
||||
@ -515,8 +549,10 @@ bool WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
|
||||
// fast exit path when the global maximum for the whole element array buffer
|
||||
// falls in the allowed range
|
||||
if (tree->GlobalMaximum() <= maxAllowedT)
|
||||
T globalMax = tree->GlobalMaximum();
|
||||
if (globalMax <= maxAllowedT)
|
||||
{
|
||||
SetUpperBound(out_upperBound, globalMax);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -527,14 +563,18 @@ bool WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
size_t firstElementAdjustmentEnd = std::min(lastElement,
|
||||
tree->LastElementUnderSameLeaf(firstElement));
|
||||
while (firstElement <= firstElementAdjustmentEnd) {
|
||||
if (elements[firstElement] > maxAllowedT)
|
||||
const T& curData = elements[firstElement];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowedT)
|
||||
return false;
|
||||
firstElement++;
|
||||
}
|
||||
size_t lastElementAdjustmentEnd = std::max(firstElement,
|
||||
tree->FirstElementUnderSameLeaf(lastElement));
|
||||
while (lastElement >= lastElementAdjustmentEnd) {
|
||||
if (elements[lastElement] > maxAllowedT)
|
||||
const T& curData = elements[lastElement];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowedT)
|
||||
return false;
|
||||
lastElement--;
|
||||
}
|
||||
@ -546,20 +586,29 @@ bool WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
// general case
|
||||
return tree->Validate(maxAllowedT,
|
||||
tree->LeafForElement(firstElement),
|
||||
tree->LeafForElement(lastElement));
|
||||
tree->LeafForElement(lastElement),
|
||||
out_upperBound);
|
||||
}
|
||||
|
||||
bool WebGLElementArrayCache::Validate(GLenum type, uint32_t maxAllowed, size_t firstElement, size_t countElements) {
|
||||
bool
|
||||
WebGLElementArrayCache::Validate(GLenum type, uint32_t maxAllowed,
|
||||
size_t firstElement, size_t countElements,
|
||||
uint32_t* out_upperBound)
|
||||
{
|
||||
if (type == LOCAL_GL_UNSIGNED_BYTE)
|
||||
return Validate<uint8_t>(maxAllowed, firstElement, countElements);
|
||||
return Validate<uint8_t>(maxAllowed, firstElement, countElements, out_upperBound);
|
||||
if (type == LOCAL_GL_UNSIGNED_SHORT)
|
||||
return Validate<uint16_t>(maxAllowed, firstElement, countElements);
|
||||
return Validate<uint16_t>(maxAllowed, firstElement, countElements, out_upperBound);
|
||||
if (type == LOCAL_GL_UNSIGNED_INT)
|
||||
return Validate<uint32_t>(maxAllowed, firstElement, countElements);
|
||||
return Validate<uint32_t>(maxAllowed, firstElement, countElements, out_upperBound);
|
||||
|
||||
MOZ_ASSERT(false, "Invalid type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t WebGLElementArrayCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
size_t
|
||||
WebGLElementArrayCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t uint8TreeSize = mUint8Tree ? mUint8Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
size_t uint16TreeSize = mUint16Tree ? mUint16Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
size_t uint32TreeSize = mUint32Tree ? mUint32Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
|
@ -33,7 +33,8 @@ public:
|
||||
bool BufferData(const void* ptr, size_t byteSize);
|
||||
void BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
|
||||
|
||||
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count);
|
||||
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count,
|
||||
uint32_t* out_upperBound = nullptr);
|
||||
|
||||
template<typename T>
|
||||
T Element(size_t i) const { return Elements<T>()[i]; }
|
||||
@ -53,7 +54,8 @@ public:
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
bool Validate(uint32_t maxAllowed, size_t first, size_t count);
|
||||
bool Validate(uint32_t maxAllowed, size_t first, size_t count,
|
||||
uint32_t* out_upperBound);
|
||||
|
||||
size_t ByteSize() const {
|
||||
return mByteSize;
|
||||
|
@ -1221,6 +1221,16 @@ MediaStreamGraphImpl::RunThread()
|
||||
}
|
||||
}
|
||||
|
||||
// The loop is woken up so soon that mCurrentTime barely advances and we
|
||||
// end up having endBlockingDecisions == mStateComputedTime.
|
||||
// Since stream blocking is computed in the interval of
|
||||
// [mStateComputedTime, endBlockingDecisions), it won't be computed at all.
|
||||
// We should ensure next iteration so that pending blocking changes will be
|
||||
// computed in next loop.
|
||||
if (endBlockingDecisions == mStateComputedTime) {
|
||||
ensureNextIteration = true;
|
||||
}
|
||||
|
||||
// Figure out which streams are blocked and when.
|
||||
GraphTime prevComputedTime = mStateComputedTime;
|
||||
RecomputeBlocking(endBlockingDecisions);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/TextTrack.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -28,6 +29,12 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextTrackRegion)
|
||||
|
||||
static bool RegionsEnabled(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
return Preferences::GetBool("media.webvtt.enabled") &&
|
||||
Preferences::GetBool("media.webvtt.regions.enabled");
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -380,7 +380,6 @@ skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(bug 90
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out in small-shot.mp3) b2g-desktop(timed out in small-shot.mp3)
|
||||
[test_readyState.html]
|
||||
[test_referer.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
[test_reset_events_async.html]
|
||||
[test_replay_metadata.html]
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
|
||||
|
@ -74,7 +74,7 @@ var tests = [
|
||||
// is(v.networkState, v.NETWORK_IDLE, "(1) NetworkState must be NETWORK_IDLE");
|
||||
maybeFinish(v, 1);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -86,6 +86,8 @@ var tests = [
|
||||
v.src = test.name;
|
||||
document.body.appendChild(v); // Causes implicit load, which will be halted due to preload:none.
|
||||
},
|
||||
|
||||
name: "test1",
|
||||
},
|
||||
{
|
||||
// 2. Add preload:metadata video with src to document. Should halt with NETWORK_IDLE, HAVE_CURRENT_DATA
|
||||
@ -100,7 +102,7 @@ var tests = [
|
||||
// is(v.networkState, v.NETWORK_IDLE, "(2) NetworkState must be NETWORK_IDLE");
|
||||
maybeFinish(v, 2);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -113,6 +115,8 @@ var tests = [
|
||||
document.body.appendChild(v); // Causes implicit load, which will be halted after
|
||||
// metadata due to preload:metadata.
|
||||
},
|
||||
|
||||
name: "test2",
|
||||
},
|
||||
{
|
||||
// 3. Add preload:auto to document. Should receive canplaythrough eventually.
|
||||
@ -123,7 +127,7 @@ var tests = [
|
||||
is(v._gotLoadedMetaData, true, "(3) Must get loadedmetadata.");
|
||||
maybeFinish(v, 3);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -135,6 +139,8 @@ var tests = [
|
||||
v.src = test.name; // Causes implicit load.
|
||||
document.body.appendChild(v);
|
||||
},
|
||||
|
||||
name: "test3",
|
||||
},
|
||||
{
|
||||
// 4. Add preload:none video to document. Call play(), should load then play through.
|
||||
@ -152,13 +158,13 @@ var tests = [
|
||||
// is(v.networkState, v.NETWORK_IDLE, "(4) NetworkState must be NETWORK_IDLE");
|
||||
v.play(); // Should load and play through.
|
||||
},
|
||||
|
||||
|
||||
ended:
|
||||
function(e) {
|
||||
ok(true, "(4) Got playback ended");
|
||||
maybeFinish(e.target, 4);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -172,6 +178,8 @@ var tests = [
|
||||
v.src = test.name;
|
||||
document.body.appendChild(v);
|
||||
},
|
||||
|
||||
name: "test4",
|
||||
},
|
||||
{
|
||||
// 5. preload:none video without resource, add to document, will implicitly start a
|
||||
@ -186,7 +194,7 @@ var tests = [
|
||||
// is(v.networkState, v.NETWORK_IDLE, "(5) NetworkState must be NETWORK_IDLE");
|
||||
maybeFinish(v, 5);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -198,6 +206,8 @@ var tests = [
|
||||
document.body.appendChild(v); // Causes implicit load, which will be halted due to no resource.
|
||||
v.src = test.name; // Load should start, and halt at preload:none.
|
||||
},
|
||||
|
||||
name: "test5",
|
||||
},
|
||||
{
|
||||
// 6. preload:none video without resource, add to document, will implicitly start a
|
||||
@ -212,7 +222,7 @@ var tests = [
|
||||
// is(v.networkState, v.NETWORK_IDLE, "(6) NetworkState must be NETWORK_IDLE");
|
||||
maybeFinish(v, 6);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -227,6 +237,8 @@ var tests = [
|
||||
s.type = test.type;
|
||||
v.appendChild(s); // Load should start, and halt at preload:none.
|
||||
},
|
||||
|
||||
name: "test6",
|
||||
},
|
||||
{
|
||||
// 7. create a preload:none document with multiple sources, the first of which is invalid.
|
||||
@ -252,7 +264,7 @@ var tests = [
|
||||
is(v._gotErrorEvent, true, "(7) Should get error event from first source load failure");
|
||||
maybeFinish(v, 7);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -274,6 +286,8 @@ var tests = [
|
||||
v.appendChild(s2);
|
||||
document.body.appendChild(v); // Causes implicit load, which will be halt at preload:none on the second resource.
|
||||
},
|
||||
|
||||
name: "test7",
|
||||
},
|
||||
{
|
||||
// 8. Change preload value from none to metadata should cause metadata to be loaded.
|
||||
@ -286,7 +300,7 @@ var tests = [
|
||||
// is(v.networkState, v.NETWORK_IDLE, "(8) NetworkState must be NETWORK_IDLE when load is halted");
|
||||
maybeFinish(v, 8);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadedMetaData = false;
|
||||
@ -297,6 +311,8 @@ var tests = [
|
||||
v.src = test.name; // Causes implicit load.
|
||||
document.body.appendChild(v);
|
||||
},
|
||||
|
||||
name: "test8",
|
||||
},
|
||||
/*{
|
||||
// 9. Change preload value from metadata to auto should cause entire media to be loaded.
|
||||
@ -309,7 +325,7 @@ var tests = [
|
||||
is(v._gotLoadedMetaData, true, "(9) Must get loadedmetadata.");
|
||||
maybeFinish(v, 9);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -331,7 +347,7 @@ var tests = [
|
||||
is(v._gotLoadedMetaData, true, "(10) Must get loadedmetadata.");
|
||||
maybeFinish(v, 10);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadedMetaData = false;
|
||||
@ -342,6 +358,8 @@ var tests = [
|
||||
v.src = test.name; // Causes implicit load.
|
||||
document.body.appendChild(v);
|
||||
},
|
||||
|
||||
name: "test10",
|
||||
},
|
||||
{
|
||||
// 11. Change preload value from none to metadata should cause metadata to load.
|
||||
@ -365,10 +383,14 @@ var tests = [
|
||||
v.src = test.name; // Causes implicit load.
|
||||
document.body.appendChild(v);
|
||||
},
|
||||
|
||||
name: "test11",
|
||||
},
|
||||
{
|
||||
/*{
|
||||
// 12. Change preload value from auto to metadata after load started,
|
||||
// should still do full load, should not halt after metadata only.
|
||||
// disable this test since the spec is no longer found in the document
|
||||
// http://dev.w3.org/html5/spec-preview/media-elements.html
|
||||
canplaythrough:
|
||||
function(e) {
|
||||
var v = e.target;
|
||||
@ -389,7 +411,9 @@ var tests = [
|
||||
document.body.appendChild(v);
|
||||
v.preload = "metadata";
|
||||
},
|
||||
},
|
||||
|
||||
name: "test12",
|
||||
},*/
|
||||
{
|
||||
// 13. Change preload value from auto to none after specifying a src
|
||||
// should load according to preload none, no buffering should have taken place
|
||||
@ -416,7 +440,9 @@ var tests = [
|
||||
v.addEventListener("suspend", this.suspend, false);
|
||||
document.body.appendChild(v); // Causes implicit load, should load according to preload none
|
||||
var s = document.createElement("source");
|
||||
}
|
||||
},
|
||||
|
||||
name: "test13",
|
||||
},
|
||||
{
|
||||
// 14. Add preload:metadata video with src to document. Play(), should play through.
|
||||
@ -430,7 +456,7 @@ var tests = [
|
||||
// is(v.networkState, v.NETWORK_IDLE, "(14) NetworkState must be NETWORK_IDLE");
|
||||
v.play();
|
||||
},
|
||||
|
||||
|
||||
ended:
|
||||
function(e) {
|
||||
ok(true, "(14) Got playback ended");
|
||||
@ -451,6 +477,8 @@ var tests = [
|
||||
document.body.appendChild(v); // Causes implicit load, which will be halted after
|
||||
// metadata due to preload:metadata.
|
||||
},
|
||||
|
||||
name: "test14",
|
||||
},
|
||||
{
|
||||
// 15. Autoplay should override preload:none.
|
||||
@ -460,7 +488,7 @@ var tests = [
|
||||
var v = e.target;
|
||||
maybeFinish(v, 15);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v._gotLoadStart = false;
|
||||
@ -473,6 +501,8 @@ var tests = [
|
||||
v.src = test.name; // Causes implicit load.
|
||||
document.body.appendChild(v);
|
||||
},
|
||||
|
||||
name: "test15",
|
||||
},
|
||||
{
|
||||
// 16. Autoplay should override preload:metadata.
|
||||
@ -482,7 +512,7 @@ var tests = [
|
||||
var v = e.target;
|
||||
maybeFinish(v, 16);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v.preload = "metadata";
|
||||
@ -491,6 +521,8 @@ var tests = [
|
||||
v.src = test.name; // Causes implicit load.
|
||||
document.body.appendChild(v);
|
||||
},
|
||||
|
||||
name: "test16",
|
||||
},
|
||||
{
|
||||
// 17. On a preload:none video, adding autoplay should disable preload none, i.e. don't break autoplay!
|
||||
@ -500,7 +532,7 @@ var tests = [
|
||||
var v = e.target;
|
||||
maybeFinish(v, 17);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v.addEventListener("ended", this.ended, false);
|
||||
@ -508,7 +540,9 @@ var tests = [
|
||||
document.body.appendChild(v); // Causes implicit load, which will be halted due to preload:none.
|
||||
v.autoplay = true;
|
||||
v.src = test.name;
|
||||
},
|
||||
},
|
||||
|
||||
name: "test17",
|
||||
},
|
||||
{
|
||||
// 18. On a preload='none' video, call play() before load algorithms's sync
|
||||
@ -519,7 +553,7 @@ var tests = [
|
||||
var v = e.target;
|
||||
maybeFinish(v, 18);
|
||||
},
|
||||
|
||||
|
||||
setup:
|
||||
function(v) {
|
||||
v.addEventListener("ended", this.ended, false);
|
||||
@ -527,7 +561,9 @@ var tests = [
|
||||
v.src = test.name; // Schedules async section to continue load algorithm.
|
||||
document.body.appendChild(v);
|
||||
v.play(); // Should cause preload:none to be overridden.
|
||||
},
|
||||
},
|
||||
|
||||
name: "test18",
|
||||
},
|
||||
{
|
||||
// 19. Set preload='auto' on first video source then switching preload='none' and swapping the video source to another.
|
||||
@ -555,7 +591,9 @@ var tests = [
|
||||
// add a listener for when the video has loaded, so we know preload auto has worked
|
||||
v.addEventListener( "loadedmetadata", this.loadedmetadata, false);
|
||||
document.body.appendChild(v);
|
||||
}
|
||||
},
|
||||
|
||||
name: "test19",
|
||||
}
|
||||
];
|
||||
|
||||
@ -563,6 +601,7 @@ var iterationCount = 0;
|
||||
function startTest(test, token) {
|
||||
if (test == tests[0]) {
|
||||
++iterationCount;
|
||||
info("iterationCount=" + iterationCount);
|
||||
}
|
||||
if (iterationCount == 2) {
|
||||
// Do this series of tests on logically different resources
|
||||
|
@ -28,12 +28,20 @@ function checkComplete() {
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
function removeNode(v) {
|
||||
v.removeEventListener("error", loadError, false);
|
||||
v.removeEventListener("loadedmetadata", loadedMetadata, false);
|
||||
v.remove();
|
||||
v.src = "";
|
||||
}
|
||||
|
||||
function loadError(evt) {
|
||||
// If no referer is sent then the sjs returns an error
|
||||
ok(false, "check referer is sent with media request");
|
||||
evt.target._complete = true;
|
||||
checkComplete();
|
||||
removeNode(evt.target);
|
||||
}
|
||||
|
||||
function loadedMetadata(evt) {
|
||||
@ -41,6 +49,7 @@ function loadedMetadata(evt) {
|
||||
ok(true, "check referer is sent with media request");
|
||||
evt.target._complete = true;
|
||||
checkComplete();
|
||||
removeNode(evt.target);
|
||||
}
|
||||
|
||||
// Create all media objects.
|
||||
@ -56,6 +65,8 @@ for (var i=0; i<gSmallTests.length; ++i) {
|
||||
if (!v.canPlayType(test.type)) {
|
||||
continue;
|
||||
}
|
||||
// ensure metadata is loaded for default preload is none on b2g
|
||||
v.preload = "metadata";
|
||||
v._complete = false;
|
||||
v.addEventListener("error", loadError, false);
|
||||
v.addEventListener("loadedmetadata", loadedMetadata, false);
|
||||
|
@ -17,7 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=833386
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true],
|
||||
["media.webvtt.regions.enabled", true]]},
|
||||
function() {
|
||||
var video = document.createElement("video");
|
||||
video.src = "seek.webm";
|
||||
|
@ -17,7 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=917945
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true],
|
||||
["media.webvtt.regions.enabled", true]]},
|
||||
function() {
|
||||
var video = document.createElement("video");
|
||||
video.src = "seek.webm";
|
||||
|
@ -25,7 +25,16 @@ interface nsIRilMobileMessageDatabaseRecordCallback : nsISupports
|
||||
void notify(in nsresult aRv, in jsval aMessageRecord, in nsISupports aDomMessage);
|
||||
};
|
||||
|
||||
[scriptable, uuid(596ef782-9f7a-11e3-8508-ff3a7d599531)]
|
||||
[scriptable, function, uuid(1b0ff03c-a2bc-11e3-a443-838d034c9805)]
|
||||
interface nsIRilMobileMessageDatabaseConcatenationCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* |aCompleteMessage|: jsval: the completely concatenated message. Noted, this value might be null.
|
||||
*/
|
||||
void notify(in nsresult aRv, in jsval aCompleteMessage);
|
||||
};
|
||||
|
||||
[scriptable, uuid(0b437a5c-a2bc-11e3-bd1b-dbb173eb35f8)]
|
||||
interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
|
||||
{
|
||||
/**
|
||||
@ -126,4 +135,12 @@ interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
|
||||
* @returns the error code defined in nsIMobileMessageCallback
|
||||
*/
|
||||
jsval translateCrErrorToMessageCallbackError(in nsresult aCrError);
|
||||
|
||||
/**
|
||||
* |aSmsSegment| jsval: Decoded Single SMS PDU.
|
||||
* |aCallback| nsIRilMobileMessageDatabaseConcatenationCallback: a callback which
|
||||
* takes result flag, and complete mesage as parameters.
|
||||
*/
|
||||
void saveSmsSegment(in jsval aSmsSegment,
|
||||
in nsIRilMobileMessageDatabaseConcatenationCallback aCallback);
|
||||
};
|
||||
|
@ -23,11 +23,12 @@ const DEBUG = false;
|
||||
const DISABLE_MMS_GROUPING_FOR_RECEIVING = true;
|
||||
|
||||
|
||||
const DB_VERSION = 21;
|
||||
const DB_VERSION = 22;
|
||||
const MESSAGE_STORE_NAME = "sms";
|
||||
const THREAD_STORE_NAME = "thread";
|
||||
const PARTICIPANT_STORE_NAME = "participant";
|
||||
const MOST_RECENT_STORE_NAME = "most-recent";
|
||||
const SMS_SEGMENT_STORE_NAME = "sms-segment";
|
||||
|
||||
const DELIVERY_SENDING = "sending";
|
||||
const DELIVERY_SENT = "sent";
|
||||
@ -240,6 +241,10 @@ MobileMessageDB.prototype = {
|
||||
self.upgradeSchema20(event.target.transaction, next);
|
||||
break;
|
||||
case 21:
|
||||
if (DEBUG) debug("Upgrade to version 22. Add sms-segment store.");
|
||||
self.upgradeSchema21(db, event.target.transaction, next);
|
||||
break;
|
||||
case 22:
|
||||
// This will need to be moved for each new version
|
||||
if (DEBUG) debug("Upgrade finished.");
|
||||
break;
|
||||
@ -1344,6 +1349,65 @@ MobileMessageDB.prototype = {
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Add smsSegmentStore to store uncomplete SMS segments.
|
||||
*/
|
||||
upgradeSchema21: function(db, transaction, next) {
|
||||
/**
|
||||
* This smsSegmentStore is used to store uncomplete SMS segments.
|
||||
* Each entry looks like this:
|
||||
*
|
||||
* {
|
||||
* [Common fields in SMS segment]
|
||||
* messageType: <Number>,
|
||||
* teleservice: <Number>,
|
||||
* SMSC: <String>,
|
||||
* sentTimestamp: <Number>,
|
||||
* timestamp: <Number>,
|
||||
* sender: <String>,
|
||||
* pid: <Number>,
|
||||
* encoding: <Number>,
|
||||
* messageClass: <String>,
|
||||
* iccId: <String>,
|
||||
*
|
||||
* [Concatenation Info]
|
||||
* segmentRef: <Number>,
|
||||
* segmentSeq: <Number>,
|
||||
* segmentMaxSeq: <Number>,
|
||||
*
|
||||
* [Application Port Info]
|
||||
* originatorPort: <Number>,
|
||||
* destinationPort: <Number>,
|
||||
*
|
||||
* [MWI status]
|
||||
* mwiPresent: <Boolean>,
|
||||
* mwiDiscard: <Boolean>,
|
||||
* mwiMsgCount: <Number>,
|
||||
* mwiActive: <Boolean>,
|
||||
*
|
||||
* [CDMA Cellbroadcast related fields]
|
||||
* serviceCategory: <Number>,
|
||||
* language: <String>,
|
||||
*
|
||||
* [Message Body]
|
||||
* data: <Uint8Array>, (available if it's 8bit encoding)
|
||||
* body: <String>, (normal text body)
|
||||
*
|
||||
* [Handy fields created by DB for concatenation]
|
||||
* id: <Number>, keypath of this objectStore.
|
||||
* hash: <String>, Use to identify the segments to the same SMS.
|
||||
* receivedSegments: <Number>,
|
||||
* segments: []
|
||||
* }
|
||||
*
|
||||
*/
|
||||
let smsSegmentStore = db.createObjectStore(SMS_SEGMENT_STORE_NAME,
|
||||
{ keyPath: "id",
|
||||
autoIncrement: true });
|
||||
smsSegmentStore.createIndex("hash", "hash", { unique: true });
|
||||
next();
|
||||
},
|
||||
|
||||
matchParsedPhoneNumbers: function(addr1, parsedAddr1, addr2, parsedAddr2) {
|
||||
if ((parsedAddr1.internationalNumber &&
|
||||
parsedAddr1.internationalNumber === parsedAddr2.internationalNumber) ||
|
||||
@ -2428,6 +2492,128 @@ MobileMessageDB.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
saveSmsSegment: function(aSmsSegment, aCallback) {
|
||||
let completeMessage = null;
|
||||
this.newTxn(READ_WRITE, function(error, txn, segmentStore) {
|
||||
if (error) {
|
||||
if (DEBUG) debug(error);
|
||||
aCallback.notify(error, null);
|
||||
return;
|
||||
}
|
||||
|
||||
txn.oncomplete = function oncomplete(event) {
|
||||
if (DEBUG) debug("Transaction " + txn + " completed.");
|
||||
if (completeMessage) {
|
||||
// Rebuild full body
|
||||
if (completeMessage.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
// Uint8Array doesn't have `concat`, so
|
||||
// we have to merge all segements by hand.
|
||||
let fullDataLen = 0;
|
||||
for (let i = 1; i <= completeMessage.segmentMaxSeq; i++) {
|
||||
fullDataLen += completeMessage.segments[i].length;
|
||||
}
|
||||
|
||||
completeMessage.fullData = new Uint8Array(fullDataLen);
|
||||
for (let d = 0, i = 1; i <= completeMessage.segmentMaxSeq; i++) {
|
||||
let data = completeMessage.segments[i];
|
||||
for (let j = 0; j < data.length; j++) {
|
||||
completeMessage.fullData[d++] = data[j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completeMessage.fullBody = completeMessage.segments.join("");
|
||||
}
|
||||
|
||||
// Remove handy fields after completing the concatenation.
|
||||
delete completeMessage.id;
|
||||
delete completeMessage.hash;
|
||||
delete completeMessage.receivedSegments;
|
||||
delete completeMessage.segments;
|
||||
}
|
||||
aCallback.notify(Cr.NS_OK, completeMessage);
|
||||
};
|
||||
|
||||
txn.onabort = function onerror(event) {
|
||||
if (DEBUG) debug("Caught error on transaction", event.target.errorCode);
|
||||
aCallback.notify(Cr.NS_ERROR_FAILURE, null, null);
|
||||
};
|
||||
|
||||
aSmsSegment.hash = aSmsSegment.sender + ":" +
|
||||
aSmsSegment.segmentRef + ":" +
|
||||
aSmsSegment.segmentMaxSeq + ":" +
|
||||
aSmsSegment.iccId;
|
||||
let seq = aSmsSegment.segmentSeq;
|
||||
if (DEBUG) {
|
||||
debug("Saving SMS Segment: " + aSmsSegment.hash + ", seq: " + seq);
|
||||
}
|
||||
let getRequest = segmentStore.index("hash").get(aSmsSegment.hash);
|
||||
getRequest.onsuccess = function(event) {
|
||||
let segmentRecord = event.target.result;
|
||||
if (!segmentRecord) {
|
||||
if (DEBUG) {
|
||||
debug("Not found! Create a new record to store the segments.");
|
||||
}
|
||||
aSmsSegment.receivedSegments = 1;
|
||||
aSmsSegment.segments = [];
|
||||
if (aSmsSegment.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
aSmsSegment.segments[seq] = aSmsSegment.data;
|
||||
} else {
|
||||
aSmsSegment.segments[seq] = aSmsSegment.body;
|
||||
}
|
||||
|
||||
segmentStore.add(aSmsSegment);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
debug("Append SMS Segment into existed message object: " + segmentRecord.id);
|
||||
}
|
||||
|
||||
if (segmentRecord.segments[seq]) {
|
||||
if (DEBUG) debug("Got duplicated segment no. " + seq);
|
||||
return;
|
||||
}
|
||||
|
||||
segmentRecord.timestamp = aSmsSegment.timestamp;
|
||||
|
||||
if (segmentRecord.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
segmentRecord.segments[seq] = aSmsSegment.data;
|
||||
} else {
|
||||
segmentRecord.segments[seq] = aSmsSegment.body;
|
||||
}
|
||||
segmentRecord.receivedSegments++;
|
||||
|
||||
// The port information is only available in 1st segment for CDMA WAP Push.
|
||||
// If the segments of a WAP Push are not received in sequence
|
||||
// (e.g., SMS with seq == 1 is not the 1st segment received by the device),
|
||||
// we have to retrieve the port information from 1st segment and
|
||||
// save it into the segmentRecord.
|
||||
if (aSmsSegment.teleservice === RIL.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP
|
||||
&& seq === 1) {
|
||||
if (aSmsSegment.originatorPort) {
|
||||
segmentRecord.originatorPort = aSmsSegment.originatorPort;
|
||||
}
|
||||
|
||||
if (aSmsSegment.destinationPort) {
|
||||
segmentRecord.destinationPort = aSmsSegment.destinationPort;
|
||||
}
|
||||
}
|
||||
|
||||
if (segmentRecord.receivedSegments < segmentRecord.segmentMaxSeq) {
|
||||
if (DEBUG) debug("Message is incomplete.");
|
||||
segmentStore.put(segmentRecord);
|
||||
return;
|
||||
}
|
||||
|
||||
completeMessage = segmentRecord;
|
||||
|
||||
// Delete Record in DB
|
||||
segmentStore.delete(segmentRecord.id);
|
||||
};
|
||||
}, [SMS_SEGMENT_STORE_NAME]);
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIMobileMessageDatabaseService API
|
||||
*/
|
||||
|
@ -99,6 +99,10 @@ MobileMessageDatabaseService.prototype = {
|
||||
return this.mmdb.translateCrErrorToMessageCallbackError(aCrError);
|
||||
},
|
||||
|
||||
saveSmsSegment: function(aSmsSegment, aCallback) {
|
||||
this.mmdb.saveSmsSegment(aSmsSegment, aCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIMobileMessageDatabaseService API
|
||||
*/
|
||||
|
@ -45,6 +45,31 @@ function ensureMobileMessage() {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for one named MobileMessageManager event.
|
||||
*
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
*
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
*
|
||||
* @param aEventName
|
||||
* A string event name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForManagerEvent(aEventName) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
manager.addEventListener(aEventName, function onevent(aEvent) {
|
||||
manager.removeEventListener(aEventName, onevent);
|
||||
|
||||
ok(true, "MobileMessageManager event '" + aEventName + "' got.");
|
||||
deferred.resolve(aEvent);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a SMS message to a single receiver. Resolve if it succeeds, reject
|
||||
* otherwise.
|
||||
@ -331,6 +356,9 @@ function sendTextSmsToEmulator(aFrom, aText) {
|
||||
/**
|
||||
* Send raw SMS TPDU to emulator.
|
||||
*
|
||||
* @param: aPdu
|
||||
* A hex string representing the whole SMS T-PDU.
|
||||
*
|
||||
* Fulfill params:
|
||||
* result -- an array of emulator response lines.
|
||||
*
|
||||
|
@ -44,3 +44,4 @@ qemu = true
|
||||
[test_mmdb_foreachmatchedmmsdeliveryinfo.js]
|
||||
[test_mmdb_full_storage.js]
|
||||
[test_replace_short_message_type.js]
|
||||
[test_mt_sms_concatenation.js]
|
||||
|
138
dom/mobilemessage/tests/marionette/test_mt_sms_concatenation.js
Normal file
138
dom/mobilemessage/tests/marionette/test_mt_sms_concatenation.js
Normal file
@ -0,0 +1,138 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const PDU_SMSC_NONE = "00"; // no SMSC Address
|
||||
|
||||
const PDU_FIRST_OCTET = "40"; // RP:no, UDHI:yes, SRI:no, MMS:no, MTI:SMS-DELIVER
|
||||
|
||||
const PDU_SENDER = "0A912143658709"; // +1234567890
|
||||
const SENDER = "+1234567890";
|
||||
|
||||
const PDU_PID_NORMAL = "00";
|
||||
|
||||
const PDU_DCS_NORMAL_UCS2 = "08";
|
||||
const PDU_DCS_CLASS0_UCS2 = "18";
|
||||
const PDU_DCS_NORMAL_8BIT = "04";
|
||||
const PDU_DCS_CLASS0_8BIT = "14";
|
||||
|
||||
const PDU_TIMESTAMP = "00101000000000"; // 2000/01/01
|
||||
|
||||
function byteValueToHexString(aValue) {
|
||||
let str = Number(aValue).toString(16).toUpperCase();
|
||||
return str.length == 1 ? "0" + str : str;
|
||||
}
|
||||
|
||||
let ref_num = 0;
|
||||
function buildTextPdus(aDcs) {
|
||||
ref_num++;
|
||||
|
||||
let IEI_CONCATE_1 = "0003" + byteValueToHexString(ref_num) + "0301";
|
||||
let IEI_CONCATE_2 = "0003" + byteValueToHexString(ref_num) + "0302";
|
||||
let IEI_CONCATE_3 = "0003" + byteValueToHexString(ref_num) + "0303";
|
||||
let PDU_UDL = "08"; // UDHL(1) + UDH(5) + UCS2 Char (2)
|
||||
let PDU_UDHL = "05";
|
||||
|
||||
let PDU_UD_A = "0041"; // "A"
|
||||
let PDU_UD_B = "0042"; // "B"
|
||||
let PDU_UD_C = "0043"; // "C"
|
||||
|
||||
let PDU_COMMON = PDU_SMSC_NONE + PDU_FIRST_OCTET + PDU_SENDER +
|
||||
PDU_PID_NORMAL + aDcs + PDU_TIMESTAMP + PDU_UDL + PDU_UDHL;
|
||||
|
||||
return [
|
||||
PDU_COMMON + IEI_CONCATE_1 + PDU_UD_A,
|
||||
PDU_COMMON + IEI_CONCATE_2 + PDU_UD_B,
|
||||
PDU_COMMON + IEI_CONCATE_3 + PDU_UD_C
|
||||
];
|
||||
}
|
||||
|
||||
function buildBinaryPdus(aDcs) {
|
||||
ref_num++;
|
||||
let IEI_PORT = "05040B8423F0";
|
||||
|
||||
let PDU_DATA1 = "C106316170706C69636174696F6E2F76" +
|
||||
"6E642E7761702E6D6D732D6D65737361" +
|
||||
"676500B131302E382E3133302E313800" +
|
||||
"AF84B4818C82986B4430595538595347" +
|
||||
"77464E446741416B4876736C58303141" +
|
||||
"41414141414141008D90890380310096" +
|
||||
"05EA4D4D53008A808E02024188058103" +
|
||||
"015F9083687474703A2F2F6D6D732E65";
|
||||
|
||||
let PDU_DATA2 = "6D6F6D652E6E65743A383030322F6B44" +
|
||||
"3059553859534777464E446741416B48" +
|
||||
"76736C583031414141414141414100";
|
||||
|
||||
let PDU_COMMON = PDU_SMSC_NONE + PDU_FIRST_OCTET + PDU_SENDER +
|
||||
PDU_PID_NORMAL + aDcs + PDU_TIMESTAMP;
|
||||
|
||||
function construstBinaryUserData(aBinaryData, aSeqNum) {
|
||||
let ieiConcat = "0003" + byteValueToHexString(ref_num) + "02" +
|
||||
byteValueToHexString(aSeqNum);
|
||||
|
||||
let udh = IEI_PORT + ieiConcat;
|
||||
let udhl = byteValueToHexString(udh.length / 2);
|
||||
let ud = udhl + udh + aBinaryData;
|
||||
let udl = byteValueToHexString(ud.length / 2);
|
||||
|
||||
return udl + ud;
|
||||
}
|
||||
|
||||
return [
|
||||
PDU_COMMON + construstBinaryUserData(PDU_DATA1, 1),
|
||||
PDU_COMMON + construstBinaryUserData(PDU_DATA2, 2)
|
||||
];
|
||||
}
|
||||
|
||||
function sendRawSmsAndWait(aPdus) {
|
||||
let promises = [];
|
||||
|
||||
promises.push(waitForManagerEvent("received"));
|
||||
for (let pdu of aPdus) {
|
||||
promises.push(sendRawSmsToEmulator(pdu));
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function verifyTextMessage(aMessage, aMessageClass) {
|
||||
is(aMessage.messageClass, aMessageClass, "SmsMessage class");
|
||||
is(aMessage.sender, SENDER, "SmsMessage sender");
|
||||
is(aMessage.body, "ABC", "SmsMessage body");
|
||||
}
|
||||
|
||||
function verifyBinaryMessage(aMessage) {
|
||||
is(aMessage.type, "mms", "MmsMessage type");
|
||||
is(aMessage.delivery, "not-downloaded", "MmsMessage delivery");
|
||||
|
||||
// remove duplicated M-Notification.ind for next test.
|
||||
return deleteMessagesById([aMessage.id]);
|
||||
}
|
||||
|
||||
function testText(aDcs, aClass) {
|
||||
log("testText(): aDcs = " + aDcs + ", aClass = " + aClass);
|
||||
return sendRawSmsAndWait(buildTextPdus(aDcs))
|
||||
.then((resolutions) => verifyTextMessage(resolutions[0].message, aClass));
|
||||
}
|
||||
|
||||
function testBinary(aDcs) {
|
||||
log("testBinary(): aDcs = " + aDcs);
|
||||
return sendRawSmsAndWait(buildBinaryPdus(aDcs))
|
||||
.then((resolutions) => verifyBinaryMessage(resolutions[0].message));
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{"set": [["dom.mms.retrieval_mode", "manual"]]},
|
||||
function startTest() {
|
||||
startTestCommon(function testCaseMain() {
|
||||
return Promise.resolve()
|
||||
.then(() => testText(PDU_DCS_NORMAL_UCS2, "normal"))
|
||||
.then(() => testText(PDU_DCS_CLASS0_UCS2, "class-0"))
|
||||
.then(() => testBinary(PDU_DCS_NORMAL_8BIT))
|
||||
.then(() => testBinary(PDU_DCS_CLASS0_8BIT));
|
||||
});
|
||||
}
|
||||
);
|
@ -1905,6 +1905,8 @@ function RadioInterface(aClientId, aWorkerMessenger) {
|
||||
this.portAddressedSmsApps = {};
|
||||
this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
|
||||
|
||||
this._receivedSmsSegmentsMap = {};
|
||||
|
||||
this._sntp = new Sntp(this.setClockBySntp.bind(this),
|
||||
Services.prefs.getIntPref("network.sntp.maxRetryCount"),
|
||||
Services.prefs.getIntPref("network.sntp.refreshPeriod"),
|
||||
@ -2207,13 +2209,8 @@ RadioInterface.prototype = {
|
||||
this.clientId, message);
|
||||
break;
|
||||
case "sms-received":
|
||||
let ackOk = this.handleSmsReceived(message);
|
||||
// Note: ACK has been done by modem for NEW_SMS_ON_SIM
|
||||
if (ackOk && message.simStatus === undefined) {
|
||||
this.workerMessenger.send("ackSMS", { result: RIL.PDU_FCS_OK });
|
||||
}
|
||||
return;
|
||||
case "broadcastsms-received":
|
||||
this.handleSmsMultipart(message);
|
||||
break;
|
||||
case "cellbroadcast-received":
|
||||
message.timestamp = Date.now();
|
||||
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
|
||||
@ -2719,9 +2716,9 @@ RadioInterface.prototype = {
|
||||
let options = {
|
||||
bearer: WAP.WDP_BEARER_GSM_SMS_GSM_MSISDN,
|
||||
sourceAddress: message.sender,
|
||||
sourcePort: message.header.originatorPort,
|
||||
sourcePort: message.originatorPort,
|
||||
destinationAddress: this.rilContext.iccInfo.msisdn,
|
||||
destinationPort: message.header.destinationPort,
|
||||
destinationPort: message.destinationPort,
|
||||
serviceId: this.clientId
|
||||
};
|
||||
WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length,
|
||||
@ -2767,23 +2764,7 @@ RadioInterface.prototype = {
|
||||
_smsHandledWakeLock: null,
|
||||
_smsHandledWakeLockTimer: null,
|
||||
|
||||
_releaseSmsHandledWakeLock: function() {
|
||||
if (DEBUG) this.debug("Releasing the CPU wake lock for handling SMS.");
|
||||
if (this._smsHandledWakeLockTimer) {
|
||||
this._smsHandledWakeLockTimer.cancel();
|
||||
}
|
||||
if (this._smsHandledWakeLock) {
|
||||
this._smsHandledWakeLock.unlock();
|
||||
this._smsHandledWakeLock = null;
|
||||
}
|
||||
},
|
||||
|
||||
portAddressedSmsApps: null,
|
||||
handleSmsReceived: function(message) {
|
||||
if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
|
||||
|
||||
// We need to acquire a CPU wake lock to avoid the system falling into
|
||||
// the sleep mode when the RIL handles the received SMS.
|
||||
_acquireSmsHandledWakeLock: function() {
|
||||
if (!this._smsHandledWakeLock) {
|
||||
if (DEBUG) this.debug("Acquiring a CPU wake lock for handling SMS.");
|
||||
this._smsHandledWakeLock = gPowerManagerService.newWakeLock("cpu");
|
||||
@ -2798,17 +2779,251 @@ RadioInterface.prototype = {
|
||||
.initWithCallback(this._releaseSmsHandledWakeLock.bind(this),
|
||||
SMS_HANDLED_WAKELOCK_TIMEOUT,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
// FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers
|
||||
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
message.fullData = new Uint8Array(message.fullData);
|
||||
_releaseSmsHandledWakeLock: function() {
|
||||
if (DEBUG) this.debug("Releasing the CPU wake lock for handling SMS.");
|
||||
if (this._smsHandledWakeLockTimer) {
|
||||
this._smsHandledWakeLockTimer.cancel();
|
||||
}
|
||||
if (this._smsHandledWakeLock) {
|
||||
this._smsHandledWakeLock.unlock();
|
||||
this._smsHandledWakeLock = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hash map for received multipart sms fragments. Messages are hashed with
|
||||
* its sender address and concatenation reference number. Three additional
|
||||
* attributes `segmentMaxSeq`, `receivedSegments`, `segments` are inserted.
|
||||
*/
|
||||
_receivedSmsSegmentsMap: null,
|
||||
|
||||
/**
|
||||
* Helper for processing received multipart SMS.
|
||||
*
|
||||
* @return null for handled segments, and an object containing full message
|
||||
* body/data once all segments are received.
|
||||
*/
|
||||
_processReceivedSmsSegment: function(aSegment) {
|
||||
|
||||
// Directly replace full message body for single SMS.
|
||||
if (!(aSegment.segmentMaxSeq && (aSegment.segmentMaxSeq > 1))) {
|
||||
if (aSegment.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
aSegment.fullData = aSegment.data;
|
||||
} else {
|
||||
aSegment.fullBody = aSegment.body;
|
||||
}
|
||||
return aSegment;
|
||||
}
|
||||
|
||||
// Handle Concatenation for Class 0 SMS
|
||||
let hash = aSegment.sender + ":" +
|
||||
aSegment.segmentRef + ":" +
|
||||
aSegment.segmentMaxSeq;
|
||||
let seq = aSegment.segmentSeq;
|
||||
|
||||
let options = this._receivedSmsSegmentsMap[hash];
|
||||
if (!options) {
|
||||
options = aSegment;
|
||||
this._receivedSmsSegmentsMap[hash] = options;
|
||||
|
||||
options.receivedSegments = 0;
|
||||
options.segments = [];
|
||||
} else if (options.segments[seq]) {
|
||||
// Duplicated segment?
|
||||
if (DEBUG) {
|
||||
this.debug("Got duplicated segment no." + seq +
|
||||
" of a multipart SMS: " + JSON.stringify(aSegment));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (options.receivedSegments > 0) {
|
||||
// Update received timestamp.
|
||||
options.timestamp = aSegment.timestamp;
|
||||
}
|
||||
|
||||
if (options.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
options.segments[seq] = aSegment.data;
|
||||
} else {
|
||||
options.segments[seq] = aSegment.body;
|
||||
}
|
||||
options.receivedSegments++;
|
||||
|
||||
// The port information is only available in 1st segment for CDMA WAP Push.
|
||||
// If the segments of a WAP Push are not received in sequence
|
||||
// (e.g., SMS with seq == 1 is not the 1st segment received by the device),
|
||||
// we have to retrieve the port information from 1st segment and
|
||||
// save it into the cached options.
|
||||
if (aSegment.teleservice === RIL.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP
|
||||
&& seq === 1) {
|
||||
if (!options.originatorPort && aSegment.originatorPort) {
|
||||
options.originatorPort = aSegment.originatorPort;
|
||||
}
|
||||
|
||||
if (!options.destinationPort && aSegment.destinationPort) {
|
||||
options.destinationPort = aSegment.destinationPort;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.receivedSegments < options.segmentMaxSeq) {
|
||||
if (DEBUG) {
|
||||
this.debug("Got segment no." + seq + " of a multipart SMS: " +
|
||||
JSON.stringify(options));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove from map
|
||||
delete this._receivedSmsSegmentsMap[hash];
|
||||
|
||||
// Rebuild full body
|
||||
if (options.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
// Uint8Array doesn't have `concat`, so we have to merge all segements
|
||||
// by hand.
|
||||
let fullDataLen = 0;
|
||||
for (let i = 1; i <= options.segmentMaxSeq; i++) {
|
||||
fullDataLen += options.segments[i].length;
|
||||
}
|
||||
|
||||
options.fullData = new Uint8Array(fullDataLen);
|
||||
for (let d= 0, i = 1; i <= options.segmentMaxSeq; i++) {
|
||||
let data = options.segments[i];
|
||||
for (let j = 0; j < data.length; j++) {
|
||||
options.fullData[d++] = data[j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
options.fullBody = options.segments.join("");
|
||||
}
|
||||
|
||||
// Remove handy fields after completing the concatenation.
|
||||
delete options.receivedSegments;
|
||||
delete options.segments;
|
||||
|
||||
if (DEBUG) {
|
||||
this.debug("Got full multipart SMS: " + JSON.stringify(options));
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper to create Savable SmsSegment.
|
||||
*/
|
||||
_createSavableSmsSegment: function(aMessage) {
|
||||
// We precisely define what data fields to be stored into
|
||||
// DB here for better data migration.
|
||||
let segment = {};
|
||||
segment.messageType = aMessage.messageType;
|
||||
segment.teleservice = aMessage.teleservice;
|
||||
segment.SMSC = aMessage.SMSC;
|
||||
segment.sentTimestamp = aMessage.sentTimestamp;
|
||||
segment.timestamp = Date.now();
|
||||
segment.sender = aMessage.sender;
|
||||
segment.pid = aMessage.pid;
|
||||
segment.encoding = aMessage.encoding;
|
||||
segment.messageClass = aMessage.messageClass;
|
||||
segment.iccId = this.getIccId();
|
||||
if (aMessage.header) {
|
||||
segment.segmentRef = aMessage.header.segmentRef;
|
||||
segment.segmentSeq = aMessage.header.segmentSeq;
|
||||
segment.segmentMaxSeq = aMessage.header.segmentMaxSeq;
|
||||
segment.originatorPort = aMessage.header.originatorPort;
|
||||
segment.destinationPort = aMessage.header.destinationPort;
|
||||
}
|
||||
segment.mwiPresent = (aMessage.mwi)? true: false;
|
||||
segment.mwiDiscard = (segment.mwiPresent)? aMessage.mwi.discard: false;
|
||||
segment.mwiMsgCount = (segment.mwiPresent)? aMessage.mwi.msgCount: 0;
|
||||
segment.mwiActive = (segment.mwiPresent)? aMessage.mwi.active: false;
|
||||
segment.serviceCategory = aMessage.serviceCategory;
|
||||
segment.language = aMessage.language;
|
||||
segment.data = aMessage.data;
|
||||
segment.body = aMessage.body;
|
||||
|
||||
return segment;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper to purge complete message.
|
||||
*
|
||||
* We remove unnessary fields defined in _createSavableSmsSegment() after
|
||||
* completing the concatenation.
|
||||
*/
|
||||
_purgeCompleteSmsMessage: function(aMessage) {
|
||||
// Purge concatenation info
|
||||
delete aMessage.segmentRef;
|
||||
delete aMessage.segmentSeq;
|
||||
delete aMessage.segmentMaxSeq;
|
||||
|
||||
// Purge partial message body
|
||||
delete aMessage.data;
|
||||
delete aMessage.body;
|
||||
},
|
||||
|
||||
/**
|
||||
* handle concatenation of received SMS.
|
||||
*/
|
||||
handleSmsMultipart: function(aMessage) {
|
||||
if (DEBUG) this.debug("handleSmsMultipart: " + JSON.stringify(aMessage));
|
||||
|
||||
this._acquireSmsHandledWakeLock();
|
||||
|
||||
let segment = this._createSavableSmsSegment(aMessage);
|
||||
|
||||
let isMultipart = (segment.segmentMaxSeq && (segment.segmentMaxSeq > 1));
|
||||
let messageClass = segment.messageClass;
|
||||
|
||||
let handleReceivedAndAck = function(aRvOfIncompleteMsg, aCompleteMessage) {
|
||||
if (aCompleteMessage) {
|
||||
this._purgeCompleteSmsMessage(aCompleteMessage);
|
||||
if (this.handleSmsReceived(aCompleteMessage)) {
|
||||
this.sendAckSms(Cr.NS_OK, aCompleteMessage);
|
||||
}
|
||||
// else Ack will be sent after further process in handleSmsReceived.
|
||||
} else {
|
||||
this.sendAckSms(aRvOfIncompleteMsg, segment);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
// No need to access SmsSegmentStore for Class 0 SMS and Single SMS.
|
||||
if (!isMultipart ||
|
||||
(messageClass == RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0])) {
|
||||
// `When a mobile terminated message is class 0 and the MS has the
|
||||
// capability of displaying short messages, the MS shall display the
|
||||
// message immediately and send an acknowledgement to the SC when the
|
||||
// message has successfully reached the MS irrespective of whether
|
||||
// there is memory available in the (U)SIM or ME. The message shall
|
||||
// not be automatically stored in the (U)SIM or ME.`
|
||||
// ~ 3GPP 23.038 clause 4
|
||||
|
||||
handleReceivedAndAck(Cr.NS_OK, // ACK OK For Incomplete Class 0
|
||||
this._processReceivedSmsSegment(segment));
|
||||
} else {
|
||||
gMobileMessageDatabaseService
|
||||
.saveSmsSegment(segment, function notifyResult(aRv, aCompleteMessage) {
|
||||
handleReceivedAndAck(aRv, // Ack according to the result after saving
|
||||
aCompleteMessage);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
portAddressedSmsApps: null,
|
||||
handleSmsReceived: function(message) {
|
||||
if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
|
||||
|
||||
if (message.messageType == RIL.PDU_CDMA_MSG_TYPE_BROADCAST) {
|
||||
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
|
||||
this.clientId, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dispatch to registered handler if application port addressing is
|
||||
// available. Note that the destination port can possibly be zero when
|
||||
// representing a UDP/TCP port.
|
||||
if (message.header && message.header.destinationPort != null) {
|
||||
let handler = this.portAddressedSmsApps[message.header.destinationPort];
|
||||
if (message.destinationPort != null) {
|
||||
let handler = this.portAddressedSmsApps[message.destinationPort];
|
||||
if (handler) {
|
||||
handler(message);
|
||||
}
|
||||
@ -2824,8 +3039,6 @@ RadioInterface.prototype = {
|
||||
message.sender = message.sender || null;
|
||||
message.receiver = this.getPhoneNumber();
|
||||
message.body = message.fullBody = message.fullBody || null;
|
||||
message.timestamp = Date.now();
|
||||
message.iccId = this.getIccId();
|
||||
|
||||
if (gSmsService.isSilentNumber(message.sender)) {
|
||||
message.id = -1;
|
||||
@ -2855,8 +3068,14 @@ RadioInterface.prototype = {
|
||||
return true;
|
||||
}
|
||||
|
||||
let mwi = message.mwi;
|
||||
if (mwi) {
|
||||
if (message.mwiPresent) {
|
||||
let mwi = {
|
||||
discard: message.mwiDiscard,
|
||||
msgCount: message.mwiMsgCount,
|
||||
active: message.mwiActive
|
||||
};
|
||||
this.workerMessenger.send("updateMwis", { mwi: mwi });
|
||||
|
||||
mwi.returnNumber = message.sender;
|
||||
mwi.returnMessage = message.fullBody;
|
||||
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
|
||||
@ -2864,7 +3083,7 @@ RadioInterface.prototype = {
|
||||
|
||||
// Dicarded MWI comes without text body.
|
||||
// Hence, we discard it here after notifying the MWI status.
|
||||
if (mwi.discard) {
|
||||
if (message.mwiDiscard) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2872,14 +3091,7 @@ RadioInterface.prototype = {
|
||||
let notifyReceived = function notifyReceived(rv, domMessage) {
|
||||
let success = Components.isSuccessCode(rv);
|
||||
|
||||
// Acknowledge the reception of the SMS.
|
||||
// Note: Ack has been done by modem for NEW_SMS_ON_SIM
|
||||
if (message.simStatus === undefined) {
|
||||
this.workerMessenger.send("ackSMS", {
|
||||
result: (success ? RIL.PDU_FCS_OK
|
||||
: RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED)
|
||||
});
|
||||
}
|
||||
this.sendAckSms(rv, message);
|
||||
|
||||
if (!success) {
|
||||
// At this point we could send a message to content to notify the user
|
||||
@ -2926,6 +3138,26 @@ RadioInterface.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle ACK response of received SMS.
|
||||
*/
|
||||
sendAckSms: function(aRv, aMessage) {
|
||||
if (aMessage.messageClass === RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_2]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = RIL.PDU_FCS_OK;
|
||||
if (!Components.isSuccessCode(aRv)) {
|
||||
if (DEBUG) this.debug("Failed to handle received sms: " + aRv);
|
||||
result = (aRv === Cr.NS_ERROR_FILE_NO_DEVICE_SPACE)
|
||||
? RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED
|
||||
: RIL.PDU_FCS_UNSPECIFIED;
|
||||
}
|
||||
|
||||
this.workerMessenger.send("ackSMS", { result: result });
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the setting value of "time.clock.automatic-update.available".
|
||||
*/
|
||||
|
@ -213,7 +213,6 @@ function RilObject(aContext) {
|
||||
this.currentCalls = {};
|
||||
this.currentConference = {state: null, participants: {}};
|
||||
this.currentDataCalls = {};
|
||||
this._receivedSmsSegmentsMap = {};
|
||||
this._pendingSentSmsMap = {};
|
||||
this.pendingNetworkType = {};
|
||||
this._receivedSmsCbPagesMap = {};
|
||||
@ -243,13 +242,6 @@ RilObject.prototype = {
|
||||
*/
|
||||
currentDataCalls: null,
|
||||
|
||||
/**
|
||||
* Hash map for received multipart sms fragments. Messages are hashed with
|
||||
* its sender address and concatenation reference number. Three additional
|
||||
* attributes `segmentMaxSeq`, `receivedSegments`, `segments` are inserted.
|
||||
*/
|
||||
_receivedSmsSegmentsMap: null,
|
||||
|
||||
/**
|
||||
* Outgoing messages waiting for SMS-STATUS-REPORT.
|
||||
*/
|
||||
@ -378,7 +370,7 @@ RilObject.prototype = {
|
||||
this.deactivateDataCall(datacall);
|
||||
}
|
||||
|
||||
// Don't clean up this._receivedSmsSegmentsMap or this._pendingSentSmsMap
|
||||
// Don't clean up this._pendingSentSmsMap
|
||||
// because on rild restart: we may continue with the pending segments.
|
||||
|
||||
/**
|
||||
@ -1814,6 +1806,15 @@ RilObject.prototype = {
|
||||
Buf.sendParcel();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update received MWI into EF_MWIS.
|
||||
*/
|
||||
updateMwis: function(options) {
|
||||
if (this.context.ICCUtilsHelper.isICCServiceAvailable("MWIS")) {
|
||||
this.context.SimRecordHelper.updateMWIS(options.mwi);
|
||||
}
|
||||
},
|
||||
|
||||
setCellBroadcastDisabled: function(options) {
|
||||
this.cellBroadcastDisabled = options.disabled;
|
||||
|
||||
@ -4396,55 +4397,19 @@ RilObject.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper for processing multipart SMS.
|
||||
* Helper to delegate the received sms segment to RadioInterface to process.
|
||||
*
|
||||
* @param message
|
||||
* Received sms message.
|
||||
*
|
||||
* @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22.
|
||||
* @return MOZ_FCS_WAIT_FOR_EXPLICIT_ACK
|
||||
*/
|
||||
_processSmsMultipart: function(message) {
|
||||
if (message.header && message.header.segmentMaxSeq &&
|
||||
(message.header.segmentMaxSeq > 1)) {
|
||||
message = this._processReceivedSmsSegment(message);
|
||||
} else {
|
||||
if (message.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
message.fullData = message.data;
|
||||
delete message.data;
|
||||
} else {
|
||||
message.fullBody = message.body;
|
||||
delete message.body;
|
||||
}
|
||||
}
|
||||
message.rilMessageType = "sms-received";
|
||||
|
||||
if (message) {
|
||||
message.result = PDU_FCS_OK;
|
||||
if (message.messageClass == GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]) {
|
||||
// `MS shall ensure that the message has been to the SMS data field in
|
||||
// the (U)SIM before sending an ACK to the SC.` ~ 3GPP 23.038 clause 4
|
||||
message.result = PDU_FCS_RESERVED;
|
||||
}
|
||||
this.sendChromeMessage(message);
|
||||
|
||||
if (message.messageType == PDU_CDMA_MSG_TYPE_BROADCAST) {
|
||||
message.rilMessageType = "broadcastsms-received";
|
||||
} else {
|
||||
message.rilMessageType = "sms-received";
|
||||
}
|
||||
|
||||
this.sendChromeMessage(message);
|
||||
|
||||
// Update MWI Status into ICC if present.
|
||||
if (message.mwi &&
|
||||
this.context.ICCUtilsHelper.isICCServiceAvailable("MWIS")) {
|
||||
this.context.SimRecordHelper.updateMWIS(message.mwi);
|
||||
}
|
||||
|
||||
// We will acknowledge receipt of the SMS after we try to store it
|
||||
// in the database.
|
||||
return MOZ_FCS_WAIT_FOR_EXPLICIT_ACK;
|
||||
}
|
||||
|
||||
return PDU_FCS_OK;
|
||||
return MOZ_FCS_WAIT_FOR_EXPLICIT_ACK;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -4603,95 +4568,6 @@ RilObject.prototype = {
|
||||
return this._processSmsMultipart(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper for processing received multipart SMS.
|
||||
*
|
||||
* @return null for handled segments, and an object containing full message
|
||||
* body/data once all segments are received.
|
||||
*/
|
||||
_processReceivedSmsSegment: function(original) {
|
||||
let hash = original.sender + ":" + original.header.segmentRef;
|
||||
let seq = original.header.segmentSeq;
|
||||
|
||||
let options = this._receivedSmsSegmentsMap[hash];
|
||||
if (!options) {
|
||||
options = original;
|
||||
this._receivedSmsSegmentsMap[hash] = options;
|
||||
|
||||
options.segmentMaxSeq = original.header.segmentMaxSeq;
|
||||
options.receivedSegments = 0;
|
||||
options.segments = [];
|
||||
} else if (options.segments[seq]) {
|
||||
// Duplicated segment?
|
||||
if (DEBUG) {
|
||||
this.context.debug("Got duplicated segment no." + seq +
|
||||
" of a multipart SMS: " + JSON.stringify(original));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
options.segments[seq] = original.data;
|
||||
delete original.data;
|
||||
} else {
|
||||
options.segments[seq] = original.body;
|
||||
delete original.body;
|
||||
}
|
||||
options.receivedSegments++;
|
||||
|
||||
// The port information is only available in 1st segment for CDMA WAP Push.
|
||||
// If the segments of a WAP Push are not received in sequence
|
||||
// (e.g., SMS with seq == 1 is not the 1st segment received by the device),
|
||||
// we have to retrieve the port information from 1st segment and
|
||||
// save it into the cached options.header.
|
||||
if (original.teleservice === PDU_CDMA_MSG_TELESERIVCIE_ID_WAP && seq === 1) {
|
||||
if (!options.header.originatorPort && original.header.originatorPort) {
|
||||
options.header.originatorPort = original.header.originatorPort;
|
||||
}
|
||||
|
||||
if (!options.header.destinationPort && original.header.destinationPort) {
|
||||
options.header.destinationPort = original.header.destinationPort;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.receivedSegments < options.segmentMaxSeq) {
|
||||
if (DEBUG) {
|
||||
this.context.debug("Got segment no." + seq + " of a multipart SMS: " +
|
||||
JSON.stringify(options));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove from map
|
||||
delete this._receivedSmsSegmentsMap[hash];
|
||||
|
||||
// Rebuild full body
|
||||
if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
// Uint8Array doesn't have `concat`, so we have to merge all segements
|
||||
// by hand.
|
||||
let fullDataLen = 0;
|
||||
for (let i = 1; i <= options.segmentMaxSeq; i++) {
|
||||
fullDataLen += options.segments[i].length;
|
||||
}
|
||||
|
||||
options.fullData = new Uint8Array(fullDataLen);
|
||||
for (let d= 0, i = 1; i <= options.segmentMaxSeq; i++) {
|
||||
let data = options.segments[i];
|
||||
for (let j = 0; j < data.length; j++) {
|
||||
options.fullData[d++] = data[j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
options.fullBody = options.segments.join("");
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
this.context.debug("Got full multipart SMS: " + JSON.stringify(options));
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper for processing sent multipart SMS.
|
||||
*/
|
||||
@ -7618,24 +7494,24 @@ GsmPDUHelperObject.prototype = {
|
||||
// D:DELIVER, DR:DELIVER-REPORT, S:SUBMIT, SR:SUBMIT-REPORT,
|
||||
// ST:STATUS-REPORT, C:COMMAND
|
||||
// M:Mandatory, O:Optional, X:Unavailable
|
||||
// D DR S SR ST C
|
||||
SMSC: null, // M M M M M M
|
||||
mti: null, // M M M M M M
|
||||
udhi: null, // M M O M M M
|
||||
sender: null, // M X X X X X
|
||||
recipient: null, // X X M X M M
|
||||
pid: null, // M O M O O M
|
||||
epid: null, // M O M O O M
|
||||
dcs: null, // M O M O O X
|
||||
mwi: null, // O O O O O O
|
||||
replace: false, // O O O O O O
|
||||
header: null, // M M O M M M
|
||||
body: null, // M O M O O O
|
||||
data: null, // M O M O O O
|
||||
timestamp: null, // M X X X X X
|
||||
status: null, // X X X X M X
|
||||
scts: null, // X X X M M X
|
||||
dt: null, // X X X X M X
|
||||
// D DR S SR ST C
|
||||
SMSC: null, // M M M M M M
|
||||
mti: null, // M M M M M M
|
||||
udhi: null, // M M O M M M
|
||||
sender: null, // M X X X X X
|
||||
recipient: null, // X X M X M M
|
||||
pid: null, // M O M O O M
|
||||
epid: null, // M O M O O M
|
||||
dcs: null, // M O M O O X
|
||||
mwi: null, // O O O O O O
|
||||
replace: false, // O O O O O O
|
||||
header: null, // M M O M M M
|
||||
body: null, // M O M O O O
|
||||
data: null, // M O M O O O
|
||||
sentTimestamp: null, // M X X X X X
|
||||
status: null, // X X X X M X
|
||||
scts: null, // X X X M M X
|
||||
dt: null, // X X X X M X
|
||||
};
|
||||
|
||||
// SMSC info
|
||||
@ -8904,7 +8780,7 @@ CdmaPDUHelperObject.prototype = {
|
||||
header: message.header,
|
||||
body: message.body,
|
||||
data: message.data,
|
||||
timestamp: message[PDU_CDMA_MSG_USERDATA_TIMESTAMP],
|
||||
sentTimestamp: message[PDU_CDMA_MSG_USERDATA_TIMESTAMP],
|
||||
language: message[PDU_CDMA_LANGUAGE_INDICATOR],
|
||||
status: null,
|
||||
scts: null,
|
||||
|
@ -2979,7 +2979,7 @@ add_test(function test_read_new_sms_on_sim() {
|
||||
do_check_eq("sms-received", postedMessage.rilMessageType);
|
||||
do_check_eq("+0123456789", postedMessage.SMSC);
|
||||
do_check_eq("+9876543210", postedMessage.sender);
|
||||
do_check_eq("How are you?", postedMessage.fullBody);
|
||||
do_check_eq("How are you?", postedMessage.body);
|
||||
}
|
||||
|
||||
do_test();
|
||||
|
@ -307,18 +307,11 @@ add_test(function test_processCdmaSmsWapPush() {
|
||||
do_check_eq(orig_address, postedMessage.sender);
|
||||
do_check_eq(0x23F0, postedMessage.header.originatorPort);
|
||||
do_check_eq(0x0B84, postedMessage.header.destinationPort);
|
||||
do_check_eq(fullDataHexString, bytesToHexString(postedMessage.fullData));
|
||||
do_check_eq(fullDataHexString, bytesToHexString(postedMessage.data));
|
||||
}
|
||||
|
||||
// Verify Single WAP PDU
|
||||
test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F"]);
|
||||
|
||||
// Verify Concatenated WAP PDUs
|
||||
test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F", "0F0E0D0C0B0A09080706050403020100"]);
|
||||
|
||||
// Verify Concatenated WAP PDUs received in reversed order.
|
||||
// Note: the port information is only available in 1st segment in CDMA WAP Push.
|
||||
test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F", "0F0E0D0C0B0A09080706050403020100"], true);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -1118,7 +1118,7 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"VTTCue",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"VTTRegion",
|
||||
{name: "VTTRegion", pref: "media.webvtt.regions.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"WaveShaperNode",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -32,6 +32,7 @@ interface VTTCue : EventTarget {
|
||||
attribute double startTime;
|
||||
attribute double endTime;
|
||||
attribute boolean pauseOnExit;
|
||||
[Pref="media.webvtt.regions.enabled"]
|
||||
attribute VTTRegion? region;
|
||||
attribute DirectionSetting vertical;
|
||||
attribute boolean snapToLines;
|
||||
|
@ -7,7 +7,7 @@
|
||||
* http://dev.w3.org/html5/webvtt/#extension-of-the-texttrack-interface-for-region-support
|
||||
*/
|
||||
|
||||
[Constructor, Pref="media.webvtt.enabled"]
|
||||
[Constructor, Func="TextTrackRegion::RegionsEnabled"]
|
||||
interface VTTRegion {
|
||||
[SetterThrows]
|
||||
attribute double width;
|
||||
|
@ -138,6 +138,7 @@ static const char *sExtensionNames[] = {
|
||||
"GL_ARB_half_float_pixel",
|
||||
"GL_EXT_frag_depth",
|
||||
"GL_OES_compressed_ETC1_RGB8_texture",
|
||||
"GL_EXT_draw_range_elements",
|
||||
nullptr
|
||||
};
|
||||
|
||||
@ -1073,6 +1074,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::draw_range_elements)) {
|
||||
SymLoadStruct imageSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElementsEXT", "DrawRangeElements", nullptr } },
|
||||
{ nullptr, { nullptr } },
|
||||
};
|
||||
|
||||
if (!LoadSymbols(&imageSymbols[0], trygl, prefix)) {
|
||||
NS_ERROR("GL supports draw_range_elements without supplying its functions.");
|
||||
|
||||
MarkUnsupported(GLFeature::draw_range_elements);
|
||||
mSymbols.fDrawRangeElements = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Load developer symbols, don't fail if we can't find them.
|
||||
SymLoadStruct auxSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
|
||||
|
@ -87,6 +87,7 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
|
||||
depth_texture,
|
||||
draw_buffers,
|
||||
draw_instanced,
|
||||
draw_range_elements,
|
||||
element_index_uint,
|
||||
ES2_compatibility,
|
||||
ES3_compatibility,
|
||||
@ -419,6 +420,7 @@ public:
|
||||
ARB_half_float_pixel,
|
||||
EXT_frag_depth,
|
||||
OES_compressed_ETC1_RGB8_texture,
|
||||
EXT_draw_range_elements,
|
||||
Extensions_Max,
|
||||
Extensions_End
|
||||
};
|
||||
@ -2228,6 +2230,17 @@ public:
|
||||
AfterGLDrawCall();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Feature draw_range_elements
|
||||
public:
|
||||
void fDrawRangeElements(GLenum mode, GLuint start, GLuint end,
|
||||
GLsizei count, GLenum type, const GLvoid* indices)
|
||||
{
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fDrawRangeElements);
|
||||
mSymbols.fDrawRangeElements(mode, start, end, count, type, indices);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Package XXX_framebuffer_blit
|
||||
@ -2698,7 +2711,7 @@ protected:
|
||||
// storage to support DebugMode on an arbitrary thread.
|
||||
static unsigned sCurrentGLContextTLS;
|
||||
#endif
|
||||
|
||||
|
||||
ScopedDeletePtr<GLBlitHelper> mBlitHelper;
|
||||
ScopedDeletePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
|
||||
ScopedDeletePtr<GLReadTexImageHelper> mReadTexImageHelper;
|
||||
|
@ -84,6 +84,15 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"draw_range_elements",
|
||||
120, // OpenGL version
|
||||
300, // OpenGL ES version
|
||||
{
|
||||
GLContext::EXT_draw_range_elements,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"element_index_uint",
|
||||
200, // OpenGL version
|
||||
|
@ -493,6 +493,10 @@ struct GLContextSymbols
|
||||
PFNGLOBJECTPTRLABEL fObjectPtrLabel;
|
||||
typedef void (GLAPIENTRY * PFNGLGETOBJECTPTRLABEL) (const GLvoid* ptr, GLsizei bufSize, GLsizei* length, GLchar* label);
|
||||
PFNGLGETOBJECTPTRLABEL fGetObjectPtrLabel;
|
||||
|
||||
// draw_range_elements
|
||||
typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTS) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
|
||||
PFNGLDRAWRANGEELEMENTS fDrawRangeElements;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -286,19 +286,15 @@ CopyableCanvasLayer::PaintWithOpacity(gfx::DrawTarget* aTarget,
|
||||
|
||||
DrawOptions options = DrawOptions(aOpacity, CompositionOp::OP_SOURCE);
|
||||
|
||||
// If content opaque, then save off current operator and set to source.
|
||||
// This ensures that alpha is not applied even if the source surface
|
||||
// has an alpha channel
|
||||
if (GetContentFlags() & CONTENT_OPAQUE) {
|
||||
options.mCompositionOp = CompositionOp::OP_SOURCE;
|
||||
}
|
||||
|
||||
if (aOperator != CompositionOp::OP_OVER) {
|
||||
options.mCompositionOp = aOperator;
|
||||
}
|
||||
|
||||
// XXX: This needs rewriting for acceptable performance using CoreGraphics.
|
||||
// Therefore - this ::PaintWithOpacity is currently not used
|
||||
Rect rect = Rect(0, 0, mBounds.width, mBounds.height);
|
||||
aTarget->FillRect(rect, pat, options);
|
||||
|
||||
if (aMaskSurface) {
|
||||
aTarget->MaskSurface(pat, aMaskSurface, Point(0, 0), options);
|
||||
}
|
||||
|
@ -79,10 +79,10 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
bool updated = false;
|
||||
{
|
||||
// Restrict drawTarget to a scope so that terminates before Unlock.
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
mBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
|
||||
if (drawTarget) {
|
||||
aLayer->UpdateTarget(drawTarget);
|
||||
nsRefPtr<gfxASurface> surface =
|
||||
mBuffer->AsTextureClientSurface()->GetAsSurface();
|
||||
if (surface) {
|
||||
aLayer->DeprecatedUpdateSurface(surface);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
@ -76,11 +76,12 @@ public:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!child->GetInvalidRegion().IsEmpty()) {
|
||||
ToClientLayer(child)->RenderLayer();
|
||||
|
||||
if (!ClientManager()->GetRepeatTransaction() &&
|
||||
!child->GetInvalidRegion().IsEmpty()) {
|
||||
child->Mutated();
|
||||
}
|
||||
|
||||
ToClientLayer(child)->RenderLayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,10 +194,10 @@ ClientLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
|
||||
|
||||
GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
|
||||
|
||||
if (!GetRoot()->GetInvalidRegion().IsEmpty()) {
|
||||
root->RenderLayer();
|
||||
if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) {
|
||||
GetRoot()->Mutated();
|
||||
}
|
||||
root->RenderLayer();
|
||||
|
||||
mThebesLayerCallback = nullptr;
|
||||
mThebesLayerCallbackData = nullptr;
|
||||
|
@ -51,6 +51,8 @@
|
||||
#endif
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/ipc/ProtocolTypes.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
|
||||
using namespace base;
|
||||
using namespace mozilla;
|
||||
@ -109,6 +111,11 @@ static void ReleaseCompositorThread()
|
||||
}
|
||||
}
|
||||
|
||||
static void SetThreadPriority()
|
||||
{
|
||||
hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorParent::StartUpWithExistingThread(MessageLoop* aMsgLoop,
|
||||
PlatformThreadId aThreadID)
|
||||
@ -162,6 +169,7 @@ bool CompositorParent::CreateThread()
|
||||
sCompositorThread = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -200,6 +208,8 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
|
||||
CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor,
|
||||
this, &mCompositorID));
|
||||
|
||||
CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(SetThreadPriority));
|
||||
|
||||
mRootLayerTreeID = AllocateLayerTreeId();
|
||||
sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
|
||||
|
||||
|
@ -30,8 +30,8 @@ class nsIWidget;
|
||||
// IID for the nsITheme interface
|
||||
// {b0f3efe9-0bd4-4f6b-8daa-0ec7f6006822}
|
||||
#define NS_ITHEME_IID \
|
||||
{ 0x2e49c679, 0x2130, 0x432c, \
|
||||
{ 0x92, 0xcb, 0xd4, 0x8e, 0x9a, 0xe2, 0x34, 0x75 } }
|
||||
{ 0x4440b5c7, 0xd8bd, 0x4d9c, \
|
||||
{ 0x9c, 0x3e, 0xa5, 0xe6, 0x26, 0x81, 0x10, 0xa0 } }
|
||||
// {D930E29B-6909-44e5-AB4B-AF10D6923705}
|
||||
#define NS_THEMERENDERER_CID \
|
||||
{ 0x9020805b, 0x14a3, 0x4125, \
|
||||
@ -63,8 +63,7 @@ public:
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIntRegion* aRegionToClear = nullptr) = 0;
|
||||
const nsRect& aDirtyRect) = 0;
|
||||
|
||||
/**
|
||||
* Get the computed CSS border for the widget, in pixels.
|
||||
|
18
hal/Hal.cpp
18
hal/Hal.cpp
@ -871,6 +871,12 @@ SetProcessPriority(int aPid,
|
||||
aBackgroundLRU));
|
||||
}
|
||||
|
||||
void
|
||||
SetCurrentThreadPriority(ThreadPriority aPriority)
|
||||
{
|
||||
PROXY_IF_SANDBOXED(SetCurrentThreadPriority(aPriority));
|
||||
}
|
||||
|
||||
// From HalTypes.h.
|
||||
const char*
|
||||
ProcessPriorityToString(ProcessPriority aPriority)
|
||||
@ -898,6 +904,18 @@ ProcessPriorityToString(ProcessPriority aPriority)
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
ThreadPriorityToString(ThreadPriority aPriority)
|
||||
{
|
||||
switch (aPriority) {
|
||||
case THREAD_PRIORITY_COMPOSITOR:
|
||||
return "COMPOSITOR";
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
// From HalTypes.h.
|
||||
const char*
|
||||
ProcessPriorityToString(ProcessPriority aPriority,
|
||||
|
@ -496,6 +496,13 @@ void SetProcessPriority(int aPid,
|
||||
hal::ProcessCPUPriority aCPUPriority,
|
||||
uint32_t aLRU = 0);
|
||||
|
||||
/**
|
||||
* Set the current thread's priority to appropriate platform-specific value for
|
||||
* given functionality. Instead of providing arbitrary priority numbers you
|
||||
* must specify a type of function like THREAD_PRIORITY_COMPOSITOR.
|
||||
*/
|
||||
void SetCurrentThreadPriority(hal::ThreadPriority aPriority);
|
||||
|
||||
/**
|
||||
* Register an observer for the FM radio.
|
||||
*/
|
||||
|
@ -99,6 +99,16 @@ enum ProcessCPUPriority {
|
||||
NUM_PROCESS_CPU_PRIORITY
|
||||
};
|
||||
|
||||
// Values that can be passed to hal::SetThreadPriority(). These should be
|
||||
// functional in nature, such as COMPOSITOR, instead of levels, like LOW/HIGH.
|
||||
// This allows us to tune our priority scheme for the system in one place such
|
||||
// that it makes sense holistically for the overall operating system. On gonk
|
||||
// or android we may want different priority schemes than on windows, etc.
|
||||
enum ThreadPriority {
|
||||
THREAD_PRIORITY_COMPOSITOR,
|
||||
NUM_THREAD_PRIORITY
|
||||
};
|
||||
|
||||
// Convert a ProcessPriority enum value (with an optional ProcessCPUPriority)
|
||||
// to a string. The strings returned by this function are statically
|
||||
// allocated; do not attempt to free one!
|
||||
@ -112,6 +122,14 @@ const char*
|
||||
ProcessPriorityToString(ProcessPriority aPriority,
|
||||
ProcessCPUPriority aCPUPriority);
|
||||
|
||||
// Convert a ThreadPriority enum value to a string. The strings returned by
|
||||
// this function are statically allocated; do not attempt to free one!
|
||||
//
|
||||
// If you pass an unknown process priority (or NUM_THREAD_PRIORITY), we
|
||||
// fatally assert in debug builds and otherwise return "???".
|
||||
const char *
|
||||
ThreadPriorityToString(ThreadPriority aPriority);
|
||||
|
||||
/**
|
||||
* Used by ModifyWakeLock
|
||||
*/
|
||||
|
20
hal/fallback/FallbackThreadPriority.cpp
Normal file
20
hal/fallback/FallbackThreadPriority.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Hal.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
SetCurrentThreadPriority(ThreadPriority aPriority)
|
||||
{
|
||||
HAL_LOG(("FallbackThreadPriority - SetCurrentThreadPriority(%d)\n",
|
||||
ThreadPriorityToString(aPriority)));
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // namespace mozilla
|
@ -27,6 +27,7 @@
|
||||
#include <sys/resource.h>
|
||||
#include <time.h>
|
||||
#include <asm/page.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
@ -38,6 +39,7 @@
|
||||
#include "hardware_legacy/vibrator.h"
|
||||
#include "hardware_legacy/power.h"
|
||||
#include "libdisplay/GonkDisplay.h"
|
||||
#include "utils/threads.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
|
||||
@ -1348,6 +1350,14 @@ SetNiceForPid(int aPid, int aNice)
|
||||
|
||||
int tid = static_cast<int>(tidlong);
|
||||
|
||||
// Do not set the priority of threads running with a real-time policy
|
||||
// as part of the bulk process adjustment. These threads need to run
|
||||
// at their specified priority in order to meet timing guarantees.
|
||||
int schedPolicy = sched_getscheduler(tid);
|
||||
if (schedPolicy == SCHED_FIFO || schedPolicy == SCHED_RR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
// Get and set the task's new priority.
|
||||
int origtaskpriority = getpriority(PRIO_PROCESS, tid);
|
||||
@ -1360,6 +1370,15 @@ SetNiceForPid(int aPid, int aNice)
|
||||
|
||||
int newtaskpriority =
|
||||
std::max(origtaskpriority - origProcPriority + aNice, aNice);
|
||||
|
||||
// Do not reduce priority of threads already running at priorities greater
|
||||
// than normal. These threads are likely special service threads that need
|
||||
// elevated priorities to process audio, display composition, etc.
|
||||
if (newtaskpriority > origtaskpriority &&
|
||||
origtaskpriority < ANDROID_PRIORITY_NORMAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
|
||||
|
||||
if (rv) {
|
||||
@ -1454,6 +1473,54 @@ SetProcessPriority(int aPid,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SetCurrentThreadPriority(ThreadPriority aPriority)
|
||||
{
|
||||
int policy = SCHED_OTHER;
|
||||
int priorityOrNice = ANDROID_PRIORITY_NORMAL;
|
||||
|
||||
switch(aPriority) {
|
||||
case THREAD_PRIORITY_COMPOSITOR:
|
||||
priorityOrNice = Preferences::GetInt("hal.gonk.compositor.rt_priority", 0);
|
||||
if (priorityOrNice >= sched_get_priority_min(SCHED_FIFO) &&
|
||||
priorityOrNice <= sched_get_priority_max(SCHED_FIFO)) {
|
||||
policy = SCHED_FIFO;
|
||||
} else {
|
||||
priorityOrNice = Preferences::GetInt("hal.gonk.compositor.nice",
|
||||
ANDROID_PRIORITY_URGENT_DISPLAY);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG("Unrecognized thread priority %d; Doing nothing", aPriority);
|
||||
return;
|
||||
}
|
||||
|
||||
int tid = gettid();
|
||||
int rv = 0;
|
||||
|
||||
// If a RT scheduler policy is used, then we must set the priority using
|
||||
// sched_setscheduler() and the sched_param.sched_priority value.
|
||||
if (policy == SCHED_FIFO || policy == SCHED_RR) {
|
||||
LOG("Setting thread %d to priority level %s; RT priority %d",
|
||||
tid, ThreadPriorityToString(aPriority), priorityOrNice);
|
||||
sched_param schedParam;
|
||||
schedParam.sched_priority = priorityOrNice;
|
||||
rv = sched_setscheduler(tid, policy, &schedParam);
|
||||
|
||||
// Otherwise priority is solely defined by the nice level, so use the
|
||||
// setpriority() function.
|
||||
} else {
|
||||
LOG("Setting thread %d to priority level %s; nice level %d",
|
||||
tid, ThreadPriorityToString(aPriority), priorityOrNice);
|
||||
rv = setpriority(PRIO_PROCESS, tid, priorityOrNice);
|
||||
}
|
||||
|
||||
if (rv) {
|
||||
LOG("Failed to set thread %d to priority level %s; error code %d",
|
||||
tid, ThreadPriorityToString(aPriority), rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FactoryReset()
|
||||
{
|
||||
|
@ -151,6 +151,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
'fallback/FallbackProcessPriority.cpp',
|
||||
'fallback/FallbackScreenPower.cpp',
|
||||
'fallback/FallbackSwitch.cpp',
|
||||
'fallback/FallbackThreadPriority.cpp',
|
||||
'fallback/FallbackTime.cpp',
|
||||
'fallback/FallbackWakeLocks.cpp',
|
||||
]
|
||||
|
@ -362,6 +362,12 @@ SetProcessPriority(int aPid,
|
||||
NS_RUNTIMEABORT("Only the main process may set processes' priorities.");
|
||||
}
|
||||
|
||||
void
|
||||
SetCurrentThreadPriority(ThreadPriority aPriority)
|
||||
{
|
||||
NS_RUNTIMEABORT("Only the main process may set thread priorities.");
|
||||
}
|
||||
|
||||
void
|
||||
EnableFMRadio(const hal::FMRadioSettings& aSettings)
|
||||
{
|
||||
|
@ -906,6 +906,11 @@ namespace JSC {
|
||||
return m_buffer.uncheckedSize();
|
||||
}
|
||||
|
||||
size_t allocSize() const
|
||||
{
|
||||
return m_buffer.allocSize();
|
||||
}
|
||||
|
||||
void ensureSpace(int insnSpace, int constSpace)
|
||||
{
|
||||
m_buffer.ensureSpace(insnSpace, constSpace);
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <stdarg.h>
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
#include "jit/IonSpewer.h"
|
||||
#include "js/RootingAPI.h"
|
||||
@ -63,6 +64,7 @@ namespace JSC {
|
||||
: m_buffer(m_inlineBuffer)
|
||||
, m_capacity(inlineCapacity)
|
||||
, m_size(0)
|
||||
, m_allocSize(0)
|
||||
, m_oom(false)
|
||||
{
|
||||
}
|
||||
@ -143,6 +145,11 @@ namespace JSC {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
size_t allocSize() const
|
||||
{
|
||||
return m_allocSize;
|
||||
}
|
||||
|
||||
bool oom() const
|
||||
{
|
||||
return m_oom;
|
||||
@ -159,7 +166,9 @@ namespace JSC {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* result = allocator->alloc(m_size, poolp, kind);
|
||||
m_allocSize = js::AlignBytes(m_size, sizeof(void *));
|
||||
|
||||
void* result = allocator->alloc(m_allocSize, poolp, kind);
|
||||
if (!result) {
|
||||
*poolp = NULL;
|
||||
return 0;
|
||||
@ -255,6 +264,7 @@ namespace JSC {
|
||||
char* m_buffer;
|
||||
size_t m_capacity;
|
||||
size_t m_size;
|
||||
size_t m_allocSize;
|
||||
bool m_oom;
|
||||
};
|
||||
|
||||
|
@ -66,38 +66,19 @@ public:
|
||||
LinkBuffer(MacroAssembler* masm, ExecutableAllocator* executableAllocator,
|
||||
ExecutablePool** poolp, bool* ok, CodeKind codeKind)
|
||||
{
|
||||
// LinkBuffer is only used by Yarr. MacroAssemblerCodeRef::release relies on this.
|
||||
MOZ_ASSERT(codeKind == REGEXP_CODE);
|
||||
m_codeKind = codeKind;
|
||||
m_code = executableAllocAndCopy(*masm, executableAllocator, poolp);
|
||||
m_executablePool = *poolp;
|
||||
m_size = masm->m_assembler.size(); // must come after call to executableAllocAndCopy()!
|
||||
m_allocSize = masm->m_assembler.allocSize();
|
||||
#ifndef NDEBUG
|
||||
m_completed = false;
|
||||
#endif
|
||||
*ok = !!m_code;
|
||||
}
|
||||
|
||||
LinkBuffer(CodeKind kind)
|
||||
: m_executablePool(NULL)
|
||||
, m_code(NULL)
|
||||
, m_size(0)
|
||||
, m_codeKind(kind)
|
||||
#ifndef NDEBUG
|
||||
, m_completed(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
LinkBuffer(uint8_t* ncode, size_t size, CodeKind kind)
|
||||
: m_executablePool(NULL)
|
||||
, m_code(ncode)
|
||||
, m_size(size)
|
||||
, m_codeKind(kind)
|
||||
#ifndef NDEBUG
|
||||
, m_completed(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
~LinkBuffer()
|
||||
{
|
||||
ASSERT(!m_executablePool || m_completed);
|
||||
@ -183,7 +164,8 @@ public:
|
||||
{
|
||||
performFinalization();
|
||||
|
||||
return CodeRef(m_code, m_executablePool, m_size);
|
||||
MOZ_ASSERT(m_allocSize >= m_size);
|
||||
return CodeRef(m_code, m_executablePool, m_allocSize);
|
||||
}
|
||||
CodeLocationLabel finalizeCodeAddendum()
|
||||
{
|
||||
@ -225,6 +207,7 @@ protected:
|
||||
ExecutablePool* m_executablePool;
|
||||
void* m_code;
|
||||
size_t m_size;
|
||||
size_t m_allocSize;
|
||||
CodeKind m_codeKind;
|
||||
#ifndef NDEBUG
|
||||
bool m_completed;
|
||||
|
@ -182,14 +182,14 @@ class MacroAssemblerCodeRef {
|
||||
public:
|
||||
MacroAssemblerCodeRef()
|
||||
: m_executablePool(NULL),
|
||||
m_size(0)
|
||||
m_allocSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
MacroAssemblerCodeRef(void* code, ExecutablePool* executablePool, size_t size)
|
||||
MacroAssemblerCodeRef(void* code, ExecutablePool* executablePool, size_t allocSize)
|
||||
: m_code(code)
|
||||
, m_executablePool(executablePool)
|
||||
, m_size(size)
|
||||
, m_allocSize(allocSize)
|
||||
{
|
||||
}
|
||||
|
||||
@ -201,22 +201,23 @@ public:
|
||||
|
||||
#if defined DEBUG && (defined WTF_CPU_X86 || defined WTF_CPU_X86_64)
|
||||
void *addr = m_code.executableAddress();
|
||||
memset(addr, 0xcc, m_size);
|
||||
memset(addr, 0xcc, m_allocSize);
|
||||
#endif
|
||||
m_executablePool->release();
|
||||
// MacroAssemblerCodeRef is only used by Yarr.
|
||||
m_executablePool->release(m_allocSize, REGEXP_CODE);
|
||||
m_executablePool = NULL;
|
||||
}
|
||||
|
||||
MacroAssemblerCodePtr code() const {
|
||||
return m_code;
|
||||
}
|
||||
size_t size() const {
|
||||
return m_size;
|
||||
size_t allocSize() const {
|
||||
return m_allocSize;
|
||||
}
|
||||
|
||||
MacroAssemblerCodePtr m_code;
|
||||
ExecutablePool* m_executablePool;
|
||||
size_t m_size;
|
||||
size_t m_allocSize;
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
@ -440,6 +440,7 @@ public:
|
||||
};
|
||||
|
||||
size_t size() const { return m_formatter.size(); }
|
||||
size_t allocSize() const { return m_formatter.allocSize(); }
|
||||
unsigned char *buffer() const { return m_formatter.buffer(); }
|
||||
bool oom() const { return m_formatter.oom(); }
|
||||
|
||||
@ -3867,6 +3868,7 @@ private:
|
||||
// Administrative methods:
|
||||
|
||||
size_t size() const { return m_buffer.size(); }
|
||||
size_t allocSize() const { return m_buffer.allocSize(); }
|
||||
unsigned char *buffer() const { return m_buffer.buffer(); }
|
||||
bool oom() const { return m_buffer.oom(); }
|
||||
bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
|
||||
|
@ -38,6 +38,11 @@ size_t ExecutableAllocator::largeAllocSize = 0;
|
||||
|
||||
ExecutablePool::~ExecutablePool()
|
||||
{
|
||||
MOZ_ASSERT(m_ionCodeBytes == 0);
|
||||
MOZ_ASSERT(m_baselineCodeBytes == 0);
|
||||
MOZ_ASSERT(m_regexpCodeBytes == 0);
|
||||
MOZ_ASSERT(m_otherCodeBytes == 0);
|
||||
|
||||
m_allocator->releasePoolPages(this);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ namespace JSC {
|
||||
|
||||
class ExecutableAllocator;
|
||||
|
||||
enum CodeKind { ION_CODE, BASELINE_CODE, REGEXP_CODE, OTHER_CODE };
|
||||
enum CodeKind { ION_CODE = 0, BASELINE_CODE, REGEXP_CODE, OTHER_CODE };
|
||||
|
||||
// These are reference-counted. A new one starts with a count of 1.
|
||||
class ExecutablePool {
|
||||
@ -130,6 +130,31 @@ public:
|
||||
if (--m_refCount == 0)
|
||||
js_delete(this);
|
||||
}
|
||||
void release(size_t n, CodeKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case ION_CODE:
|
||||
m_ionCodeBytes -= n;
|
||||
MOZ_ASSERT(m_ionCodeBytes < m_allocation.size); // Shouldn't underflow.
|
||||
break;
|
||||
case BASELINE_CODE:
|
||||
m_baselineCodeBytes -= n;
|
||||
MOZ_ASSERT(m_baselineCodeBytes < m_allocation.size);
|
||||
break;
|
||||
case REGEXP_CODE:
|
||||
m_regexpCodeBytes -= n;
|
||||
MOZ_ASSERT(m_regexpCodeBytes < m_allocation.size);
|
||||
break;
|
||||
case OTHER_CODE:
|
||||
m_otherCodeBytes -= n;
|
||||
MOZ_ASSERT(m_otherCodeBytes < m_allocation.size);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("bad code kind");
|
||||
}
|
||||
|
||||
release();
|
||||
}
|
||||
|
||||
ExecutablePool(ExecutableAllocator* allocator, Allocation a)
|
||||
: m_allocator(allocator), m_freePtr(a.pages), m_end(m_freePtr + a.size), m_allocation(a),
|
||||
@ -223,10 +248,11 @@ public:
|
||||
// pool; i.e. alloc() increments the count before returning the object.
|
||||
void* alloc(size_t n, ExecutablePool** poolp, CodeKind type)
|
||||
{
|
||||
// Round 'n' up to a multiple of word size; if all allocations are of
|
||||
// word sized quantities, then all subsequent allocations will be
|
||||
// Caller must ensure 'n' is word-size aligned. If all allocations are
|
||||
// of word sized quantities, then all subsequent allocations will be
|
||||
// aligned.
|
||||
n = roundUpAllocationSize(n, sizeof(void*));
|
||||
JS_ASSERT(roundUpAllocationSize(n, sizeof(void*)) == n);
|
||||
|
||||
if (n == OVERSIZE_ALLOCATION) {
|
||||
*poolp = NULL;
|
||||
return NULL;
|
||||
@ -347,7 +373,7 @@ public:
|
||||
ExecutablePool* pool = createPool(largeAllocSize);
|
||||
if (!pool)
|
||||
return NULL;
|
||||
// At this point, local |pool| is the owner.
|
||||
// At this point, local |pool| is the owner.
|
||||
|
||||
if (m_smallPools.length() < maxSmallPools) {
|
||||
// We haven't hit the maximum number of live pools; add the new pool.
|
||||
@ -373,7 +399,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Pass ownership to the caller.
|
||||
// Pass ownership to the caller.
|
||||
return pool;
|
||||
}
|
||||
|
||||
|
@ -615,25 +615,28 @@ JitRuntime::getVMWrapper(const VMFunction &f) const
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JitCode *
|
||||
JitCode::New(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool)
|
||||
JitCode::New(JSContext *cx, uint8_t *code, uint32_t bufferSize, uint32_t headerSize,
|
||||
JSC::ExecutablePool *pool, JSC::CodeKind kind)
|
||||
{
|
||||
JitCode *codeObj = js::NewJitCode<allowGC>(cx);
|
||||
if (!codeObj) {
|
||||
pool->release();
|
||||
pool->release(headerSize + bufferSize, kind);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
new (codeObj) JitCode(code, bufferSize, pool);
|
||||
new (codeObj) JitCode(code, bufferSize, headerSize, pool, kind);
|
||||
return codeObj;
|
||||
}
|
||||
|
||||
template
|
||||
JitCode *
|
||||
JitCode::New<CanGC>(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool);
|
||||
JitCode::New<CanGC>(JSContext *cx, uint8_t *code, uint32_t bufferSize, uint32_t headerSize,
|
||||
JSC::ExecutablePool *pool, JSC::CodeKind kind);
|
||||
|
||||
template
|
||||
JitCode *
|
||||
JitCode::New<NoGC>(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool);
|
||||
JitCode::New<NoGC>(JSContext *cx, uint8_t *code, uint32_t bufferSize, uint32_t headerSize,
|
||||
JSC::ExecutablePool *pool, JSC::CodeKind kind);
|
||||
|
||||
void
|
||||
JitCode::copyFrom(MacroAssembler &masm)
|
||||
@ -696,7 +699,7 @@ JitCode::finalize(FreeOp *fop)
|
||||
// Horrible hack: if we are using perf integration, we don't
|
||||
// want to reuse code addresses, so we just leak the memory instead.
|
||||
if (!PerfEnabled())
|
||||
pool_->release();
|
||||
pool_->release(headerSize_ + bufferSize_, JSC::CodeKind(kind_));
|
||||
pool_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "jsinfer.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "gc/Heap.h"
|
||||
#include "jit/IonOptimizationLevels.h"
|
||||
#include "jit/IonTypes.h"
|
||||
@ -37,13 +38,15 @@ class JitCode : public gc::BarrieredCell<JitCode>
|
||||
protected:
|
||||
uint8_t *code_;
|
||||
JSC::ExecutablePool *pool_;
|
||||
uint32_t bufferSize_; // Total buffer size.
|
||||
uint32_t bufferSize_; // Total buffer size. Does not include headerSize_.
|
||||
uint32_t insnSize_; // Instruction stream size.
|
||||
uint32_t dataSize_; // Size of the read-only data area.
|
||||
uint32_t jumpRelocTableBytes_; // Size of the jump relocation table.
|
||||
uint32_t dataRelocTableBytes_; // Size of the data relocation table.
|
||||
uint32_t preBarrierTableBytes_; // Size of the prebarrier table.
|
||||
bool invalidated_; // Whether the code object has been invalidated.
|
||||
uint8_t headerSize_ : 5; // Number of bytes allocated before codeStart.
|
||||
uint8_t kind_ : 3; // JSC::CodeKind, for the memory reporters.
|
||||
bool invalidated_ : 1; // Whether the code object has been invalidated.
|
||||
// This is necessary to prevent GC tracing.
|
||||
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
@ -55,7 +58,8 @@ class JitCode : public gc::BarrieredCell<JitCode>
|
||||
: code_(nullptr),
|
||||
pool_(nullptr)
|
||||
{ }
|
||||
JitCode(uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool)
|
||||
JitCode(uint8_t *code, uint32_t bufferSize, uint32_t headerSize, JSC::ExecutablePool *pool,
|
||||
JSC::CodeKind kind)
|
||||
: code_(code),
|
||||
pool_(pool),
|
||||
bufferSize_(bufferSize),
|
||||
@ -64,8 +68,13 @@ class JitCode : public gc::BarrieredCell<JitCode>
|
||||
jumpRelocTableBytes_(0),
|
||||
dataRelocTableBytes_(0),
|
||||
preBarrierTableBytes_(0),
|
||||
headerSize_(headerSize),
|
||||
kind_(kind),
|
||||
invalidated_(false)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(JSC::CodeKind(kind_) == kind);
|
||||
MOZ_ASSERT(headerSize_ == headerSize);
|
||||
}
|
||||
|
||||
uint32_t dataOffset() const {
|
||||
return insnSize_;
|
||||
@ -126,7 +135,8 @@ class JitCode : public gc::BarrieredCell<JitCode>
|
||||
// object can be allocated, nullptr is returned. On failure, |pool| is
|
||||
// automatically released, so the code may be freed.
|
||||
template <AllowGC allowGC>
|
||||
static JitCode *New(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool);
|
||||
static JitCode *New(JSContext *cx, uint8_t *code, uint32_t bufferSize, uint32_t headerSize,
|
||||
JSC::ExecutablePool *pool, JSC::CodeKind kind);
|
||||
|
||||
public:
|
||||
static inline ThingRootKind rootKind() { return THING_ROOT_JIT_CODE; }
|
||||
|
@ -44,6 +44,9 @@ class Linker
|
||||
if (bytesNeeded >= MAX_BUFFER_SIZE)
|
||||
return fail(cx);
|
||||
|
||||
// ExecutableAllocator requires bytesNeeded to be word-size aligned.
|
||||
bytesNeeded = AlignBytes(bytesNeeded, sizeof(void *));
|
||||
|
||||
uint8_t *result = (uint8_t *)execAlloc->alloc(bytesNeeded, &pool, kind);
|
||||
if (!result)
|
||||
return fail(cx);
|
||||
@ -54,8 +57,8 @@ class Linker
|
||||
// Bump the code up to a nice alignment.
|
||||
codeStart = (uint8_t *)AlignBytes((uintptr_t)codeStart, CodeAlignment);
|
||||
uint32_t headerSize = codeStart - result;
|
||||
JitCode *code = JitCode::New<allowGC>(cx, codeStart,
|
||||
bytesNeeded - headerSize, pool);
|
||||
JitCode *code = JitCode::New<allowGC>(cx, codeStart, bytesNeeded - headerSize,
|
||||
headerSize, pool, kind);
|
||||
if (!code)
|
||||
return nullptr;
|
||||
if (masm.oom())
|
||||
|
@ -2549,7 +2549,7 @@ DefineConstructorAndPrototype(JSContext *cx, HandleObject obj, JSProtoKey key, H
|
||||
* (FIXME: remove this dependency on the exact identity of the parent,
|
||||
* perhaps as part of bug 638316.)
|
||||
*/
|
||||
RootedFunction fun(cx, NewFunction(cx, NullPtr(), constructor, nargs,
|
||||
RootedFunction fun(cx, NewFunction(cx, js::NullPtr(), constructor, nargs,
|
||||
JSFunction::NATIVE_CTOR, obj, atom, ctorKind));
|
||||
if (!fun)
|
||||
goto bad;
|
||||
|
@ -82,16 +82,16 @@ public:
|
||||
bool isFallBack() { return m_needFallBack; }
|
||||
|
||||
#ifdef YARR_8BIT_CHAR_SUPPORT
|
||||
bool has8BitCode() const { return m_ref8.size(); }
|
||||
bool has8BitCode() const { return m_ref8.allocSize(); }
|
||||
void set8BitCode(MacroAssemblerCodeRef ref) { m_ref8 = ref; }
|
||||
bool has8BitCodeMatchOnly() const { return m_matchOnly8.size(); }
|
||||
bool has8BitCodeMatchOnly() const { return m_matchOnly8.allocSize(); }
|
||||
void set8BitCodeMatchOnly(MacroAssemblerCodeRef matchOnly) { m_matchOnly8 = matchOnly; }
|
||||
#endif
|
||||
|
||||
bool has16BitCode() const { return m_ref16.size(); }
|
||||
bool has16BitCode() const { return m_ref16.allocSize(); }
|
||||
void set16BitCode(MacroAssemblerCodeRef ref) { m_ref16 = ref; }
|
||||
|
||||
bool has16BitCodeMatchOnly() const { return m_matchOnly16.size(); }
|
||||
bool has16BitCodeMatchOnly() const { return m_matchOnly16.allocSize(); }
|
||||
void set16BitCodeMatchOnly(MacroAssemblerCodeRef matchOnly) { m_matchOnly16 = matchOnly; }
|
||||
|
||||
#if YARR_8BIT_CHAR_SUPPORT
|
||||
|
@ -3761,9 +3761,6 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
|
||||
rc->Init(presContext->DeviceContext(), aContext);
|
||||
|
||||
nsIntRegion temp = builder->GetRegionToClear();
|
||||
builder->ResetRegionToClear();
|
||||
|
||||
if (shouldDrawRectsSeparately) {
|
||||
nsIntRegionRectIterator it(aRegionToDraw);
|
||||
while (const nsIntRect* iterRect = it.Next()) {
|
||||
@ -3805,12 +3802,6 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
if (!aRegionToInvalidate.IsEmpty()) {
|
||||
aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds());
|
||||
}
|
||||
|
||||
if (!builder->GetRegionToClear().IsEmpty()) {
|
||||
aLayer->Manager()->SetRegionToClear(builder->GetRegionToClear());
|
||||
}
|
||||
builder->ResetRegionToClear();
|
||||
builder->AddRegionToClear(temp);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -854,7 +854,8 @@ nsCaret::GetCaretFrameForNodeOffset(nsIContent* aContentNode,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsCaret::CheckCaretDrawingState()
|
||||
void
|
||||
nsCaret::CheckCaretDrawingState()
|
||||
{
|
||||
if (mDrawn) {
|
||||
// The caret is drawn; if it shouldn't be, erase it.
|
||||
@ -867,7 +868,6 @@ nsresult nsCaret::CheckCaretDrawingState()
|
||||
if (mPendingDraw && (mVisible && MustDrawCaret(true)))
|
||||
DrawCaret(true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
|
@ -163,7 +163,7 @@ class nsCaret : public nsISelectionListener
|
||||
nsIFrame** aReturnFrame,
|
||||
int32_t* aReturnOffset);
|
||||
|
||||
NS_IMETHOD CheckCaretDrawingState();
|
||||
void CheckCaretDrawingState();
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -2358,6 +2358,7 @@ nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuil
|
||||
case NS_THEME_WINDOW_TITLEBAR:
|
||||
case NS_THEME_WINDOW_BUTTON_BOX:
|
||||
case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON:
|
||||
case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED:
|
||||
RegisterThemeGeometry(aBuilder, aFrame);
|
||||
break;
|
||||
case NS_THEME_WIN_BORDERLESS_GLASS:
|
||||
@ -2445,11 +2446,7 @@ nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder* aBuilder,
|
||||
theme->GetWidgetOverflow(presContext->DeviceContext(), mFrame, mAppearance,
|
||||
&drawing);
|
||||
drawing.IntersectRect(drawing, aBounds);
|
||||
nsIntRegion clear;
|
||||
theme->DrawWidgetBackground(aCtx, mFrame, mAppearance, borderArea, drawing, &clear);
|
||||
MOZ_ASSERT(clear.IsEmpty() || ReferenceFrame() == aBuilder->RootReferenceFrame(),
|
||||
"Can't add to clear region if we're transformed!");
|
||||
aBuilder->AddRegionToClear(clear);
|
||||
theme->DrawWidgetBackground(aCtx, mFrame, mAppearance, borderArea, drawing);
|
||||
}
|
||||
|
||||
bool nsDisplayThemedBackground::IsWindowActive()
|
||||
|
@ -641,10 +641,6 @@ public:
|
||||
|
||||
DisplayListClipState& ClipState() { return mClipState; }
|
||||
|
||||
void AddRegionToClear(const nsIntRegion& aRegion) { mRegionToClear.Or(mRegionToClear, aRegion); }
|
||||
const nsIntRegion& GetRegionToClear() { return mRegionToClear; }
|
||||
void ResetRegionToClear() { mRegionToClear.SetEmpty(); }
|
||||
|
||||
private:
|
||||
void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
|
||||
const nsRect& aDirtyRect);
|
||||
@ -678,8 +674,6 @@ private:
|
||||
const nsIFrame* mCachedReferenceFrame;
|
||||
nsPoint mCachedOffset;
|
||||
nsRegion mExcludedGlassRegion;
|
||||
// Area of the window (in pixels) to clear so the OS can draw them.
|
||||
nsIntRegion mRegionToClear;
|
||||
// The display item for the Windows window glass background, if any
|
||||
nsDisplayItem* mGlassDisplayItem;
|
||||
nsTArray<DisplayItemClip*> mDisplayItemClipsToDestroy;
|
||||
|
@ -5,7 +5,7 @@
|
||||
MOZ_APP_BASENAME=Fennec
|
||||
MOZ_APP_VENDOR=Mozilla
|
||||
|
||||
MOZ_APP_VERSION=30.0a1
|
||||
MOZ_APP_VERSION=31.0a1
|
||||
MOZ_APP_UA_NAME=Firefox
|
||||
|
||||
MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial
|
||||
|
@ -294,6 +294,7 @@ pref("media.tabstreaming.time_per_frame", 40);
|
||||
|
||||
// TextTrack support
|
||||
pref("media.webvtt.enabled", true);
|
||||
pref("media.webvtt.regions.enabled", false);
|
||||
|
||||
// Whether to enable MediaSource support
|
||||
pref("media.mediasource.enabled", false);
|
||||
|
@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Definitions used by constants.js.
|
||||
weave_version := 1.32.0
|
||||
weave_version := 1.33.0
|
||||
weave_id := {340c2bbc-ce74-4362-90b5-7c26312808ef}
|
||||
|
||||
# Preprocess files.
|
||||
|
@ -25,6 +25,15 @@ This is likely the same like id.heading in crashes.dtd. -->
|
||||
<!ENTITY aboutSupport.extensionVersion "Version">
|
||||
<!ENTITY aboutSupport.extensionId "ID">
|
||||
|
||||
<!ENTITY aboutSupport.experimentsTitle "Experimental Features">
|
||||
<!ENTITY aboutSupport.experimentName "Name">
|
||||
<!ENTITY aboutSupport.experimentId "ID">
|
||||
<!ENTITY aboutSupport.experimentDescription "Description">
|
||||
<!ENTITY aboutSupport.experimentActive "Active">
|
||||
<!ENTITY aboutSupport.experimentEndDate "End Date">
|
||||
<!ENTITY aboutSupport.experimentHomepage "Homepage">
|
||||
|
||||
|
||||
<!ENTITY aboutSupport.appBasicsTitle "Application Basics">
|
||||
<!ENTITY aboutSupport.appBasicsName "Name">
|
||||
<!ENTITY aboutSupport.appBasicsVersion "Version">
|
||||
|
@ -34,8 +34,7 @@ public:
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIntRegion* aRegionToClear);
|
||||
const nsRect& aDirtyRect);
|
||||
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
|
@ -2080,8 +2080,7 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIntRegion* aRegionToClear)
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
|
@ -752,8 +752,7 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIntRegion* aRegionToClear)
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
GtkWidgetState state;
|
||||
GtkThemeWidgetType gtkWidgetType;
|
||||
|
@ -24,8 +24,7 @@ public:
|
||||
NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame, uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIntRegion* aRegionToClear);
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
|
||||
uint8_t aWidgetType, nsIntMargin* aResult);
|
||||
|
@ -1536,8 +1536,7 @@ nsNativeThemeWin::DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIntRegion* aRegionToClear)
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
HANDLE theme = GetTheme(aWidgetType);
|
||||
if (!theme)
|
||||
@ -1568,6 +1567,10 @@ nsNativeThemeWin::DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
case NS_THEME_WIN_BORDERLESS_GLASS:
|
||||
// Nothing to draw, this is the glass background.
|
||||
return NS_OK;
|
||||
case NS_THEME_WINDOW_BUTTON_BOX:
|
||||
case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED:
|
||||
// We handle these through nsIWidget::UpdateThemeGeometries
|
||||
return NS_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1900,20 +1903,6 @@ RENDER_AGAIN:
|
||||
DrawThemeBackground(theme, hdc, gripPart, state, &widgetRect, &clipRect);
|
||||
}
|
||||
}
|
||||
else if ((aWidgetType == NS_THEME_WINDOW_BUTTON_BOX ||
|
||||
aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) &&
|
||||
nsUXThemeData::CheckForCompositor())
|
||||
{
|
||||
// The caption buttons are drawn by the DWM, we just need to clear the area where they
|
||||
// are because we might have drawn something above them (like a background-image).
|
||||
NS_ASSERTION(aRegionToClear, "Must have a clear region to set!");
|
||||
if (aRegionToClear) {
|
||||
// Create a rounded rectangle to follow the buttons' look.
|
||||
*aRegionToClear = nsIntRect(dr.X(), dr.Y(), dr.Width(), dr.Height() - 2.0);
|
||||
aRegionToClear->Or(*aRegionToClear, nsIntRect(dr.X() + 1.0, dr.YMost() - 2.0, dr.Width() - 1.0, 1.0));
|
||||
aRegionToClear->Or(*aRegionToClear, nsIntRect(dr.X() + 2.0, dr.YMost() - 1.0, dr.Width() - 3.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
nativeDrawing.EndNativeDrawing();
|
||||
|
||||
|
@ -31,8 +31,7 @@ public:
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect,
|
||||
nsIntRegion* aRegionToClear);
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
|
@ -127,6 +127,7 @@
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsIAppStartup.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsThemeConstants.h"
|
||||
|
||||
#ifdef MOZ_ENABLE_D3D9_LAYER
|
||||
#include "LayerManagerD3D9.h"
|
||||
@ -3556,6 +3557,28 @@ nsWindow::EndRemoteDrawing()
|
||||
mCompositeDC = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries)
|
||||
{
|
||||
nsIntRegion clearRegion;
|
||||
for (size_t i = 0; i < aThemeGeometries.Length(); i++) {
|
||||
if ((aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX ||
|
||||
aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) &&
|
||||
nsUXThemeData::CheckForCompositor())
|
||||
{
|
||||
nsIntRect bounds = aThemeGeometries[i].mRect;
|
||||
clearRegion = nsIntRect(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height() - 2.0);
|
||||
clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 1.0, bounds.YMost() - 2.0, bounds.Width() - 1.0, 1.0));
|
||||
clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 2.0, bounds.YMost() - 1.0, bounds.Width() - 3.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<LayerManager> layerManager = GetLayerManager();
|
||||
if (layerManager) {
|
||||
layerManager->SetRegionToClear(clearRegion);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
**************************************************************
|
||||
**
|
||||
|
@ -196,6 +196,8 @@ public:
|
||||
mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() MOZ_OVERRIDE;
|
||||
virtual void EndRemoteDrawing() MOZ_OVERRIDE;
|
||||
|
||||
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Event helpers
|
||||
*/
|
||||
|
@ -21,7 +21,7 @@ namespace mozilla {
|
||||
*/
|
||||
struct Module
|
||||
{
|
||||
static const unsigned int kVersion = 30;
|
||||
static const unsigned int kVersion = 31;
|
||||
|
||||
struct CIDEntry;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user