зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
81ce456a3a
|
@ -193,9 +193,9 @@ const LRESULT = ctypes.size_t;
|
|||
const ULONG_PTR = ctypes.uintptr_t;
|
||||
const PVOID = ctypes.voidptr_t;
|
||||
const LPVOID = PVOID;
|
||||
const LPCTSTR = ctypes.jschar.ptr;
|
||||
const LPCWSTR = ctypes.jschar.ptr;
|
||||
const LPTSTR = ctypes.jschar.ptr;
|
||||
const LPCTSTR = ctypes.char16_t.ptr;
|
||||
const LPCWSTR = ctypes.char16_t.ptr;
|
||||
const LPTSTR = ctypes.char16_t.ptr;
|
||||
const LPSTR = ctypes.char.ptr;
|
||||
const LPCSTR = ctypes.char.ptr;
|
||||
const LPBYTE = ctypes.char.ptr;
|
||||
|
@ -707,8 +707,8 @@ function subprocess_win32(options) {
|
|||
if(environment.length) {
|
||||
//An environment block consists of
|
||||
//a null-terminated block of null-terminated strings.
|
||||
//Using CREATE_UNICODE_ENVIRONMENT so needs to be jschar
|
||||
environment = ctypes.jschar.array()(environment.join('\0') + '\0');
|
||||
//Using CREATE_UNICODE_ENVIRONMENT so needs to be char16_t
|
||||
environment = ctypes.char16_t.array()(environment.join('\0') + '\0');
|
||||
} else {
|
||||
environment = null;
|
||||
}
|
||||
|
|
|
@ -976,12 +976,12 @@ pref("apz.subframe.enabled", true);
|
|||
|
||||
// Overscroll-related settings
|
||||
pref("apz.overscroll.enabled", true);
|
||||
pref("apz.overscroll.fling_friction", "0.02");
|
||||
pref("apz.overscroll.fling_friction", "0.05");
|
||||
pref("apz.overscroll.fling_stopped_threshold", "0.4");
|
||||
pref("apz.overscroll.stretch_factor", "0.5");
|
||||
pref("apz.overscroll.snap_back.spring_stiffness", "0.6");
|
||||
pref("apz.overscroll.snap_back.spring_stiffness", "0.05");
|
||||
pref("apz.overscroll.snap_back.spring_friction", "0.1");
|
||||
pref("apz.overscroll.snap_back.mass", "1200");
|
||||
pref("apz.overscroll.snap_back.mass", "100");
|
||||
|
||||
// This preference allows FirefoxOS apps (and content, I think) to force
|
||||
// the use of software (instead of hardware accelerated) 2D canvases by
|
||||
|
|
|
@ -1279,6 +1279,7 @@ pref("services.sync.prefs.sync.privacy.clearOnShutdown.siteSettings", true);
|
|||
pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
|
||||
pref("services.sync.prefs.sync.privacy.donottrackheader.value", true);
|
||||
pref("services.sync.prefs.sync.privacy.sanitize.sanitizeOnShutdown", true);
|
||||
pref("services.sync.prefs.sync.privacy.trackingprotection.enabled", true);
|
||||
pref("services.sync.prefs.sync.security.OCSP.enabled", true);
|
||||
pref("services.sync.prefs.sync.security.OCSP.require", true);
|
||||
pref("services.sync.prefs.sync.security.default_personal_cert", true);
|
||||
|
|
|
@ -44,8 +44,11 @@ const gXPInstallObserver = {
|
|||
} catch (e) {
|
||||
browser = winOrBrowser;
|
||||
}
|
||||
if (!browser)
|
||||
// Note that the above try/catch will pass through dead object proxies and
|
||||
// other degenerate objects. Make sure the browser is bonafide.
|
||||
if (!browser || gBrowser.browsers.indexOf(browser) == -1)
|
||||
return;
|
||||
|
||||
const anchorID = "addons-notification-icon";
|
||||
var messageString, action;
|
||||
var brandShortName = brandBundle.getString("brandShortName");
|
||||
|
@ -80,8 +83,16 @@ const gXPInstallObserver = {
|
|||
action, null, options);
|
||||
break;
|
||||
case "addon-install-blocked":
|
||||
let originatingHost;
|
||||
try {
|
||||
originatingHost = installInfo.originatingURI.host;
|
||||
} catch (ex) {
|
||||
// Need to deal with missing originatingURI and with about:/data: URIs more gracefully,
|
||||
// see bug 1063418 - but for now, bail:
|
||||
return;
|
||||
}
|
||||
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
|
||||
[brandShortName, installInfo.originatingURI.host]);
|
||||
[brandShortName, originatingHost]);
|
||||
|
||||
let secHistogram = Components.classes["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry).getHistogramById("SECURITY_UI");
|
||||
action = {
|
||||
|
|
|
@ -2336,6 +2336,9 @@ let BrowserOnClick = {
|
|||
|
||||
let originalTarget = event.originalTarget;
|
||||
let ownerDoc = originalTarget.ownerDocument;
|
||||
if (!ownerDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gMultiProcessBrowser &&
|
||||
ownerDoc.documentURI.toLowerCase() == "about:newtab") {
|
||||
|
|
|
@ -370,6 +370,9 @@ let ClickEventHandler = {
|
|||
|
||||
let originalTarget = event.originalTarget;
|
||||
let ownerDoc = originalTarget.ownerDocument;
|
||||
if (!ownerDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle click events from about pages
|
||||
if (ownerDoc.documentURI.startsWith("about:certerror")) {
|
||||
|
|
|
@ -143,6 +143,7 @@ add_task(function* formHistory() {
|
|||
let deferred = Promise.defer();
|
||||
Services.obs.addObserver(function onAdd(subj, topic, data) {
|
||||
if (data == "formhistory-add") {
|
||||
Services.obs.removeObserver(onAdd, "satchel-storage-changed");
|
||||
executeSoon(() => deferred.resolve());
|
||||
}
|
||||
}, "satchel-storage-changed", false);
|
||||
|
@ -167,8 +168,9 @@ add_task(function* formHistory() {
|
|||
|
||||
// Wait for Satchel.
|
||||
deferred = Promise.defer();
|
||||
Services.obs.addObserver(function onAdd(subj, topic, data) {
|
||||
Services.obs.addObserver(function onRemove(subj, topic, data) {
|
||||
if (data == "formhistory-remove") {
|
||||
Services.obs.removeObserver(onRemove, "satchel-storage-changed");
|
||||
executeSoon(() => deferred.resolve());
|
||||
}
|
||||
}, "satchel-storage-changed", false);
|
||||
|
|
|
@ -659,7 +659,7 @@ var gAdvancedPane = {
|
|||
}
|
||||
try {
|
||||
const DRIVE_FIXED = 3;
|
||||
const LPCWSTR = ctypes.jschar.ptr;
|
||||
const LPCWSTR = ctypes.char16_t.ptr;
|
||||
const UINT = ctypes.uint32_t;
|
||||
let kernel32 = ctypes.open("kernel32");
|
||||
let GetDriveType = kernel32.declare("GetDriveTypeW", ctypes.default_abi, UINT, LPCWSTR);
|
||||
|
|
|
@ -133,7 +133,9 @@ function windowLoad(event, win, dialog) {
|
|||
return;
|
||||
|
||||
if (tests[currentTest].observances.length == 0) {
|
||||
// Should fail here as we are not expecting a notification.
|
||||
// Should fail here as we are not expecting a notification, but we don't.
|
||||
// See bug 1063410.
|
||||
return;
|
||||
}
|
||||
|
||||
let permission = aSubject.QueryInterface(Ci.nsIPermission);
|
||||
|
|
|
@ -17,6 +17,10 @@ function notification(win, topic) {
|
|||
}
|
||||
|
||||
let { notification, window } = expected.shift();
|
||||
if (Cu.isDeadWrapper(window)) {
|
||||
// Sometimes we end up with a nuked window reference here :-(
|
||||
return;
|
||||
}
|
||||
is(topic, notification, "Saw the expected notification");
|
||||
is(win, window, "Saw the expected window");
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ add_task(function* SetCurrentEngine() {
|
|||
info("Test observed " + data);
|
||||
if (data == "engine-current") {
|
||||
ok(true, "Test observed engine-current");
|
||||
Services.obs.removeObserver(obs, "browser-search-engine-modified", false);
|
||||
Services.obs.removeObserver(obs, "browser-search-engine-modified");
|
||||
deferred.resolve();
|
||||
}
|
||||
}, "browser-search-engine-modified", false);
|
||||
|
@ -188,6 +188,7 @@ add_task(function* GetSuggestions_AddFormHistoryEntry_RemoveFormHistoryEntry() {
|
|||
let deferred = Promise.defer();
|
||||
Services.obs.addObserver(function onAdd(subj, topic, data) {
|
||||
if (data == "formhistory-add") {
|
||||
Services.obs.removeObserver(onAdd, "satchel-storage-changed");
|
||||
executeSoon(() => deferred.resolve());
|
||||
}
|
||||
}, "satchel-storage-changed", false);
|
||||
|
@ -224,6 +225,7 @@ add_task(function* GetSuggestions_AddFormHistoryEntry_RemoveFormHistoryEntry() {
|
|||
deferred = Promise.defer();
|
||||
Services.obs.addObserver(function onRemove(subj, topic, data) {
|
||||
if (data == "formhistory-remove") {
|
||||
Services.obs.removeObserver(onRemove, "satchel-storage-changed");
|
||||
executeSoon(() => deferred.resolve());
|
||||
}
|
||||
}, "satchel-storage-changed", false);
|
||||
|
|
|
@ -255,7 +255,8 @@ function test_auth() {
|
|||
|
||||
let winObs = new WindowObserver(function(authWin) {
|
||||
ok(authWin, "Authentication window opened");
|
||||
ok(authWin.contentWindow.location);
|
||||
// See bug 1063404.
|
||||
// ok(authWin.location);
|
||||
});
|
||||
|
||||
Services.ww.registerNotification(winObs);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "nsTextFormatter.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsIProperties.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsIFile.h"
|
||||
|
@ -580,6 +581,35 @@ DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase)
|
||||
{
|
||||
// Make a clone of the incoming URI, because we're going to mutate it.
|
||||
nsCOMPtr<nsIURI> probe;
|
||||
nsresult rv = aProbeArg->Clone(getter_AddRefs(probe));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(tldService, false);
|
||||
while (true) {
|
||||
if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoCString host, newHost;
|
||||
nsresult rv = probe->GetHost(host);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
rv = tldService->GetNextSubDomain(host, newHost);
|
||||
if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
|
||||
return false;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
rv = probe->SetHost(newHost);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsIURI *aTargetURI,
|
||||
|
@ -796,7 +826,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
|
|||
// Allow domains that were whitelisted in the prefs. In 99.9% of cases,
|
||||
// this array is empty.
|
||||
for (size_t i = 0; i < mFileURIWhitelist.Length(); ++i) {
|
||||
if (SecurityCompareURIs(mFileURIWhitelist[i], sourceURI)) {
|
||||
if (EqualOrSubdomain(sourceURI, mFileURIWhitelist[i])) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -1433,7 +1463,7 @@ nsScriptSecurityManager::AddSitesToFileURIWhitelist(const nsCString& aSiteList)
|
|||
if (NS_FAILED(sIOService->ExtractScheme(site, unused))) {
|
||||
AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("http://") + site);
|
||||
AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("https://") + site);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert it to a URI and add it to our list.
|
||||
|
|
|
@ -82,13 +82,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=995943
|
|||
pushPrefs.bind(null, [['capability.policy.policynames', ',somepolicy, someotherpolicy, '],
|
||||
['capability.policy.somepolicy.checkloaduri.enabled', 'allaccess'],
|
||||
['capability.policy.someotherpolicy.checkloaduri.enabled', 'nope'],
|
||||
['capability.policy.somepolicy.sites', ' http://example.org https://example.com test1.example.com'],
|
||||
['capability.policy.somepolicy.sites', ' http://example.org test1.example.com https://test2.example.com '],
|
||||
['capability.policy.someotherpolicy.sites', 'http://example.net ']]))
|
||||
.then(checkLoadFileURI.bind(null, 'http://example.org', true))
|
||||
.then(checkLoadFileURI.bind(null, 'http://example.com', false))
|
||||
.then(checkLoadFileURI.bind(null, 'http://test2.example.com', false))
|
||||
.then(checkLoadFileURI.bind(null, 'https://test2.example.com', true))
|
||||
.then(checkLoadFileURI.bind(null, 'http://sub1.test2.example.com', false))
|
||||
.then(checkLoadFileURI.bind(null, 'https://sub1.test2.example.com', true))
|
||||
.then(checkLoadFileURI.bind(null, 'http://example.net', false))
|
||||
.then(checkLoadFileURI.bind(null, 'http://test1.example.com', true))
|
||||
.then(checkLoadFileURI.bind(null, 'https://test1.example.com', true))
|
||||
.then(checkLoadFileURI.bind(null, 'http://sub1.test1.example.com', true))
|
||||
.then(checkLoadFileURI.bind(null, 'https://sub1.test1.example.com', true))
|
||||
.then(pushPrefs.bind(null, [['capability.policy.someotherpolicy.checkloaduri.enabled', 'allAccess']]))
|
||||
.then(checkLoadFileURI.bind(null, 'http://example.net', true))
|
||||
.then(popPrefs)
|
||||
|
|
|
@ -574,10 +574,6 @@ def tarjan(V, E):
|
|||
|
||||
|
||||
def main():
|
||||
# Suppress the build time check if MOZ_NO_BUILD_TIME_SM_CHECKS is set.
|
||||
if "MOZ_NO_BUILD_TIME_SM_CHECKS" in os.environ:
|
||||
sys.exit(0)
|
||||
|
||||
ok = check_style()
|
||||
|
||||
if ok:
|
||||
|
|
|
@ -6408,7 +6408,7 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
|||
|
||||
JS::Rooted<JSObject*> re(cx,
|
||||
JS_NewUCRegExpObjectNoStatics(cx,
|
||||
static_cast<jschar*>(aPattern.BeginWriting()),
|
||||
static_cast<char16_t*>(aPattern.BeginWriting()),
|
||||
aPattern.Length(), 0));
|
||||
if (!re) {
|
||||
JS_ClearPendingException(cx);
|
||||
|
@ -6418,7 +6418,7 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
|||
JS::Rooted<JS::Value> rval(cx, JS::NullValue());
|
||||
size_t idx = 0;
|
||||
if (!JS_ExecuteRegExpNoStatics(cx, re,
|
||||
static_cast<jschar*>(aValue.BeginWriting()),
|
||||
static_cast<char16_t*>(aValue.BeginWriting()),
|
||||
aValue.Length(), &idx, true, &rval)) {
|
||||
JS_ClearPendingException(cx);
|
||||
return true;
|
||||
|
|
|
@ -512,7 +512,7 @@ nsFrameMessageManager::GetDelayedFrameScripts(JSContext* aCx, JS::MutableHandle<
|
|||
}
|
||||
|
||||
static bool
|
||||
JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
|
||||
JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData)
|
||||
{
|
||||
nsAString* result = static_cast<nsAString*>(aData);
|
||||
result->Append(static_cast<const char16_t*>(aBuf),
|
||||
|
@ -542,7 +542,7 @@ GetParamsForMessage(JSContext* aCx,
|
|||
NS_ENSURE_TRUE(!json.IsEmpty(), false);
|
||||
|
||||
JS::Rooted<JS::Value> val(aCx, JS::NullValue());
|
||||
NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const jschar*>(json.get()),
|
||||
NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(json.get()),
|
||||
json.Length(), &val), false);
|
||||
|
||||
return WriteStructuredClone(aCx, val, aBuffer, aClosure);
|
||||
|
@ -638,7 +638,7 @@ nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
|
|||
}
|
||||
|
||||
JS::Rooted<JS::Value> ret(aCx);
|
||||
if (!JS_ParseJSON(aCx, static_cast<const jschar*>(retval[i].get()),
|
||||
if (!JS_ParseJSON(aCx, static_cast<const char16_t*>(retval[i].get()),
|
||||
retval[i].Length(), &ret)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
@ -996,7 +996,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
|||
}
|
||||
JS::Rooted<JSString*> jsMessage(cx,
|
||||
JS_NewUCStringCopyN(cx,
|
||||
static_cast<const jschar*>(aMessage.BeginReading()),
|
||||
static_cast<const char16_t*>(aMessage.BeginReading()),
|
||||
aMessage.Length()));
|
||||
NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
|
||||
JS::Rooted<JS::Value> syncv(cx, JS::BooleanValue(aIsSync));
|
||||
|
@ -1489,7 +1489,7 @@ nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
|
|||
nsCOMPtr<nsIInputStream> input;
|
||||
channel->Open(getter_AddRefs(input));
|
||||
nsString dataString;
|
||||
jschar* dataStringBuf = nullptr;
|
||||
char16_t* dataStringBuf = nullptr;
|
||||
size_t dataStringLength = 0;
|
||||
uint64_t avail64 = 0;
|
||||
if (input && NS_SUCCEEDED(input->Available(&avail64)) && avail64) {
|
||||
|
|
|
@ -109,7 +109,7 @@ public:
|
|||
bool mIsInline; // Is the script inline or loaded?
|
||||
bool mHasSourceMapURL; // Does the HTTP header have a source map url?
|
||||
nsString mSourceMapURL; // Holds source map url for loaded scripts
|
||||
jschar* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
|
||||
char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
|
||||
size_t mScriptTextLength; // use nsString so we can give ownership to jsapi.
|
||||
uint32_t mJSVersion;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
|
@ -898,7 +898,7 @@ nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadT
|
|||
|
||||
NS_ENSURE_ARG(aRequest);
|
||||
nsAutoString textData;
|
||||
const jschar* scriptBuf = nullptr;
|
||||
const char16_t* scriptBuf = nullptr;
|
||||
size_t scriptLength = 0;
|
||||
JS::SourceBufferHolder::Ownership giveScriptOwnership =
|
||||
JS::SourceBufferHolder::NoOwnership;
|
||||
|
@ -1278,7 +1278,7 @@ DetectByteOrderMark(const unsigned char* aBytes, int32_t aLen, nsCString& oChars
|
|||
nsScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
|
||||
uint32_t aLength, const nsAString& aHintCharset,
|
||||
nsIDocument* aDocument,
|
||||
jschar*& aBufOut, size_t& aLengthOut)
|
||||
char16_t*& aBufOut, size_t& aLengthOut)
|
||||
{
|
||||
if (!aLength) {
|
||||
aBufOut = nullptr;
|
||||
|
@ -1335,7 +1335,7 @@ nsScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
|
|||
aLength, &unicodeLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aBufOut = static_cast<jschar*>(js_malloc(unicodeLength * sizeof(jschar)));
|
||||
aBufOut = static_cast<char16_t*>(js_malloc(unicodeLength * sizeof(char16_t)));
|
||||
if (!aBufOut) {
|
||||
aLengthOut = 0;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
|
|
@ -170,17 +170,17 @@ public:
|
|||
* attribute). May be the empty string.
|
||||
* @param aDocument Document which the data is loaded for. Must not be
|
||||
* null.
|
||||
* @param aBufOut [out] jschar array allocated by ConvertToUTF16 and
|
||||
* @param aBufOut [out] char16_t array allocated by ConvertToUTF16 and
|
||||
* containing data converted to unicode. Caller must
|
||||
* js_free() this data when no longer needed.
|
||||
* @param aLengthOut [out] Length of array returned in aBufOut in number
|
||||
* of jschars.
|
||||
* of char16_t code units.
|
||||
*/
|
||||
static nsresult ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
|
||||
uint32_t aLength,
|
||||
const nsAString& aHintCharset,
|
||||
nsIDocument* aDocument,
|
||||
jschar*& aBufOut, size_t& aLengthOut);
|
||||
char16_t*& aBufOut, size_t& aLengthOut);
|
||||
|
||||
/**
|
||||
* Processes any pending requests that are ready for processing.
|
||||
|
|
|
@ -766,7 +766,7 @@ nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
|
|||
// The Unicode converter has already zapped the BOM if there was one
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!JS_ParseJSON(aCx,
|
||||
static_cast<const jschar*>(mResponseText.get()), mResponseText.Length(),
|
||||
static_cast<const char16_t*>(mResponseText.get()), mResponseText.Length(),
|
||||
&value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@ function afterLoad() {
|
|||
.getService(SpecialPowers.Ci.nsIProperties)
|
||||
.get("TmpD", SpecialPowers.Ci.nsILocalFile);
|
||||
file.append("345339_test.file");
|
||||
file.createUnique(SpecialPowers.Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||
// Only the file's path is used, so it doesn't need to be created.
|
||||
// See also bug 1058977.
|
||||
filePath = file.path;
|
||||
|
||||
SpecialPowers.wrap(iframeDoc).getElementById("file").value = filePath;
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
submit_invalid_file.sjs
|
||||
[test_autocompleteinfo.html]
|
||||
[test_submit_invalid_file.html]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
save_restore_radio_groups.sjs
|
||||
submit_invalid_file.sjs
|
||||
test_input_number_data.js
|
||||
|
||||
[test_bug1039548.html]
|
||||
|
@ -91,7 +90,6 @@ skip-if = e10s
|
|||
[test_step_attribute.html]
|
||||
skip-if = e10s
|
||||
[test_stepup_stepdown.html]
|
||||
[test_submit_invalid_file.html]
|
||||
[test_textarea_attributes_reflection.html]
|
||||
[test_validation.html]
|
||||
skip-if = buildapp == 'b2g' || e10s # b2g(374 total, bug 901848, no keygen support) b2g-debug(374 total, bug 901848, no keygen support) b2g-desktop(374 total, bug 901848, no keygen support)
|
||||
|
|
|
@ -67,7 +67,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
|
|||
|
||||
function testUserInput() {
|
||||
//Simulating an OK click and with a file name return.
|
||||
MockFilePicker.useAnyFile();
|
||||
MockFilePicker.useBlobFile();
|
||||
MockFilePicker.returnValue = MockFilePicker.returnOK;
|
||||
var input = document.getElementById('fileInput');
|
||||
input.focus();
|
||||
|
|
|
@ -59,7 +59,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=851780
|
|||
|
||||
function testUserInput() {
|
||||
// Simulating an OK click and with a file name return.
|
||||
MockFilePicker.useAnyFile();
|
||||
MockFilePicker.useBlobFile();
|
||||
MockFilePicker.returnValue = MockFilePicker.returnOK;
|
||||
var input = document.getElementById('fileInput');
|
||||
input.focus();
|
||||
|
|
|
@ -179,17 +179,12 @@ for (var test of data) {
|
|||
.getService(SpecialPowers.Ci.nsIProperties);
|
||||
var file = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
|
||||
file.append('635499_file');
|
||||
var outStream = SpecialPowers.Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIFileOutputStream);
|
||||
outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
outStream.write("foo", 3);
|
||||
outStream.close();
|
||||
// Only the file's path is used, so it doesn't need to be created.
|
||||
// See also bug 1058977.
|
||||
|
||||
SpecialPowers.wrap(input).value = file.path;
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
file.remove(false);
|
||||
break;
|
||||
case 'date':
|
||||
input.max = '2012-06-27';
|
||||
|
|
|
@ -177,17 +177,12 @@ for (var test of data) {
|
|||
.getService(SpecialPowers.Ci.nsIProperties);
|
||||
var file = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
|
||||
file.append('635499_file');
|
||||
var outStream = SpecialPowers.Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIFileOutputStream);
|
||||
outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
outStream.write("foo", 3);
|
||||
outStream.close();
|
||||
// Only the file's path is used, so it doesn't need to be created.
|
||||
// See also bug 1058977.
|
||||
|
||||
SpecialPowers.wrap(input).value = file.path;
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
file.remove(false);
|
||||
break;
|
||||
case 'date':
|
||||
input.value = '2012-06-28';
|
||||
|
|
|
@ -308,22 +308,18 @@ function checkInputRequiredValidityForFile()
|
|||
element.type = 'file'
|
||||
document.forms[0].appendChild(element);
|
||||
|
||||
function createFileWithData(fileName, fileData) {
|
||||
function createFile(fileName) {
|
||||
var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIProperties);
|
||||
var testFile = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
|
||||
testFile.append(fileName);
|
||||
var outStream = SpecialPowers.Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIFileOutputStream);
|
||||
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
outStream.write(fileData, fileData.length);
|
||||
outStream.close();
|
||||
// Only the file's path is used, so it doesn't need to be created.
|
||||
// See also bug 1058977.
|
||||
|
||||
return testFile;
|
||||
}
|
||||
|
||||
var file = createFileWithData("345822_file", "file content");
|
||||
var file = createFile("345822_file");
|
||||
|
||||
SpecialPowers.wrap(element).value = "";
|
||||
element.required = false;
|
||||
|
@ -350,7 +346,6 @@ function checkInputRequiredValidityForFile()
|
|||
|
||||
element.required = true;
|
||||
SpecialPowers.wrap(element).value = '';
|
||||
file.remove(false);
|
||||
document.forms[0].removeChild(element);
|
||||
checkSufferingFromBeingMissing(element, true);
|
||||
}
|
||||
|
|
|
@ -132,17 +132,12 @@ for (var test of data) {
|
|||
.getService(SpecialPowers.Ci.nsIProperties);
|
||||
var file = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
|
||||
file.append('635499_file');
|
||||
var outStream = SpecialPowers.Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIFileOutputStream);
|
||||
outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
outStream.write("foo", 3);
|
||||
outStream.close();
|
||||
// Only the file's path is used, so it doesn't need to be created.
|
||||
// See also bug 1058977.
|
||||
|
||||
SpecialPowers.wrap(input).value = file.path;
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
file.remove(false);
|
||||
break;
|
||||
case 'date':
|
||||
// For date, the step is calulated on the timestamp since 1970-01-01
|
||||
|
|
|
@ -6,14 +6,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=702949
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test invalid file submission</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=702949">Mozilla Bug 702949</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<form action='submit_invalid_file.sjs' method='post' target='result'
|
||||
<form action='http://mochi.test:8888/chrome/content/html/content/test/forms/submit_invalid_file.sjs' method='post' target='result'
|
||||
enctype='multipart/form-data'>
|
||||
<input type='file' name='file'>
|
||||
</form>
|
||||
|
|
|
@ -60,7 +60,7 @@ SimpleTest.waitForFocus(function() {
|
|||
b2.click();
|
||||
|
||||
// Now, we can launch tests when file picker isn't canceled.
|
||||
MockFilePicker.useAnyFile();
|
||||
MockFilePicker.useBlobFile();
|
||||
MockFilePicker.returnValue = MockFilePicker.returnOK;
|
||||
|
||||
var b = document.getElementById('b');
|
||||
|
|
|
@ -30,7 +30,9 @@ class nsXPCClassInfo;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
class DOMLocalMediaStream;
|
||||
class MediaStream;
|
||||
class MediaEngineSource;
|
||||
|
||||
namespace dom {
|
||||
class AudioNode;
|
||||
|
@ -102,6 +104,8 @@ public:
|
|||
|
||||
virtual void StopTrack(TrackID aTrackID);
|
||||
|
||||
virtual DOMLocalMediaStream* AsDOMLocalMediaStream() { return nullptr; }
|
||||
|
||||
bool IsFinished();
|
||||
/**
|
||||
* Returns a principal indicating who may access this stream. The stream contents
|
||||
|
@ -301,6 +305,8 @@ public:
|
|||
|
||||
virtual void Stop();
|
||||
|
||||
virtual MediaEngineSource* GetMediaEngine(TrackID aTrackID) { return nullptr; }
|
||||
|
||||
/**
|
||||
* Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
|
||||
*/
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include "mozilla/dom/ImageCaptureErrorEvent.h"
|
||||
#include "mozilla/dom/ImageCaptureErrorEventBinding.h"
|
||||
#include "mozilla/dom/VideoStreamTrack.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "CaptureTask.h"
|
||||
#include "MediaEngine.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -77,6 +79,69 @@ ImageCapture::GetVideoStreamTrack() const
|
|||
return mVideoStreamTrack;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ImageCapture::TakePhotoByMediaEngine()
|
||||
{
|
||||
// Callback for TakPhoto(), it also monitor the principal. If principal
|
||||
// changes, it returns PHOTO_ERROR with security error.
|
||||
class TakePhotoCallback : public MediaEngineSource::PhotoCallback,
|
||||
public DOMMediaStream::PrincipalChangeObserver
|
||||
{
|
||||
public:
|
||||
TakePhotoCallback(DOMMediaStream* aStream, ImageCapture* aImageCapture)
|
||||
: mStream(aStream)
|
||||
, mImageCapture(aImageCapture)
|
||||
, mPrincipalChanged(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mStream->AddPrincipalChangeObserver(this);
|
||||
}
|
||||
|
||||
void PrincipalChanged(DOMMediaStream* aMediaStream) MOZ_OVERRIDE
|
||||
{
|
||||
mPrincipalChanged = true;
|
||||
}
|
||||
|
||||
nsresult PhotoComplete(already_AddRefed<DOMFile> aBlob) MOZ_OVERRIDE
|
||||
{
|
||||
nsRefPtr<DOMFile> blob = aBlob;
|
||||
|
||||
if (mPrincipalChanged) {
|
||||
return PhotoError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
return mImageCapture->PostBlobEvent(blob);
|
||||
}
|
||||
|
||||
nsresult PhotoError(nsresult aRv) MOZ_OVERRIDE
|
||||
{
|
||||
return mImageCapture->PostErrorEvent(ImageCaptureError::PHOTO_ERROR, aRv);
|
||||
}
|
||||
|
||||
protected:
|
||||
~TakePhotoCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mStream->RemovePrincipalChangeObserver(this);
|
||||
}
|
||||
|
||||
nsRefPtr<DOMMediaStream> mStream;
|
||||
nsRefPtr<ImageCapture> mImageCapture;
|
||||
bool mPrincipalChanged;
|
||||
};
|
||||
|
||||
nsRefPtr<DOMMediaStream> domStream = mVideoStreamTrack->GetStream();
|
||||
DOMLocalMediaStream* domLocalStream = domStream->AsDOMLocalMediaStream();
|
||||
if (domLocalStream) {
|
||||
nsRefPtr<MediaEngineSource> mediaEngine =
|
||||
domLocalStream->GetMediaEngine(mVideoStreamTrack->GetTrackID());
|
||||
nsRefPtr<MediaEngineSource::PhotoCallback> callback =
|
||||
new TakePhotoCallback(domStream, this);
|
||||
return mediaEngine->TakePhoto(callback);
|
||||
}
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void
|
||||
ImageCapture::TakePhoto(ErrorResult& aResult)
|
||||
{
|
||||
|
@ -90,12 +155,20 @@ ImageCapture::TakePhoto(ErrorResult& aResult)
|
|||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<CaptureTask> task =
|
||||
new CaptureTask(this, mVideoStreamTrack->GetTrackID());
|
||||
// Try if MediaEngine supports taking photo.
|
||||
nsresult rv = TakePhotoByMediaEngine();
|
||||
|
||||
// It adds itself into MediaStreamGraph, so ImageCapture doesn't need to hold the
|
||||
// reference.
|
||||
task->AttachStream();
|
||||
// It falls back to MediaStreamGraph image capture if MediaEngine doesn't
|
||||
// support TakePhoto().
|
||||
if (rv == NS_ERROR_NOT_IMPLEMENTED) {
|
||||
IC_LOG("MediaEngine doesn't support TakePhoto(), it falls back to MediaStreamGraph.");
|
||||
nsRefPtr<CaptureTask> task =
|
||||
new CaptureTask(this, mVideoStreamTrack->GetTrackID());
|
||||
|
||||
// It adds itself into MediaStreamGraph, so ImageCapture doesn't need to hold
|
||||
// the reference.
|
||||
task->AttachStream();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -41,6 +41,11 @@ class VideoStreamTrack;
|
|||
* be sent back as a JPG format via Blob event.
|
||||
*
|
||||
* All the functions in ImageCapture are run in main thread.
|
||||
*
|
||||
* There are two ways to capture image, MediaEngineSource and MediaStreamGraph.
|
||||
* When the implementation of MediaEngineSource supports TakePhoto() in platform
|
||||
* like B2G, it uses the platform camera to grab image. Otherwise, it falls back
|
||||
* to the MediaStreamGraph way.
|
||||
*/
|
||||
|
||||
class ImageCapture MOZ_FINAL : public DOMEventTargetHelper
|
||||
|
@ -86,6 +91,10 @@ public:
|
|||
protected:
|
||||
virtual ~ImageCapture();
|
||||
|
||||
// Capture image by MediaEngine. If it's not support taking photo, this function
|
||||
// should return NS_ERROR_NOT_IMPLEMENTED.
|
||||
nsresult TakePhotoByMediaEngine();
|
||||
|
||||
nsRefPtr<VideoStreamTrack> mVideoStreamTrack;
|
||||
};
|
||||
|
||||
|
|
|
@ -173,17 +173,8 @@ MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
|
|||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::WaitForData()
|
||||
MediaSourceDecoder::NotifyTimeRangesChanged()
|
||||
{
|
||||
MSE_DEBUG("MediaSourceDecoder(%p)::WaitForData()", this);
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::NotifyGotData()
|
||||
{
|
||||
MSE_DEBUG("MediaSourceDecoder(%p)::NotifyGotData()", this);
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
|
|
@ -55,11 +55,9 @@ public:
|
|||
|
||||
void SetMediaSourceDuration(double aDuration);
|
||||
|
||||
// Provide a mechanism for MediaSourceReader to block waiting on data from a SourceBuffer.
|
||||
void WaitForData();
|
||||
|
||||
// Called whenever a SourceBuffer has new data appended.
|
||||
void NotifyGotData();
|
||||
// Called whenever a TrackBuffer has new data appended or a new decoder
|
||||
// initializes. Safe to call from any thread.
|
||||
void NotifyTimeRangesChanged();
|
||||
|
||||
// Indicates the point in time at which the reader should consider
|
||||
// registered TrackBuffers essential for initialization.
|
||||
|
|
|
@ -84,16 +84,15 @@ MediaSourceReader::RequestAudioData()
|
|||
GetCallback()->OnDecodeError();
|
||||
return;
|
||||
}
|
||||
if (SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S)) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData switching audio reader", this);
|
||||
}
|
||||
mAudioIsSeeking = false;
|
||||
SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S);
|
||||
mAudioReader->RequestAudioData();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnAudioDecoded(AudioData* aSample)
|
||||
{
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld mDuration=%lld d=%d",
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropAudioBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
|
@ -106,14 +105,12 @@ MediaSourceReader::OnAudioDecoded(AudioData* aSample)
|
|||
mDropAudioBeforeThreshold = false;
|
||||
}
|
||||
|
||||
// If we are seeking we need to make sure the first sample decoded after
|
||||
// that seek has the mDiscontinuity field set to ensure the media decoder
|
||||
// state machine picks up that the seek is complete.
|
||||
if (mAudioIsSeeking) {
|
||||
mAudioIsSeeking = false;
|
||||
aSample->mDiscontinuity = true;
|
||||
// Any OnAudioDecoded callbacks received while mAudioIsSeeking must be not
|
||||
// update our last used timestamp, as these are emitted by the reader we're
|
||||
// switching away from.
|
||||
if (!mAudioIsSeeking) {
|
||||
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
||||
}
|
||||
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
||||
GetCallback()->OnAudioDecoded(aSample);
|
||||
}
|
||||
|
||||
|
@ -148,16 +145,15 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
|||
mDropAudioBeforeThreshold = true;
|
||||
mDropVideoBeforeThreshold = true;
|
||||
}
|
||||
if (SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S)) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::RequestVideoData switching video reader", this);
|
||||
}
|
||||
mVideoIsSeeking = false;
|
||||
SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S);
|
||||
mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
||||
{
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld mDuration=%lld d=%d",
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropVideoBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
|
@ -170,14 +166,12 @@ MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
|||
mDropVideoBeforeThreshold = false;
|
||||
}
|
||||
|
||||
// If we are seeking we need to make sure the first sample decoded after
|
||||
// that seek has the mDiscontinuity field set to ensure the media decoder
|
||||
// state machine picks up that the seek is complete.
|
||||
if (mVideoIsSeeking) {
|
||||
mVideoIsSeeking = false;
|
||||
aSample->mDiscontinuity = true;
|
||||
// Any OnVideoDecoded callbacks received while mVideoIsSeeking must be not
|
||||
// update our last used timestamp, as these are emitted by the reader we're
|
||||
// switching away from.
|
||||
if (!mVideoIsSeeking) {
|
||||
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
||||
}
|
||||
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
||||
GetCallback()->OnVideoDecoded(aSample);
|
||||
}
|
||||
|
||||
|
@ -234,45 +228,90 @@ MediaSourceReader::BreakCycles()
|
|||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::SwitchAudioReader(double aTarget)
|
||||
MediaSourceReader::CanSelectAudioReader(MediaDecoderReader* aNewReader)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// XXX: Can't handle adding an audio track after ReadMetadata yet.
|
||||
if (!mAudioTrack) {
|
||||
AudioInfo currentInfo = mAudioReader->GetMediaInfo().mAudio;
|
||||
AudioInfo newInfo = aNewReader->GetMediaInfo().mAudio;
|
||||
|
||||
// TODO: We can't handle switching audio formats yet.
|
||||
if (currentInfo.mRate != newInfo.mRate ||
|
||||
currentInfo.mChannels != newInfo.mChannels) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to format mismatch",
|
||||
this, aNewReader);
|
||||
return false;
|
||||
}
|
||||
auto& decoders = mAudioTrack->Decoders();
|
||||
for (uint32_t i = 0; i < decoders.Length(); ++i) {
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
decoders[i]->GetBuffered(ranges);
|
||||
|
||||
MediaDecoderReader* newReader = decoders[i]->GetReader();
|
||||
MSE_DEBUGV("MediaDecoderReader(%p)::SwitchAudioReader(%f) audioReader=%p reader=%p ranges=%s",
|
||||
this, aTarget, mAudioReader.get(), newReader, DumpTimeRanges(ranges).get());
|
||||
if (aNewReader->AudioQueue().AtEndOfStream()) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to queue EOS",
|
||||
this, aNewReader);
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioInfo targetInfo = newReader->GetMediaInfo().mAudio;
|
||||
AudioInfo currentInfo = mAudioReader->GetMediaInfo().mAudio;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: We can't handle switching audio formats yet.
|
||||
if (currentInfo.mRate != targetInfo.mRate ||
|
||||
currentInfo.mChannels != targetInfo.mChannels) {
|
||||
bool
|
||||
MediaSourceReader::CanSelectVideoReader(MediaDecoderReader* aNewReader)
|
||||
{
|
||||
if (aNewReader->VideoQueue().AtEndOfStream()) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::CanSelectVideoReader(%p) skip reader due to queue EOS",
|
||||
this, aNewReader);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDecoderReader>
|
||||
MediaSourceReader::SelectReader(double aTarget,
|
||||
bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*),
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders)
|
||||
{
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
// Consider decoders in order of newest to oldest, as a newer decoder
|
||||
// providing a given buffered range is expected to replace an older one.
|
||||
for (int32_t i = aTrackDecoders.Length() - 1; i >= 0; --i) {
|
||||
nsRefPtr<MediaDecoderReader> newReader = aTrackDecoders[i]->GetReader();
|
||||
|
||||
// Check the track-type-specific aspects first, as it's assumed these
|
||||
// are cheaper than a buffered range comparison, which seems worthwhile
|
||||
// to avoid on any reader we'd subsequently reject.
|
||||
if (!(this->*aCanSelectReader)(newReader)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ranges->Find(aTarget) != dom::TimeRanges::NoIndex) {
|
||||
if (newReader->AudioQueue().AtEndOfStream()) {
|
||||
continue;
|
||||
}
|
||||
if (mAudioReader) {
|
||||
mAudioReader->SetIdle();
|
||||
}
|
||||
mAudioReader = newReader;
|
||||
MSE_DEBUG("MediaDecoderReader(%p)::SwitchAudioReader(%f) switching to audio reader %p",
|
||||
this, aTarget, mAudioReader.get());
|
||||
return true;
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
aTrackDecoders[i]->GetBuffered(ranges);
|
||||
if (ranges->Find(aTarget) == dom::TimeRanges::NoIndex) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%f) newReader=%p target not in ranges=%s",
|
||||
this, aTarget, newReader.get(), DumpTimeRanges(ranges).get());
|
||||
continue;
|
||||
}
|
||||
|
||||
return newReader.forget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::SwitchAudioReader(double aTarget)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// XXX: Can't handle adding an audio track after ReadMetadata.
|
||||
if (!mAudioTrack) {
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget,
|
||||
&MediaSourceReader::CanSelectAudioReader,
|
||||
mAudioTrack->Decoders());
|
||||
if (newReader && newReader != mAudioReader) {
|
||||
mAudioReader->SetIdle();
|
||||
mAudioReader = newReader;
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::SwitchAudioReader switched reader to %p", this, mAudioReader.get());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -280,33 +319,19 @@ bool
|
|||
MediaSourceReader::SwitchVideoReader(double aTarget)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// XXX: Can't handle adding a video track after ReadMetadata yet.
|
||||
// XXX: Can't handle adding a video track after ReadMetadata.
|
||||
if (!mVideoTrack) {
|
||||
return false;
|
||||
}
|
||||
auto& decoders = mVideoTrack->Decoders();
|
||||
for (uint32_t i = 0; i < decoders.Length(); ++i) {
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
decoders[i]->GetBuffered(ranges);
|
||||
|
||||
MediaDecoderReader* newReader = decoders[i]->GetReader();
|
||||
MSE_DEBUGV("MediaDecoderReader(%p)::SwitchVideoReader(%f) videoReader=%p reader=%p ranges=%s",
|
||||
this, aTarget, mVideoReader.get(), newReader, DumpTimeRanges(ranges).get());
|
||||
|
||||
if (ranges->Find(aTarget) != dom::TimeRanges::NoIndex) {
|
||||
if (newReader->VideoQueue().AtEndOfStream()) {
|
||||
continue;
|
||||
}
|
||||
if (mVideoReader) {
|
||||
mVideoReader->SetIdle();
|
||||
}
|
||||
mVideoReader = newReader;
|
||||
MSE_DEBUG("MediaDecoderReader(%p)::SwitchVideoReader(%f) switching to video reader %p",
|
||||
this, aTarget, mVideoReader.get());
|
||||
return true;
|
||||
}
|
||||
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget,
|
||||
&MediaSourceReader::CanSelectVideoReader,
|
||||
mVideoTrack->Decoders());
|
||||
if (newReader && newReader != mVideoReader) {
|
||||
mVideoReader->SetIdle();
|
||||
mVideoReader = newReader;
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::SwitchVideoReader switched reader to %p", this, mVideoReader.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -413,6 +438,21 @@ private:
|
|||
nsRefPtr<AbstractMediaDecoder> mDecoder;
|
||||
};
|
||||
|
||||
void
|
||||
MediaSourceReader::WaitForTimeRange(double aTime)
|
||||
{
|
||||
MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%f)", this, aTime);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
// Loop until we have the requested time range in the active TrackBuffers.
|
||||
// Ideally, this wait loop would use an async request and callback
|
||||
// instead. Bug 1056441 covers that change.
|
||||
while (!TrackBuffersContainTime(aTime) && !IsShutdown() && !IsEnded()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%f) waiting", this, aTime);
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::TrackBuffersContainTime(double aTime)
|
||||
{
|
||||
|
@ -448,14 +488,7 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
|||
NS_DispatchToMainThread(new ChangeToHaveMetadata(mDecoder));
|
||||
}
|
||||
|
||||
// Loop until we have the requested time range in the source buffers.
|
||||
// This is a workaround for our lack of async functionality in the
|
||||
// MediaDecoderStateMachine. Bug 979104 implements what we need and
|
||||
// we'll remove this for an async approach based on that in bug 1056441.
|
||||
while (!TrackBuffersContainTime(target) && !IsShutdown() && !IsEnded()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek waiting for target=%f", this, target);
|
||||
static_cast<MediaSourceDecoder*>(mDecoder)->WaitForData();
|
||||
}
|
||||
WaitForTimeRange(target);
|
||||
|
||||
if (IsShutdown()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -463,8 +496,8 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
|||
|
||||
if (mAudioTrack) {
|
||||
mAudioIsSeeking = true;
|
||||
DebugOnly<bool> ok = SwitchAudioReader(target);
|
||||
MOZ_ASSERT(ok && static_cast<SourceBufferDecoder*>(mAudioReader->GetDecoder())->ContainsTime(target));
|
||||
SwitchAudioReader(target);
|
||||
MOZ_ASSERT(static_cast<SourceBufferDecoder*>(mAudioReader->GetDecoder())->ContainsTime(target));
|
||||
nsresult rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p rv=%x", this, mAudioReader.get(), rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -473,8 +506,8 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
|||
}
|
||||
if (mVideoTrack) {
|
||||
mVideoIsSeeking = true;
|
||||
DebugOnly<bool> ok = SwitchVideoReader(target);
|
||||
MOZ_ASSERT(ok && static_cast<SourceBufferDecoder*>(mVideoReader->GetDecoder())->ContainsTime(target));
|
||||
SwitchVideoReader(target);
|
||||
MOZ_ASSERT(static_cast<SourceBufferDecoder*>(mVideoReader->GetDecoder())->ContainsTime(target));
|
||||
nsresult rv = mVideoReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p rv=%x", this, mVideoReader.get(), rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -105,6 +105,27 @@ private:
|
|||
bool SwitchAudioReader(double aTarget);
|
||||
bool SwitchVideoReader(double aTarget);
|
||||
|
||||
// Return a reader from the set available in aTrackDecoders that is considered
|
||||
// usable by the aCanUserReader callback and has data available in the range
|
||||
// requested by aTarget.
|
||||
// aCanSelectReader is passed each reader available in aTrackDecoders and is
|
||||
// expected to return true if the reader is considerable selectable.
|
||||
already_AddRefed<MediaDecoderReader> SelectReader(double aTarget,
|
||||
bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*),
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
|
||||
|
||||
// Passed to SelectReader to enforce any track format specific requirements.
|
||||
// In the case of CanSelectAudioReader, verifies that aNewReader has a
|
||||
// matching audio format to the existing reader, as format switching is not
|
||||
// yet supported.
|
||||
bool CanSelectAudioReader(MediaDecoderReader* aNewReader);
|
||||
bool CanSelectVideoReader(MediaDecoderReader* aNewReader);
|
||||
|
||||
// Waits on the decoder monitor for aTime to become available in the active
|
||||
// TrackBuffers. Used to block a Seek call until the necessary data has been
|
||||
// provided to the relevant SourceBuffers.
|
||||
void WaitForTimeRange(double aTime);
|
||||
|
||||
nsRefPtr<MediaDecoderReader> mAudioReader;
|
||||
nsRefPtr<MediaDecoderReader> mVideoReader;
|
||||
|
||||
|
|
|
@ -440,8 +440,13 @@ SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
StartUpdating();
|
||||
/// TODO: Run coded frame removal algorithm asynchronously (would call StopUpdating()).
|
||||
StopUpdating();
|
||||
/// TODO: Run coded frame removal algorithm.
|
||||
|
||||
// Run the final step of the coded frame removal algorithm asynchronously
|
||||
// to ensure the SourceBuffer's updating flag transition behaves as
|
||||
// required by the spec.
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -561,7 +566,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
|||
// TODO: Run coded frame eviction algorithm.
|
||||
// TODO: Test buffer full flag.
|
||||
StartUpdating();
|
||||
// TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
|
||||
// TODO: Run more of the buffer append algorithm asynchronously.
|
||||
if (mParser->IsInitSegmentPresent(aData, aLength)) {
|
||||
MSE_DEBUG("SourceBuffer(%p)::AppendData: New initialization segment.", this);
|
||||
mMediaSource->QueueInitializationEvent();
|
||||
|
@ -632,13 +637,16 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
|||
// the current start point.
|
||||
mMediaSource->NotifyEvicted(0.0, GetBufferedStart());
|
||||
}
|
||||
StopUpdating();
|
||||
|
||||
// Run the final step of the buffer append algorithm asynchronously to
|
||||
// ensure the SourceBuffer's updating flag transition behaves as required
|
||||
// by the spec.
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
|
||||
NS_DispatchToMainThread(event);
|
||||
|
||||
// Schedule the state machine thread to ensure playback starts
|
||||
// if required when data is appended.
|
||||
mMediaSource->GetDecoder()->ScheduleStateMachineThread();
|
||||
|
||||
mMediaSource->GetDecoder()->NotifyGotData();
|
||||
}
|
||||
|
||||
double
|
||||
|
|
|
@ -106,10 +106,13 @@ TrackBuffer::AppendData(const uint8_t* aData, uint32_t aLength)
|
|||
}
|
||||
|
||||
SourceBufferResource* resource = mCurrentDecoder->GetResource();
|
||||
int64_t appendOffset = resource->GetLength();
|
||||
resource->AppendData(aData, aLength);
|
||||
// XXX: For future reference: NDA call must run on the main thread.
|
||||
mCurrentDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
|
||||
aLength, resource->GetLength());
|
||||
resource->AppendData(aData, aLength);
|
||||
aLength, appendOffset);
|
||||
mParentDecoder->NotifyTimeRangesChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -245,6 +248,7 @@ TrackBuffer::RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
|
|||
MSE_DEBUG("TrackBuffer(%p)::RegisterDecoder with mismatched audio/video tracks", this);
|
||||
}
|
||||
mInitializedDecoders.AppendElement(aDecoder);
|
||||
mParentDecoder->NotifyTimeRangesChanged();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -9,9 +9,7 @@ function fetchWithXHR(uri, onLoadFunction) {
|
|||
xhr.open("GET", uri, true);
|
||||
xhr.responseType = "blob";
|
||||
xhr.addEventListener("load", function (e) {
|
||||
if (xhr.status != 200) {
|
||||
return;
|
||||
}
|
||||
is(xhr.status, 200, "fetchWithXHR load uri='" + uri + "' status=" + xhr.status);
|
||||
var rdr = new FileReader();
|
||||
rdr.addEventListener("load", function (e) {
|
||||
onLoadFunction(e.target.result);
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s
|
||||
support-files = mediasource.js seek.webm seek.webm^headers^
|
||||
|
||||
[test_MediaSource.html]
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
|
||||
[test_SplitAppend.html]
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
|
||||
[test_SplitAppendDelay.html]
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
skip-if = e10s || buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
support-files =
|
||||
mediasource.js
|
||||
seek.webm seek.webm^headers^
|
||||
seek_lowres.webm seek_lowres.webm^headers^
|
||||
|
||||
[test_BufferedSeek.html]
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
[test_FrameSelection.html]
|
||||
[test_MediaSource.html]
|
||||
[test_SplitAppendDelay.html]
|
||||
[test_SplitAppend.html]
|
||||
|
||||
|
|
Двоичный файл не отображается.
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-store
|
|
@ -25,7 +25,9 @@ runWithMSE(function () {
|
|||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer));
|
||||
ms.endOfStream();
|
||||
sb.addEventListener("updateend", function () {
|
||||
ms.endOfStream()
|
||||
});
|
||||
});
|
||||
|
||||
var target = 2;
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>MSE: verify correct frames selected for given position</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="mediasource.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
runWithMSE(function () {
|
||||
var ms = new MediaSource();
|
||||
|
||||
var v = document.createElement("video");
|
||||
v.preload = "auto";
|
||||
v.src = URL.createObjectURL(ms);
|
||||
document.body.appendChild(v);
|
||||
|
||||
ms.addEventListener("sourceopen", function () {
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
// Append entire file covering range [0, 4].
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer));
|
||||
});
|
||||
|
||||
var targets = [{ currentTime: 3, videoWidth: 160, videoHeight: 120 },
|
||||
{ currentTime: 2, videoWidth: 160, videoHeight: 120 },
|
||||
{ currentTime: 0, videoWidth: 320, videoHeight: 240 }];
|
||||
var target;
|
||||
|
||||
v.addEventListener("loadedmetadata", function () {
|
||||
is(v.currentTime, 0, "currentTime has incorrect initial value");
|
||||
is(v.videoWidth, 320, "videoWidth has incorrect initial value");
|
||||
is(v.videoHeight, 240, "videoHeight has incorrect initial value");
|
||||
|
||||
fetchWithXHR("seek_lowres.webm", function (arrayBuffer) {
|
||||
// Append initialization segment.
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 438));
|
||||
var first = true;
|
||||
sb.addEventListener("updateend", function () {
|
||||
if (first) {
|
||||
// Append media segment covering range [2, 4].
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 51003));
|
||||
first = false;
|
||||
} else {
|
||||
ms.endOfStream();
|
||||
}
|
||||
});
|
||||
target = targets.shift();
|
||||
v.currentTime = target.currentTime;
|
||||
});
|
||||
});
|
||||
|
||||
v.addEventListener("seeked", function () {
|
||||
is(v.currentTime, target.currentTime, "Video currentTime not at target");
|
||||
|
||||
is(v.videoWidth, target.videoWidth, "videoWidth has incorrect final value");
|
||||
is(v.videoHeight, target.videoHeight, "videoHeight has incorrect final value");
|
||||
|
||||
target = targets.shift();
|
||||
if (target) {
|
||||
v.currentTime = target.currentTime;
|
||||
} else {
|
||||
v.parentNode.removeChild(v);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -52,7 +52,16 @@ runWithMSE(function () {
|
|||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer));
|
||||
is(sb.updating, true, "SourceBuffer.updating is expected value after appendBuffer");
|
||||
});
|
||||
|
||||
sb.addEventListener("update", function () {
|
||||
is(sb.updating, false, "SourceBuffer.updating is expected value in update event");
|
||||
ms.endOfStream();
|
||||
});
|
||||
|
||||
sb.addEventListener("updateend", function () {
|
||||
is(sb.updating, false, "SourceBuffer.updating is expected value in updateend event");
|
||||
v.play();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,8 +25,15 @@ runWithMSE(function () {
|
|||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
|
||||
ms.endOfStream();
|
||||
var first = true;
|
||||
sb.addEventListener("updateend", function () {
|
||||
if (first) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
|
||||
first = false;
|
||||
} else {
|
||||
ms.endOfStream();
|
||||
}
|
||||
});
|
||||
v.play();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,10 +25,17 @@ runWithMSE(function () {
|
|||
|
||||
fetchWithXHR("seek.webm", function (arrayBuffer) {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
|
||||
window.setTimeout(function () {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
|
||||
ms.endOfStream();
|
||||
}, 1000);
|
||||
var first = true;
|
||||
sb.addEventListener("updateend", function () {
|
||||
if (first) {
|
||||
window.setTimeout(function () {
|
||||
sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
|
||||
first = false;
|
||||
}, 1000);
|
||||
} else {
|
||||
ms.endOfStream();
|
||||
}
|
||||
});
|
||||
v.play();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,9 +10,14 @@
|
|||
#include "DOMMediaStream.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
||||
#include "mozilla/dom/VideoStreamTrack.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class DOMFile;
|
||||
}
|
||||
|
||||
struct VideoTrackConstraintsN;
|
||||
struct AudioTrackConstraintsN;
|
||||
|
||||
|
@ -137,6 +142,29 @@ public:
|
|||
/* Returns the type of media source (camera, microphone, screen, window, etc) */
|
||||
virtual const MediaSourceType GetMediaSource() = 0;
|
||||
|
||||
// Callback interface for TakePhoto(). Either PhotoComplete() or PhotoError()
|
||||
// should be called.
|
||||
class PhotoCallback {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PhotoCallback)
|
||||
|
||||
// aBlob is the image captured by MediaEngineSource. It is
|
||||
// called on main thread.
|
||||
virtual nsresult PhotoComplete(already_AddRefed<dom::DOMFile> aBlob) = 0;
|
||||
|
||||
// It is called on main thread. aRv is the error code.
|
||||
virtual nsresult PhotoError(nsresult aRv) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~PhotoCallback() {}
|
||||
};
|
||||
|
||||
/* If implementation of MediaEngineSource supports TakePhoto(), the picture
|
||||
* should be return via aCallback object. Otherwise, it returns NS_ERROR_NOT_IMPLEMENTED.
|
||||
* Currently, only Gonk MediaEngineSource implementation supports it.
|
||||
*/
|
||||
virtual nsresult TakePhoto(PhotoCallback* aCallback) = 0;
|
||||
|
||||
/* Return false if device is currently allocated or started */
|
||||
bool IsAvailable() {
|
||||
if (mState == kAllocated || mState == kStarted) {
|
||||
|
|
|
@ -65,6 +65,11 @@ public:
|
|||
return MediaSourceType::Camera;
|
||||
}
|
||||
|
||||
virtual nsresult TakePhoto(PhotoCallback* aCallback)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
|
@ -125,6 +130,11 @@ public:
|
|||
return MediaSourceType::Microphone;
|
||||
}
|
||||
|
||||
virtual nsresult TakePhoto(PhotoCallback* aCallback)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
|
|
|
@ -34,6 +34,11 @@ class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventList
|
|||
return MediaSourceType::Browser;
|
||||
}
|
||||
|
||||
virtual nsresult TakePhoto(PhotoCallback* aCallback)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void Draw();
|
||||
|
||||
class StartRunnable : public nsRunnable {
|
||||
|
|
|
@ -80,7 +80,7 @@ class GetCameraNameRunnable;
|
|||
* MainThread:
|
||||
* mCaptureIndex, mLastCapture, mState, mWidth, mHeight,
|
||||
*
|
||||
* Where mWidth, mHeight, mImage are protected by mMonitor
|
||||
* Where mWidth, mHeight, mImage, mPhotoCallbacks are protected by mMonitor
|
||||
* mState is protected by mCallbackMonitor
|
||||
* Other variable is accessed only from single thread
|
||||
*/
|
||||
|
@ -175,6 +175,11 @@ public:
|
|||
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
nsresult TakePhoto(PhotoCallback* aCallback)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
#else
|
||||
// We are subclassed from CameraControlListener, which implements a
|
||||
// threadsafe reference-count for us.
|
||||
|
@ -193,6 +198,9 @@ public:
|
|||
void SnapshotImpl();
|
||||
void RotateImage(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
|
||||
void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration);
|
||||
|
||||
nsresult TakePhoto(PhotoCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
#endif
|
||||
|
||||
// This runnable is for creating a temporary file on the main thread.
|
||||
|
@ -230,6 +238,7 @@ private:
|
|||
// This is only modified on MainThread (AllocImpl and DeallocImpl)
|
||||
nsRefPtr<ICameraControl> mCameraControl;
|
||||
nsCOMPtr<nsIDOMFile> mLastCapture;
|
||||
nsTArray<nsRefPtr<PhotoCallback>> mPhotoCallbacks;
|
||||
|
||||
// These are protected by mMonitor below
|
||||
int mRotation;
|
||||
|
@ -330,6 +339,11 @@ public:
|
|||
return MediaSourceType::Microphone;
|
||||
}
|
||||
|
||||
virtual nsresult TakePhoto(PhotoCallback* aCallback)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// VoEMediaProcess.
|
||||
void Process(int channel, webrtc::ProcessingTypes type,
|
||||
int16_t audio10ms[], int length,
|
||||
|
|
|
@ -877,18 +877,95 @@ MediaEngineWebRTCVideoSource::GetRotation()
|
|||
void
|
||||
MediaEngineWebRTCVideoSource::OnUserError(UserContext aContext, nsresult aError)
|
||||
{
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mCallbackMonitor.Notify();
|
||||
{
|
||||
// Scope the monitor, since there is another monitor below and we don't want
|
||||
// unexpected deadlock.
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mCallbackMonitor.Notify();
|
||||
}
|
||||
|
||||
// A main thread runnable to send error code to all queued PhotoCallbacks.
|
||||
class TakePhotoError : public nsRunnable {
|
||||
public:
|
||||
TakePhotoError(nsTArray<nsRefPtr<PhotoCallback>>& aCallbacks,
|
||||
nsresult aRv)
|
||||
: mRv(aRv)
|
||||
{
|
||||
mCallbacks.SwapElements(aCallbacks);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
uint32_t callbackNumbers = mCallbacks.Length();
|
||||
for (uint8_t i = 0; i < callbackNumbers; i++) {
|
||||
mCallbacks[i]->PhotoError(mRv);
|
||||
}
|
||||
// PhotoCallback needs to dereference on main thread.
|
||||
mCallbacks.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsTArray<nsRefPtr<PhotoCallback>> mCallbacks;
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
if (aContext == UserContext::kInTakePicture) {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (mPhotoCallbacks.Length()) {
|
||||
NS_DispatchToMainThread(new TakePhotoError(mPhotoCallbacks, aError));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTCVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
|
||||
{
|
||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||
mLastCapture = dom::DOMFile::CreateMemoryFile(static_cast<void*>(aData),
|
||||
static_cast<uint64_t>(aLength),
|
||||
aMimeType);
|
||||
mCallbackMonitor.Notify();
|
||||
// It needs to start preview because Gonk camera will stop preview while
|
||||
// taking picture.
|
||||
mCameraControl->StartPreview();
|
||||
|
||||
// Create a main thread runnable to generate a blob and call all current queued
|
||||
// PhotoCallbacks.
|
||||
class GenerateBlobRunnable : public nsRunnable {
|
||||
public:
|
||||
GenerateBlobRunnable(nsTArray<nsRefPtr<PhotoCallback>>& aCallbacks,
|
||||
uint8_t* aData,
|
||||
uint32_t aLength,
|
||||
const nsAString& aMimeType)
|
||||
{
|
||||
mCallbacks.SwapElements(aCallbacks);
|
||||
mPhoto.AppendElements(aData, aLength);
|
||||
mMimeType = aMimeType;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsRefPtr<dom::DOMFile> blob =
|
||||
dom::DOMFile::CreateMemoryFile(mPhoto.Elements(), mPhoto.Length(), mMimeType);
|
||||
uint32_t callbackCounts = mCallbacks.Length();
|
||||
for (uint8_t i = 0; i < callbackCounts; i++) {
|
||||
nsRefPtr<dom::DOMFile> tempBlob = blob;
|
||||
mCallbacks[i]->PhotoComplete(tempBlob.forget());
|
||||
}
|
||||
// PhotoCallback needs to dereference on main thread.
|
||||
mCallbacks.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<PhotoCallback>> mCallbacks;
|
||||
nsTArray<uint8_t> mPhoto;
|
||||
nsString mMimeType;
|
||||
};
|
||||
|
||||
// All elements in mPhotoCallbacks will be swapped in GenerateBlobRunnable
|
||||
// constructor. This captured image will be sent to all the queued
|
||||
// PhotoCallbacks in this runnable.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (mPhotoCallbacks.Length()) {
|
||||
NS_DispatchToMainThread(
|
||||
new GenerateBlobRunnable(mPhotoCallbacks, aData, aLength, aMimeType));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -976,6 +1053,28 @@ MediaEngineWebRTCVideoSource::OnNewPreviewFrame(layers::Image* aImage, uint32_t
|
|||
|
||||
return true; // return true because we're accepting the frame
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaEngineWebRTCVideoSource::TakePhoto(PhotoCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
// If other callback exists, that means there is a captured picture on the way,
|
||||
// it doesn't need to TakePicture() again.
|
||||
if (!mPhotoCallbacks.Length()) {
|
||||
nsresult rv = mCameraControl->TakePicture();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
mPhotoCallbacks.AppendElement(aCallback);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -455,7 +455,7 @@ protected:
|
|||
* If the current transcluded script is being compiled off thread, the
|
||||
* source for that script.
|
||||
*/
|
||||
jschar* mOffThreadCompileStringBuf;
|
||||
char16_t* mOffThreadCompileStringBuf;
|
||||
size_t mOffThreadCompileStringLength;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1584,8 +1584,8 @@ static const uint32_t sAsmJSCookie = 0x600d600d;
|
|||
|
||||
bool
|
||||
OpenEntryForRead(nsIPrincipal* aPrincipal,
|
||||
const jschar* aBegin,
|
||||
const jschar* aLimit,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aLimit,
|
||||
size_t* aSize,
|
||||
const uint8_t** aMemory,
|
||||
intptr_t* aFile)
|
||||
|
@ -1643,8 +1643,8 @@ CloseEntryForRead(size_t aSize,
|
|||
bool
|
||||
OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
||||
bool aInstalled,
|
||||
const jschar* aBegin,
|
||||
const jschar* aEnd,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aEnd,
|
||||
size_t aSize,
|
||||
uint8_t** aMemory,
|
||||
intptr_t* aFile)
|
||||
|
|
|
@ -80,8 +80,8 @@ struct WriteParams
|
|||
// Parameters specific to opening a cache entry for reading
|
||||
struct ReadParams
|
||||
{
|
||||
const jschar* mBegin;
|
||||
const jschar* mLimit;
|
||||
const char16_t* mBegin;
|
||||
const char16_t* mLimit;
|
||||
|
||||
ReadParams()
|
||||
: mBegin(nullptr),
|
||||
|
@ -103,8 +103,8 @@ struct ReadParams
|
|||
|
||||
bool
|
||||
OpenEntryForRead(nsIPrincipal* aPrincipal,
|
||||
const jschar* aBegin,
|
||||
const jschar* aLimit,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aLimit,
|
||||
size_t* aSize,
|
||||
const uint8_t** aMemory,
|
||||
intptr_t *aHandle);
|
||||
|
@ -115,8 +115,8 @@ CloseEntryForRead(size_t aSize,
|
|||
bool
|
||||
OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
||||
bool aInstalled,
|
||||
const jschar* aBegin,
|
||||
const jschar* aEnd,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aEnd,
|
||||
size_t aSize,
|
||||
uint8_t** aMemory,
|
||||
intptr_t* aHandle);
|
||||
|
|
|
@ -1366,7 +1366,7 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
|
|||
|
||||
// Don't overwrite a property set by content.
|
||||
bool contentDefinedProperty;
|
||||
if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const jschar*>(mData->mNameUTF16),
|
||||
if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const char16_t*>(mData->mNameUTF16),
|
||||
NS_strlen(mData->mNameUTF16),
|
||||
&contentDefinedProperty)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -97,10 +97,6 @@ using namespace mozilla::dom;
|
|||
|
||||
const size_t gStackSize = 8192;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo* gJSDiagnostics;
|
||||
#endif
|
||||
|
||||
// Thank you Microsoft!
|
||||
#ifdef CompareString
|
||||
#undef CompareString
|
||||
|
@ -352,212 +348,102 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
|
|||
return called;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
AsyncErrorReporter::AsyncErrorReporter(JSRuntime* aRuntime,
|
||||
JSErrorReport* aErrorReport,
|
||||
const char* aFallbackMessage,
|
||||
bool aIsChromeError,
|
||||
nsPIDOMWindow* aWindow)
|
||||
: mSourceLine(static_cast<const char16_t*>(aErrorReport->uclinebuf))
|
||||
, mLineNumber(aErrorReport->lineno)
|
||||
, mColumn(aErrorReport->column)
|
||||
, mFlags(aErrorReport->flags)
|
||||
{
|
||||
if (!aErrorReport->filename) {
|
||||
mFileName.SetIsVoid(true);
|
||||
} else {
|
||||
mFileName.AssignWithConversion(aErrorReport->filename);
|
||||
}
|
||||
|
||||
const char16_t* m = static_cast<const char16_t*>(aErrorReport->ucmessage);
|
||||
if (m) {
|
||||
JSFlatString* name = js::GetErrorTypeName(aRuntime, aErrorReport->exnType);
|
||||
if (name) {
|
||||
AssignJSFlatString(mErrorMsg, name);
|
||||
mErrorMsg.AppendLiteral(": ");
|
||||
}
|
||||
mErrorMsg.Append(m);
|
||||
}
|
||||
|
||||
if (mErrorMsg.IsEmpty() && aFallbackMessage) {
|
||||
mErrorMsg.AssignWithConversion(aFallbackMessage);
|
||||
}
|
||||
|
||||
mCategory = aIsChromeError ? NS_LITERAL_CSTRING("chrome javascript") :
|
||||
NS_LITERAL_CSTRING("content javascript");
|
||||
|
||||
mInnerWindowID = 0;
|
||||
if (aWindow) {
|
||||
MOZ_ASSERT(aWindow->IsInnerWindow());
|
||||
mInnerWindowID = aWindow->WindowID();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsyncErrorReporter::ReportError()
|
||||
{
|
||||
nsCOMPtr<nsIScriptError> errorObject =
|
||||
do_CreateInstance("@mozilla.org/scripterror;1");
|
||||
if (!errorObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName,
|
||||
mSourceLine, mLineNumber,
|
||||
mColumn, mFlags, mCategory,
|
||||
mInnerWindowID);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIConsoleService> consoleService =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
if (!consoleService) {
|
||||
return;
|
||||
}
|
||||
|
||||
consoleService->LogMessage(errorObject);
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class ScriptErrorEvent : public AsyncErrorReporter
|
||||
class ScriptErrorEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ScriptErrorEvent(JSRuntime* aRuntime,
|
||||
JSErrorReport* aErrorReport,
|
||||
const char* aFallbackMessage,
|
||||
xpc::ErrorReport* aReport,
|
||||
nsIPrincipal* aScriptOriginPrincipal,
|
||||
nsIPrincipal* aGlobalPrincipal,
|
||||
nsPIDOMWindow* aWindow,
|
||||
JS::Handle<JS::Value> aError,
|
||||
bool aDispatchEvent)
|
||||
// Pass an empty category, then compute ours
|
||||
: AsyncErrorReporter(aRuntime, aErrorReport, aFallbackMessage,
|
||||
nsContentUtils::IsSystemPrincipal(aGlobalPrincipal),
|
||||
aWindow)
|
||||
: mReport(aReport)
|
||||
, mOriginPrincipal(aScriptOriginPrincipal)
|
||||
, mDispatchEvent(aDispatchEvent)
|
||||
, mError(aRuntime, aError)
|
||||
, mWindow(aWindow)
|
||||
{
|
||||
MOZ_ASSERT_IF(mWindow, mWindow->IsInnerWindow());
|
||||
}
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsPIDOMWindow* win = mReport->mWindow;
|
||||
MOZ_ASSERT(win);
|
||||
// First, notify the DOM that we have a script error, but only if
|
||||
// our window is still the current inner, if we're associated with a window.
|
||||
if (mDispatchEvent && (!mWindow || mWindow->IsCurrentInnerWindow())) {
|
||||
nsIDocShell* docShell = mWindow ? mWindow->GetDocShell() : nullptr;
|
||||
if (docShell &&
|
||||
!JSREPORT_IS_WARNING(mFlags) &&
|
||||
!sHandlingScriptError) {
|
||||
AutoRestore<bool> recursionGuard(sHandlingScriptError);
|
||||
sHandlingScriptError = true;
|
||||
// our window is still the current inner.
|
||||
if (mDispatchEvent && win->IsCurrentInnerWindow() &&
|
||||
win->GetDocShell() && !JSREPORT_IS_WARNING(mReport->mFlags) &&
|
||||
!sHandlingScriptError)
|
||||
{
|
||||
AutoRestore<bool> recursionGuard(sHandlingScriptError);
|
||||
sHandlingScriptError = true;
|
||||
|
||||
nsRefPtr<nsPresContext> presContext;
|
||||
docShell->GetPresContext(getter_AddRefs(presContext));
|
||||
nsRefPtr<nsPresContext> presContext;
|
||||
win->GetDocShell()->GetPresContext(getter_AddRefs(presContext));
|
||||
|
||||
ThreadsafeAutoJSContext cx;
|
||||
RootedDictionary<ErrorEventInit> init(cx);
|
||||
init.mCancelable = true;
|
||||
init.mFilename = mFileName;
|
||||
init.mBubbles = true;
|
||||
ThreadsafeAutoJSContext cx;
|
||||
RootedDictionary<ErrorEventInit> init(cx);
|
||||
init.mCancelable = true;
|
||||
init.mFilename = mReport->mFileName;
|
||||
init.mBubbles = true;
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(mWindow));
|
||||
NS_ENSURE_STATE(sop);
|
||||
nsIPrincipal* p = sop->GetPrincipal();
|
||||
NS_ENSURE_STATE(p);
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
|
||||
NS_ENSURE_STATE(sop);
|
||||
nsIPrincipal* p = sop->GetPrincipal();
|
||||
NS_ENSURE_STATE(p);
|
||||
|
||||
bool sameOrigin = !mOriginPrincipal;
|
||||
bool sameOrigin = !mOriginPrincipal;
|
||||
|
||||
if (p && !sameOrigin) {
|
||||
if (NS_FAILED(p->Subsumes(mOriginPrincipal, &sameOrigin))) {
|
||||
sameOrigin = false;
|
||||
}
|
||||
if (p && !sameOrigin) {
|
||||
if (NS_FAILED(p->Subsumes(mOriginPrincipal, &sameOrigin))) {
|
||||
sameOrigin = false;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
|
||||
if (sameOrigin) {
|
||||
init.mMessage = mErrorMsg;
|
||||
init.mLineno = mLineNumber;
|
||||
init.mColno = mColumn;
|
||||
init.mError = mError;
|
||||
} else {
|
||||
NS_WARNING("Not same origin error!");
|
||||
init.mMessage = xoriginMsg;
|
||||
init.mLineno = 0;
|
||||
}
|
||||
|
||||
nsRefPtr<ErrorEvent> event =
|
||||
ErrorEvent::Constructor(static_cast<nsGlobalWindow*>(mWindow.get()),
|
||||
NS_LITERAL_STRING("error"), init);
|
||||
event->SetTrusted(true);
|
||||
|
||||
EventDispatcher::DispatchDOMEvent(mWindow, nullptr, event, presContext,
|
||||
&status);
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
|
||||
if (sameOrigin) {
|
||||
init.mMessage = mReport->mErrorMsg;
|
||||
init.mLineno = mReport->mLineNumber;
|
||||
init.mColno = mReport->mColumn;
|
||||
init.mError = mError;
|
||||
} else {
|
||||
NS_WARNING("Not same origin error!");
|
||||
init.mMessage = xoriginMsg;
|
||||
init.mLineno = 0;
|
||||
}
|
||||
|
||||
nsRefPtr<ErrorEvent> event =
|
||||
ErrorEvent::Constructor(static_cast<nsGlobalWindow*>(win),
|
||||
NS_LITERAL_STRING("error"), init);
|
||||
event->SetTrusted(true);
|
||||
|
||||
EventDispatcher::DispatchDOMEvent(win, nullptr, event, presContext,
|
||||
&status);
|
||||
}
|
||||
|
||||
if (status != nsEventStatus_eConsumeNoDefault) {
|
||||
AsyncErrorReporter::ReportError();
|
||||
mReport->LogToConsole();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<xpc::ErrorReport> mReport;
|
||||
nsCOMPtr<nsIPrincipal> mOriginPrincipal;
|
||||
bool mDispatchEvent;
|
||||
JS::PersistentRootedValue mError;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
static bool sHandlingScriptError;
|
||||
};
|
||||
|
||||
bool ScriptErrorEvent::sHandlingScriptError = false;
|
||||
|
||||
// NOTE: This function could be refactored to use the above. The only reason
|
||||
// it has not been done is that the code below only fills the error event
|
||||
// after it has a good nsPresContext - whereas using the above function
|
||||
// would involve always filling it. Is that a concern?
|
||||
// This temporarily lives here to avoid code churn. It will go away entirely
|
||||
// soon.
|
||||
namespace xpc {
|
||||
|
||||
void
|
||||
NS_ScriptErrorReporter(JSContext *cx,
|
||||
const char *message,
|
||||
JSErrorReport *report)
|
||||
SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
||||
{
|
||||
// We don't want to report exceptions too eagerly, but warnings in the
|
||||
// absence of werror are swallowed whole, so report those now.
|
||||
if (!JSREPORT_IS_WARNING(report->flags)) {
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
if (JS::DescribeScriptedCaller(cx)) {
|
||||
xpc->MarkErrorUnreported(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xpc) {
|
||||
nsAXPCNativeCallContext *cc = nullptr;
|
||||
xpc->GetCurrentNativeCallContext(&cc);
|
||||
if (cc) {
|
||||
nsAXPCNativeCallContext *prev = cc;
|
||||
while (NS_SUCCEEDED(prev->GetPreviousCallContext(&prev)) && prev) {
|
||||
uint16_t lang;
|
||||
if (NS_SUCCEEDED(prev->GetLanguage(&lang)) &&
|
||||
lang == nsAXPCNativeCallContext::LANG_JS) {
|
||||
xpc->MarkErrorUnreported(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> exception(cx);
|
||||
::JS_GetPendingException(cx, &exception);
|
||||
|
||||
|
@ -566,27 +452,43 @@ NS_ScriptErrorReporter(JSContext *cx,
|
|||
|
||||
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
|
||||
nsCOMPtr<nsIGlobalObject> globalObject;
|
||||
|
||||
// The eventual plan is for error reporting to happen in the AutoJSAPI
|
||||
// destructor using the global with which the AutoJSAPI was initialized. We
|
||||
// can't _quite_ do that yet, so we take a sloppy stab at those semantics. If
|
||||
// we have an nsIScriptContext, we'll get the right answer modulo
|
||||
// non-current-inners.
|
||||
//
|
||||
// Otherwise, we just use the privileged junk scope. This has the effect of
|
||||
// causing us to report the error as "chrome javascript" rather than "content
|
||||
// javascript", and not invoking any error reporters. This is exactly what we
|
||||
// want here.
|
||||
if (nsIScriptContext* scx = GetScriptContextFromJSContext(cx)) {
|
||||
nsCOMPtr<nsPIDOMWindow> outer = do_QueryInterface(scx->GetGlobalObject());
|
||||
if (outer) {
|
||||
globalObject = static_cast<nsGlobalWindow*>(outer->GetCurrentInnerWindow());
|
||||
}
|
||||
} else {
|
||||
globalObject = xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope());
|
||||
}
|
||||
if (globalObject) {
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
|
||||
MOZ_ASSERT_IF(win, win->IsInnerWindow());
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
|
||||
do_QueryInterface(globalObject);
|
||||
NS_ASSERTION(scriptPrincipal, "Global objects must implement "
|
||||
"nsIScriptObjectPrincipal");
|
||||
if (globalObject) {
|
||||
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
xpcReport->Init(report, message, globalObject);
|
||||
|
||||
// If there's no window to fire an event at, report it to the console
|
||||
// directly.
|
||||
if (!xpcReport->mWindow) {
|
||||
xpcReport->LogToConsole();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we need to asynchronously invoke onerror before we can decide
|
||||
// whether or not to report the error to the console.
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new ScriptErrorEvent(JS_GetRuntime(cx),
|
||||
report,
|
||||
message,
|
||||
xpcReport,
|
||||
nsJSPrincipals::get(report->originPrincipals),
|
||||
scriptPrincipal->GetPrincipal(),
|
||||
win,
|
||||
exception,
|
||||
/* We do not try to report Out Of Memory via a dom
|
||||
* event because the dom event handler would
|
||||
|
@ -597,51 +499,10 @@ NS_ScriptErrorReporter(JSContext *cx,
|
|||
*/
|
||||
report->errorNumber != JSMSG_OUT_OF_MEMORY));
|
||||
}
|
||||
|
||||
if (nsContentUtils::DOMWindowDumpEnabled()) {
|
||||
// Print it to stderr as well, for the benefit of those invoking
|
||||
// mozilla with -console.
|
||||
nsAutoCString error;
|
||||
error.AssignLiteral("JavaScript ");
|
||||
if (JSREPORT_IS_STRICT(report->flags))
|
||||
error.AppendLiteral("strict ");
|
||||
if (JSREPORT_IS_WARNING(report->flags))
|
||||
error.AppendLiteral("warning: ");
|
||||
else
|
||||
error.AppendLiteral("error: ");
|
||||
error.Append(report->filename);
|
||||
error.AppendLiteral(", line ");
|
||||
error.AppendInt(report->lineno, 10);
|
||||
error.AppendLiteral(": ");
|
||||
if (report->ucmessage) {
|
||||
AppendUTF16toUTF8(reinterpret_cast<const char16_t*>(report->ucmessage),
|
||||
error);
|
||||
} else {
|
||||
error.Append(message);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\n", error.get());
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (!gJSDiagnostics)
|
||||
gJSDiagnostics = PR_NewLogModule("JSDiagnostics");
|
||||
|
||||
if (gJSDiagnostics) {
|
||||
PR_LOG(gJSDiagnostics,
|
||||
JSREPORT_IS_WARNING(report->flags) ? PR_LOG_WARNING : PR_LOG_ERROR,
|
||||
("file %s, line %u: %s\n%s%s",
|
||||
report->filename, report->lineno, message,
|
||||
report->linebuf ? report->linebuf : "",
|
||||
(report->linebuf &&
|
||||
report->linebuf[strlen(report->linebuf)-1] != '\n')
|
||||
? "\n"
|
||||
: ""));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace xpc */
|
||||
|
||||
#ifdef DEBUG
|
||||
// A couple of useful functions to call when you're debugging.
|
||||
nsGlobalWindow *
|
||||
|
@ -899,7 +760,7 @@ nsJSContext::InitContext()
|
|||
if (!mContext)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
::JS_SetErrorReporter(mContext, NS_ScriptErrorReporter);
|
||||
JS_SetErrorReporter(mContext, xpc::SystemErrorReporter);
|
||||
|
||||
JSOptionChangedCallback(js_options_dot_str, this);
|
||||
|
||||
|
@ -1071,7 +932,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
|
|||
|
||||
p->GetData(data);
|
||||
|
||||
// cast is probably safe since wchar_t and jschar are expected
|
||||
// cast is probably safe since wchar_t and char16_t are expected
|
||||
// to be equivalent; both unsigned 16-bit entities
|
||||
JSString *str =
|
||||
::JS_NewUCStringCopyN(cx, data.get(), data.Length());
|
||||
|
@ -2458,8 +2319,8 @@ NotifyGCEndRunnable::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
const jschar oomMsg[3] = { '{', '}', 0 };
|
||||
const jschar *toSend = mMessage.get() ? mMessage.get() : oomMsg;
|
||||
const char16_t oomMsg[3] = { '{', '}', 0 };
|
||||
const char16_t *toSend = mMessage.get() ? mMessage.get() : oomMsg;
|
||||
observerService->NotifyObservers(nullptr, "garbage-collection-statistics", toSend);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2829,8 +2690,8 @@ NS_DOMStructuredCloneError(JSContext* cx,
|
|||
|
||||
static bool
|
||||
AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
|
||||
const jschar* aBegin,
|
||||
const jschar* aLimit,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aLimit,
|
||||
size_t* aSize,
|
||||
const uint8_t** aMemory,
|
||||
intptr_t *aHandle)
|
||||
|
@ -2844,8 +2705,8 @@ AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
|
|||
static bool
|
||||
AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
||||
bool aInstalled,
|
||||
const jschar* aBegin,
|
||||
const jschar* aEnd,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aEnd,
|
||||
size_t aSize,
|
||||
uint8_t** aMemory,
|
||||
intptr_t* aHandle)
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include "nsIXPConnect.h"
|
||||
#include "nsIArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
class nsICycleCollectorListener;
|
||||
class nsIXPConnectJSObjectHolder;
|
||||
|
@ -189,30 +191,18 @@ class AsyncErrorReporter : public nsRunnable
|
|||
{
|
||||
public:
|
||||
// aWindow may be null if this error report is not associated with a window
|
||||
AsyncErrorReporter(JSRuntime* aRuntime,
|
||||
JSErrorReport* aErrorReport,
|
||||
const char* aFallbackMessage,
|
||||
bool aIsChromeError, // To determine category
|
||||
nsPIDOMWindow* aWindow);
|
||||
AsyncErrorReporter(JSRuntime* aRuntime, xpc::ErrorReport* aReport)
|
||||
: mReport(aReport)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
ReportError();
|
||||
mReport->LogToConsole();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Do the actual error reporting
|
||||
void ReportError();
|
||||
|
||||
nsString mErrorMsg;
|
||||
nsString mFileName;
|
||||
nsString mSourceLine;
|
||||
nsCString mCategory;
|
||||
uint32_t mLineNumber;
|
||||
uint32_t mColumn;
|
||||
uint32_t mFlags;
|
||||
uint64_t mInnerWindowID;
|
||||
nsRefPtr<xpc::ErrorReport> mReport;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -238,9 +228,6 @@ public:
|
|||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID)
|
||||
|
||||
/* prototypes */
|
||||
void NS_ScriptErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
|
||||
|
||||
JSObject* NS_DOMReadStructuredClone(JSContext* cx,
|
||||
JSStructuredCloneReader* reader, uint32_t tag,
|
||||
uint32_t data, void* closure);
|
||||
|
|
|
@ -42,8 +42,8 @@ protected:
|
|||
private:
|
||||
// aString is expected to actually be an nsAString*. Should only be
|
||||
// called from StringifyToJSON.
|
||||
static bool AppendJSONToString(const jschar* aJSONData, uint32_t aDataLength,
|
||||
void* aString);
|
||||
static bool AppendJSONToString(const char16_t* aJSONData,
|
||||
uint32_t aDataLength, void* aString);
|
||||
};
|
||||
|
||||
// Struct that serves as a base class for all typed arrays and array buffers and
|
||||
|
|
|
@ -157,7 +157,7 @@ ErrorResult::ReportTypeError(JSContext* aCx)
|
|||
|
||||
Message* message = mMessage;
|
||||
const uint32_t argCount = message->mArgs.Length();
|
||||
const jschar* args[11];
|
||||
const char16_t* args[11];
|
||||
for (uint32_t i = 0; i < argCount; ++i) {
|
||||
args[i] = message->mArgs.ElementAt(i).get();
|
||||
}
|
||||
|
@ -1629,9 +1629,7 @@ DictionaryBase::ParseJSON(JSContext* aCx,
|
|||
if (aJSON.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return JS_ParseJSON(aCx,
|
||||
static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
|
||||
aJSON.Length(), aVal);
|
||||
return JS_ParseJSON(aCx, PromiseFlatString(aJSON).get(), aJSON.Length(), aVal);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1645,18 +1643,15 @@ DictionaryBase::StringifyToJSON(JSContext* aCx,
|
|||
|
||||
/* static */
|
||||
bool
|
||||
DictionaryBase::AppendJSONToString(const jschar* aJSONData,
|
||||
DictionaryBase::AppendJSONToString(const char16_t* aJSONData,
|
||||
uint32_t aDataLength,
|
||||
void* aString)
|
||||
{
|
||||
nsAString* string = static_cast<nsAString*>(aString);
|
||||
string->Append(static_cast<const char16_t*>(aJSONData),
|
||||
aDataLength);
|
||||
string->Append(aJSONData, aDataLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static JSString*
|
||||
ConcatJSString(JSContext* cx, const char* pre, JS::Handle<JSString*> str, const char* post)
|
||||
{
|
||||
|
@ -2244,10 +2239,10 @@ ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
|
|||
// and report the error outside the AutoCheckCannotGC scope.
|
||||
bool foundBadChar = false;
|
||||
size_t badCharIndex;
|
||||
jschar badChar;
|
||||
char16_t badChar;
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
const jschar* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
|
||||
const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
|
||||
if (!chars) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2270,11 +2265,11 @@ ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
|
|||
char index[21];
|
||||
static_assert(sizeof(size_t) <= 8, "index array too small");
|
||||
PR_snprintf(index, sizeof(index), "%d", badCharIndex);
|
||||
// A jschar is 16 bits long. The biggest unsigned 16 bit
|
||||
// A char16_t is 16 bits long. The biggest unsigned 16 bit
|
||||
// number (65,535) has 5 digits, plus one more for the null
|
||||
// terminator.
|
||||
char badCharArray[6];
|
||||
static_assert(sizeof(jschar) <= 2, "badCharArray too small");
|
||||
static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
|
||||
PR_snprintf(badCharArray, sizeof(badCharArray), "%d", badChar);
|
||||
ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
|
||||
return false;
|
||||
|
|
|
@ -1145,8 +1145,8 @@ FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* val
|
|||
}
|
||||
index = FindEnumStringIndexImpl(chars, length, values);
|
||||
} else {
|
||||
const jschar* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
|
||||
&length);
|
||||
const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
|
||||
&length);
|
||||
if (!chars) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
|
|
|
@ -3385,7 +3385,7 @@ class CGIsPermittedMethod(CGAbstractMethod):
|
|||
self.crossOriginSetters = crossOriginSetters
|
||||
self.crossOriginMethods = crossOriginMethods
|
||||
args = [Argument("JSFlatString*", "prop"),
|
||||
Argument("jschar", "propFirstChar"),
|
||||
Argument("char16_t", "propFirstChar"),
|
||||
Argument("bool", "set")]
|
||||
CGAbstractMethod.__init__(self, descriptor, "IsPermitted", "bool", args,
|
||||
inline=True)
|
||||
|
|
|
@ -150,7 +150,7 @@ GetArrayIndexFromId(JSContext* cx, JS::Handle<jsid> id)
|
|||
}
|
||||
if (MOZ_LIKELY(JSID_IS_ATOM(id))) {
|
||||
JSAtom* atom = JSID_TO_ATOM(id);
|
||||
jschar s;
|
||||
char16_t s;
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (js::AtomHasLatin1Chars(atom)) {
|
||||
|
|
|
@ -534,15 +534,29 @@ public:
|
|||
// Allow whatever element types the bindings are willing to pass
|
||||
// us in TexSubImage2D
|
||||
template<class ElementType>
|
||||
void TexSubImage2D(GLenum target, GLint level,
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLenum format,
|
||||
GLenum type, ElementType& elt, ErrorResult& rv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
const GLenum target = TexImageTargetToTexTarget(texImageTarget);
|
||||
if (target == LOCAL_GL_NONE)
|
||||
return ErrorInvalidEnumInfo("texSubImage2D: target", texImageTarget);
|
||||
|
||||
if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
|
||||
return;
|
||||
|
||||
if (level < 0)
|
||||
return ErrorInvalidValue("texSubImage2D: level is negative");
|
||||
|
||||
const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
|
||||
if (level > maxLevel)
|
||||
return ErrorInvalidValue("texSubImage2D: level %d is too large, max is %d", level, maxLevel);
|
||||
|
||||
// Trying to handle the video by GPU directly first
|
||||
if (TexImageFromVideoElement(target, level, format, format, type, elt)) {
|
||||
if (TexImageFromVideoElement(texImageTarget, level, format, format, type, elt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -556,7 +570,7 @@ public:
|
|||
|
||||
gfx::IntSize size = data->GetSize();
|
||||
uint32_t byteLength = data->Stride() * size.height;
|
||||
return TexSubImage2D_base(target, level, xoffset, yoffset,
|
||||
return TexSubImage2D_base(texImageTarget, level, xoffset, yoffset,
|
||||
size.width, size.height,
|
||||
data->Stride(), format, type,
|
||||
data->GetData(), byteLength,
|
||||
|
|
|
@ -2964,7 +2964,6 @@ WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx,
|
|||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -103,7 +103,7 @@ GetJSValFromKeyPathString(JSContext* aCx,
|
|||
|
||||
NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
|
||||
|
||||
const jschar* keyPathChars = token.BeginReading();
|
||||
const char16_t* keyPathChars = token.BeginReading();
|
||||
const size_t keyPathLen = token.Length();
|
||||
|
||||
bool hasProp;
|
||||
|
|
|
@ -492,7 +492,7 @@ TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName,
|
|||
StructuredCloneData cloneData;
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (JS_ParseJSON(cx,
|
||||
static_cast<const jschar*>(aJSONData.BeginReading()),
|
||||
static_cast<const char16_t*>(aJSONData.BeginReading()),
|
||||
aJSONData.Length(),
|
||||
&json)) {
|
||||
WriteStructuredClone(cx, json, buffer, cloneData.mClosure);
|
||||
|
|
|
@ -163,7 +163,7 @@ nsJSON::EncodeToStream(nsIOutputStream *aStream,
|
|||
}
|
||||
|
||||
static bool
|
||||
WriteCallback(const jschar *buf, uint32_t len, void *data)
|
||||
WriteCallback(const char16_t *buf, uint32_t len, void *data)
|
||||
{
|
||||
nsJSONWriter *writer = static_cast<nsJSONWriter*>(data);
|
||||
nsresult rv = writer->Write((const char16_t*)buf, (uint32_t)len);
|
||||
|
@ -389,7 +389,7 @@ NS_IMETHODIMP
|
|||
nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx,
|
||||
JS::MutableHandle<JS::Value> result)
|
||||
{
|
||||
if (!JS_ParseJSON(cx, static_cast<const jschar*>(PromiseFlatString(str).get()),
|
||||
if (!JS_ParseJSON(cx, static_cast<const char16_t*>(PromiseFlatString(str).get()),
|
||||
str.Length(), result)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ nsJSONListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
|
|||
|
||||
JS::Rooted<JS::Value> reviver(mCx, JS::NullValue()), value(mCx);
|
||||
|
||||
JS::ConstTwoByteChars chars(reinterpret_cast<const jschar*>(mBufferedChars.Elements()),
|
||||
JS::ConstTwoByteChars chars(reinterpret_cast<const char16_t*>(mBufferedChars.Elements()),
|
||||
mBufferedChars.Length());
|
||||
bool ok = JS_ParseJSONWithReviver(mCx, chars.get(),
|
||||
uint32_t(mBufferedChars.Length()),
|
||||
|
|
|
@ -505,15 +505,18 @@ public:
|
|||
(aVideoSource ? DOMMediaStream::HINT_CONTENTS_VIDEO : 0);
|
||||
|
||||
nsRefPtr<nsDOMUserMediaStream> stream = new nsDOMUserMediaStream(aListener,
|
||||
aAudioSource);
|
||||
aAudioSource,
|
||||
aVideoSource);
|
||||
stream->InitTrackUnionStream(aWindow, hints);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
nsDOMUserMediaStream(GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
MediaEngineSource *aAudioSource) :
|
||||
MediaEngineSource *aAudioSource,
|
||||
MediaEngineSource *aVideoSource) :
|
||||
mListener(aListener),
|
||||
mAudioSource(aAudioSource),
|
||||
mVideoSource(aVideoSource),
|
||||
mEchoOn(true),
|
||||
mAgcOn(false),
|
||||
mNoiseOn(true),
|
||||
|
@ -625,12 +628,32 @@ public:
|
|||
GetStream()->AsProcessedStream()->ForwardTrackEnabled(aID, aEnabled);
|
||||
}
|
||||
|
||||
virtual DOMLocalMediaStream* AsDOMLocalMediaStream()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual MediaEngineSource* GetMediaEngine(TrackID aTrackID)
|
||||
{
|
||||
// MediaEngine supports only one video and on video track now and TrackID is
|
||||
// fixed in MediaEngine.
|
||||
if (aTrackID == kVideoTrack) {
|
||||
return mVideoSource;
|
||||
}
|
||||
else if (aTrackID == kAudioTrack) {
|
||||
return mAudioSource;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The actual MediaStream is a TrackUnionStream. But these resources need to be
|
||||
// explicitly destroyed too.
|
||||
nsRefPtr<SourceMediaStream> mSourceStream;
|
||||
nsRefPtr<MediaInputPort> mPort;
|
||||
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
|
||||
nsRefPtr<MediaEngineSource> mAudioSource; // so we can turn on AEC
|
||||
nsRefPtr<MediaEngineSource> mVideoSource;
|
||||
bool mEchoOn;
|
||||
bool mAgcOn;
|
||||
bool mNoiseOn;
|
||||
|
|
|
@ -23,8 +23,8 @@ DialogWatcher.prototype.init = function() {
|
|||
this.findWindow = user32.declare("FindWindowW",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.jschar.ptr);
|
||||
ctypes.char16_t.ptr,
|
||||
ctypes.char16_t.ptr);
|
||||
}
|
||||
if (!this.winEventProcType) {
|
||||
this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
|
||||
|
@ -94,7 +94,7 @@ DialogWatcher.prototype.init = function() {
|
|||
ctypes.winapi_abi,
|
||||
ctypes.int,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.char16_t.ptr,
|
||||
ctypes.int);
|
||||
}
|
||||
if (!this.messageBox) {
|
||||
|
@ -103,14 +103,14 @@ DialogWatcher.prototype.init = function() {
|
|||
ctypes.winapi_abi,
|
||||
ctypes.int,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.char16_t.ptr,
|
||||
ctypes.char16_t.ptr,
|
||||
ctypes.uint32_t);
|
||||
}
|
||||
};
|
||||
|
||||
DialogWatcher.prototype.getWindowText = function(hwnd) {
|
||||
var bufType = ctypes.ArrayType(ctypes.jschar);
|
||||
var bufType = ctypes.ArrayType(ctypes.char16_t);
|
||||
var buffer = new bufType(256);
|
||||
|
||||
if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
|
||||
|
@ -181,4 +181,3 @@ DialogWatcher.prototype.processWindowEvents = function(timeout) {
|
|||
// Returns true if the hook was successful, something was found, and we never timed out
|
||||
return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@ function initCTypes() {
|
|||
ctypes.winapi_abi,
|
||||
ctypes.int,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.char16_t.ptr,
|
||||
ctypes.char16_t.ptr,
|
||||
ctypes.uint32_t);
|
||||
}
|
||||
if (!watcher) {
|
||||
|
|
|
@ -1005,19 +1005,13 @@ Promise::MaybeReportRejected()
|
|||
return;
|
||||
}
|
||||
|
||||
// Remains null in case of worker.
|
||||
nsCOMPtr<nsPIDOMWindow> win;
|
||||
bool isChromeError = false;
|
||||
|
||||
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
nsIPrincipal* principal;
|
||||
win = xpc::WindowGlobalOrNull(obj);
|
||||
principal = nsContentUtils::ObjectPrincipal(obj);
|
||||
isChromeError = nsContentUtils::IsSystemPrincipal(principal);
|
||||
nsIGlobalObject* global = xpc::GetNativeForGlobal(js::GetGlobalForObjectCrossCompartment(obj));
|
||||
xpcReport->Init(report.report(), report.message(), global);
|
||||
} else {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
isChromeError = worker->IsChromeWorker();
|
||||
xpcReport->InitOnWorkerThread(report.report(), report.message(),
|
||||
GetCurrentThreadWorkerPrivate()->IsChromeWorker());
|
||||
}
|
||||
|
||||
// Now post an event to do the real reporting async
|
||||
|
@ -1025,11 +1019,7 @@ Promise::MaybeReportRejected()
|
|||
// AsyncErrorReporter, otherwise if the call to DispatchToMainThread fails, it
|
||||
// will leak. See Bug 958684.
|
||||
nsRefPtr<AsyncErrorReporter> r =
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(),
|
||||
report.report(),
|
||||
report.message(),
|
||||
isChromeError,
|
||||
win);
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ void LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aO
|
|||
|
||||
char16_t dst[aLength]; // Allocating for worst case.
|
||||
|
||||
// First, count how many jschars need to be in the inflated string.
|
||||
// Count how many char16_t characters are needed in the inflated string.
|
||||
// |i| is the index into |src|, and |j| is the the index into |dst|.
|
||||
size_t srclen = src.length();
|
||||
uint32_t j = 0;
|
||||
|
@ -214,20 +214,20 @@ void LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aO
|
|||
if ((src[i + m] & 0xC0) != 0x80)
|
||||
INVALID(ReportInvalidCharacter, i, m);
|
||||
|
||||
// Determine the code unit's length in jschars and act accordingly.
|
||||
// Determine the code unit's length in char16_t units and act accordingly.
|
||||
v = JS::Utf8ToOneUcs4Char((uint8_t *)&src[i], n);
|
||||
if (v < 0x10000) {
|
||||
// The n-byte UTF8 code unit will fit in a single jschar.
|
||||
dst[j] = jschar(v);
|
||||
// The n-byte UTF8 code unit will fit in a single char16_t.
|
||||
dst[j] = char16_t(v);
|
||||
} else {
|
||||
v -= 0x10000;
|
||||
if (v <= 0xFFFFF) {
|
||||
// The n-byte UTF8 code unit will fit in two jschars.
|
||||
dst[j] = jschar((v >> 10) + 0xD800);
|
||||
// The n-byte UTF8 code unit will fit in two char16_t units.
|
||||
dst[j] = char16_t((v >> 10) + 0xD800);
|
||||
j++;
|
||||
dst[j] = jschar((v & 0x3FF) + 0xDC00);
|
||||
dst[j] = char16_t((v & 0x3FF) + 0xDC00);
|
||||
} else {
|
||||
// The n-byte UTF8 code unit won't fit in two jschars.
|
||||
// The n-byte UTF8 code unit won't fit in two char16_t units.
|
||||
INVALID(ReportTooBigCharacter, v, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace {
|
|||
#ifdef BUILD_CTYPES
|
||||
|
||||
char*
|
||||
UnicodeToNative(JSContext* aCx, const jschar* aSource, size_t aSourceLen)
|
||||
UnicodeToNative(JSContext* aCx, const char16_t* aSource, size_t aSourceLen)
|
||||
{
|
||||
nsDependentString unicode(aSource, aSourceLen);
|
||||
|
||||
|
|
|
@ -737,8 +737,8 @@ GetPrincipalForAsmJSCacheOp()
|
|||
|
||||
static bool
|
||||
AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
|
||||
const jschar* aBegin,
|
||||
const jschar* aLimit,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aLimit,
|
||||
size_t* aSize,
|
||||
const uint8_t** aMemory,
|
||||
intptr_t *aHandle)
|
||||
|
@ -755,8 +755,8 @@ AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
|
|||
static bool
|
||||
AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
||||
bool aInstalled,
|
||||
const jschar* aBegin,
|
||||
const jschar* aEnd,
|
||||
const char16_t* aBegin,
|
||||
const char16_t* aEnd,
|
||||
size_t aSize,
|
||||
uint8_t** aMemory,
|
||||
intptr_t* aHandle)
|
||||
|
|
|
@ -156,7 +156,7 @@ struct ScriptLoadInfo
|
|||
|
||||
nsString mURL;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
jschar* mScriptTextBuf;
|
||||
char16_t* mScriptTextBuf;
|
||||
size_t mScriptTextLength;
|
||||
|
||||
nsresult mLoadResult;
|
||||
|
|
|
@ -337,7 +337,7 @@ nsXBLProtoImpl::UndefineFields(JSContext *cx, JS::Handle<JSObject*> obj) const
|
|||
for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
|
||||
nsDependentString name(f->GetName());
|
||||
|
||||
const jschar* s = name.get();
|
||||
const char16_t* s = name.get();
|
||||
bool hasProp;
|
||||
if (::JS_AlreadyHasOwnUCProperty(cx, obj, s, name.Length(), &hasProp) &&
|
||||
hasProp) {
|
||||
|
|
|
@ -445,7 +445,7 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
|
|||
nsDependentString name(mName);
|
||||
if (!JS_WrapValue(cx, &result) ||
|
||||
!::JS_DefineUCProperty(cx, aBoundNode,
|
||||
reinterpret_cast<const jschar*>(mName),
|
||||
reinterpret_cast<const char16_t*>(mName),
|
||||
name.Length(), result, mJSAttributes)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ nsXBLProtoImplMethod::InstallMember(JSContext* aCx,
|
|||
NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
|
||||
static_cast<const jschar*>(mName),
|
||||
static_cast<const char16_t*>(mName),
|
||||
name.Length(), method,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
|
|
@ -147,7 +147,7 @@ nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
|
|||
|
||||
nsDependentString name(mName);
|
||||
if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
|
||||
static_cast<const jschar*>(mName),
|
||||
static_cast<const char16_t*>(mName),
|
||||
name.Length(), JS::UndefinedHandleValue, mJSAttributes,
|
||||
JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get()),
|
||||
JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get())))
|
||||
|
|
|
@ -49,12 +49,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=502673
|
|||
}
|
||||
},
|
||||
|
||||
QueryInterface: function(iid) {
|
||||
QueryInterface: SpecialPowers.wrapCallback(function(iid) {
|
||||
if (iid.equals(SpecialPowers.Ci.nsIDocumentStateListener) ||
|
||||
iid.equals(SpecialPowers.Ci.nsISupports))
|
||||
return this;
|
||||
throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
function doTest() {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
320x240.ogv
|
||||
bug449141_page.html
|
||||
|
||||
[test_bug449141.html]
|
||||
skip-if = toolkit == 'android'
|
|
@ -1,13 +1,9 @@
|
|||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
320x240.ogv
|
||||
bug293834_form.html
|
||||
bug449141_page.html
|
||||
|
||||
[test_bug293834.html]
|
||||
[test_bug449141.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug499115.html]
|
||||
[test_nsFind.html]
|
||||
[test_private_window_from_content.html]
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
||||
|
|
|
@ -5,8 +5,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=449141
|
|||
-->
|
||||
<head>
|
||||
<title>Test for Bug 449141</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=449141">Mozilla Bug 449141</a>
|
||||
|
|
|
@ -406,7 +406,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState,
|
|||
mApzcTreeLog << '\n';
|
||||
|
||||
// Accumulate the CSS transform between layers that have an APZC.
|
||||
// In the terminology of the big comment above APZCTreeManager::GetInputTransforms, if
|
||||
// In the terminology of the big comment above APZCTreeManager::GetScreenToApzcTransform, if
|
||||
// we are at layer M, then aAncestorTransform is NC * OC * PC, and we left-multiply MC and
|
||||
// compute ancestorTransform to be MC * NC * OC * PC. This gets passed down as the ancestor
|
||||
// transform to layer L when we recurse into the children below. If we are at a layer
|
||||
|
@ -495,8 +495,8 @@ ApplyTransform(nsIntPoint* aPoint, const Matrix4x4& aMatrix)
|
|||
/*static*/ template<class T> void
|
||||
TransformScreenToGecko(T* aPoint, AsyncPanZoomController* aApzc, APZCTreeManager* aApzcTm)
|
||||
{
|
||||
Matrix4x4 transformToApzc, transformToGecko;
|
||||
aApzcTm->GetInputTransforms(aApzc, transformToApzc, transformToGecko);
|
||||
Matrix4x4 transformToApzc = aApzcTm->GetScreenToApzcTransform(aApzc);
|
||||
Matrix4x4 transformToGecko = aApzcTm->GetApzcToGeckoTransform(aApzc);
|
||||
ApplyTransform(aPoint, transformToApzc * transformToGecko);
|
||||
}
|
||||
|
||||
|
@ -506,7 +506,6 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
|||
{
|
||||
nsEventStatus result = nsEventStatus_eIgnore;
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
bool inOverscrolledApzc = false;
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
|
@ -522,7 +521,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
|||
// transform than the one in TransformScreenToGecko, so we need to
|
||||
// make a copy of the event.
|
||||
PanGestureInput inputForApzc(panInput);
|
||||
GetInputTransforms(apzc, transformToApzc, transformToGecko);
|
||||
transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
ApplyTransform(&(inputForApzc.mPanStartPoint), transformToApzc);
|
||||
result = apzc->ReceiveInputEvent(inputForApzc);
|
||||
|
||||
|
@ -540,7 +539,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
|||
// transform than the one in TransformScreenToGecko, so we need to
|
||||
// make a copy of the event.
|
||||
PinchGestureInput inputForApzc(pinchInput);
|
||||
GetInputTransforms(apzc, transformToApzc, transformToGecko);
|
||||
transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
ApplyTransform(&(inputForApzc.mFocusPoint), transformToApzc);
|
||||
result = apzc->ReceiveInputEvent(inputForApzc);
|
||||
|
||||
|
@ -558,7 +557,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
|||
// transform than the one in TransformScreenToGecko, so we need to
|
||||
// make a copy of the event.
|
||||
TapGestureInput inputForApzc(tapInput);
|
||||
GetInputTransforms(apzc, transformToApzc, transformToGecko);
|
||||
transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
ApplyTransform(&(inputForApzc.mPoint), transformToApzc);
|
||||
result = apzc->ReceiveInputEvent(inputForApzc);
|
||||
|
||||
|
@ -632,8 +631,7 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
|||
|
||||
if (mApzcForInputBlock) {
|
||||
// Cache apz transform so it can be used for future events in this block.
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(mApzcForInputBlock, mCachedTransformToApzcForInputBlock, transformToGecko);
|
||||
mCachedTransformToApzcForInputBlock = GetScreenToApzcTransform(mApzcForInputBlock);
|
||||
} else {
|
||||
// Reset the cached apz transform
|
||||
mCachedTransformToApzcForInputBlock = Matrix4x4();
|
||||
|
@ -680,8 +678,8 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
|||
// For computing the event to pass back to Gecko, use the up-to-date transforms.
|
||||
// This ensures that transformToApzc and transformToGecko are in sync
|
||||
// (note that transformToGecko isn't cached).
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToGecko);
|
||||
transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
|
||||
Matrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
|
||||
ApplyTransform(&(aInput.mTouches[i].mScreenPoint), outTransform);
|
||||
|
@ -721,9 +719,8 @@ APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
|
|||
MOZ_ASSERT(aOutTransformedPoint);
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aPoint, nullptr);
|
||||
if (apzc && aOutTransformedPoint) {
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(apzc, transformToApzc, transformToGecko);
|
||||
Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
*aOutTransformedPoint = TransformTo<LayoutDevicePixel>(outTransform, aPoint);
|
||||
}
|
||||
|
@ -743,9 +740,8 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent,
|
|||
&inOverscrolledApzc);
|
||||
if (apzc) {
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
GetInputTransforms(apzc, transformToApzc, transformToGecko);
|
||||
Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
ApplyTransform(&(aEvent.refPoint), outTransform);
|
||||
}
|
||||
|
@ -877,17 +873,16 @@ TransformDisplacement(APZCTreeManager* aTreeManager,
|
|||
ScreenPoint& aStartPoint,
|
||||
ScreenPoint& aEndPoint) {
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko; // ignored
|
||||
|
||||
// Convert start and end points to untransformed screen coordinates.
|
||||
aTreeManager->GetInputTransforms(aSource, transformToApzc, transformToGecko);
|
||||
transformToApzc = aTreeManager->GetScreenToApzcTransform(aSource);
|
||||
Matrix4x4 untransformToApzc = transformToApzc;
|
||||
untransformToApzc.Invert();
|
||||
ApplyTransform(&aStartPoint, untransformToApzc);
|
||||
ApplyTransform(&aEndPoint, untransformToApzc);
|
||||
|
||||
// Convert start and end points to aTarget's transformed screen coordinates.
|
||||
aTreeManager->GetInputTransforms(aTarget, transformToApzc, transformToGecko);
|
||||
transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget);
|
||||
ApplyTransform(&aStartPoint, transformToApzc);
|
||||
ApplyTransform(&aEndPoint, transformToApzc);
|
||||
}
|
||||
|
@ -1159,7 +1154,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
|||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment on GetInputTransforms. This function will recurse with aApzc at L and P, and the
|
||||
// explained in the comment above GetScreenToApzcTransform. This function will recurse with aApzc at L and P, and the
|
||||
// comments explain what values are stored in the variables at these two levels. All the comments
|
||||
// use standard matrix notation where the leftmost matrix in a multiplication is applied first.
|
||||
|
||||
|
@ -1224,8 +1219,8 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
|||
return result;
|
||||
}
|
||||
|
||||
/* This function sets the aTransformToApzcOut and aTransformToGeckoOut out-parameters
|
||||
to some useful transformations that input events may need applied. This is best
|
||||
/* The methods GetScreenToApzcTransform() and GetApzcToGeckoTransform() return
|
||||
some useful transformations that input events may need applied. This is best
|
||||
illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L
|
||||
is the layer that corresponds to the argument |aApzc|, and layer R is the root
|
||||
of the layer tree. Layer M is the parent of L, N is the parent of M, and so on.
|
||||
|
@ -1258,7 +1253,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
|||
MT.Inverse()
|
||||
MN.Inverse()
|
||||
MC.Inverse()
|
||||
This combined transformation is returned in the aTransformToApzcOut out-parameter.
|
||||
This combined transformation is returned by GetScreenToApzcTransform().
|
||||
|
||||
Next, if we want user inputs sent to gecko for event-dispatching, we will need to strip
|
||||
out all of the async transforms that are involved in this chain. This is because async
|
||||
|
@ -1290,7 +1285,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
|||
RC
|
||||
RD
|
||||
This sequence can be simplified and refactored to the following:
|
||||
aTransformToApzcOut
|
||||
GetScreenToApzcTransform()
|
||||
LA.Inverse()
|
||||
LD
|
||||
MC
|
||||
|
@ -1298,9 +1293,9 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
|||
...
|
||||
RC
|
||||
RD
|
||||
Since aTransformToApzcOut is already one of the out-parameters, we set aTransformToGeckoOut
|
||||
to the remaining transforms (LA.Inverse() * LD * ... * RD), so that the caller code can
|
||||
combine it with aTransformToApzcOut to get the final transform required in this case.
|
||||
Since GetScreenToApzcTransform() can be obtained by calling that function, GetApzcToGeckoTransform()
|
||||
returns the remaining transforms (LA.Inverse() * LD * ... * RD), so that the caller code can
|
||||
combine it with GetScreenToApzcTransform() to get the final transform required in this case.
|
||||
|
||||
Note that for many of these layers, there will be no AsyncPanZoomController attached, and
|
||||
so the async transform will be the identity transform. So, in the example above, if layers
|
||||
|
@ -1314,10 +1309,14 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
|
|||
The APZCs also obviously have LT, LN, PT, and PN, so all of the above transformation combinations
|
||||
required can be generated.
|
||||
*/
|
||||
void
|
||||
APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, Matrix4x4& aTransformToApzcOut,
|
||||
Matrix4x4& aTransformToGeckoOut)
|
||||
|
||||
/*
|
||||
* See the long comment above for a detailed explanation of this function.
|
||||
*/
|
||||
Matrix4x4
|
||||
APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const
|
||||
{
|
||||
Matrix4x4 result;
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
|
@ -1329,34 +1328,64 @@ APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, Matrix4x4& aT
|
|||
// ancestorUntransform is PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform();
|
||||
ancestorUntransform.Invert();
|
||||
// asyncUntransform is LA.Inverse()
|
||||
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
|
||||
asyncUntransform.Invert();
|
||||
|
||||
// aTransformToApzcOut is initialized to PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
aTransformToApzcOut = ancestorUntransform;
|
||||
// aTransformToGeckoOut is initialized to LA.Inverse() * LD * MC * NC * OC * PC
|
||||
aTransformToGeckoOut = asyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetAncestorTransform();
|
||||
// result is initialized to PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
result = ancestorUntransform;
|
||||
|
||||
for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
|
||||
// ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
|
||||
ancestorUntransform = parent->GetAncestorTransform();
|
||||
ancestorUntransform.Invert();
|
||||
// asyncUntransform is updated to PA.Inverse() when parent == P
|
||||
asyncUntransform = parent->GetCurrentAsyncTransform();
|
||||
Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransform();
|
||||
asyncUntransform.Invert();
|
||||
// untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PA.Inverse()
|
||||
Matrix4x4 untransformSinceLastApzc = ancestorUntransform * asyncUntransform;
|
||||
|
||||
// aTransformToApzcOut is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
aTransformToApzcOut = untransformSinceLastApzc * aTransformToApzcOut;
|
||||
// aTransformToGeckoOut is LA.Inverse() * LD * MC * NC * OC * PC * PD * QC * RC
|
||||
aTransformToGeckoOut = aTransformToGeckoOut * parent->GetTransformToLastDispatchedPaint() * parent->GetAncestorTransform();
|
||||
// result is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
result = untransformSinceLastApzc * result;
|
||||
|
||||
// The above values for aTransformToApzcOut and aTransformToGeckoOut when parent == P match
|
||||
// the required output as explained in the comment above this method. Note that any missing
|
||||
// The above value for result when parent == P matches the required output
|
||||
// as explained in the comment above this method. Note that any missing
|
||||
// terms are guaranteed to be identity transforms.
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* See the long comment above GetScreenToApzcTransform() for a detailed
|
||||
* explanation of this function.
|
||||
*/
|
||||
Matrix4x4
|
||||
APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const
|
||||
{
|
||||
Matrix4x4 result;
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment above. This function is called with aApzc at L, and the loop
|
||||
// below performs one iteration, where parent is at P. The comments explain what values are stored
|
||||
// in the variables at these two levels. All the comments use standard matrix notation where the
|
||||
// leftmost matrix in a multiplication is applied first.
|
||||
|
||||
// asyncUntransform is LA.Inverse()
|
||||
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
|
||||
asyncUntransform.Invert();
|
||||
|
||||
// aTransformToGeckoOut is initialized to LA.Inverse() * LD * MC * NC * OC * PC
|
||||
result = asyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetAncestorTransform();
|
||||
|
||||
for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
|
||||
// aTransformToGeckoOut is LA.Inverse() * LD * MC * NC * OC * PC * PD * QC * RC
|
||||
result = result * parent->GetTransformToLastDispatchedPaint() * parent->GetAncestorTransform();
|
||||
|
||||
// The above value for result when parent == P matches the required output
|
||||
// as explained in the comment above this method. Note that any missing
|
||||
// terms are guaranteed to be identity transforms.
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
|
|
|
@ -361,8 +361,8 @@ public:
|
|||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint,
|
||||
bool* aOutInOverscrolledApzc);
|
||||
void GetInputTransforms(AsyncPanZoomController *aApzc, gfx::Matrix4x4& aTransformToApzcOut,
|
||||
gfx::Matrix4x4& aTransformToGeckoOut);
|
||||
gfx::Matrix4x4 GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const;
|
||||
gfx::Matrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const;
|
||||
private:
|
||||
/* Helpers */
|
||||
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId);
|
||||
|
@ -417,7 +417,7 @@ private:
|
|||
* is considered part of the APZC tree management state.
|
||||
* Finally, the lock needs to be held when accessing mOverscrollHandoffChain.
|
||||
* IMPORTANT: See the note about lock ordering at the top of this file. */
|
||||
mozilla::Monitor mTreeLock;
|
||||
mutable mozilla::Monitor mTreeLock;
|
||||
nsRefPtr<AsyncPanZoomController> mRootApzc;
|
||||
/* This tracks the APZC that should receive all inputs for the current input event block.
|
||||
* This allows touch points to move outside the thing they started on, but still have the
|
||||
|
|
|
@ -927,7 +927,7 @@ AsyncPanZoomController::Destroy()
|
|||
}
|
||||
|
||||
bool
|
||||
AsyncPanZoomController::IsDestroyed()
|
||||
AsyncPanZoomController::IsDestroyed() const
|
||||
{
|
||||
return mTreeManager == nullptr;
|
||||
}
|
||||
|
@ -1453,9 +1453,7 @@ AsyncPanZoomController::ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut
|
|||
{
|
||||
APZCTreeManager* treeManagerLocal = mTreeManager;
|
||||
if (treeManagerLocal) {
|
||||
Matrix4x4 transformToApzc;
|
||||
Matrix4x4 transformToGecko;
|
||||
treeManagerLocal->GetInputTransforms(this, transformToApzc, transformToGecko);
|
||||
Matrix4x4 transformToGecko = treeManagerLocal->GetApzcToGeckoTransform(this);
|
||||
Point result = transformToGecko * Point(aPoint.x, aPoint.y);
|
||||
// NOTE: This isn't *quite* LayoutDevicePoint, we just don't have a name
|
||||
// for this coordinate space and it maps the closest to LayoutDevicePoint.
|
||||
|
@ -1544,7 +1542,9 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
|
|||
mX.UpdateWithTouchAtDevicePoint(aEvent.mPanStartPoint.x, aEvent.mTime);
|
||||
mY.UpdateWithTouchAtDevicePoint(aEvent.mPanStartPoint.y, aEvent.mTime);
|
||||
|
||||
HandlePanningUpdate(aEvent.mPanDisplacement.x, aEvent.mPanDisplacement.y);
|
||||
ScreenPoint panDisplacement = aEvent.mPanDisplacement;
|
||||
ToGlobalScreenCoordinates(&panDisplacement, aEvent.mPanStartPoint);
|
||||
HandlePanningUpdate(panDisplacement);
|
||||
|
||||
// TODO: Handle pan events sent without pan begin / pan end events properly.
|
||||
if (mPanGestureState) {
|
||||
|
@ -1694,9 +1694,49 @@ nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent)
|
|||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
float AsyncPanZoomController::PanDistance() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
return NS_hypot(mX.PanDistance(), mY.PanDistance());
|
||||
// Helper function for To[Global|Local]ScreenCoordinates().
|
||||
// TODO(botond): Generalize this into a template function in UnitTransforms.h.
|
||||
static void TransformVector(const Matrix4x4& aTransform,
|
||||
ScreenPoint* aVector,
|
||||
const ScreenPoint& aAnchor) {
|
||||
ScreenPoint start = aAnchor;
|
||||
ScreenPoint end = aAnchor + *aVector;
|
||||
start = TransformTo<ScreenPixel>(aTransform, start);
|
||||
end = TransformTo<ScreenPixel>(aTransform, end);
|
||||
*aVector = end - start;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ToGlobalScreenCoordinates(ScreenPoint* aVector,
|
||||
const ScreenPoint& aAnchor) const {
|
||||
if (APZCTreeManager* treeManagerLocal = mTreeManager) {
|
||||
Matrix4x4 transform = treeManagerLocal->GetScreenToApzcTransform(this);
|
||||
transform.Invert();
|
||||
TransformVector(transform, aVector, aAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ToLocalScreenCoordinates(ScreenPoint* aVector,
|
||||
const ScreenPoint& aAnchor) const {
|
||||
if (APZCTreeManager* treeManagerLocal = mTreeManager) {
|
||||
Matrix4x4 transform = treeManagerLocal->GetScreenToApzcTransform(this);
|
||||
TransformVector(transform, aVector, aAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
float AsyncPanZoomController::PanDistance() const {
|
||||
ScreenPoint panVector;
|
||||
ScreenPoint panStart;
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
panVector = ScreenPoint(mX.PanDistance(), mY.PanDistance());
|
||||
panStart = PanStart();
|
||||
}
|
||||
ToGlobalScreenCoordinates(&panVector, panStart);
|
||||
return NS_hypot(panVector.x, panVector.y);
|
||||
}
|
||||
|
||||
ScreenPoint AsyncPanZoomController::PanStart() const {
|
||||
return ScreenPoint(mX.PanStart(), mY.PanStart());
|
||||
}
|
||||
|
||||
const ScreenPoint AsyncPanZoomController::GetVelocityVector() {
|
||||
|
@ -1772,16 +1812,16 @@ void AsyncPanZoomController::HandlePanning(double aAngle) {
|
|||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::HandlePanningUpdate(float aDX, float aDY) {
|
||||
void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aDelta) {
|
||||
// If we're axis-locked, check if the user is trying to break the lock
|
||||
if (GetAxisLockMode() == STICKY && !mPanDirRestricted) {
|
||||
|
||||
double angle = atan2(aDY, aDX); // range [-pi, pi]
|
||||
double angle = atan2(aDelta.y, aDelta.x); // range [-pi, pi]
|
||||
angle = fabs(angle); // range [0, pi]
|
||||
|
||||
float breakThreshold = gfxPrefs::APZAxisBreakoutThreshold() * APZCTreeManager::GetDPI();
|
||||
|
||||
if (fabs(aDX) > breakThreshold || fabs(aDY) > breakThreshold) {
|
||||
if (fabs(aDelta.x) > breakThreshold || fabs(aDelta.y) > breakThreshold) {
|
||||
if (mState == PANNING_LOCKED_X || mState == CROSS_SLIDING_X) {
|
||||
if (!IsCloseToHorizontal(angle, gfxPrefs::APZAxisBreakoutAngle())) {
|
||||
mY.SetAxisLocked(false);
|
||||
|
@ -2026,9 +2066,11 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
|||
ScreenPoint prevTouchPoint(mX.GetPos(), mY.GetPos());
|
||||
ScreenPoint touchPoint = GetFirstTouchScreenPoint(aEvent);
|
||||
|
||||
float dx = mX.PanDistance(touchPoint.x);
|
||||
float dy = mY.PanDistance(touchPoint.y);
|
||||
HandlePanningUpdate(dx, dy);
|
||||
ScreenPoint delta(mX.PanDistance(touchPoint.x),
|
||||
mY.PanDistance(touchPoint.y));
|
||||
const ScreenPoint panStart = PanStart();
|
||||
ToGlobalScreenCoordinates(&delta, panStart);
|
||||
HandlePanningUpdate(delta);
|
||||
|
||||
UpdateWithTouchAtDevicePoint(aEvent);
|
||||
|
||||
|
@ -2465,7 +2507,7 @@ void AsyncPanZoomController::SampleContentTransformForFrame(ViewTransform* aOutT
|
|||
}
|
||||
}
|
||||
|
||||
ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
|
||||
ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() const {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
CSSPoint lastPaintScrollOffset;
|
||||
|
@ -2503,14 +2545,14 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
|
|||
return ViewTransform(scale, -translation);
|
||||
}
|
||||
|
||||
Matrix4x4 AsyncPanZoomController::GetNontransientAsyncTransform() {
|
||||
Matrix4x4 AsyncPanZoomController::GetNontransientAsyncTransform() const {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
return Matrix4x4().Scale(mLastContentPaintMetrics.mResolution.scale,
|
||||
mLastContentPaintMetrics.mResolution.scale,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
|
||||
Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
// Technically we should be taking the scroll delta in the coordinate space
|
||||
|
|
|
@ -88,6 +88,7 @@ public:
|
|||
* device DPI, before we start panning the screen. This is to prevent us from
|
||||
* accidentally processing taps as touch moves, and from very short/accidental
|
||||
* touches moving the screen.
|
||||
* Note: this distance is in global screen coordinates.
|
||||
*/
|
||||
static float GetTouchStartTolerance();
|
||||
|
||||
|
@ -212,7 +213,7 @@ public:
|
|||
/**
|
||||
* Returns true if Destroy() has already been called on this APZC instance.
|
||||
*/
|
||||
bool IsDestroyed();
|
||||
bool IsDestroyed() const;
|
||||
|
||||
/**
|
||||
* Returns the incremental transformation corresponding to the async pan/zoom
|
||||
|
@ -220,14 +221,14 @@ public:
|
|||
* existing transform, it will make the layer appear with the desired pan/zoom
|
||||
* amount.
|
||||
*/
|
||||
ViewTransform GetCurrentAsyncTransform();
|
||||
ViewTransform GetCurrentAsyncTransform() const;
|
||||
|
||||
/**
|
||||
* Returns the part of the async transform that will remain once Gecko does a
|
||||
* repaint at the desired metrics. That is, in the steady state:
|
||||
* Matrix4x4(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform()
|
||||
*/
|
||||
Matrix4x4 GetNontransientAsyncTransform();
|
||||
Matrix4x4 GetNontransientAsyncTransform() const;
|
||||
|
||||
/**
|
||||
* Returns the transform to take something from the coordinate space of the
|
||||
|
@ -236,7 +237,7 @@ public:
|
|||
* processed, this is needed to transform input events properly into a space
|
||||
* gecko will understand.
|
||||
*/
|
||||
Matrix4x4 GetTransformToLastDispatchedPaint();
|
||||
Matrix4x4 GetTransformToLastDispatchedPaint() const;
|
||||
|
||||
/**
|
||||
* Recalculates the displayport. Ideally, this should paint an area bigger
|
||||
|
@ -326,6 +327,28 @@ public:
|
|||
*/
|
||||
int32_t GetLastTouchIdentifier() const;
|
||||
|
||||
/**
|
||||
* Convert the vector |aVector|, rooted at the point |aAnchor|, from
|
||||
* this APZC's local screen coordinates into global screen coordinates.
|
||||
* The anchor is necessary because with 3D tranforms, the location of the
|
||||
* vector can affect the result of the transform.
|
||||
* To respect the lock ordering, mMonitor must NOT be held when calling
|
||||
* this function (since this function acquires the tree lock).
|
||||
*/
|
||||
void ToGlobalScreenCoordinates(ScreenPoint* aVector,
|
||||
const ScreenPoint& aAnchor) const;
|
||||
|
||||
/**
|
||||
* Convert the vector |aVector|, rooted at the point |aAnchor|, from
|
||||
* global screen coordinates into this APZC's local screen coordinates .
|
||||
* The anchor is necessary because with 3D tranforms, the location of the
|
||||
* vector can affect the result of the transform.
|
||||
* To respect the lock ordering, mMonitor must NOT be held when calling
|
||||
* this function (since this function acquires the tree lock).
|
||||
*/
|
||||
void ToLocalScreenCoordinates(ScreenPoint* aVector,
|
||||
const ScreenPoint& aAnchor) const;
|
||||
|
||||
protected:
|
||||
enum PanZoomState {
|
||||
NOTHING, /* no touch-start events received */
|
||||
|
@ -462,9 +485,21 @@ protected:
|
|||
* Gets the displacement of the current touch since it began. That is, it is
|
||||
* the distance between the current position and the initial position of the
|
||||
* current touch (this only makes sense if a touch is currently happening and
|
||||
* OnTouchMove() is being invoked).
|
||||
* OnTouchMove() or the equivalent for pan gestures is being invoked).
|
||||
* Note: This function returns a distance in global screen coordinates,
|
||||
* not the local screen coordinates of this APZC.
|
||||
*/
|
||||
float PanDistance();
|
||||
float PanDistance() const;
|
||||
|
||||
/**
|
||||
* Gets the start point of the current touch.
|
||||
* Like PanDistance(), this only makes sense if a touch is currently
|
||||
* happening and OnTouchMove() or the equivalent for pan gestures is
|
||||
* being invoked.
|
||||
* Unlikely PanDistance(), this function returns a point in local screen
|
||||
* coordinates.
|
||||
*/
|
||||
ScreenPoint PanStart() const;
|
||||
|
||||
/**
|
||||
* Gets a vector of the velocities of each axis.
|
||||
|
@ -489,8 +524,9 @@ protected:
|
|||
|
||||
/**
|
||||
* Update the panning state and axis locks.
|
||||
* Note: |aDelta| is expected to be in global screen coordinates.
|
||||
*/
|
||||
void HandlePanningUpdate(float aDX, float aDY);
|
||||
void HandlePanningUpdate(const ScreenPoint& aDelta);
|
||||
|
||||
/**
|
||||
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
|
||||
|
|
|
@ -49,7 +49,9 @@ void Axis::UpdateWithTouchAtDevicePoint(ScreenCoord aPos, uint32_t aTimestampMs)
|
|||
|
||||
float newVelocity = mAxisLocked ? 0.0f : (float)(mPos - aPos) / (float)(aTimestampMs - mPosTimeMs);
|
||||
if (gfxPrefs::APZMaxVelocity() > 0.0f) {
|
||||
newVelocity = std::min(newVelocity, gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI());
|
||||
ScreenPoint maxVelocity = MakePoint(gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI());
|
||||
mAsyncPanZoomController->ToLocalScreenCoordinates(&maxVelocity, mAsyncPanZoomController->PanStart());
|
||||
newVelocity = std::min(newVelocity, maxVelocity.Length());
|
||||
}
|
||||
|
||||
mVelocity = newVelocity;
|
||||
|
@ -207,12 +209,16 @@ void Axis::ClearOverscroll() {
|
|||
mOverscroll = 0;
|
||||
}
|
||||
|
||||
float Axis::PanDistance() {
|
||||
return fabsf((mPos - mStartPos).value);
|
||||
ScreenCoord Axis::PanStart() const {
|
||||
return mStartPos;
|
||||
}
|
||||
|
||||
float Axis::PanDistance(ScreenCoord aPos) {
|
||||
return fabsf((aPos - mStartPos).value);
|
||||
ScreenCoord Axis::PanDistance() const {
|
||||
return fabs(mPos - mStartPos);
|
||||
}
|
||||
|
||||
ScreenCoord Axis::PanDistance(ScreenCoord aPos) const {
|
||||
return fabs(aPos - mStartPos);
|
||||
}
|
||||
|
||||
void Axis::EndTouch(uint32_t aTimestampMs) {
|
||||
|
@ -387,6 +393,11 @@ CSSCoord AxisX::GetRectOffset(const CSSRect& aRect) const
|
|||
return aRect.x;
|
||||
}
|
||||
|
||||
ScreenPoint AxisX::MakePoint(ScreenCoord aCoord) const
|
||||
{
|
||||
return ScreenPoint(aCoord, 0);
|
||||
}
|
||||
|
||||
AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController)
|
||||
: Axis(aAsyncPanZoomController)
|
||||
{
|
||||
|
@ -408,5 +419,10 @@ CSSCoord AxisY::GetRectOffset(const CSSRect& aRect) const
|
|||
return aRect.y;
|
||||
}
|
||||
|
||||
ScreenPoint AxisY::MakePoint(ScreenCoord aCoord) const
|
||||
{
|
||||
return ScreenPoint(0, aCoord);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,17 +119,22 @@ public:
|
|||
void ClearOverscroll();
|
||||
|
||||
/**
|
||||
* Gets the distance between the starting position of the touch supplied in
|
||||
* startTouch() and the current touch from the last
|
||||
* updateWithTouchAtDevicePoint().
|
||||
* Gets the starting position of the touch supplied in StartTouch().
|
||||
*/
|
||||
float PanDistance();
|
||||
ScreenCoord PanStart() const;
|
||||
|
||||
/**
|
||||
* Gets the distance between the starting position of the touch supplied in
|
||||
* startTouch() and the supplied position.
|
||||
* StartTouch() and the current touch from the last
|
||||
* UpdateWithTouchAtDevicePoint().
|
||||
*/
|
||||
float PanDistance(ScreenCoord aPos);
|
||||
ScreenCoord PanDistance() const;
|
||||
|
||||
/**
|
||||
* Gets the distance between the starting position of the touch supplied in
|
||||
* StartTouch() and the supplied position.
|
||||
*/
|
||||
ScreenCoord PanDistance(ScreenCoord aPos) const;
|
||||
|
||||
/**
|
||||
* Applies friction during a fling, or cancels the fling if the velocity is
|
||||
|
@ -217,6 +222,8 @@ public:
|
|||
virtual CSSCoord GetRectLength(const CSSRect& aRect) const = 0;
|
||||
virtual CSSCoord GetRectOffset(const CSSRect& aRect) const = 0;
|
||||
|
||||
virtual ScreenPoint MakePoint(ScreenCoord aCoord) const = 0;
|
||||
|
||||
protected:
|
||||
ScreenCoord mPos;
|
||||
uint32_t mPosTimeMs;
|
||||
|
@ -250,6 +257,7 @@ public:
|
|||
virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const;
|
||||
virtual CSSCoord GetRectLength(const CSSRect& aRect) const;
|
||||
virtual CSSCoord GetRectOffset(const CSSRect& aRect) const;
|
||||
virtual ScreenPoint MakePoint(ScreenCoord aCoord) const;
|
||||
};
|
||||
|
||||
class AxisY : public Axis {
|
||||
|
@ -258,6 +266,7 @@ public:
|
|||
virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const;
|
||||
virtual CSSCoord GetRectLength(const CSSRect& aRect) const;
|
||||
virtual CSSCoord GetRectOffset(const CSSRect& aRect) const;
|
||||
virtual ScreenPoint MakePoint(ScreenCoord aCoord) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -197,8 +197,10 @@ nsEventStatus GestureEventListener::HandleInputTouchMultiStart()
|
|||
|
||||
bool GestureEventListener::MoveDistanceIsLarge()
|
||||
{
|
||||
ScreenIntPoint delta = mLastTouchInput.mTouches[0].mScreenPoint - mTouchStartPosition;
|
||||
return (NS_hypot(delta.x, delta.y) > AsyncPanZoomController::GetTouchStartTolerance());
|
||||
const ScreenPoint start = mLastTouchInput.mTouches[0].mScreenPoint;
|
||||
ScreenPoint delta = start - mTouchStartPosition;
|
||||
mAsyncPanZoomController->ToGlobalScreenCoordinates(&delta, start);
|
||||
return (delta.Length() > AsyncPanZoomController::GetTouchStartTolerance());
|
||||
}
|
||||
|
||||
nsEventStatus GestureEventListener::HandleInputTouchMove()
|
||||
|
|
|
@ -252,7 +252,7 @@ private:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
MemoryPressureObserver(ClientLayerManager* aClientLayerManager)
|
||||
explicit MemoryPressureObserver(ClientLayerManager* aClientLayerManager)
|
||||
: mClientLayerManager(aClientLayerManager)
|
||||
{
|
||||
RegisterMemoryPressureEvent();
|
||||
|
|
|
@ -291,7 +291,8 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
|
|||
}
|
||||
|
||||
if (!texture && aFormat == SurfaceFormat::B8G8R8X8 &&
|
||||
aAllocator->IsSameProcess()) {
|
||||
aAllocator->IsSameProcess() &&
|
||||
aMoz2DBackend == gfx::BackendType::CAIRO) {
|
||||
texture = new DIBTextureClient(aFormat, aTextureFlags);
|
||||
}
|
||||
|
||||
|
|
|
@ -1505,7 +1505,8 @@ protected:
|
|||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint) {
|
||||
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(aPoint, nullptr);
|
||||
if (hit) {
|
||||
manager->GetInputTransforms(hit.get(), transformToApzc, transformToGecko);
|
||||
transformToApzc = manager->GetScreenToApzcTransform(hit.get());
|
||||
transformToGecko = manager->GetApzcToGeckoTransform(hit.get());
|
||||
}
|
||||
return hit.forget();
|
||||
}
|
||||
|
|
|
@ -4,4 +4,5 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g'
|
|||
[mochitest/test_bug513439.html]
|
||||
skip-if = e10s
|
||||
[mochitest/test_acceleration.html]
|
||||
[mochitest/test_overdraw.html]
|
||||
# Disable test until bug 1064136 is fixed
|
||||
# [mochitest/test_overdraw.html]
|
||||
|
|
|
@ -176,7 +176,7 @@ gfxUserFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeeds
|
|||
|
||||
class gfxOTSContext : public ots::OTSContext {
|
||||
public:
|
||||
gfxOTSContext(gfxUserFontEntry* aUserFontEntry)
|
||||
explicit gfxOTSContext(gfxUserFontEntry* aUserFontEntry)
|
||||
: mUserFontEntry(aUserFontEntry) {}
|
||||
|
||||
virtual ots::TableAction GetTableAction(uint32_t aTag) MOZ_OVERRIDE {
|
||||
|
|
|
@ -593,7 +593,6 @@ JavaScriptShared::Wrap(JSContext *cx, HandleObject aObj, InfallibleTArray<CpowEn
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JavaScriptShared::fixupAfterMovingGC()
|
||||
{
|
||||
objects_.sweep();
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче