This commit is contained in:
Carsten "Tomcat" Book 2014-04-22 12:34:37 +02:00
Родитель 3fcc3b9819 3ccf8c1370
Коммит 9c58c649d9
79 изменённых файлов: 1558 добавлений и 1403 удалений

Просмотреть файл

@ -15,15 +15,15 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="52720b94a4f709d5f96c23b2d63c398e7002ecb9"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<!-- Stock Android things -->
@ -98,7 +98,7 @@
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="aab7a70124d88092831b99f3619a6572dca05b8f"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="2fee3bbbfc236b883ef8507e27d88b17b203fe25"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>

Просмотреть файл

@ -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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>

Просмотреть файл

@ -15,15 +15,15 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="52720b94a4f709d5f96c23b2d63c398e7002ecb9"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<!-- Stock Android things -->
@ -98,7 +98,7 @@
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="aab7a70124d88092831b99f3619a6572dca05b8f"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="2fee3bbbfc236b883ef8507e27d88b17b203fe25"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>

Просмотреть файл

@ -18,7 +18,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
@ -119,7 +119,7 @@
<!-- Flame specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
<project name="device/qcom/common" path="device/qcom/common" revision="234ed34543345f58c0d4dcb1aa012de68802b9dc"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="92f9b79e3a5ecf24cb0f66e20d5292b300f8cac9"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="08132b26f24d3c2ec9c24f63b58bd99158e9400c"/>
<project name="kernel/msm" path="kernel" revision="b3092c54430df89636fb0670d32058bc63474017"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="f2914eacee9120680a41463708bb6ee8291749fc"/>
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="fa892235a9bd8983f8b591129fc1a9398f64e514"/>

Просмотреть файл

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "46f6f56839237440d17026f21255dac5329c681c",
"revision": "3f54f719dc145f1544db67881a48819559ecb71b",
"repo_path": "/integration/gaia-central"
}

Просмотреть файл

@ -13,11 +13,11 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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"/>

Просмотреть файл

@ -11,11 +11,11 @@
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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,11 +15,11 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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"/>

Просмотреть файл

@ -13,11 +13,11 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>

Просмотреть файл

@ -13,11 +13,11 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="84f4835833c4cb8ac7e5d9e0c94738b1cb0ef45a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f0463704888881b8ed1619e8d4b0d851b0e0311b"/>
<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"/>

Просмотреть файл

@ -944,8 +944,9 @@ WebGLContext::ValidateTexImageSize(GLenum target, GLint level,
const GLuint maxTexImageSize = MaxTextureSizeForTarget(target) >> level;
const bool isCubemapTarget = IsTexImageCubemapTarget(target);
const bool isSub = IsSubFunc(func);
if (isCubemapTarget && width != height) {
if (!isSub && isCubemapTarget && (width != height)) {
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
* "When the target parameter to TexImage2D is one of the
* six cube map two-dimensional image targets, the error

Просмотреть файл

@ -72,7 +72,7 @@ SVGTransformableElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
NS_ABORT_IF_FALSE(aModType == nsIDOMMutationEvent::MODIFICATION,
"Unknown modification type.");
// We just assume the old and new transforms are different.
NS_UpdateHint(retval, NS_CombineHint(nsChangeHint_UpdateOverflow,
NS_UpdateHint(retval, NS_CombineHint(nsChangeHint_UpdatePostTransformOverflow,
nsChangeHint_UpdateTransformLayer));
}
}
@ -135,8 +135,19 @@ SVGTransformableElement::SetAnimateMotionTransform(const gfx::Matrix* aMatrix)
(aMatrix && mAnimateMotionTransform && *aMatrix == *mAnimateMotionTransform)) {
return;
}
bool transformSet = mTransforms && mTransforms->IsExplicitlySet();
bool prevSet = mAnimateMotionTransform || transformSet;
mAnimateMotionTransform = aMatrix ? new gfx::Matrix(*aMatrix) : nullptr;
DidAnimateTransformList();
bool nowSet = mAnimateMotionTransform || transformSet;
int32_t modType;
if (prevSet && !nowSet) {
modType = nsIDOMMutationEvent::REMOVAL;
} else if(!prevSet && nowSet) {
modType = nsIDOMMutationEvent::ADDITION;
} else {
modType = nsIDOMMutationEvent::MODIFICATION;
}
DidAnimateTransformList(modType);
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
// If the result of this transform and any other transforms on this frame

Просмотреть файл

@ -11,6 +11,7 @@
#include "nsSMILValue.h"
#include "SVGContentUtils.h"
#include "SVGTransformListSMILType.h"
#include "nsIDOMMutationEvent.h"
namespace mozilla {
@ -75,6 +76,7 @@ nsresult
nsSVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
nsSVGElement *aElement)
{
bool prevSet = HasTransform() || aElement->GetAnimateMotionTransform();
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
@ -106,7 +108,13 @@ nsSVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
ClearAnimValue(aElement);
return rv;
}
aElement->DidAnimateTransformList();
int32_t modType;
if(prevSet) {
modType = nsIDOMMutationEvent::MODIFICATION;
} else {
modType = nsIDOMMutationEvent::ADDITION;
}
aElement->DidAnimateTransformList(modType);
return NS_OK;
}
@ -124,7 +132,13 @@ nsSVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement)
domWrapper->InternalAnimValListWillChangeLengthTo(mBaseVal.Length());
}
mAnimVal = nullptr;
aElement->DidAnimateTransformList();
int32_t modType;
if (HasTransform() || aElement->GetAnimateMotionTransform()) {
modType = nsIDOMMutationEvent::MODIFICATION;
} else {
modType = nsIDOMMutationEvent::REMOVAL;
}
aElement->DidAnimateTransformList(modType);
}
bool

Просмотреть файл

@ -2356,7 +2356,7 @@ nsSVGElement::DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue)
}
void
nsSVGElement::DidAnimateTransformList()
nsSVGElement::DidAnimateTransformList(int32_t aModType)
{
NS_ABORT_IF_FALSE(GetTransformListAttrName(),
"Animating non-existent transform data?");
@ -2365,10 +2365,9 @@ nsSVGElement::DidAnimateTransformList()
if (frame) {
nsIAtom *transformAttr = GetTransformListAttrName();
int32_t modType = nsIDOMMutationEvent::MODIFICATION;
frame->AttributeChanged(kNameSpaceID_None,
transformAttr,
modType);
aModType);
// When script changes the 'transform' attribute, Element::SetAttrAndNotify
// will call nsNodeUtills::AttributeChanged, under which
// SVGTransformableElement::GetAttributeChangeHint will be called and an
@ -2377,7 +2376,7 @@ nsSVGElement::DidAnimateTransformList()
// 'animateTransform' though (and sending out the mutation events that
// nsNodeUtills::AttributeChanged dispatches would be inappropriate
// anyway), so we need to post the change event ourself.
nsChangeHint changeHint = GetAttributeChangeHint(transformAttr, modType);
nsChangeHint changeHint = GetAttributeChangeHint(transformAttr, aModType);
if (changeHint) {
nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
}

Просмотреть файл

@ -239,7 +239,7 @@ public:
void DidAnimateLengthList(uint8_t aAttrEnum);
void DidAnimatePointList();
void DidAnimatePathSegList();
void DidAnimateTransformList();
void DidAnimateTransformList(int32_t aModType);
void DidAnimateString(uint8_t aAttrEnum);
enum {

Просмотреть файл

@ -33,20 +33,23 @@
"iframe with mozFrameType='content' in chrome document is typeContent");
SimpleTest.executeSoon(function () {
// Wait for the window to be closed before finishing the test
let ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
ww.registerNotification(function windowObs(subject, topic, data) {
if (topic == "domwindowclosed") {
ww.unregisterNotification(windowObs);
// First focus the parent window and then close this one.
SimpleTest.waitForFocus(function() {
let ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
ww.registerNotification(function windowObs(subject, topic, data) {
if (topic == "domwindowclosed") {
ww.unregisterNotification(windowObs);
SimpleTest.waitForFocus(function() {
SimpleTest.finish();
}, opener);
}
});
// Don't start the next test synchronously!
SimpleTest.executeSoon(function() {
SimpleTest.finish();
});
}
});
window.close();
window.close();
}, opener);
});
}
]]></script>

Просмотреть файл

@ -353,6 +353,9 @@ parent:
ReplyKeyEvent(WidgetKeyboardEvent event);
sync RequestNativeKeyBindings(WidgetKeyboardEvent event)
returns (MaybeNativeKeyBinding bindings);
child:
/**
* Notify the remote browser that it has been Show()n on this

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
/* 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
@ -2027,19 +2027,40 @@ TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
return RecvRealTouchEvent(aEvent, aGuid);
}
void
TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache,
WidgetKeyboardEvent* aEvent)
{
MaybeNativeKeyBinding maybeBindings;
if (!SendRequestNativeKeyBindings(*aEvent, &maybeBindings)) {
return;
}
if (maybeBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
const NativeKeyBinding& bindings = maybeBindings;
aAutoCache->Cache(bindings.singleLineCommands(),
bindings.multiLineCommands(),
bindings.richTextCommands());
} else {
aAutoCache->CacheNoCommands();
}
}
bool
TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
const MaybeNativeKeyBinding& aBindings)
{
{
PuppetWidget* widget = static_cast<PuppetWidget*>(mWidget.get());
AutoCacheNativeKeyCommands autoCache(widget);
if (event.message == NS_KEY_PRESS) {
PuppetWidget* widget = static_cast<PuppetWidget*>(mWidget.get());
if (aBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
const NativeKeyBinding& bindings = aBindings;
widget->CacheNativeKeyCommands(bindings.singleLineCommands(),
bindings.multiLineCommands(),
bindings.richTextCommands());
autoCache.Cache(bindings.singleLineCommands(),
bindings.multiLineCommands(),
bindings.richTextCommands());
} else {
widget->ClearNativeKeyCommands();
autoCache.CacheNoCommands();
}
}
// If content code called preventDefault() on a keydown event, then we don't

Просмотреть файл

@ -46,6 +46,10 @@ namespace layers {
class ActiveElementManager;
}
namespace widget {
struct AutoCacheNativeKeyCommands;
}
namespace dom {
class TabChild;
@ -393,6 +397,8 @@ public:
void NotifyPainted();
void RequestNativeKeyBindings(mozilla::widget::AutoCacheNativeKeyCommands* aAutoCache,
WidgetKeyboardEvent* aEvent);
/** Return a boolean indicating if the page has called preventDefault on
* the event.

Просмотреть файл

@ -791,6 +791,41 @@ DoCommandCallback(mozilla::Command aCommand, void* aData)
static_cast<InfallibleTArray<mozilla::CommandInt>*>(aData)->AppendElement(aCommand);
}
bool
TabParent::RecvRequestNativeKeyBindings(const WidgetKeyboardEvent& aEvent,
MaybeNativeKeyBinding* aBindings)
{
AutoInfallibleTArray<mozilla::CommandInt, 4> singleLine;
AutoInfallibleTArray<mozilla::CommandInt, 4> multiLine;
AutoInfallibleTArray<mozilla::CommandInt, 4> richText;
*aBindings = mozilla::void_t();
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
WidgetKeyboardEvent localEvent(aEvent);
if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
return true;
}
widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForSingleLineEditor,
localEvent, DoCommandCallback, &singleLine);
widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForMultiLineEditor,
localEvent, DoCommandCallback, &multiLine);
widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForRichTextEditor,
localEvent, DoCommandCallback, &richText);
if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) {
*aBindings = NativeKeyBinding(singleLine, multiLine, richText);
}
return true;
}
bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event)
{
if (mIsDestroyed) {

Просмотреть файл

@ -222,6 +222,9 @@ public:
void MapEventCoordinatesForChildProcess(const LayoutDeviceIntPoint& aOffset,
mozilla::WidgetEvent* aEvent);
virtual bool RecvRequestNativeKeyBindings(const mozilla::WidgetKeyboardEvent& aEvent,
MaybeNativeKeyBinding* aBindings) MOZ_OVERRIDE;
void SendMouseEvent(const nsAString& aType, float aX, float aY,
int32_t aButton, int32_t aClickCount,
int32_t aModifiers, bool aIgnoreRootScrollFrame);

Просмотреть файл

@ -0,0 +1,83 @@
Mozilla Graphics Overview {#graphicsoverview}
=================
## Work in progress. Possibly incorrect or incomplete.
Overview
--------
The graphics systems is responsible for rendering (painting, drawing) the frame tree (rendering tree) elements as created by the layout system. Each leaf in the tree has content, either bounded by a rectangle (or perhaps another shape, in the case of SVG.)
The simple approach for producing the result would thus involve traversing the frame tree, in a correct order, drawing each frame into the resulting buffer and displaying (printing non-withstanding) that buffer when the traversal is done. It is worth spending some time on the "correct order" note above. If there are no overlapping frames, this is fairly simple - any order will do, as long as there is no background. If there is background, we just have to worry about drawing that first. Since we do not control the content, chances are the page is more complicated. There are overlapping frames, likely with transparency, so we need to make sure the elements are draw "back to front", in layers, so to speak. Layers are an important concept, and we will revisit them shortly, as they are central to fixing a major issue with the above simple approach.
While the above simple approach will work, the performance will suffer. Each time anything changes in any of the frames, the complete process needs to be repeated, everything needs to be redrawn. Further, there is very little space to take advantage of the modern graphics (GPU) hardware, or multi-core computers. If you recall from the previous sections, the frame tree is only accessible from the UI thread, so while we're doing all this work, the UI is basically blocked.
### (Retained) Layers
Layers framework was introduced to address the above performance issues, by having a part of the design address each item. At the high level:
1. We create a layer tree. The leaf elements of the tree contain all frames (possibly multiple frames per leaf).
2. We render each layer tree element and cache (retain) the result.
3. We composite (combine) all the leaf elements into the final result.
Let's examine each of these steps, in reverse order.
### Compositing
We use the term composite as it implies that the order is important. If the elements being composited overlap, whether there is transparency involved or not, the order in which they are combined will effect the result.
Compositing is where we can use some of the power of the modern graphics hardware. It is optimal for doing this job. In the scenarios where only the position of individual frames changes, without the content inside them changing, we see why caching each layer would be advantageous - we only need to repeat the final compositing step, completely skipping the layer tree creation and the rendering of each leaf, thus speeding up the process considerably.
Another benefit is equally apparent in the context of the stated deficiencies of the simple approach. We can use the available graphics hardware accelerated APIs to do the compositing step. Direct3D, OpenGL can be used on different platforms and are well suited to accelerate this step.
Finally, we can now envision performing the compositing step on a separate thread, unblocking the UI thread for other work, and doing more work in parallel. More on this below.
It is important to note that the number of operations in this step is proportional to the number of layer tree (leaf) elements, so there is additional work and complexity involved, when the layer tree is large.
#### Render and retain layer elements
As we saw, the compositing step benefits from caching the intermediate result. This does result in the extra memory usage, so needs to be considered during the layer tree creation. Beyond the caching, we can accelerate the rendering of each element by (indirectly) using the available platform APIs (e.g., Direct2D, CoreGraphics, even some of the 3D APIs like OpenGL or Direct3D) as available. This is actually done through a platform independent API (see Moz2D) below, but is important to realize it does get accelerated appropriately.
#### Creating the layer tree
We need to create a layer tree (from the frames tree), which will give us the correct result while striking the right balance between a layer per frame element and a single layer for the complete frames tree. As was mentioned above, there is an overhead in traversing the whole tree and caching each of the elements, balanced by the performance improvements. Some of the performance improvements are only noticed when something changes (e.g., one element is moving, we only need to redo the compositing step).
### Refresh Driver
### Layers
#### Rendering each layer
### Tiling vs. Buffer Rotation vs. Full paint
#### Compositing for the final result
### Graphics API
#### Moz2D
* The Moz2D graphics API, part of the Azure project, is a cross-platform interface onto the various graphics backends that Gecko uses for rendering such as Direct2D (1.0 and 1.1), Skia, Cairo, Quartz, and NV Path. Adding a new graphics platform to Gecko is accomplished by adding a backend to Moz2D.
\see [Moz2D documentation on wiki](https://wiki.mozilla.org/Platform/GFX/Moz2D)
#### Compositing
#### Image Decoding
#### Image Animation
### Funny words
There are a lot of code words that we use to refer to projects, libraries, areas of the code. Here's an attempt to cover some of those:
* Azure - See Moz2D in the Graphics API section above.
* Backend - See Moz2D in the Graphics API section above.
* Cairo - http://www.cairographics.org/. Cairo is a 2D graphics library with support for multiple output devices. Currently supported output targets include the X Window System (via both Xlib and XCB), Quartz, Win32, image buffers, PostScript, PDF, and SVG file output.
* Moz2D - See Moz2D in the Graphics API section above.
* Thebes - Graphics API that preceded Moz2D.
* Reflow
* Display list
### [Historical Documents](http://www.youtube.com/watch?v=lLZQz26-kms)
A number of posts and blogs that will give you more details or more background, or reasoning that led to different solutions and approaches.
* 2010-01 [Layers: Cross Platform Acceleration] (http://www.basschouten.com/blog1.php/layers-cross-platform-acceleration)
* 2010-04 [Layers] (http://robert.ocallahan.org/2010/04/layers_01.html)
* 2010-07 [Retained Layers](http://robert.ocallahan.org/2010/07/retained-layers_16.html)
* 2011-04 [Introduction](https://blog.mozilla.org/joe/2011/04/26/introducing-the-azure-project/ Moz2D)
* 2011-07 [Layers](http://chrislord.net/index.php/2011/07/25/shadow-layers-and-learning-by-failing/ Shadow)
* 2011-09 [Graphics API Design](http://robert.ocallahan.org/2011/09/graphics-api-design.html)
* 2012-04 [Moz2D Canvas on OSX](http://muizelaar.blogspot.ca/2012/04/azure-canvas-on-os-x.html)
* 2012-05 [Mask Layers](http://featherweightmusings.blogspot.co.uk/2012/05/mask-layers_26.html)
* 2013-07 [Graphics related](http://www.basschouten.com/blog1.php)

21
gfx/doc/MainPage.md Normal file
Просмотреть файл

@ -0,0 +1,21 @@
Mozilla Graphics {#mainpage}
======================
## Work in progress. Possibly incorrect or incomplete.
Introduction
-------
This collection of linked pages contains a combination of Doxygen
extracted source code documentation and design documents for the
Mozilla graphics architecture. The design documents live in gfx/docs directory.
This [wiki page](https://wiki.mozilla.org/Platform/GFX) contains
information about graphics and the graphics team at MoCo.
Continue here for a [very high level introductory overview](@ref graphicsoverview)
if you don't know where to start.
Useful pointers for creating documentation
------
[The mechanics of creating these files](https://wiki.mozilla.org/Platform/GFX/DesignDocumentationGuidelines)

Просмотреть файл

@ -849,7 +849,10 @@ void imgFrame::ApplyDirtToSurfaces()
void imgFrame::SetDiscardable()
{
MOZ_ASSERT(mLockCount, "Expected to be locked when SetDiscardable is called");
// Disabled elsewhere due to the cost of calling GetSourceSurfaceForSurface.
#ifdef MOZ_WIDGET_ANDROID
mDiscardable = true;
#endif
}
int32_t imgFrame::GetRawTimeout() const

Просмотреть файл

@ -472,9 +472,19 @@ nsresult nsExtensibleStringBundle::GetSimpleEnumeration(nsISimpleEnumerator ** a
#define MAX_CACHED_BUNDLES 16
struct bundleCacheEntry_t : public LinkedListElement<bundleCacheEntry_t> {
struct bundleCacheEntry_t MOZ_FINAL : public LinkedListElement<bundleCacheEntry_t> {
nsAutoPtr<nsCStringKey> mHashKey;
nsCOMPtr<nsIStringBundle> mBundle;
bundleCacheEntry_t()
{
MOZ_COUNT_CTOR(bundleCacheEntry_t);
}
~bundleCacheEntry_t()
{
MOZ_COUNT_DTOR(bundleCacheEntry_t);
}
};

Просмотреть файл

@ -11,6 +11,13 @@
#include "assembler/assembler/MacroAssemblerX86Common.h"
#if WTF_COMPILER_MSVC
#if WTF_CPU_X86_64
/* for __cpuid */
#include <intrin.h>
#endif
#endif
using namespace JSC;
MacroAssemblerX86Common::SSECheckState MacroAssemblerX86Common::s_sseCheckState = NotCheckedSSE;
@ -20,5 +27,112 @@ bool MacroAssemblerX86Common::s_SSE3Disabled = false;
bool MacroAssemblerX86Common::s_SSE4Disabled = false;
#endif
void MacroAssemblerX86Common::setSSECheckState()
{
// Default the flags value to zero; if the compiler is
// not MSVC or GCC we will read this as SSE2 not present.
int flags_edx = 0;
int flags_ecx = 0;
#if WTF_COMPILER_MSVC
#if WTF_CPU_X86_64
int cpuinfo[4];
__cpuid(cpuinfo, 1);
flags_ecx = cpuinfo[2];
flags_edx = cpuinfo[3];
#else
_asm {
mov eax, 1 // cpuid function 1 gives us the standard feature set
cpuid;
mov flags_ecx, ecx;
mov flags_edx, edx;
}
#endif
#elif WTF_COMPILER_GCC
#if WTF_CPU_X86_64
asm (
"movl $0x1, %%eax;"
"cpuid;"
: "=c" (flags_ecx), "=d" (flags_edx)
:
: "%eax", "%ebx"
);
#else
// On 32-bit x86, we must preserve ebx; the compiler needs it for PIC mode.
asm (
"movl $0x1, %%eax;"
"pushl %%ebx;"
"cpuid;"
"popl %%ebx;"
: "=c" (flags_ecx), "=d" (flags_edx)
:
: "%eax"
);
#endif
#elif WTF_COMPILER_SUNCC
#if WTF_CPU_X86_64
asm (
"movl $0x1, %%eax;"
"pushq %%rbx;"
"cpuid;"
"popq %%rbx;"
"movl %%ecx, (%rsi);"
"movl %%edx, (%rdi);"
:
: "S" (&flags_ecx), "D" (&flags_edx)
: "%eax", "%ecx", "%edx"
);
#else
asm (
"movl $0x1, %eax;"
"pushl %ebx;"
"cpuid;"
"popl %ebx;"
"movl %ecx, (%esi);"
"movl %edx, (%edi);"
:
: "S" (&flags_ecx), "D" (&flags_edx)
: "%eax", "%ecx", "%edx"
);
#endif
#endif
#ifdef DEBUG
if (s_floatingPointDisabled) {
// Disable SSE2.
s_sseCheckState = HasSSE;
return;
}
#endif
static const int SSEFeatureBit = 1 << 25;
static const int SSE2FeatureBit = 1 << 26;
static const int SSE3FeatureBit = 1 << 0;
static const int SSSE3FeatureBit = 1 << 9;
static const int SSE41FeatureBit = 1 << 19;
static const int SSE42FeatureBit = 1 << 20;
if (flags_ecx & SSE42FeatureBit)
s_sseCheckState = HasSSE4_2;
else if (flags_ecx & SSE41FeatureBit)
s_sseCheckState = HasSSE4_1;
else if (flags_ecx & SSSE3FeatureBit)
s_sseCheckState = HasSSSE3;
else if (flags_ecx & SSE3FeatureBit)
s_sseCheckState = HasSSE3;
else if (flags_edx & SSE2FeatureBit)
s_sseCheckState = HasSSE2;
else if (flags_edx & SSEFeatureBit)
s_sseCheckState = HasSSE;
else
s_sseCheckState = NoSSE;
#ifdef DEBUG
if (s_sseCheckState >= HasSSE4_1 && s_SSE4Disabled)
s_sseCheckState = HasSSE3;
if (s_sseCheckState >= HasSSE3 && s_SSE3Disabled)
s_sseCheckState = HasSSE2;
#endif
}
#endif /* WTF_CPU_X86 || WTF_CPU_X86_64 */

Просмотреть файл

@ -37,13 +37,6 @@
#include "assembler/assembler/X86Assembler.h"
#include "assembler/assembler/AbstractMacroAssembler.h"
#if WTF_COMPILER_MSVC
#if WTF_CPU_X86_64
/* for __cpuid */
#include <intrin.h>
#endif
#endif
namespace JSC {
class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> {
@ -1300,140 +1293,15 @@ private:
static SSECheckState s_sseCheckState;
static void setSSECheckState()
{
// Default the flags value to zero; if the compiler is
// not MSVC or GCC we will read this as SSE2 not present.
volatile int flags_edx = 0;
volatile int flags_ecx = 0;
#if WTF_COMPILER_MSVC
#if WTF_CPU_X86_64
int cpuinfo[4];
__cpuid(cpuinfo, 1);
flags_ecx = cpuinfo[2];
flags_edx = cpuinfo[3];
#else
_asm {
mov eax, 1 // cpuid function 1 gives us the standard feature set
cpuid;
mov flags_ecx, ecx;
mov flags_edx, edx;
}
#endif
#elif WTF_COMPILER_GCC
#if WTF_CPU_X86_64
asm (
"movl $0x1, %%eax;"
"pushq %%rbx;"
"cpuid;"
"popq %%rbx;"
"movl %%ecx, %0;"
"movl %%edx, %1;"
: "=g" (flags_ecx), "=g" (flags_edx)
:
: "%eax", "%ecx", "%edx"
);
#else
asm (
"movl $0x1, %%eax;"
"pushl %%ebx;"
"cpuid;"
"popl %%ebx;"
"movl %%ecx, %0;"
"movl %%edx, %1;"
: "=g" (flags_ecx), "=g" (flags_edx)
:
: "%eax", "%ecx", "%edx"
);
#endif
#elif WTF_COMPILER_SUNCC
#if WTF_CPU_X86_64
asm (
"movl $0x1, %%eax;"
"pushq %%rbx;"
"cpuid;"
"popq %%rbx;"
"movl %%ecx, (%rsi);"
"movl %%edx, (%rdi);"
:
: "S" (&flags_ecx), "D" (&flags_edx)
: "%eax", "%ecx", "%edx"
);
#else
asm (
"movl $0x1, %eax;"
"pushl %ebx;"
"cpuid;"
"popl %ebx;"
"movl %ecx, (%esi);"
"movl %edx, (%edi);"
:
: "S" (&flags_ecx), "D" (&flags_edx)
: "%eax", "%ecx", "%edx"
);
#endif
#endif
#ifdef DEBUG
if (s_floatingPointDisabled) {
// Disable SSE2.
s_sseCheckState = HasSSE;
return;
}
#endif
static const int SSEFeatureBit = 1 << 25;
static const int SSE2FeatureBit = 1 << 26;
static const int SSE3FeatureBit = 1 << 0;
static const int SSSE3FeatureBit = 1 << 9;
static const int SSE41FeatureBit = 1 << 19;
static const int SSE42FeatureBit = 1 << 20;
if (flags_ecx & SSE42FeatureBit)
s_sseCheckState = HasSSE4_2;
else if (flags_ecx & SSE41FeatureBit)
s_sseCheckState = HasSSE4_1;
else if (flags_ecx & SSSE3FeatureBit)
s_sseCheckState = HasSSSE3;
else if (flags_ecx & SSE3FeatureBit)
s_sseCheckState = HasSSE3;
else if (flags_edx & SSE2FeatureBit)
s_sseCheckState = HasSSE2;
else if (flags_edx & SSEFeatureBit)
s_sseCheckState = HasSSE;
else
s_sseCheckState = NoSSE;
#ifdef DEBUG
if (s_sseCheckState >= HasSSE4_1 && s_SSE4Disabled)
s_sseCheckState = HasSSE3;
if (s_sseCheckState >= HasSSE3 && s_SSE3Disabled)
s_sseCheckState = HasSSE2;
#endif
}
static void setSSECheckState();
public:
#if WTF_CPU_X86
#if WTF_OS_MAC_OS_X
// All X86 Macs are guaranteed to support at least SSE2
static bool isSSEPresent()
{
#if defined(__SSE__) && !defined(DEBUG)
return true;
}
static bool isSSE2Present()
{
#ifdef DEBUG
if (s_floatingPointDisabled)
return false;
#endif
return true;
}
#else // OS(MAC_OS_X)
static bool isSSEPresent()
{
#else
if (s_sseCheckState == NotCheckedSSE) {
setSSECheckState();
}
@ -1441,10 +1309,14 @@ private:
ASSERT(s_sseCheckState != NotCheckedSSE);
return s_sseCheckState >= HasSSE;
#endif
}
static bool isSSE2Present()
{
#if defined(__SSE2__) && !defined(DEBUG)
return true;
#else
if (s_sseCheckState == NotCheckedSSE) {
setSSECheckState();
}
@ -1452,9 +1324,9 @@ private:
ASSERT(s_sseCheckState != NotCheckedSSE);
return s_sseCheckState >= HasSSE2;
#endif
}
#endif // PLATFORM(MAC)
#elif !defined(NDEBUG) // CPU(X86)
// On x86-64 we should never be checking for SSE2 in a non-debug build,
@ -1467,6 +1339,9 @@ private:
#endif
static bool isSSE3Present()
{
#if defined(__SSE3__) && !defined(DEBUG)
return true;
#else
if (s_sseCheckState == NotCheckedSSE) {
setSSECheckState();
}
@ -1474,10 +1349,14 @@ private:
ASSERT(s_sseCheckState != NotCheckedSSE);
return s_sseCheckState >= HasSSE3;
#endif
}
static bool isSSSE3Present()
{
#if defined(__SSSE3__) && !defined(DEBUG)
return true;
#else
if (s_sseCheckState == NotCheckedSSE) {
setSSECheckState();
}
@ -1485,10 +1364,14 @@ private:
ASSERT(s_sseCheckState != NotCheckedSSE);
return s_sseCheckState >= HasSSSE3;
#endif
}
static bool isSSE41Present()
{
#if defined(__SSE4_1__) && !defined(DEBUG)
return true;
#else
if (s_sseCheckState == NotCheckedSSE) {
setSSECheckState();
}
@ -1496,10 +1379,14 @@ private:
ASSERT(s_sseCheckState != NotCheckedSSE);
return s_sseCheckState >= HasSSE4_1;
#endif
}
static bool isSSE42Present()
{
#if defined(__SSE4_2__) && !defined(DEBUG)
return true;
#else
if (s_sseCheckState == NotCheckedSSE) {
setSSECheckState();
}
@ -1507,8 +1394,10 @@ private:
ASSERT(s_sseCheckState != NotCheckedSSE);
return s_sseCheckState >= HasSSE4_2;
#endif
}
private:
#ifdef DEBUG
static bool s_floatingPointDisabled;
static bool s_SSE3Disabled;

Просмотреть файл

@ -89,6 +89,14 @@ GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
if (!JS_SetProperty(cx, info, "x64", value))
return false;
#ifdef JS_ARM_SIMULATOR
value = BooleanValue(true);
#else
value = BooleanValue(false);
#endif
if (!JS_SetProperty(cx, info, "arm-simulator", value))
return false;
#ifdef MOZ_ASAN
value = BooleanValue(true);
#else

Просмотреть файл

@ -972,7 +972,7 @@ AssertValidColor(const void *thing, uint32_t color)
{
#ifdef DEBUG
ArenaHeader *aheader = reinterpret_cast<const Cell *>(thing)->arenaHeader();
JS_ASSERT_IF(color, color < aheader->getThingSize() / CellSize);
JS_ASSERT(color < aheader->getThingSize() / CellSize);
#endif
}
@ -1015,6 +1015,7 @@ bool
Cell::isMarked(uint32_t color /* = BLACK */) const
{
JS_ASSERT(isTenured());
JS_ASSERT(arenaHeader()->allocated());
AssertValidColor(this, color);
return chunk()->bitmap.isMarked(this, color);
}

Просмотреть файл

@ -356,19 +356,24 @@ IsAboutToBeFinalized(T **thingp)
JS_ASSERT(thingp);
JS_ASSERT(*thingp);
T *thing = *thingp;
JSRuntime *rt = thing->runtimeFromAnyThread();
/* Permanent atoms are never finalized by non-owning runtimes. */
if (ThingIsPermanentAtom(*thingp) &&
!TlsPerThreadData.get()->associatedWith((*thingp)->runtimeFromAnyThread()))
{
if (ThingIsPermanentAtom(thing) && !TlsPerThreadData.get()->associatedWith(rt))
return false;
}
#ifdef JSGC_GENERATIONAL
Nursery &nursery = (*thingp)->runtimeFromMainThread()->gcNursery;
if (nursery.isInside(*thingp))
return !nursery.getForwardedPointer(thingp);
Nursery &nursery = rt->gcNursery;
JS_ASSERT_IF(!rt->isHeapMinorCollecting(), !nursery.isInside(thing));
if (rt->isHeapMinorCollecting()) {
if (nursery.isInside(thing))
return !nursery.getForwardedPointer(thingp);
return false;
}
#endif
if (!(*thingp)->tenuredZone()->isGCSweeping())
if (!thing->tenuredZone()->isGCSweeping())
return false;
/*
@ -378,10 +383,9 @@ IsAboutToBeFinalized(T **thingp)
* compartment group and during minor gc. Rather than do the extra check,
* we just assert that it's not necessary.
*/
JS_ASSERT_IF(!(*thingp)->runtimeFromAnyThread()->isHeapMinorCollecting(),
!(*thingp)->arenaHeader()->allocatedDuringIncremental);
JS_ASSERT_IF(!rt->isHeapMinorCollecting(), !thing->arenaHeader()->allocatedDuringIncremental);
return !(*thingp)->isMarked();
return !thing->isMarked();
}
template <typename T>

Просмотреть файл

@ -0,0 +1,10 @@
var w = new WeakMap();
var g = newGlobal();
var k = g.eval('for (var i=0; i<100; i++) new Object(); var q = new Object(); q');
w.set(k, {});
k = null;
gc();
g.eval('q = null');
gc(g);
gc();

Просмотреть файл

@ -781,14 +781,16 @@ class AssemblerX86Shared
masm.int3();
}
#ifdef DEBUG
static bool HasSSE2() {
return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE2;
return JSC::MacroAssembler::isSSE2Present();
}
#endif
static bool HasSSE3() {
return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE3;
return JSC::MacroAssembler::isSSE3Present();
}
static bool HasSSE41() {
return JSC::MacroAssembler::getSSEState() >= JSC::MacroAssembler::HasSSE4_1;
return JSC::MacroAssembler::isSSE41Present();
}
// The below cmpl methods switch the lhs and rhs when it invokes the

Просмотреть файл

@ -1069,7 +1069,7 @@ CodeGeneratorShared::computeDivisionConstants(int d) {
// M * n if this is the case (cf. item (a) above).
ReciprocalMulConstants rmc;
rmc.multiplier = int32_t((int64_t(1) << (shift+32))/d + 1);
rmc.shift_amount = shift;
rmc.shiftAmount = shift;
return rmc;
}

Просмотреть файл

@ -47,7 +47,7 @@ struct PatchableBackedgeInfo
struct ReciprocalMulConstants {
int32_t multiplier;
int32_t shift_amount;
int32_t shiftAmount;
};
class CodeGeneratorShared : public LInstructionVisitor

Просмотреть файл

@ -928,6 +928,7 @@ CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
// This emits the division answer into edx or the modulus answer into eax.
JS_ASSERT(output == eax || output == edx);
JS_ASSERT(lhs != eax && lhs != edx);
bool isDiv = (output == edx);
// The absolute value of the denominator isn't a power of 2 (see LDivPowTwoI
// and LModPowTwoI).
@ -942,12 +943,11 @@ CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
// is non-negative or (rmc.multiplier * n) + (2^32 * n) otherwise. This is the
// desired division result if n is non-negative, and is one less than the result
// otherwise.
masm.movl(lhs, eax);
masm.movl(Imm32(rmc.multiplier), edx);
masm.imull(edx);
masm.movl(Imm32(rmc.multiplier), eax);
masm.imull(lhs);
if (rmc.multiplier < 0)
masm.addl(lhs, edx);
masm.sarl(Imm32(rmc.shift_amount), edx);
masm.sarl(Imm32(rmc.shiftAmount), edx);
// We'll subtract -1 instead of adding 1, because (n < 0 ? -1 : 0) can be
// computed with just a sign-extending shift of 31 bits.
@ -957,17 +957,17 @@ CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
masm.subl(eax, edx);
}
// After this, edx contains the correct division result.
// After this, edx contains the correct truncated division result.
if (d < 0)
masm.negl(edx);
if (output == eax) {
if (!isDiv) {
masm.imull(Imm32(-d), edx, eax);
masm.addl(lhs, eax);
}
if (!ins->mir()->isTruncated()) {
if (output == edx) {
if (isDiv) {
// This is a division op. Multiply the obtained value by d to check if
// the correct answer is an integer. This cannot overflow, since |d| > 1.
masm.imull(Imm32(d), edx, eax);

Просмотреть файл

@ -938,6 +938,7 @@ void
nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
const nsFrameList& aFrames,
const nsRect& aDirtyRect) {
mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength());
for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
mFramesMarkedForDisplay.AppendElement(e.get());
MarkOutOfFlowFrameForDisplay(aDirtyFrame, e.get(), aDirtyRect);

Просмотреть файл

@ -8905,6 +8905,7 @@ PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) :
aEvent->message,
aEvent->widget);
keyEvent->AssignKeyEventData(*aEvent, false);
keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests;
mEvent = keyEvent;
}

Просмотреть файл

@ -12554,8 +12554,13 @@ CSSParserImpl::ParseFunction(nsCSSKeyword aFunction,
/* Read in a list of values as an array, failing if we can't or if
* it's out of bounds.
*
* We reserve 16 entries in the foundValues array in order to avoid
* having to resize the array dynamically when parsing some well-formed
* functions. The number 16 is coming from the number of arguments that
* matrix3d() accepts.
*/
InfallibleTArray<nsCSSValue> foundValues;
AutoInfallibleTArray<nsCSSValue, 16> foundValues;
if (!ParseFunctionInternals(aAllowedTypes, aAllowedTypesAll, aMinElems,
aMaxElems, foundValues)) {
return false;

Просмотреть файл

@ -771,7 +771,7 @@ var gFlexboxTestcases =
// max-size violated (the second one) and restart the algorithm. This time,
// all the available space (200px - 50px = 150px) goes to the not-yet-frozen
// first item, and that puts it above its min-size, so all is well.
{
{
items:
[
{

Просмотреть файл

@ -48,7 +48,9 @@
#include "mtransport_test_utils.h"
#include "gtest_ringbuffer_dumper.h"
MtransportTestUtils *test_utils;
nsCOMPtr<nsIThread> gThread;
nsCOMPtr<nsIThread> gMainThread;
nsCOMPtr<nsIThread> gGtestThread;
bool gTestsComplete = false;
#ifndef USE_FAKE_MEDIA_STREAMS
#error USE_FAKE_MEDIA_STREAMS undefined
@ -213,19 +215,6 @@ enum mediaPipelineFlags
};
static bool SetupGlobalThread() {
if (!gThread) {
nsIThread *thread;
nsresult rv = NS_NewNamedThread("pseudo-main",&thread);
if (NS_FAILED(rv))
return false;
gThread = thread;
}
return true;
}
class TestObserver : public AFakePCObserver
{
public:
@ -703,7 +692,7 @@ class SignalingAgent {
~SignalingAgent() {
mozilla::SyncRunnable::DispatchToThread(gThread,
mozilla::SyncRunnable::DispatchToThread(gMainThread,
WrapRunnable(this, &SignalingAgent::Close));
}
@ -1282,7 +1271,6 @@ class SignalingEnvironment : public ::testing::Environment {
class SignalingAgentTest : public ::testing::Test {
public:
static void SetUpTestCase() {
ASSERT_TRUE(SetupGlobalThread());
}
void TearDown() {
@ -1301,7 +1289,7 @@ class SignalingAgentTest : public ::testing::Test {
ScopedDeletePtr<SignalingAgent> agent(
new SignalingAgent("agent", stun_addr, stun_port));
agent->Init(gThread);
agent->Init(gMainThread);
if (wait_for_gather) {
if (!agent->WaitForGatherAllowFail())
@ -1345,7 +1333,6 @@ public:
stun_port_(stun_port) {}
static void SetUpTestCase() {
ASSERT_TRUE(SetupGlobalThread());
}
void EnsureInit() {
@ -1356,8 +1343,8 @@ public:
a1_ = new SignalingAgent(callerName, stun_addr_, stun_port_);
a2_ = new SignalingAgent(calleeName, stun_addr_, stun_port_);
a1_->Init(gThread);
a2_->Init(gThread);
a1_->Init(gMainThread);
a2_->Init(gMainThread);
if (wait_for_gather_) {
WaitForGather();
@ -1370,7 +1357,6 @@ public:
}
static void TearDownTestCase() {
gThread = nullptr;
}
void CreateOffer(sipcc::MediaConstraints& constraints,
@ -1636,12 +1622,51 @@ public:
uint16_t stun_port_;
};
static void SetIntPrefOnMainThread(nsCOMPtr<nsIPrefBranch> prefs,
const char *pref_name,
int new_value) {
MOZ_ASSERT(NS_IsMainThread());
prefs->SetIntPref(pref_name, new_value);
}
static void SetMaxFsFr(nsCOMPtr<nsIPrefBranch> prefs,
int max_fs,
int max_fr) {
gMainThread->Dispatch(
WrapRunnableNM(SetIntPrefOnMainThread,
prefs,
"media.navigator.video.max_fs",
max_fs),
NS_DISPATCH_SYNC);
gMainThread->Dispatch(
WrapRunnableNM(SetIntPrefOnMainThread,
prefs,
"media.navigator.video.max_fr",
max_fr),
NS_DISPATCH_SYNC);
}
class FsFrPrefClearer {
public:
FsFrPrefClearer(nsCOMPtr<nsIPrefBranch> prefs): mPrefs(prefs) {}
~FsFrPrefClearer() {
mPrefs->ClearUserPref("media.navigator.video.max_fs");
mPrefs->ClearUserPref("media.navigator.video.max_fr");
gMainThread->Dispatch(
WrapRunnableNM(FsFrPrefClearer::ClearUserPrefOnMainThread,
mPrefs,
"media.navigator.video.max_fs"),
NS_DISPATCH_SYNC);
gMainThread->Dispatch(
WrapRunnableNM(FsFrPrefClearer::ClearUserPrefOnMainThread,
mPrefs,
"media.navigator.video.max_fr"),
NS_DISPATCH_SYNC);
}
static void ClearUserPrefOnMainThread(nsCOMPtr<nsIPrefBranch> prefs,
const char *pref_name) {
MOZ_ASSERT(NS_IsMainThread());
prefs->ClearUserPref(pref_name);
}
private:
nsCOMPtr<nsIPrefBranch> mPrefs;
@ -3458,8 +3483,7 @@ TEST_F(SignalingTest, MaxFsFrInOffer)
ASSERT_TRUE(prefs);
FsFrPrefClearer prefClearer(prefs);
prefs->SetIntPref("media.navigator.video.max_fs", 300);
prefs->SetIntPref("media.navigator.video.max_fr", 30);
SetMaxFsFr(prefs, 300, 30);
a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
@ -3479,8 +3503,7 @@ TEST_F(SignalingTest, MaxFsFrInAnswer)
FsFrPrefClearer prefClearer(prefs);
// We don't want max_fs and max_fr prefs impact SDP at this moment
prefs->SetIntPref("media.navigator.video.max_fs", 0);
prefs->SetIntPref("media.navigator.video.max_fr", 0);
SetMaxFsFr(prefs, 0, 0);
a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
@ -3489,8 +3512,7 @@ TEST_F(SignalingTest, MaxFsFrInAnswer)
a2_->SetRemote(TestObserver::OFFER, a1_->offer());
prefs->SetIntPref("media.navigator.video.max_fs", 600);
prefs->SetIntPref("media.navigator.video.max_fr", 60);
SetMaxFsFr(prefs, 600, 60);
a2_->CreateAnswer(constraints, a1_->offer(), OFFER_AV | ANSWER_AV);
@ -3510,8 +3532,7 @@ TEST_F(SignalingTest, MaxFsFrCalleeCodec)
FsFrPrefClearer prefClearer(prefs);
// We don't want max_fs and max_fr prefs impact SDP at this moment
prefs->SetIntPref("media.navigator.video.max_fs", 0);
prefs->SetIntPref("media.navigator.video.max_fr", 0);
SetMaxFsFr(prefs, 0, 0);
a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
@ -3567,8 +3588,7 @@ TEST_F(SignalingTest, MaxFsFrCallerCodec)
FsFrPrefClearer prefClearer(prefs);
// We don't want max_fs and max_fr prefs impact SDP at this moment
prefs->SetIntPref("media.navigator.video.max_fs", 0);
prefs->SetIntPref("media.navigator.video.max_fr", 0);
SetMaxFsFr(prefs, 0, 0);
a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
a1_->SetLocal(TestObserver::OFFER, a1_->offer());
@ -3642,6 +3662,39 @@ static std::string get_environment(const char *name) {
return value;
}
// This exists to send as an event to trigger shutdown.
static void tests_complete() {
gTestsComplete = true;
}
// The GTest thread runs this instead of the main thread so it can
// do things like ASSERT_TRUE_WAIT which you could not do on the main thread.
static int gtest_main(int argc, char **argv) {
MOZ_ASSERT(!NS_IsMainThread());
::testing::InitGoogleTest(&argc, argv);
for(int i=0; i<argc; i++) {
if (!strcmp(argv[i],"-t")) {
kDefaultTimeout = 20000;
}
}
::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment);
int result = RUN_ALL_TESTS();
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
// Set the global shutdown flag and tickle the main thread
// The main thread did not go through Init() so calling Shutdown()
// on it will not work.
gMainThread->Dispatch(WrapRunnableNM(tests_complete), NS_DISPATCH_SYNC);
return result;
}
int main(int argc, char **argv) {
// This test can cause intermittent oranges on the builders
@ -3667,14 +3720,6 @@ int main(int argc, char **argv) {
NSS_NoDB_Init(nullptr);
NSS_SetDomesticPolicy();
::testing::InitGoogleTest(&argc, argv);
for(int i=0; i<argc; i++) {
if (!strcmp(argv[i],"-t")) {
kDefaultTimeout = 20000;
}
}
::testing::TestEventListeners& listeners =
::testing::UnitTest::GetInstance()->listeners();
// Adds a listener to the end. Google Test takes the ownership.
@ -3682,15 +3727,28 @@ int main(int argc, char **argv) {
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment);
int result = RUN_ALL_TESTS();
// Set the main thread global which is this thread.
nsIThread *thread;
NS_GetMainThread(&thread);
gMainThread = thread;
MOZ_ASSERT(NS_IsMainThread());
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
// Now create the GTest thread and run all of the tests on it
// When it is complete it will set gTestsComplete
NS_NewNamedThread("gtest_thread", &thread);
gGtestThread = thread;
int result;
gGtestThread->Dispatch(
WrapRunnableNMRet(gtest_main, argc, argv, &result), NS_DISPATCH_NORMAL);
// Here we handle the event queue for dispatches to the main thread
// When the GTest thread is complete it will send one more dispatch
// with gTestsComplete == true.
while (!gTestsComplete && NS_ProcessNextEvent());
gGtestThread->Shutdown();
// Because we don't initialize on the main thread, we can't register for
// XPCOM shutdown callbacks (where the context is usually shut down) --
// so we need to explictly destroy the context.
sipcc::PeerConnectionCtx::Destroy();
delete test_utils;

Просмотреть файл

@ -136,17 +136,37 @@ typedef std::vector<std::pair<pthread_key_t, void *>,
LibcAllocator<std::pair<pthread_key_t, void *> > >
TLSInfoList;
/**
* Return the system's page size
*/
static size_t getPageSize(void) {
#ifdef HAVE_GETPAGESIZE
return getpagesize();
#elif defined(_SC_PAGESIZE)
return sysconf(_SC_PAGESIZE);
#elif defined(PAGE_SIZE)
return PAGE_SIZE;
#else
#warning "Hard-coding page size to 4096 bytes"
return 4096
#endif
}
/**
* Align the pointer to the next page boundary unless it's already aligned
*/
static uintptr_t ceilToPage(uintptr_t aPtr) {
size_t pageSize = getPageSize();
return ((aPtr + pageSize - 1) / pageSize) * pageSize;
}
/**
* The stack size is chosen carefully so the frozen threads doesn't consume too
* much memory in the Nuwa process. The threads shouldn't run deep recursive
* methods or do large allocations on the stack to avoid stack overflow.
*/
#ifndef NUWA_STACK_SIZE
#ifndef PAGE_SIZE
#warning "Hard-coding page size to 4096 byte"
#define PAGE_SIZE 4096ul
#endif
#define PAGE_ALIGN_MASK (~(PAGE_SIZE-1))
#define NUWA_STACK_SIZE (1024 * 128)
#endif
@ -495,17 +515,13 @@ thread_info_new(void) {
tinfo->recreatedThreadID = 0;
tinfo->recreatedNativeThreadID = 0;
tinfo->reacquireMutex = nullptr;
tinfo->stk = malloc(NUWA_STACK_SIZE + PAGE_SIZE);
tinfo->stk = malloc(NUWA_STACK_SIZE + getPageSize());
// We use a smaller stack size. Add protection to stack overflow: mprotect()
// stack top (the page at the lowest address) so we crash instead of corrupt
// other content that is malloc()'d.
unsigned long long pageGuard = ((unsigned long long)tinfo->stk);
pageGuard &= PAGE_ALIGN_MASK;
if (pageGuard != (unsigned long long) tinfo->stk) {
pageGuard += PAGE_SIZE; // Round up to be page-aligned.
}
mprotect((void*)pageGuard, PAGE_SIZE, PROT_READ);
uintptr_t pageGuard = ceilToPage((uintptr_t)tinfo->stk);
mprotect((void*)pageGuard, getPageSize(), PROT_READ);
pthread_attr_init(&tinfo->threadAttr);

Просмотреть файл

@ -942,15 +942,9 @@ TabActor.prototype = {
* True if the window.console object is native, or false otherwise.
*/
hasNativeConsoleAPI: function BTA_hasNativeConsoleAPI(aWindow) {
let isNative = false;
try {
// We are very explicitly examining the "console" property of
// the non-Xrayed object here.
let console = aWindow.wrappedJSObject.console;
isNative = console instanceof aWindow.Console;
}
catch (ex) { }
return isNative;
// Do not expose WebConsoleActor function directly as it is always
// loaded after the BrowserTabActor
return WebConsoleActor.prototype.hasNativeConsoleAPI(aWindow);
}
};

Просмотреть файл

@ -6,34 +6,28 @@
"use strict";
let {Cc, Ci, Cu} = require("chrome");
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let { DebuggerServer, ActorPool } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
// Symbols from script.js
let { ThreadActor, EnvironmentActor, ObjectActor, LongStringActor } = DebuggerServer;
Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "NetworkMonitor", () => {
return require("devtools/toolkit/webconsole/network-monitor")
return devtools.require("devtools/toolkit/webconsole/network-monitor")
.NetworkMonitor;
});
XPCOMUtils.defineLazyGetter(this, "NetworkMonitorChild", () => {
return require("devtools/toolkit/webconsole/network-monitor")
return devtools.require("devtools/toolkit/webconsole/network-monitor")
.NetworkMonitorChild;
});
XPCOMUtils.defineLazyGetter(this, "ConsoleProgressListener", () => {
return require("devtools/toolkit/webconsole/network-monitor")
return devtools.require("devtools/toolkit/webconsole/network-monitor")
.ConsoleProgressListener;
});
XPCOMUtils.defineLazyGetter(this, "events", () => {
return require("sdk/event/core");
});
for (let name of ["WebConsoleUtils", "ConsoleServiceListener",
"ConsoleAPIListener", "JSTermHelpers", "JSPropertyProvider",
@ -43,7 +37,7 @@ for (let name of ["WebConsoleUtils", "ConsoleServiceListener",
if (prop == "WebConsoleUtils") {
prop = "Utils";
}
return require("devtools/toolkit/webconsole/utils")[prop];
return devtools.require("devtools/toolkit/webconsole/utils")[prop];
}.bind(null, name),
configurable: true,
enumerable: true
@ -1834,12 +1828,6 @@ NetworkEventActor.prototype.requestTypes =
"getEventTimings": NetworkEventActor.prototype.onGetEventTimings,
};
exports.register = function(handle) {
handle.addGlobalActor(WebConsoleActor, "consoleActor");
handle.addTabActor(WebConsoleActor, "consoleActor");
};
DebuggerServer.addTabActor(WebConsoleActor, "consoleActor");
DebuggerServer.addGlobalActor(WebConsoleActor, "consoleActor");
exports.unregister = function(handle) {
handle.removeGlobalActor(WebConsoleActor, "consoleActor");
handle.removeTabActor(WebConsoleActor, "consoleActor");
};

Просмотреть файл

@ -360,7 +360,7 @@ var DebuggerServer = {
// In case of apps being loaded in parent process, DebuggerServer is already
// initialized and browser actors are already loaded,
// but childtab.js hasn't been loaded yet.
if (!DebuggerServer.tabActorFactories.hasOwnProperty("consoleActor")) {
if (!("WebConsoleActor" in this)) {
this.addTabActors();
}
// But webbrowser.js and childtab.js aren't loaded from shell.js.
@ -377,7 +377,7 @@ var DebuggerServer = {
*/
addTabActors: function() {
this.addActors("resource://gre/modules/devtools/server/actors/script.js");
this.registerModule("devtools/server/actors/webconsole");
this.addActors("resource://gre/modules/devtools/server/actors/webconsole.js");
this.registerModule("devtools/server/actors/inspector");
this.registerModule("devtools/server/actors/call-watcher");
this.registerModule("devtools/server/actors/canvas");

Просмотреть файл

@ -117,8 +117,7 @@ function test_profile(aClient, aProfiler)
let location = stack.name + " (" + stack.filename + ":" + funcLine + ")";
// At least one sample is expected to have been in the busy wait above.
do_check_true(aResponse.profile.threads[0].samples.some(function(sample) {
return sample.name == "(root)" &&
typeof sample.frames == "object" &&
return typeof sample.frames == "object" &&
sample.frames.length != 0 &&
sample.frames.some(function(f) {
return (f.line == stack.lineNumber) &&

Просмотреть файл

@ -26,10 +26,6 @@
#include "UnwinderThread2.h"
#include "TableTicker.h"
// JSON
#include "JSObjectBuilder.h"
#include "nsIJSRuntimeService.h"
// Meta
#include "nsXPCOM.h"
#include "nsXPCOMCID.h"

Просмотреть файл

@ -151,6 +151,9 @@ static inline char* profiler_get_profile() { return nullptr; }
// Get the profile encoded as a JSON object.
static inline JSObject* profiler_get_profile_jsobject(JSContext* aCx) { return nullptr; }
// Get the profile and write it into a file
static inline void profiler_save_profile_to_file(char* aFilename) { }
// Get the features supported by the profiler that are accepted by profiler_init.
// Returns a null terminated char* array.
static inline char** profiler_get_features() { return nullptr; }

Просмотреть файл

@ -56,6 +56,8 @@ char* mozilla_sampler_get_profile();
JSObject *mozilla_sampler_get_profile_data(JSContext *aCx);
void mozilla_sampler_save_profile_to_file(const char* aFilename);
const char** mozilla_sampler_get_features();
void mozilla_sampler_init(void* stackTop);

Просмотреть файл

@ -143,6 +143,12 @@ JSObject* profiler_get_profile_jsobject(JSContext* aCx)
return mozilla_sampler_get_profile_data(aCx);
}
static inline
void profiler_save_profile_to_file(const char* aFilename)
{
return mozilla_sampler_save_profile_to_file(aFilename);
}
static inline
const char** profiler_get_features()
{

Просмотреть файл

@ -1,318 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "JSCustomObjectBuilder.h"
#include "mozilla/ArrayUtils.h" // for ArrayLength
#include "nsDataHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsUTF8Utils.h"
#if _MSC_VER
#define snprintf _snprintf
#endif
// These are owned and deleted by JSCustomObject
struct PropertyValue {
virtual ~PropertyValue() {}
virtual void SendToStream(std::ostream& stream) = 0;
};
template <typename T>
struct finalizer_impl
{
static void run(T) {}
};
template <typename T>
struct finalizer_impl<T*>
{
static void run(T* p) {
delete p;
}
};
template <>
struct finalizer_impl<char *>
{
static void run(char* p) {
free(p);
}
};
template <class T>
class TemplatePropertyValue : public PropertyValue {
public:
TemplatePropertyValue(T aValue)
: mValue(aValue)
{}
~TemplatePropertyValue() {
finalizer_impl<T>::run(mValue);
}
virtual void SendToStream(std::ostream& stream);
private:
T mValue;
};
// Escape a UTF8 string to a stream. When an illegal encoding
// is found it will insert "INVALID" and the function will return.
void EscapeToStream(std::ostream& stream, const char* str) {
stream << "\"";
size_t len = strlen(str);
const char* end = &str[len];
while (str < end) {
bool err;
const char* utf8CharStart = str;
uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err);
if (err) {
// Encoding error
stream << "INVALID\"";
return;
}
// See http://www.ietf.org/rfc/rfc4627.txt?number=4627
// characters that must be escaped: quotation mark,
// reverse solidus, and the control characters
// (U+0000 through U+001F).
if (ucs4Char == '\"') {
stream << "\\\"";
} else if (ucs4Char == '\\') {
stream << "\\\\";
} else if (ucs4Char > 0xFF) {
char16_t chr[2];
ConvertUTF8toUTF16 encoder(chr);
encoder.write(utf8CharStart, uint32_t(str-utf8CharStart));
char escChar[13];
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]);
stream << escChar;
} else if (ucs4Char < 0x1F || ucs4Char > 0xFF) {
char escChar[7];
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char);
stream << escChar;
} else {
stream << char(ucs4Char);
}
}
stream << "\"";
}
class JSCustomObject {
public:
JSCustomObject() {}
~JSCustomObject();
friend std::ostream& operator<<(std::ostream& stream, JSCustomObject* entry);
template<class T>
void AddProperty(const char* aName, T aValue) {
mProperties.Put(nsDependentCString(aName), new TemplatePropertyValue<T>(aValue));
}
nsDataHashtable<nsCStringHashKey, PropertyValue*> mProperties;
};
class JSCustomArray {
public:
nsTArray<PropertyValue*> mValues;
friend std::ostream& operator<<(std::ostream& stream, JSCustomArray* entry);
template<class T>
void AppendElement(T aValue) {
mValues.AppendElement(new TemplatePropertyValue<T>(aValue));
}
};
template <typename T>
struct SendToStreamImpl
{
static void run(std::ostream& stream, const T& t) {
stream << t;
}
};
template<typename T>
struct SendToStreamImpl<T*>
{
static void run(std::ostream& stream, T* t) {
stream << *t;
}
};
template <>
struct SendToStreamImpl<char *>
{
static void run(std::ostream& stream, char* p) {
EscapeToStream(stream, p);
}
};
template <>
struct SendToStreamImpl<double>
{
static void run(std::ostream& stream, double p) {
// 13 for ms, 16 of microseconds, plus an extra 2
stream.precision(18);
stream << p;
}
};
template <>
struct SendToStreamImpl<JSCustomObject*>
{
static void run(std::ostream& stream, JSCustomObject* p) {
stream << p;
}
};
template <>
struct SendToStreamImpl<JSCustomArray*>
{
static void run(std::ostream& stream, JSCustomArray* p) {
stream << p;
}
};
template <class T> void
TemplatePropertyValue<T>::SendToStream(std::ostream& stream)
{
SendToStreamImpl<T>::run(stream, mValue);
}
struct JSONStreamClosure {
std::ostream& mStream;
bool mNeedsComma;
};
PLDHashOperator HashTableOutput(const nsACString& aKey, PropertyValue* aValue, void* stream)
{
JSONStreamClosure& streamClosure = *(JSONStreamClosure*)stream;
if (streamClosure.mNeedsComma) {
streamClosure.mStream << ",";
}
streamClosure.mNeedsComma = true;
EscapeToStream(streamClosure.mStream, (const char*)aKey.BeginReading());
streamClosure.mStream << ":";
aValue->SendToStream(streamClosure.mStream);
return PL_DHASH_NEXT;
}
std::ostream&
operator<<(std::ostream& stream, JSCustomObject* entry)
{
JSONStreamClosure streamClosure = {stream, false};
stream << "{";
entry->mProperties.EnumerateRead(HashTableOutput, &streamClosure);
stream << "}";
return stream;
}
std::ostream&
operator<<(std::ostream& stream, JSCustomArray* entry)
{
bool needsComma = false;
stream << "[";
for (uint32_t i = 0; i < entry->mValues.Length(); i++) {
if (needsComma) {
stream << ",";
}
entry->mValues[i]->SendToStream(stream);
needsComma = true;
}
stream << "]";
return stream;
}
PLDHashOperator HashTableFree(const nsACString& aKey, PropertyValue* aValue, void* stream)
{
delete aValue;
return PL_DHASH_NEXT;
}
JSCustomObject::~JSCustomObject()
{
mProperties.EnumerateRead(HashTableFree, nullptr);
}
JSCustomObjectBuilder::JSCustomObjectBuilder()
{}
void
JSCustomObjectBuilder::DeleteObject(JSCustomObject* aObject)
{
delete aObject;
}
void
JSCustomObjectBuilder::Serialize(JSCustomObject* aObject, std::ostream& stream)
{
stream << aObject;
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, int aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, double aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, const char *aValue)
{
// aValue copy will be freed by the property desctructor (template specialization)
aObject->AddProperty(name, strdup(aValue));
}
void
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, int aValue)
{
aArray->AppendElement(aValue);
}
void
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, const char *aValue)
{
// aValue copy will be freed by the property desctructor (template specialization)
aArray->AppendElement(strdup(aValue));
}
void
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject)
{
aArray->AppendElement(aObject);
}
JSCustomArray*
JSCustomObjectBuilder::CreateArray() {
return new JSCustomArray();
}
JSCustomObject*
JSCustomObjectBuilder::CreateObject() {
return new JSCustomObject();
}

Просмотреть файл

@ -1,65 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef JSCUSTOMOBJECTBUILDER_H
#define JSCUSTOMOBJECTBUILDER_H
#include <ostream>
#include <stdlib.h>
#include "js/RootingAPI.h"
class JSCustomObject;
class JSCustomArray;
class JSCustomObjectBuilder
{
public:
typedef JSCustomObject* Object;
typedef JSCustomArray* Array;
typedef JSCustomObject* ObjectHandle;
typedef JSCustomArray* ArrayHandle;
typedef js::FakeRooted<JSCustomObject*> RootedObject;
typedef js::FakeRooted<JSCustomArray*> RootedArray;
// We need to ensure that this object lives on the stack so that GC sees it properly
JSCustomObjectBuilder();
void Serialize(JSCustomObject* aObject, std::ostream& stream);
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue);
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue);
void DefineProperty(JSCustomObject *aObject, const char *name, int value);
void DefineProperty(JSCustomObject *aObject, const char *name, double value);
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value, size_t valueLength);
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value);
void ArrayPush(JSCustomArray *aArray, int value);
void ArrayPush(JSCustomArray *aArray, const char *value);
void ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject);
JSCustomArray *CreateArray();
JSCustomObject *CreateObject();
// Delete this object and all of its descendant
void DeleteObject(JSCustomObject* aObject);
JSContext *context() const { return nullptr; }
private:
// This class can't be copied
JSCustomObjectBuilder(const JSCustomObjectBuilder&);
JSCustomObjectBuilder& operator=(const JSCustomObjectBuilder&);
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) {
// Since JSCustomObjectBuilder has a virtual destructor the compiler
// has to provide a destructor in the object file that will call
// operate delete in case there is a derived class since its
// destructor wont know how to free this instance.
abort();
}
void operator delete[](void*);
};
#endif

Просмотреть файл

@ -1,145 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "jsapi.h"
#include "nsString.h"
#include "JSObjectBuilder.h"
JSObjectBuilder::JSObjectBuilder(JSContext *aCx) : mCx(aCx), mOk(true)
{}
void
JSObjectBuilder::DefineProperty(JS::HandleObject aObject, const char *name, JS::HandleObject aValue)
{
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, aValue, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JS::HandleObject aObject, const char *name, int value)
{
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, value, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JS::HandleObject aObject, const char *name, double value)
{
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, value, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JS::HandleObject aObject, const char *name, nsAString &value)
{
if (!mOk)
return;
const nsString &flat = PromiseFlatString(value);
JS::RootedString string(mCx, JS_NewUCStringCopyN(mCx, static_cast<const jschar*>(flat.get()), flat.Length()));
if (!string)
mOk = false;
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, string, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JS::HandleObject aObject, const char *name, const char *value, size_t valueLength)
{
if (!mOk)
return;
JS::RootedString string(mCx, JS_InternStringN(mCx, value, valueLength));
if (!string) {
mOk = false;
return;
}
mOk = JS_DefineProperty(mCx, aObject, name, string, JSPROP_ENUMERATE); }
void
JSObjectBuilder::DefineProperty(JS::HandleObject aObject, const char *name, const char *value)
{
DefineProperty(aObject, name, value, strlen(value));
}
void
JSObjectBuilder::ArrayPush(JS::HandleObject aArray, int value)
{
if (!mOk)
return;
uint32_t length;
mOk = JS_GetArrayLength(mCx, aArray, &length);
if (!mOk)
return;
mOk = JS_SetElement(mCx, aArray, length, value);
}
void
JSObjectBuilder::ArrayPush(JS::HandleObject aArray, const char *value)
{
if (!mOk)
return;
JS::RootedString string(mCx, JS_NewStringCopyN(mCx, value, strlen(value)));
if (!string) {
mOk = false;
return;
}
uint32_t length;
mOk = JS_GetArrayLength(mCx, aArray, &length);
if (!mOk)
return;
mOk = JS_SetElement(mCx, aArray, length, string);
}
void
JSObjectBuilder::ArrayPush(JS::HandleObject aArray, JS::HandleObject aObject)
{
if (!mOk)
return;
uint32_t length;
mOk = JS_GetArrayLength(mCx, aArray, &length);
if (!mOk)
return;
mOk = JS_SetElement(mCx, aArray, length, aObject);
}
JSObject*
JSObjectBuilder::CreateArray() {
JSObject *array = JS_NewArrayObject(mCx, 0);
if (!array)
mOk = false;
return array;
}
JSObject*
JSObjectBuilder::CreateObject() {
JSObject *obj = JS_NewObject(mCx, nullptr, JS::NullPtr(), JS::NullPtr());
if (!obj)
mOk = false;
return obj;
}

Просмотреть файл

@ -1,67 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef JSOBJECTBUILDER_H
#define JSOBJECTBUILDER_H
#include "js/TypeDecls.h"
#include "js/RootingAPI.h"
class JSCustomArray;
class JSCustomObject;
class JSCustomObjectBuilder;
class nsAString;
/* this is handy wrapper around JSAPI to make it more pleasant to use.
* We collect the JSAPI errors and so that callers don't need to */
class JSObjectBuilder
{
public:
typedef JS::Handle<JSObject*> ObjectHandle;
typedef JS::Handle<JSObject*> ArrayHandle;
typedef JS::Rooted<JSObject*> RootedObject;
typedef JS::Rooted<JSObject*> RootedArray;
typedef JSObject* Object;
typedef JSObject* Array;
// We need to ensure that this object lives on the stack so that GC sees it properly
explicit JSObjectBuilder(JSContext *aCx);
~JSObjectBuilder() {}
void DefineProperty(JS::HandleObject aObject, const char *name, JS::HandleObject aValue);
void DefineProperty(JS::HandleObject aObject, const char *name, int value);
void DefineProperty(JS::HandleObject aObject, const char *name, double value);
void DefineProperty(JS::HandleObject aObject, const char *name, nsAString &value);
void DefineProperty(JS::HandleObject aObject, const char *name, const char *value, size_t valueLength);
void DefineProperty(JS::HandleObject aObject, const char *name, const char *value);
void ArrayPush(JS::HandleObject aArray, int value);
void ArrayPush(JS::HandleObject aArray, const char *value);
void ArrayPush(JS::HandleObject aArray, JS::HandleObject aObject);
JSObject *CreateArray();
JSObject *CreateObject();
JSContext *context() const { return mCx; }
private:
JSObjectBuilder(const JSObjectBuilder&);
JSObjectBuilder& operator=(const JSObjectBuilder&);
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) {
// Since JSObjectBuilder has a virtual destructor the compiler
// has to provide a destructor in the object file that will call
// operate delete in case there is a derived class since its
// destructor wont know how to free this instance.
abort();
}
void operator delete[](void*);
JSContext *mCx;
int mOk;
};
#endif

Просмотреть файл

@ -0,0 +1,180 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "JSStreamWriter.h"
#include "mozilla/ArrayUtils.h" // for ArrayLength
#include "nsDataHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsUTF8Utils.h"
#if _MSC_VER
#define snprintf _snprintf
#endif
#define ARRAY (void*)1
#define OBJECT (void*)2
// Escape a UTF8 string to a stream. When an illegal encoding
// is found it will insert "INVALID" and the function will return.
static void EscapeToStream(std::ostream& stream, const char* str) {
stream << "\"";
size_t len = strlen(str);
const char* end = &str[len];
while (str < end) {
bool err;
const char* utf8CharStart = str;
uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err);
if (err) {
// Encoding error
stream << "INVALID\"";
return;
}
// See http://www.ietf.org/rfc/rfc4627.txt?number=4627
// characters that must be escaped: quotation mark,
// reverse solidus, and the control characters
// (U+0000 through U+001F).
if (ucs4Char == '\"') {
stream << "\\\"";
} else if (ucs4Char == '\\') {
stream << "\\\\";
} else if (ucs4Char > 0xFF) {
char16_t chr[2];
ConvertUTF8toUTF16 encoder(chr);
encoder.write(utf8CharStart, uint32_t(str-utf8CharStart));
char escChar[13];
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]);
stream << escChar;
} else if (ucs4Char < 0x1F || ucs4Char > 0xFF) {
char escChar[7];
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char);
stream << escChar;
} else {
stream << char(ucs4Char);
}
}
stream << "\"";
}
JSStreamWriter::JSStreamWriter(std::ostream& aStream)
: mStream(aStream)
, mNeedsComma(false)
, mNeedsName(false)
{ }
JSStreamWriter::~JSStreamWriter()
{
MOZ_ASSERT(mStack.GetSize() == 0);
}
void
JSStreamWriter::BeginObject()
{
MOZ_ASSERT(!mNeedsName);
if (mNeedsComma && mStack.Peek() == ARRAY) {
mStream << ",";
}
mStream << "{";
mNeedsComma = false;
mNeedsName = true;
mStack.Push(OBJECT);
}
void
JSStreamWriter::EndObject()
{
MOZ_ASSERT(mStack.Peek() == OBJECT);
mStream << "}";
mNeedsComma = true;
mNeedsName = false;
mStack.Pop();
if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) {
mNeedsName = true;
}
}
void
JSStreamWriter::BeginArray()
{
MOZ_ASSERT(!mNeedsName);
if (mNeedsComma && mStack.Peek() == ARRAY) {
mStream << ",";
}
mStream << "[";
mNeedsComma = false;
mStack.Push(ARRAY);
}
void
JSStreamWriter::EndArray()
{
MOZ_ASSERT(!mNeedsName);
MOZ_ASSERT(mStack.Peek() == ARRAY);
mStream << "]";
mNeedsComma = true;
mStack.Pop();
if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) {
mNeedsName = true;
}
}
void
JSStreamWriter::Name(const char *aName)
{
MOZ_ASSERT(mNeedsName);
if (mNeedsComma && mStack.Peek() == OBJECT) {
mStream << ",";
}
EscapeToStream(mStream, aName);
mStream << ":";
mNeedsName = false;
}
void
JSStreamWriter::Value(int aValue)
{
MOZ_ASSERT(!mNeedsName);
if (mNeedsComma && mStack.Peek() == ARRAY) {
mStream << ",";
}
mStream << aValue;
mNeedsComma = true;
if (mStack.Peek() == OBJECT) {
mNeedsName = true;
}
}
void
JSStreamWriter::Value(double aValue)
{
MOZ_ASSERT(!mNeedsName);
if (mNeedsComma && mStack.Peek() == ARRAY) {
mStream << ",";
}
mStream.precision(18);
mStream << aValue;
mNeedsComma = true;
if (mStack.Peek() == OBJECT) {
mNeedsName = true;
}
}
void
JSStreamWriter::Value(const char *aValue)
{
MOZ_ASSERT(!mNeedsName);
if (mNeedsComma && mStack.Peek() == ARRAY) {
mStream << ",";
}
EscapeToStream(mStream, aValue);
mNeedsComma = true;
if (mStack.Peek() == OBJECT) {
mNeedsName = true;
}
}

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef JSSTREAMWRITER_H
#define JSSTREAMWRITER_H
#include <ostream>
#include <stdlib.h>
#include "nsDeque.h"
class JSStreamWriter
{
public:
JSStreamWriter(std::ostream& aStream);
~JSStreamWriter();
void BeginObject();
void EndObject();
void BeginArray();
void EndArray();
void Name(const char *name);
void Value(int value);
void Value(double value);
void Value(const char *value, size_t valueLength);
void Value(const char *value);
template <typename T>
void NameValue(const char *aName, T aValue)
{
Name(aName);
Value(aValue);
}
private:
std::ostream& mStream;
bool mNeedsComma;
bool mNeedsName;
nsDeque mStack;
// This class can't be copied
JSStreamWriter(const JSStreamWriter&);
JSStreamWriter& operator=(const JSStreamWriter&);
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) {
// Since JSStreamWriter has a virtual destructor the compiler
// has to provide a destructor in the object file that will call
// operate delete in case there is a derived class since its
// destructor won't know how to free this instance.
abort();
}
void operator delete[](void*);
};
#endif

Просмотреть файл

@ -4,13 +4,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <ostream>
#include <sstream>
#include "platform.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "jsapi.h"
// JSON
#include "JSObjectBuilder.h"
#include "JSCustomObjectBuilder.h"
#include "JSStreamWriter.h"
// Self
#include "ProfileEntry.h"
@ -308,138 +309,159 @@ void ThreadProfile::IterateTags(IterateTagsCallback aCallback)
void ThreadProfile::ToStreamAsJSON(std::ostream& stream)
{
JSCustomObjectBuilder b;
JSCustomObject *profile = b.CreateObject();
BuildJSObject(b, profile);
b.Serialize(profile, stream);
b.DeleteObject(profile);
JSStreamWriter b(stream);
StreamJSObject(b);
}
void ThreadProfile::StreamJSObject(JSStreamWriter& b)
{
b.BeginObject();
// Thread meta data
if (XRE_GetProcessType() == GeckoProcessType_Plugin) {
// TODO Add the proper plugin name
b.NameValue("name", "Plugin");
} else {
b.NameValue("name", mName);
}
b.NameValue("tid", static_cast<int>(mThreadId));
b.Name("samples");
b.BeginArray();
bool sample = false;
int readPos = mReadPos;
while (readPos != mLastFlushPos) {
// Number of tag consumed
ProfileEntry entry = mEntries[readPos];
switch (entry.mTagName) {
case 'r':
{
if (sample) {
b.NameValue("responsiveness", entry.mTagFloat);
}
}
break;
case 'p':
{
if (sample) {
b.NameValue("power", entry.mTagFloat);
}
}
break;
case 'f':
{
if (sample) {
b.NameValue("frameNumber", entry.mTagLine);
}
}
break;
case 't':
{
if (sample) {
b.NameValue("time", entry.mTagFloat);
}
}
break;
case 's':
{
// end the previous sample if there was one
if (sample) {
b.EndObject();
}
// begin the next sample
b.BeginObject();
sample = true;
// Seek forward through the entire sample, looking for frames
// this is an easier approach to reason about than adding more
// control variables and cases to the loop that goes through the buffer once
b.Name("frames");
b.BeginArray();
b.BeginObject();
b.NameValue("location", "(root)");
b.EndObject();
int framePos = (readPos + 1) % mEntrySize;
ProfileEntry frame = mEntries[framePos];
while (framePos != mLastFlushPos && frame.mTagName != 's') {
int incBy = 1;
frame = mEntries[framePos];
// Read ahead to the next tag, if it's a 'd' tag process it now
const char* tagStringData = frame.mTagData;
int readAheadPos = (framePos + 1) % mEntrySize;
char tagBuff[DYNAMIC_MAX_STRING];
// Make sure the string is always null terminated if it fills up
// DYNAMIC_MAX_STRING-2
tagBuff[DYNAMIC_MAX_STRING-1] = '\0';
if (readAheadPos != mLastFlushPos && mEntries[readAheadPos].mTagName == 'd') {
tagStringData = processDynamicTag(framePos, &incBy, tagBuff);
}
// Write one frame. It can have either
// 1. only location - 'l' containing a memory address
// 2. location and line number - 'c' followed by 'd's and an optional 'n'
if (frame.mTagName == 'l') {
b.BeginObject();
// Bug 753041
// We need a double cast here to tell GCC that we don't want to sign
// extend 32-bit addresses starting with 0xFXXXXXX.
unsigned long long pc = (unsigned long long)(uintptr_t)frame.mTagPtr;
snprintf(tagBuff, DYNAMIC_MAX_STRING, "%#llx", pc);
b.NameValue("location", tagBuff);
b.EndObject();
} else if (frame.mTagName == 'c') {
b.BeginObject();
b.NameValue("location", tagStringData);
readAheadPos = (framePos + incBy) % mEntrySize;
if (readAheadPos != mLastFlushPos &&
mEntries[readAheadPos].mTagName == 'n') {
b.NameValue("line", mEntries[readAheadPos].mTagLine);
incBy++;
}
b.EndObject();
}
framePos = (framePos + incBy) % mEntrySize;
}
b.EndArray();
}
break;
}
readPos = (readPos + 1) % mEntrySize;
}
if (sample) {
b.EndObject();
}
b.EndArray();
b.Name("markers");
b.BeginArray();
readPos = mReadPos;
while (readPos != mLastFlushPos) {
ProfileEntry entry = mEntries[readPos];
if (entry.mTagName == 'm') {
entry.getMarker()->StreamJSObject(b);
}
readPos = (readPos + 1) % mEntrySize;
}
b.EndArray();
b.EndObject();
}
JSObject* ThreadProfile::ToJSObject(JSContext *aCx)
{
JSObjectBuilder b(aCx);
JS::RootedObject profile(aCx, b.CreateObject());
BuildJSObject(b, profile);
return profile;
JS::RootedValue val(aCx);
std::stringstream ss;
JSStreamWriter b(ss);
StreamJSObject(b);
NS_ConvertUTF8toUTF16 js_string(nsDependentCString(ss.str().c_str()));
JS_ParseJSON(aCx, static_cast<const jschar*>(js_string.get()), js_string.Length(), &val);
return &val.toObject();
}
template <typename Builder>
void ThreadProfile::BuildJSObject(Builder& b,
typename Builder::ObjectHandle profile)
{
// Thread meta data
if (XRE_GetProcessType() == GeckoProcessType_Plugin) {
// TODO Add the proper plugin name
b.DefineProperty(profile, "name", "Plugin");
} else {
b.DefineProperty(profile, "name", mName);
}
b.DefineProperty(profile, "tid", static_cast<int>(mThreadId));
typename Builder::RootedArray samples(b.context(), b.CreateArray());
b.DefineProperty(profile, "samples", samples);
typename Builder::RootedArray markers(b.context(), b.CreateArray());
b.DefineProperty(profile, "markers", markers);
typename Builder::RootedObject sample(b.context());
typename Builder::RootedArray frames(b.context());
int readPos = mReadPos;
while (readPos != mLastFlushPos) {
// Number of tag consumed
int incBy = 1;
ProfileEntry entry = mEntries[readPos];
// Read ahead to the next tag, if it's a 'd' tag process it now
const char* tagStringData = entry.mTagData;
int readAheadPos = (readPos + 1) % mEntrySize;
char tagBuff[DYNAMIC_MAX_STRING];
// Make sure the string is always null terminated if it fills up
// DYNAMIC_MAX_STRING-2
tagBuff[DYNAMIC_MAX_STRING-1] = '\0';
if (readAheadPos != mLastFlushPos && mEntries[readAheadPos].mTagName == 'd') {
tagStringData = processDynamicTag(readPos, &incBy, tagBuff);
}
switch (entry.mTagName) {
case 'm':
{
entry.getMarker()->BuildJSObject(b, markers);
}
break;
case 'r':
{
if (sample) {
b.DefineProperty(sample, "responsiveness", entry.mTagFloat);
}
}
break;
case 'p':
{
if (sample) {
b.DefineProperty(sample, "power", entry.mTagFloat);
}
}
break;
case 'f':
{
if (sample) {
b.DefineProperty(sample, "frameNumber", entry.mTagLine);
}
}
break;
case 't':
{
if (sample) {
b.DefineProperty(sample, "time", entry.mTagFloat);
}
}
break;
case 's':
sample = b.CreateObject();
b.DefineProperty(sample, "name", tagStringData);
frames = b.CreateArray();
b.DefineProperty(sample, "frames", frames);
b.ArrayPush(samples, sample);
// Fall though to create a label for the 's' tag
case 'c':
case 'l':
{
if (sample) {
typename Builder::RootedObject frame(b.context(), b.CreateObject());
if (entry.mTagName == 'l') {
// Bug 753041
// We need a double cast here to tell GCC that we don't want to sign
// extend 32-bit addresses starting with 0xFXXXXXX.
unsigned long long pc = (unsigned long long)(uintptr_t)entry.mTagPtr;
snprintf(tagBuff, DYNAMIC_MAX_STRING, "%#llx", pc);
b.DefineProperty(frame, "location", tagBuff);
} else {
b.DefineProperty(frame, "location", tagStringData);
readAheadPos = (readPos + incBy) % mEntrySize;
if (readAheadPos != mLastFlushPos &&
mEntries[readAheadPos].mTagName == 'n') {
b.DefineProperty(frame, "line",
mEntries[readAheadPos].mTagLine);
incBy++;
}
}
b.ArrayPush(frames, frame);
}
}
}
readPos = (readPos + incBy) % mEntrySize;
}
}
template void ThreadProfile::BuildJSObject<JSObjectBuilder>(JSObjectBuilder& b,
JS::HandleObject profile);
template void ThreadProfile::BuildJSObject<JSCustomObjectBuilder>(JSCustomObjectBuilder& b,
JSCustomObject *profile);
PseudoStack* ThreadProfile::GetPseudoStack()
{
return mPseudoStack;

Просмотреть файл

@ -10,6 +10,7 @@
#include <ostream>
#include "GeckoProfiler.h"
#include "platform.h"
#include "JSStreamWriter.h"
#include "ProfilerBacktrace.h"
#include "mozilla/Mutex.h"
@ -82,7 +83,7 @@ public:
JSObject *ToJSObject(JSContext *aCx);
PseudoStack* GetPseudoStack();
mozilla::Mutex* GetMutex();
template <typename Builder> void BuildJSObject(Builder& b, typename Builder::ObjectHandle profile);
void StreamJSObject(JSStreamWriter& b);
void BeginUnwind();
virtual void EndUnwind();
virtual SyncProfile* AsSyncProfile() { return nullptr; }

Просмотреть файл

@ -4,11 +4,11 @@
* 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 "JSCustomObjectBuilder.h"
#include "JSObjectBuilder.h"
#include "JSStreamWriter.h"
#include "ProfilerBacktrace.h"
#include "SyncProfile.h"
ProfilerBacktrace::ProfilerBacktrace(SyncProfile* aProfile)
: mProfile(aProfile)
{
@ -22,18 +22,9 @@ ProfilerBacktrace::~ProfilerBacktrace()
}
}
template<typename Builder> void
ProfilerBacktrace::BuildJSObject(Builder& aObjBuilder,
typename Builder::ObjectHandle aScope)
void
ProfilerBacktrace::StreamJSObject(JSStreamWriter& b)
{
mozilla::MutexAutoLock lock(*mProfile->GetMutex());
mProfile->BuildJSObject(aObjBuilder, aScope);
mProfile->StreamJSObject(b);
}
template void
ProfilerBacktrace::BuildJSObject<JSCustomObjectBuilder>(
JSCustomObjectBuilder& aObjBuilder,
JSCustomObjectBuilder::ObjectHandle aScope);
template void
ProfilerBacktrace::BuildJSObject<JSObjectBuilder>(JSObjectBuilder& aObjBuilder,
JSObjectBuilder::ObjectHandle aScope);

Просмотреть файл

@ -15,8 +15,7 @@ public:
ProfilerBacktrace(SyncProfile* aProfile);
~ProfilerBacktrace();
template<typename Builder> void
BuildJSObject(Builder& aObjBuilder, typename Builder::ObjectHandle aScope);
void StreamJSObject(JSStreamWriter& b);
private:
ProfilerBacktrace(const ProfilerBacktrace&);

Просмотреть файл

@ -26,89 +26,62 @@ ProfilerMarkerPayload::~ProfilerMarkerPayload()
profiler_free_backtrace(mStack);
}
template<typename Builder> void
ProfilerMarkerPayload::prepareCommonProps(const char* aMarkerType,
Builder& aBuilder,
typename Builder::ObjectHandle aObject)
void
ProfilerMarkerPayload::streamCommonProps(const char* aMarkerType,
JSStreamWriter& b)
{
MOZ_ASSERT(aMarkerType);
aBuilder.DefineProperty(aObject, "type", aMarkerType);
b.NameValue("type", aMarkerType);
if (!mStartTime.IsNull()) {
aBuilder.DefineProperty(aObject, "startTime", profiler_time(mStartTime));
b.NameValue("startTime", profiler_time(mStartTime));
}
if (!mEndTime.IsNull()) {
aBuilder.DefineProperty(aObject, "endTime", profiler_time(mEndTime));
b.NameValue("endTime", profiler_time(mEndTime));
}
if (mStack) {
typename Builder::RootedObject stack(aBuilder.context(),
aBuilder.CreateObject());
aBuilder.DefineProperty(aObject, "stack", stack);
mStack->BuildJSObject(aBuilder, stack);
b.Name("stack");
mStack->StreamJSObject(b);
}
}
template void
ProfilerMarkerPayload::prepareCommonProps<JSCustomObjectBuilder>(
const char* aMarkerType,
JSCustomObjectBuilder& b,
JSCustomObjectBuilder::ObjectHandle aObject);
template void
ProfilerMarkerPayload::prepareCommonProps<JSObjectBuilder>(
const char* aMarkerType,
JSObjectBuilder& b,
JSObjectBuilder::ObjectHandle aObject);
ProfilerMarkerTracing::ProfilerMarkerTracing(const char* aCategory, TracingMetadata aMetaData)
: mCategory(aCategory)
, mMetaData(aMetaData)
{}
template<typename Builder>
typename Builder::Object
ProfilerMarkerTracing::preparePayloadImp(Builder& b)
void
ProfilerMarkerTracing::streamPayloadImp(JSStreamWriter& b)
{
typename Builder::RootedObject data(b.context(), b.CreateObject());
prepareCommonProps("tracing", b, data);
b.BeginObject();
streamCommonProps("tracing", b);
if (GetCategory()) {
b.DefineProperty(data, "category", GetCategory());
}
if (GetMetaData() != TRACING_DEFAULT) {
if (GetMetaData() == TRACING_INTERVAL_START) {
b.DefineProperty(data, "interval", "start");
} else if (GetMetaData() == TRACING_INTERVAL_END) {
b.DefineProperty(data, "interval", "end");
if (GetCategory()) {
b.NameValue("category", GetCategory());
}
}
return data;
if (GetMetaData() != TRACING_DEFAULT) {
if (GetMetaData() == TRACING_INTERVAL_START) {
b.NameValue("interval", "start");
} else if (GetMetaData() == TRACING_INTERVAL_END) {
b.NameValue("interval", "end");
}
}
b.EndObject();
}
template JSCustomObjectBuilder::Object
ProfilerMarkerTracing::preparePayloadImp<JSCustomObjectBuilder>(JSCustomObjectBuilder& b);
template JSObjectBuilder::Object
ProfilerMarkerTracing::preparePayloadImp<JSObjectBuilder>(JSObjectBuilder& b);
ProfilerMarkerImagePayload::ProfilerMarkerImagePayload(gfxASurface *aImg)
: mImg(aImg)
{}
template<typename Builder>
typename Builder::Object
ProfilerMarkerImagePayload::preparePayloadImp(Builder& b)
void
ProfilerMarkerImagePayload::streamPayloadImp(JSStreamWriter& b)
{
typename Builder::RootedObject data(b.context(), b.CreateObject());
prepareCommonProps("innerHTML", b, data);
// TODO: Finish me
//b.DefineProperty(data, "innerHTML", "<img src=''/>");
return data;
b.BeginObject();
streamCommonProps("innerHTML", b);
// TODO: Finish me
//b.NameValue("innerHTML", "<img src=''/>");
b.EndObject();
}
template JSCustomObjectBuilder::Object
ProfilerMarkerImagePayload::preparePayloadImp<JSCustomObjectBuilder>(JSCustomObjectBuilder& b);
template JSObjectBuilder::Object
ProfilerMarkerImagePayload::preparePayloadImp<JSObjectBuilder>(JSObjectBuilder& b);
IOMarkerPayload::IOMarkerPayload(const char* aSource,
const char* aFilename,
const mozilla::TimeStamp& aStartTime,
@ -125,23 +98,18 @@ IOMarkerPayload::~IOMarkerPayload(){
free(mFilename);
}
template<typename Builder> typename Builder::Object
IOMarkerPayload::preparePayloadImp(Builder& b)
void
IOMarkerPayload::streamPayloadImp(JSStreamWriter& b)
{
typename Builder::RootedObject data(b.context(), b.CreateObject());
prepareCommonProps("io", b, data);
b.DefineProperty(data, "source", mSource);
if (mFilename != nullptr) {
b.DefineProperty(data, "filename", mFilename);
}
return data;
b.BeginObject();
streamCommonProps("io", b);
b.NameValue("source", mSource);
if (mFilename != nullptr) {
b.NameValue("filename", mFilename);
}
b.EndObject();
}
template JSCustomObjectBuilder::Object
IOMarkerPayload::preparePayloadImp<JSCustomObjectBuilder>(JSCustomObjectBuilder& b);
template JSObjectBuilder::Object
IOMarkerPayload::preparePayloadImp<JSObjectBuilder>(JSObjectBuilder& b);
void
ProfilerJSEventMarker(const char *event)

Просмотреть файл

@ -6,8 +6,7 @@
#ifndef PROFILER_MARKERS_H
#define PROFILER_MARKERS_H
#include "JSCustomObjectBuilder.h"
#include "JSObjectBuilder.h"
#include "JSStreamWriter.h"
#include "mozilla/TimeStamp.h"
#include "nsAutoPtr.h"
@ -42,31 +41,21 @@ public:
/**
* Called from the main thread
*/
template<typename Builder>
typename Builder::Object PreparePayload(Builder& b)
{
return preparePayload(b);
void StreamPayload(JSStreamWriter& b) {
return streamPayload(b);
}
protected:
/**
* Called from the main thread
*/
template<typename Builder>
void prepareCommonProps(const char* aMarkerType, Builder& aBuilder,
typename Builder::ObjectHandle aObject);
void streamCommonProps(const char* aMarkerType, JSStreamWriter& b);
/**
* Called from the main thread
*/
virtual JSCustomObjectBuilder::Object
preparePayload(JSCustomObjectBuilder& b) = 0;
/**
* Called from the main thread
*/
virtual JSObjectBuilder::Object
preparePayload(JSObjectBuilder& b) = 0;
virtual void
streamPayload(JSStreamWriter& b) = 0;
private:
mozilla::TimeStamp mStartTime;
@ -83,14 +72,11 @@ public:
TracingMetadata GetMetaData() const { return mMetaData; }
protected:
virtual JSCustomObjectBuilder::Object
preparePayload(JSCustomObjectBuilder& b) { return preparePayloadImp(b); }
virtual JSObjectBuilder::Object
preparePayload(JSObjectBuilder& b) { return preparePayloadImp(b); }
virtual void
streamPayload(JSStreamWriter& b) { return streamPayloadImp(b); }
private:
template<typename Builder>
typename Builder::Object preparePayloadImp(Builder& b);
void streamPayloadImp(JSStreamWriter& b);
private:
const char *mCategory;
@ -105,14 +91,11 @@ public:
ProfilerMarkerImagePayload(gfxASurface *aImg);
protected:
virtual JSCustomObjectBuilder::Object
preparePayload(JSCustomObjectBuilder& b) { return preparePayloadImp(b); }
virtual JSObjectBuilder::Object
preparePayload(JSObjectBuilder& b) { return preparePayloadImp(b); }
virtual void
streamPayload(JSStreamWriter& b) { return streamPayloadImp(b); }
private:
template<typename Builder>
typename Builder::Object preparePayloadImp(Builder& b);
void streamPayloadImp(JSStreamWriter& b);
nsRefPtr<gfxASurface> mImg;
};
@ -126,14 +109,11 @@ public:
~IOMarkerPayload();
protected:
virtual JSCustomObjectBuilder::Object
preparePayload(JSCustomObjectBuilder& b) { return preparePayloadImp(b); }
virtual JSObjectBuilder::Object
preparePayload(JSObjectBuilder& b) { return preparePayloadImp(b); }
virtual void
streamPayload(JSStreamWriter& b) { return streamPayloadImp(b); }
private:
template<typename Builder>
typename Builder::Object preparePayloadImp(Builder& b);
void streamPayloadImp(JSStreamWriter& b);
const char* mSource;
char* mFilename;

Просмотреть файл

@ -110,7 +110,7 @@ public:
class ProfilerMarkerPayload;
template<typename T>
class ProfilerLinkedList;
class JSAObjectBuilder;
class JSStreamWriter;
class JSCustomArray;
class ThreadProfile;
class ProfilerMarker {
@ -126,8 +126,8 @@ public:
return mMarkerName;
}
template<typename Builder> void
BuildJSObject(Builder& b, typename Builder::ArrayHandle markers) const;
void
StreamJSObject(JSStreamWriter& b) const;
void SetGeneration(int aGenID);

Просмотреть файл

@ -6,15 +6,6 @@
#include "SaveProfileTask.h"
#include "GeckoProfiler.h"
static bool
WriteCallback(const jschar *buf, uint32_t len, void *data)
{
std::ofstream& stream = *static_cast<std::ofstream*>(data);
nsAutoCString profile = NS_ConvertUTF16toUTF8(buf, len);
stream << profile.Data();
return true;
}
nsresult
SaveProfileTask::Run() {
// Get file path
@ -39,48 +30,7 @@ SaveProfileTask::Run() {
return rv;
#endif
// Create a JSContext to run a JSObjectBuilder :(
// Based on XPCShellEnvironment
JSRuntime *rt;
JSContext *cx;
nsCOMPtr<nsIJSRuntimeService> rtsvc
= do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
if (!rtsvc || NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
LOG("failed to get RuntimeService");
return NS_ERROR_FAILURE;;
}
cx = JS_NewContext(rt, 8192);
if (!cx) {
LOG("Failed to get context");
return NS_ERROR_FAILURE;
}
{
JSAutoRequest ar(cx);
static const JSClass c = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
nullptr, nullptr, nullptr, nullptr,
JS_GlobalObjectTraceHook
};
JSObject *obj = JS_NewGlobalObject(cx, &c, nullptr, JS::FireOnNewGlobalHook);
std::ofstream stream;
stream.open(tmpPath.get());
if (stream.is_open()) {
JSAutoCompartment autoComp(cx, obj);
JSObject* profileObj = profiler_get_profile_jsobject(cx);
JS::Rooted<JS::Value> val(cx, OBJECT_TO_JSVAL(profileObj));
JS_Stringify(cx, &val, JS::NullPtr(), JS::NullHandleValue, WriteCallback, &stream);
stream.close();
LOGF("Saved to %s", tmpPath.get());
} else {
LOG("Fail to open profile log file.");
}
}
JS_DestroyContext(cx);
profiler_save_profile_to_file(tmpPath.get());
return NS_OK;
}

Просмотреть файл

@ -15,9 +15,6 @@
#include "nsIJSRuntimeService.h"
#include "nsIProfileSaveEvent.h"
#include <ostream>
#include <fstream>
#ifdef XP_WIN
#include <windows.h>
#define getpid GetCurrentProcessId

Просмотреть файл

@ -21,8 +21,7 @@
#include "nsXULAppAPI.h"
// JSON
#include "JSObjectBuilder.h"
#include "JSCustomObjectBuilder.h"
#include "JSStreamWriter.h"
// Meta
#include "nsXPCOM.h"
@ -105,203 +104,209 @@ void TableTicker::HandleSaveRequest()
NS_DispatchToMainThread(runnable);
}
template <typename Builder>
typename Builder::Object TableTicker::GetMetaJSCustomObject(Builder& b)
void TableTicker::StreamMetaJSCustomObject(JSStreamWriter& b)
{
typename Builder::RootedObject meta(b.context(), b.CreateObject());
b.BeginObject();
b.DefineProperty(meta, "version", 2);
b.DefineProperty(meta, "interval", interval());
b.DefineProperty(meta, "stackwalk", mUseStackWalk);
b.DefineProperty(meta, "jank", mJankOnly);
b.DefineProperty(meta, "processType", XRE_GetProcessType());
b.NameValue("version", 2);
b.NameValue("interval", interval());
b.NameValue("stackwalk", mUseStackWalk);
b.NameValue("jank", mJankOnly);
b.NameValue("processType", XRE_GetProcessType());
TimeDuration delta = TimeStamp::Now() - sStartTime;
b.DefineProperty(meta, "startTime", static_cast<float>(PR_Now()/1000.0 - delta.ToMilliseconds()));
TimeDuration delta = TimeStamp::Now() - sStartTime;
b.NameValue("startTime", static_cast<float>(PR_Now()/1000.0 - delta.ToMilliseconds()));
nsresult res;
nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res);
if (!NS_FAILED(res)) {
nsAutoCString string;
nsresult res;
nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res);
if (!NS_FAILED(res)) {
nsAutoCString string;
res = http->GetPlatform(string);
if (!NS_FAILED(res))
b.DefineProperty(meta, "platform", string.Data());
res = http->GetPlatform(string);
if (!NS_FAILED(res))
b.NameValue("platform", string.Data());
res = http->GetOscpu(string);
if (!NS_FAILED(res))
b.DefineProperty(meta, "oscpu", string.Data());
res = http->GetOscpu(string);
if (!NS_FAILED(res))
b.NameValue("oscpu", string.Data());
res = http->GetMisc(string);
if (!NS_FAILED(res))
b.DefineProperty(meta, "misc", string.Data());
}
res = http->GetMisc(string);
if (!NS_FAILED(res))
b.NameValue("misc", string.Data());
}
nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
if (runtime) {
nsAutoCString string;
nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
if (runtime) {
nsAutoCString string;
res = runtime->GetXPCOMABI(string);
if (!NS_FAILED(res))
b.DefineProperty(meta, "abi", string.Data());
res = runtime->GetXPCOMABI(string);
if (!NS_FAILED(res))
b.NameValue("abi", string.Data());
res = runtime->GetWidgetToolkit(string);
if (!NS_FAILED(res))
b.DefineProperty(meta, "toolkit", string.Data());
}
res = runtime->GetWidgetToolkit(string);
if (!NS_FAILED(res))
b.NameValue("toolkit", string.Data());
}
nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
if (appInfo) {
nsAutoCString string;
nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
if (appInfo) {
nsAutoCString string;
res = appInfo->GetName(string);
if (!NS_FAILED(res))
b.DefineProperty(meta, "product", string.Data());
}
res = appInfo->GetName(string);
if (!NS_FAILED(res))
b.NameValue("product", string.Data());
}
return meta;
b.EndObject();
}
void TableTicker::ToStreamAsJSON(std::ostream& stream)
{
JSCustomObjectBuilder b;
JSCustomObject* profile = b.CreateObject();
BuildJSObject(b, profile);
b.Serialize(profile, stream);
b.DeleteObject(profile);
JSStreamWriter b(stream);
StreamJSObject(b);
}
JSObject* TableTicker::ToJSObject(JSContext *aCx)
{
JSObjectBuilder b(aCx);
JS::RootedObject profile(aCx, b.CreateObject());
BuildJSObject(b, profile);
return profile;
JS::RootedValue val(aCx);
std::stringstream ss;
JSStreamWriter b(ss);
StreamJSObject(b);
NS_ConvertUTF8toUTF16 js_string(nsDependentCString(ss.str().c_str()));
JS_ParseJSON(aCx, static_cast<const jschar*>(js_string.get()), js_string.Length(), &val);
return &val.toObject();
}
template <typename Builder>
struct SubprocessClosure {
SubprocessClosure(Builder *aBuilder, typename Builder::ArrayHandle aThreads)
: mBuilder(aBuilder), mThreads(aThreads)
SubprocessClosure(JSStreamWriter *aWriter)
: mWriter(aWriter)
{}
Builder* mBuilder;
typename Builder::ArrayHandle mThreads;
JSStreamWriter* mWriter;
};
template <typename Builder>
void SubProcessCallback(const char* aProfile, void* aClosure)
{
// Called by the observer to get their profile data included
// as a sub profile
SubprocessClosure<Builder>* closure = (SubprocessClosure<Builder>*)aClosure;
SubprocessClosure* closure = (SubprocessClosure*)aClosure;
closure->mBuilder->ArrayPush(closure->mThreads, aProfile);
// Add the string profile into the profile
closure->mWriter->Value(aProfile);
}
#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
template <typename Builder>
static
typename Builder::Object BuildJavaThreadJSObject(Builder& b)
void BuildJavaThreadJSObject(JSStreamWriter& b)
{
typename Builder::RootedObject javaThread(b.context(), b.CreateObject());
b.DefineProperty(javaThread, "name", "Java Main Thread");
b.BeginObject();
typename Builder::RootedArray samples(b.context(), b.CreateArray());
b.DefineProperty(javaThread, "samples", samples);
b.NameValue("name", "Java Main Thread");
int sampleId = 0;
while (true) {
int frameId = 0;
typename Builder::RootedObject sample(b.context());
typename Builder::RootedArray frames(b.context());
while (true) {
nsCString result;
bool hasFrame = AndroidBridge::Bridge()->GetFrameNameJavaProfiling(0, sampleId, frameId, result);
if (!hasFrame) {
if (frames) {
b.DefineProperty(sample, "frames", frames);
b.Name("samples");
b.BeginArray();
// for each sample
for (int sampleId = 0; true; sampleId++) {
bool firstRun = true;
// for each frame
for (int frameId = 0; true; frameId++) {
nsCString result;
bool hasFrame = AndroidBridge::Bridge()->GetFrameNameJavaProfiling(0, sampleId, frameId, result);
// when we run out of frames, we stop looping
if (!hasFrame) {
// if we found at least one frame, we have objects to close
if (!firstRun) {
b.EndArray();
b.EndObject();
}
break;
}
// the first time around, open the sample object and frames array
if (firstRun) {
firstRun = false;
double sampleTime =
mozilla::widget::android::GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
b.BeginObject();
b.NameValue("time", sampleTime);
b.Name("frames");
b.BeginArray();
}
// add a frame to the sample
b.BeginObject();
b.NameValue("location", result.BeginReading());
b.EndObject();
}
// if we found no frames for this sample, we are done
if (firstRun) {
break;
}
break;
}
if (!sample) {
sample = b.CreateObject();
frames = b.CreateArray();
b.DefineProperty(sample, "frames", frames);
b.ArrayPush(samples, sample);
double sampleTime =
mozilla::widget::android::GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
b.DefineProperty(sample, "time", sampleTime);
}
typename Builder::RootedObject frame(b.context(), b.CreateObject());
b.DefineProperty(frame, "location", result.BeginReading());
b.ArrayPush(frames, frame);
frameId++;
}
if (frameId == 0) {
break;
}
sampleId++;
}
b.EndArray();
return javaThread;
b.EndObject();
}
#endif
template <typename Builder>
void TableTicker::BuildJSObject(Builder& b, typename Builder::ObjectHandle profile)
void TableTicker::StreamJSObject(JSStreamWriter& b)
{
// Put shared library info
b.DefineProperty(profile, "libs", GetSharedLibraryInfoString().c_str());
b.BeginObject();
// Put shared library info
b.NameValue("libs", GetSharedLibraryInfoString().c_str());
// Put meta data
typename Builder::RootedObject meta(b.context(), GetMetaJSCustomObject(b));
b.DefineProperty(profile, "meta", meta);
// Put meta data
b.Name("meta");
StreamMetaJSCustomObject(b);
// Lists the samples for each ThreadProfile
typename Builder::RootedArray threads(b.context(), b.CreateArray());
b.DefineProperty(profile, "threads", threads);
// Lists the samples for each ThreadProfile
b.Name("threads");
b.BeginArray();
SetPaused(true);
SetPaused(true);
{
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
{
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
// Thread not being profiled, skip it
if (!sRegisteredThreads->at(i)->Profile())
continue;
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
// Thread not being profiled, skip it
if (!sRegisteredThreads->at(i)->Profile())
continue;
MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex());
MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex());
typename Builder::RootedObject threadSamples(b.context(), b.CreateObject());
sRegisteredThreads->at(i)->Profile()->BuildJSObject(b, threadSamples);
b.ArrayPush(threads, threadSamples);
}
}
sRegisteredThreads->at(i)->Profile()->StreamJSObject(b);
}
}
#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
if (ProfileJava()) {
mozilla::widget::android::GeckoJavaSampler::PauseJavaProfiling();
// Send a event asking any subprocesses (plugins) to
// give us their information
SubprocessClosure closure(&b);
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
nsRefPtr<ProfileSaveEvent> pse = new ProfileSaveEvent(SubProcessCallback, &closure);
os->NotifyObservers(pse, "profiler-subprocess", nullptr);
}
typename Builder::RootedObject javaThread(b.context(), BuildJavaThreadJSObject(b));
b.ArrayPush(threads, javaThread);
#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
if (ProfileJava()) {
mozilla::widget::android::GeckoJavaSampler::PauseJavaProfiling();
mozilla::widget::android::GeckoJavaSampler::UnpauseJavaProfiling();
}
#endif
BuildJavaThreadJSObject(b);
SetPaused(false);
mozilla::widget::android::GeckoJavaSampler::UnpauseJavaProfiling();
}
#endif
SetPaused(false);
b.EndArray();
b.EndObject();
// Send a event asking any subprocesses (plugins) to
// give us their information
SubprocessClosure<Builder> closure(&b, threads);
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
nsRefPtr<ProfileSaveEvent> pse = new ProfileSaveEvent(SubProcessCallback<Builder>, &closure);
os->NotifyObservers(pse, "profiler-subprocess", nullptr);
}
}
// END SaveProfileTask et al

Просмотреть файл

@ -176,8 +176,7 @@ class TableTicker: public Sampler {
void ToStreamAsJSON(std::ostream& stream);
virtual JSObject *ToJSObject(JSContext *aCx);
template <typename Builder> typename Builder::Object GetMetaJSCustomObject(Builder& b);
void StreamMetaJSCustomObject(JSStreamWriter& b);
bool HasUnwinderThread() const { return mUnwinderThread; }
bool ProfileJS() const { return mProfileJS; }
bool ProfileJava() const { return mProfileJava; }
@ -196,7 +195,7 @@ protected:
// Not implemented on platforms which do not support backtracing
void doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample);
template <typename Builder> void BuildJSObject(Builder& b, typename Builder::ObjectHandle profile);
void StreamJSObject(JSStreamWriter& b);
// This represent the application's main thread (SAMPLER_INIT)
ThreadProfile* mPrimaryThreadProfile;

Просмотреть файл

@ -24,8 +24,7 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
]
UNIFIED_SOURCES += [
'BreakpadSampler.cpp',
'JSCustomObjectBuilder.cpp',
'JSObjectBuilder.cpp',
'JSStreamWriter.cpp',
'nsProfiler.cpp',
'nsProfilerFactory.cpp',
'platform.cpp',

Просмотреть файл

@ -204,10 +204,10 @@ nsProfiler::GetSharedLibraryInformation(nsAString& aOutString)
NS_IMETHODIMP nsProfiler::GetProfileData(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult)
{
JSObject *obj = profiler_get_profile_jsobject(aCx);
if (!obj)
JS::RootedObject obj(aCx, profiler_get_profile_jsobject(aCx));
if (!obj) {
return NS_ERROR_FAILURE;
}
aResult.setObject(*obj);
return NS_OK;
}

Просмотреть файл

@ -132,29 +132,20 @@ ProfilerMarker::GetTime() {
return mTime;
}
template<typename Builder> void
ProfilerMarker::BuildJSObject(Builder& b, typename Builder::ArrayHandle markers) const {
typename Builder::RootedObject marker(b.context(), b.CreateObject());
b.DefineProperty(marker, "name", GetMarkerName());
// TODO: Store the callsite for this marker if available:
// if have location data
// b.DefineProperty(marker, "location", ...);
if (mPayload) {
typename Builder::RootedObject markerData(b.context(),
mPayload->PreparePayload(b));
b.DefineProperty(marker, "data", markerData);
}
b.DefineProperty(marker, "time", mTime);
b.ArrayPush(markers, marker);
void ProfilerMarker::StreamJSObject(JSStreamWriter& b) const {
b.BeginObject();
b.NameValue("name", GetMarkerName());
// TODO: Store the callsite for this marker if available:
// if have location data
// b.NameValue(marker, "location", ...);
if (mPayload) {
b.Name("data");
mPayload->StreamPayload(b);
}
b.NameValue("time", mTime);
b.EndObject();
}
template void
ProfilerMarker::BuildJSObject<JSCustomObjectBuilder>(JSCustomObjectBuilder& b,
JSCustomObjectBuilder::ArrayHandle markers) const;
template void
ProfilerMarker::BuildJSObject<JSObjectBuilder>(JSObjectBuilder& b,
JSObjectBuilder::ArrayHandle markers) const;
PendingMarkers::~PendingMarkers() {
clearMarkers();
if (mSignalLock != false) {
@ -573,6 +564,24 @@ JSObject *mozilla_sampler_get_profile_data(JSContext *aCx)
return t->ToJSObject(aCx);
}
void mozilla_sampler_save_profile_to_file(const char* aFilename)
{
TableTicker *t = tlsTicker.get();
if (!t) {
return;
}
std::ofstream stream;
stream.open(aFilename);
if (stream.is_open()) {
t->ToStreamAsJSON(stream);
stream.close();
LOGF("Saved to %s", aFilename);
} else {
LOG("Fail to open profile log file.");
}
}
const char** mozilla_sampler_get_features()
{

Просмотреть файл

@ -0,0 +1,183 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "gtest/gtest.h"
#include <sstream>
#include "JSStreamWriter.h"
TEST(JSStreamWriter, NoOutput) {
std::stringstream ss;
JSStreamWriter b(ss);
ASSERT_TRUE(ss.str().compare("") == 0);
}
TEST(JSStreamWriter, EmptyObject) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginObject();
b.EndObject();
ASSERT_TRUE(ss.str().compare("{}") == 0);
}
TEST(JSStreamWriter, OnePropertyObject) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginObject();
b.Name("a");
b.Value(1);
b.EndObject();
ASSERT_TRUE(ss.str().compare("{\"a\":1}") == 0);
}
TEST(JSStreamWriter, MultiPropertyObject) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginObject();
b.Name("a");
b.Value(1);
b.Name("b");
b.Value(2);
b.EndObject();
ASSERT_TRUE(ss.str().compare("{\"a\":1,\"b\":2}") == 0);
}
TEST(JSStreamWriter, OnePropertyArray) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginArray();
b.Value(1);
b.EndArray();
ASSERT_TRUE(ss.str().compare("[1]") == 0);
}
TEST(JSStreamWriter, MultiPropertyArray) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginArray();
b.Value(1);
b.Value(2);
b.EndArray();
ASSERT_TRUE(ss.str().compare("[1,2]") == 0);
}
TEST(JSStreamWriter, NestedObject) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginObject();
b.Name("a");
b.BeginObject();
b.Name("b");
b.Value(1);
b.EndObject();
b.EndObject();
ASSERT_TRUE(ss.str().compare("{\"a\":{\"b\":1}}") == 0);
}
TEST(JSStreamWriter, NestedObjectInArray) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginArray();
b.BeginObject();
b.Name("a");
b.Value(1);
b.EndObject();
b.EndArray();
ASSERT_TRUE(ss.str().compare("[{\"a\":1}]") == 0);
}
TEST(JSStreamWriter, NestedArrayInObject) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginObject();
b.Name("a");
b.BeginArray();
b.Value(1);
b.EndArray();
b.EndObject();
ASSERT_TRUE(ss.str().compare("{\"a\":[1]}") == 0);
}
TEST(JSStreamWriter, StingEscaping) {
std::stringstream ss;
JSStreamWriter b(ss);
b.Value("a\"a");
ASSERT_TRUE(ss.str().compare("\"a\\\"a\"") == 0);
std::stringstream ss2;
JSStreamWriter b2(ss2);
b2.Value("a\na");
ASSERT_TRUE(ss2.str().compare("\"a\\u000Aa\"") == 0);
}
TEST(JSStreamWriter, ArrayOfOjects) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginArray();
b.BeginObject();
b.EndObject();
b.BeginObject();
b.EndObject();
b.EndArray();
ASSERT_TRUE(ss.str().compare("[{},{}]") == 0);
}
TEST(JSStreamWriter, Complex) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginObject();
b.Name("a");
b.BeginArray();
b.Value(1);
b.BeginObject();
b.EndObject();
b.BeginObject();
b.Name("b");
b.Value("c");
b.EndObject();
b.EndArray();
b.Name("b");
b.BeginArray();
b.BeginArray();
b.EndArray();
b.EndArray();
b.EndObject();
ASSERT_TRUE(ss.str().compare("{\"a\":[1,{},{\"b\":\"c\"}],\"b\":[[]]}") == 0);
}
TEST(JSStreamWriter, Complex2) {
std::stringstream ss;
JSStreamWriter b(ss);
b.BeginObject();
b.Name("a");
b.BeginArray();
b.BeginObject();
b.Name("b");
b.Value("c");
b.Name("d");
b.BeginArray();
b.BeginObject();
b.Name("e");
b.BeginArray();
b.BeginObject();
b.Name("f");
b.Value("g");
b.EndObject();
b.BeginObject();
b.Name("h");
b.Value("i");
b.EndObject();
b.EndArray();
b.EndObject();
b.EndArray();
b.EndObject();
b.EndArray();
b.EndObject();
ASSERT_TRUE(ss.str().compare("{\"a\":[{\"b\":\"c\",\"d\":[{\"e\":[{\"f\":\"g\"},{\"h\":\"i\"}]}]}]}")
}

Просмотреть файл

@ -521,6 +521,7 @@ public:
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction);
NS_IMETHOD_(InputContext) GetInputContext();
NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent);
NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
NativeKeyBindingsType aType,
const mozilla::WidgetKeyboardEvent& aEvent,

Просмотреть файл

@ -1942,6 +1942,13 @@ nsChildView::GetInputContext()
return mInputContext;
}
NS_IMETHODIMP
nsChildView::AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent)
{
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
return mTextInputHandler->AttachNativeKeyEvent(aEvent);
}
NS_IMETHODIMP_(bool)
nsChildView::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
const WidgetKeyboardEvent& aEvent,

Просмотреть файл

@ -100,8 +100,8 @@ typedef void* nsNativeWidget;
#endif
#define NS_IWIDGET_IID \
{ 0x8e081187, 0xf123, 0x4572, \
{ 0x82, 0xc6, 0x4c, 0xcd, 0xc2, 0x0e, 0xbd, 0xf9 } }
{ 0x87d80888, 0x9917, 0x4bfb, \
{ 0x81, 0xa9, 0x1c, 0x5e, 0x30, 0x9c, 0x78, 0xb4 } }
/*
* Window shadow styles
@ -1811,6 +1811,14 @@ public:
*/
NS_IMETHOD_(InputContext) GetInputContext() = 0;
/*
* Given a WidgetKeyboardEvent, this method synthesizes a corresponding
* native (OS-level) event for it. This method allows tests to simulate
* keystrokes that trigger native key bindings (which require a native
* event).
*/
NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) = 0;
/*
* Execute native key bindings for aType.
*/

Просмотреть файл

@ -79,6 +79,7 @@ PuppetWidget::PuppetWidget(TabChild* aTabChild)
: mTabChild(aTabChild)
, mDPI(-1)
, mDefaultScale(-1)
, mNativeKeyCommandsValid(false)
{
MOZ_COUNT_CTOR(PuppetWidget);
@ -275,6 +276,14 @@ PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
NS_ABORT_IF_FALSE(!mChild || mChild->mWindowType == eWindowType_popup,
"Unexpected event dispatch!");
AutoCacheNativeKeyCommands autoCache(this);
if (event->mFlags.mIsSynthesizedForTests && !mNativeKeyCommandsValid) {
WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
if (keyEvent) {
mTabChild->RequestNativeKeyBindings(&autoCache, keyEvent);
}
}
aStatus = nsEventStatus_eIgnore;
if (event->message == NS_COMPOSITION_START) {
@ -319,6 +328,12 @@ PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
DoCommandCallback aCallback,
void* aCallbackData)
{
// B2G doesn't have native key bindings.
#ifdef MOZ_B2G
return false;
#else // #ifdef MOZ_B2G
MOZ_ASSERT(mNativeKeyCommandsValid);
nsTArray<mozilla::CommandInt>& commands = mSingleLineCommands;
switch (aType) {
case nsIWidget::NativeKeyBindingsForSingleLineEditor:
@ -340,6 +355,7 @@ PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
aCallback(static_cast<mozilla::Command>(commands[i]), aCallbackData);
}
return true;
#endif
}
LayerManager*

Просмотреть файл

@ -33,6 +33,8 @@ class TabChild;
namespace widget {
class AutoCacheNativeKeyCommands;
class PuppetWidget : public nsBaseWidget, public nsSupportsWeakReference
{
typedef mozilla::dom::TabChild TabChild;
@ -136,21 +138,7 @@ public:
DoCommandCallback aCallback,
void* aCallbackData) MOZ_OVERRIDE;
void CacheNativeKeyCommands(const InfallibleTArray<mozilla::CommandInt>& aSingleLineCommands,
const InfallibleTArray<mozilla::CommandInt>& aMultiLineCommands,
const InfallibleTArray<mozilla::CommandInt>& aRichTextCommands)
{
mSingleLineCommands = aSingleLineCommands;
mMultiLineCommands = aMultiLineCommands;
mRichTextCommands = aRichTextCommands;
}
void ClearNativeKeyCommands()
{
mSingleLineCommands.Clear();
mMultiLineCommands.Clear();
mRichTextCommands.Clear();
}
friend class AutoCacheNativeKeyCommands;
//
// nsBaseWidget methods we override
@ -250,11 +238,57 @@ private:
double mDefaultScale;
// Precomputed answers for ExecuteNativeKeyBinding
bool mNativeKeyCommandsValid;
InfallibleTArray<mozilla::CommandInt> mSingleLineCommands;
InfallibleTArray<mozilla::CommandInt> mMultiLineCommands;
InfallibleTArray<mozilla::CommandInt> mRichTextCommands;
};
struct AutoCacheNativeKeyCommands
{
AutoCacheNativeKeyCommands(PuppetWidget* aWidget)
: mWidget(aWidget)
{
mSavedValid = mWidget->mNativeKeyCommandsValid;
mSavedSingleLine = mWidget->mSingleLineCommands;
mSavedMultiLine = mWidget->mMultiLineCommands;
mSavedRichText = mWidget->mRichTextCommands;
}
void Cache(const InfallibleTArray<mozilla::CommandInt>& aSingleLineCommands,
const InfallibleTArray<mozilla::CommandInt>& aMultiLineCommands,
const InfallibleTArray<mozilla::CommandInt>& aRichTextCommands)
{
mWidget->mNativeKeyCommandsValid = true;
mWidget->mSingleLineCommands = aSingleLineCommands;
mWidget->mMultiLineCommands = aMultiLineCommands;
mWidget->mRichTextCommands = aRichTextCommands;
}
void CacheNoCommands()
{
mWidget->mNativeKeyCommandsValid = true;
mWidget->mSingleLineCommands.Clear();
mWidget->mMultiLineCommands.Clear();
mWidget->mRichTextCommands.Clear();
}
~AutoCacheNativeKeyCommands()
{
mWidget->mNativeKeyCommandsValid = mSavedValid;
mWidget->mSingleLineCommands = mSavedSingleLine;
mWidget->mMultiLineCommands = mSavedMultiLine;
mWidget->mRichTextCommands = mSavedRichText;
}
private:
PuppetWidget* mWidget;
bool mSavedValid;
InfallibleTArray<mozilla::CommandInt> mSavedSingleLine;
InfallibleTArray<mozilla::CommandInt> mSavedMultiLine;
InfallibleTArray<mozilla::CommandInt> mSavedRichText;
};
class PuppetScreen : public nsBaseScreen
{
public:

Просмотреть файл

@ -181,6 +181,7 @@ public:
virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
NativeKeyBindingsType aType,
const mozilla::WidgetKeyboardEvent& aEvent,

Просмотреть файл

@ -79,6 +79,34 @@ ThreadStackHelper::~ThreadStackHelper()
#endif
}
#if defined(XP_LINUX) && defined(__arm__)
// Some (old) Linux kernels on ARM have a bug where a signal handler
// can be called without clearing the IT bits in CPSR first. The result
// is that the first few instructions of the handler could be skipped,
// ultimately resulting in crashes. To workaround this bug, the handler
// on ARM is a trampoline that starts with enough NOP instructions, so
// that even if the IT bits are not cleared, only the NOP instructions
// will be skipped over.
template <void (*H)(int, siginfo_t*, void*)>
__attribute__((naked)) void
SignalTrampoline(int aSignal, siginfo_t* aInfo, void* aContext)
{
asm volatile (
"nop; nop; nop; nop"
: : : "memory");
// Because the assembler may generate additional insturctions below, we
// need to ensure NOPs are inserted first by separating them out above.
asm volatile (
"bx %0"
:
: "r"(H), "l"(aSignal), "l"(aInfo), "l"(aContext)
: "memory");
}
#endif // XP_LINUX && __arm__
void
ThreadStackHelper::GetStack(Stack& aStack)
{
@ -99,7 +127,11 @@ ThreadStackHelper::GetStack(Stack& aStack)
}
sCurrent = this;
struct sigaction sigact = {};
#ifdef __arm__
sigact.sa_sigaction = SignalTrampoline<SigAction>;
#else
sigact.sa_sigaction = SigAction;
#endif
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO | SA_RESTART;
if (::sigaction(SIGPROF, &sigact, &sOldSigAction)) {