import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1236786 - [WebGL2] pass getVertexAttrib in gl-object-get-calls.html, r=jgilbert (60a2c91a38)
- Bug 1233046 - Fix OES_texture_float on OSX. - r=jrmuizel (4bc0059f5f)
- Bug 1233557 - Allow RGB8 to be renderable again for web-compat. - r=jrmuizel (4c13bfd8e8)
- Bug 1233549. Disallow ES3 compressed texture formats. r=jgilbert (1073033161)
- Bug 1241702 - Allow unsized DEPTH_STENCIL for RBs in WebGL 2. - r=kamidphish (87d17d2cf9)
- Bug 1239126. Handle gl_InstanceID attribute with no location. r=jgilbert (4894997e98)
- Bug 1236782 - [WebGL2] pass getProgramParameter in gl-object-get-calls.html; r=jgilbert (2136fcce48)
- Bug 1232462. Only ask for a higher version of GLSL when using WebGL2. r=jgilbert (0317be4eb4)
- Bug 1242330 - "Four extensions were promoted to core in WebGL 2 and should no longer be available as extensions." r=jgilbert r=jmuizelaar (6df020b8d4)
- Bug 1233626 - Default MaxDrawingBuffers to 1 unless ext/webgl2. - r=jrmuizel (a7580d661c)
- Bug 1231657. Don't allow linking different versions shaders. r=jgilbert (e610f98066)
- Bug 1241777 - TexCompareFunc should be stored in ascending order. r=jgilbert (b6151a0076)
- Bug 1228885 - Implement WebGLTexture::MemoryUsage. - r=kamidphish (ea06815414)
- Bug 1239259 - Fix WebGL2 generateMipmap checking. r=jgilbert (39f587c421)
- Bug 1242347 - Allow unsized internal format when generate mipmap. r=jgilbert (b203a8898c)
- Bug 1232502. Use the correct internalFormat when calling CopyTexImage2D. r=jgilbert (eeaef3215e)
- Bug 1243663 - Max uniform and attribute location lengths in WebGL2 should be 1024. r=jgilbert (c4ec6de507)
- Bug 1239488 - Add int/uint to vertex attrib data type. r=jgilbert (11b4968025)
- Bug 1184242 - Remove aTabParent != sActiveTabParent warning from IMEStateManager::SetInputContextForChildProcess. r=masayuki (0fcda10e15)
- Bug 1178652 - Send NOTIFY_IME_OF_COMPOSITION_UPDATE to parent process correctly. r=masayuki (bce28e2c91)
- Bug 1107782 - Only accept certain mouse, gamepad events as user-active. r=smaug (00542c80b9)
- Bug 1247850 - Shrink NameTableKey in nsStaticCaseInsensitiveNameTable. r=froydnj,erahm. (ce3cb3edfb)
- Bug 1247359 - micro-optimize the common case of String{Begins,End}With; r=erahm (333e042b31)
- Bug 1239125. Add operator!=(char_type*) to nsTSubstring. r=froydnj (0cc047a9a1)
- Bug 1213862 - Align nsString whitespace handling with web specs; r=froydnj (db5b11ca52)
- Bug 1141884 - Trigger compositor smooth scrolling to snap points when APZ is enabled. r=mstange,kip (593af59f2a)
- Bug 1244582: Add back in a null check that was accidentally removed. r=smaug (76bff1b01f)
- Bug 1234176 - Introduce and use the WriteSysFile() helper function. r=dhylands (22a46fbe8b)
- missing bit of Bug 1198124 - Enable -Wshadow (f84535a7a2)
- Bug 1249171 - Simplify nsCOMArray::SizeOfExcludingThis(). r=erahm. (57efdce1c6)
- Bug 1156416 - Validate camera parameters supplied by the application. r=mikeh (f8b4b84ccf)
- Bug 1186808 - Replace nsBaseHashtable::EnumerateRead() calls in dom/camera/ with iterators. r=mikeh. (7b1db5f6a1)
- Bug 1158378 - Fix how a failed set configuration call would try to shutdown the camera after release. (9d5e323bca)
- Bug 1171374 - Permit software video codecs with the emulated camera. r=sotaro (c1ae26ea0d)
- Bug 1234458 P1 Allow the CacheChild to be "locked" into memory so it will delay destruction. r=ehsan a=ritu (9e46185779)
- Bug 1234458 P2 Lock the CacheChild actor while Cache DOM methods are running. r=ehsan a=ritu (038342a6e2)
- Bug 1244764 P1 Make Cache .add()/.addAll() fail if a Response.ok() is false. r=ehsan (ae26ca9ef1)
- Bug 1172562 - Clear QuotaManager storage when uninstalling an app. Test. r=bkelly (b07311a3b7)
- Bug 1172629 - Use the caches global property from an iframe loaded after setting the pref in order to make the tests pass with the pref disabled; r=bkelly a=RyanVM (e7c05d8b79)
- Bug 1244764 P2 Make dom/cache mochitests pass with new add()/addAll() behavior. r=ehsan (e1f667c1b4)
- Bug 1244764 P3 Make service worker tests pass with new Cache add()/addAll() behavior. r=ehsan (1518ae5225)
- Bug 1003860 - Simplify storage setup tasks in storage inspector tests. r=mratcliffe (249a8bdb2b)
- Bug 1003860 - Service worker cache for storage actor. r=mratcliffe (5c3d1ecd0c)
- Bug 1244764 P5 Fix devtools test to work with new Cache add()/addAll() behavior. r=ehsan (bf85405de8)
- Bug 1232901 - Use channel.asyncOpen2 within dom/browser-element/BrowserElementParent.js (r=sicking,aus) (2a228ed551)
- Bug 1180330 - http auth prompt shown when opening browser if prompt canceled/dismissed earlier. r=fabrice (ba3666f4bd)
- Bug 1234118 - Delete code for supporting 'do-command' and 'copypaste-docommand'. r=mtseng, r=smaug (b1b575d3c5)
- Bug 1238883 - [TV Browser] It shows "The page cannot be displayed" when user browse some webpages. r=roc (e6d7739dd6)
- Bug 1238440 - FileReader should throw an error when the blob changed size when reading, r=khuey (b006adba10)
- Bug 1230422 - FileReader should handle nested ReadAs*() calls. r=khuey (5a3ff84a31)
- Bug 1225202, part 3 - Create files in test_fileapi_slice.html using SpecialPowers.createFiles. r=baku (1137975548)
- Bug 1241171 - FormData should not force 'blob' as filename, r=smaug (748055f751)
- Bug 1246375 - Restore the previous spec version of FormData, r=smaug (3586af2b88)
- Bug 1237183 - Modify implementation of reading preference. r=seanlin (a132bc7246)
- Bug 801545 - Remove DocumentType.internalSubset, r=bz (ea30c9b5ee)
- Bug 1226440 - Expose a method to get a node's immediate dominator; r=bz,sfink (f77ae44037)
- Bug 825318 - Implement adoptDownload for mozDownloadManager, r=aus, r=sicking (e98cb05210)
- Bug 1237370 - Always log the reason for remote AppRep lookup failures. r=gcp (2c804e68fc)
- Bug 1167493 - Application Reputation: disable remote lookup of zip files on Mac/Linux, r=gcp (517459e064)
- Bug 1195519 - Use channel->ascynOpen2 toolkit/components/downloads/ApplicationReputation.cpp (r=sicking) (2856e5213a)
- Bug 1237856 - Add prefs to honor/ignore Application Reputation verdicts. r=gcp (54ee06264f)
- Bug 1243643 - Deprecate unsafe CPOW usage in contentAreaUtils' saveImage. r=jld (6ae790f1ef)
- Bug 1229224: Add an eslint plugin for importing all browser.js globals for browser-chrome tests. r=miker (9df52a7f3b)
- Bug 1245916: Add additional browser window scripts to eslint globals. r=felipe (92d316ca5e)
- Bug 1246244 - Allow non-CPOW documents to pass through saveImageURL properly. r=jaws,Margaret (c8d4ca241d)
- some missing bits after world fix (c0439eebb0)
- add some missing stuff (ddbd47dc03)
- bissing bit of 1229519 (4e255c3dae)
- Bug 1199662 - Crash ping environment block is broken when any string field contains a quotation mark. Unescape INI fields properly using the library that already exists for the purpose. r=ted (874a999edc)
- Bug 1216150 - Turn on the experimental Intl.DateTimeFormat.prototype.formatToParts in b2g certified apps. r=fabrice (40eeb1a4d4)
- Bug 1216150 - Mini-bustage fix for something I think I unintentionally qref'd into the final patch. r=bustage in a CLOSED TREE (36d9b21a67)
- Bug 1141311 - Add async mode support to GonkNativeWindow on Lollipop Gonk r=pchang (39d9d56326)
- Bug 1146671 - Ensure camera not already released when performing operations. r=dhylands (71b59caa1f)
- Bug 1248737. Improve documentation for WorkerRunnable and associated classes. r=khuey (4ff57790c5)
- Bug 1235629 - Remove dead code in WorkerFeature.h, r=smaug (75a51fcf03)
- Bug 1212333 - WorkerDebuggerManager should live on the main thread;r=khuey (11fdfbbae6)
- Bug 1226443 P3 Re-enable service worker update wpt tests. r=ehsan (605dac5f9e)
- Bug 1226443 P4 Cleanup ServiceWorkerScriptCache objects when initialization fails. r=ehsan (43de3429a2)
- Bug 1234127: Change |BluetoothAdapter.pairingReqs| as a nullable object; r=btian, r=mrbkap (45d2038f6a)
- Bug 1188487 - BrowserElement webidl changes for muting and setting volume. r=ehsan (21bea70a07)
- Bug 1238210 - Correct the Promise return types on two Clients methods; r=baku (fa41b25df0)
- Bug 1246784 - Expose Console to the WorkerDebuggerGlobalScope - part 2, r=khuey (0da9ce8ff6)
- Bug 1228702. Don't expose the 'location' property of Exception/DOMException on workers. r=bholley (0fe86ea586)
- Bug 1223825 - Change Directory.path to include the directory's name. r=baku (0cdae4c2f0)
- Bug 1238225 - Mark ExtendableMessageEvent.ports as SameObject; r=baku (45b9a9746f)
- Bug 1236933 - Return null from FetchEvent.clientId for non-subresource network requests; r=bkelly (4a9c4b40cb)
- Bug 1238213 - Make FetchEvent.request non-nullable; r=baku (751082c8ba)
- Bug 1193125 - Avoid corrupting image data in test_fetch_event.html. r=bkelly (9f6bff232f)
- Bug 1201664 - Avoid using Request's constructor when creating FetchEvent.request; r=bkelly (7a3401e345)
- Bug 1175944 - Packaged app's (app://) JS files are not loaded and do not trigger "onfetch" handler. r=jdm (62df139153)
- Bug 1233644 - use pattern matching when listening clear-origin-data. r=baku (ea2594f50e)
- Bug 1237363 - Part 1: Unregister all service workers registered in mochitests at the end of the test; r=jdm (5be97e5bb0)
- Bug 1237363 - Part 2: Fail mochitests which register a service worker without unregistering it; r=jdm (c4160ffd5f)
- Bug 1237363 - Part 3: Add a test for a mochitest finishing without unregistering its service worker; r=jdm (911d37291b)
- Bug 1174078 - Calling "fetch" inside Service Worker's "onfetch" handler in b2g causes "onfetch" again that leads to an infinite loop. Test. r=nsm (208451f346)
- Bug 1197379 - Remove support for intercepting app:// URIs using service workers; r=jdm (3cbdd725f1)
- Bug 1179399 - Part 1: Relax the ShouldIntercept checks when overriding JAR channel info; r=jdm (850bb2bdb8)
- Bug 1238213 follow-up: Mark the FetchEventInit dictionary argument to FetchEvent's constructor optional too; r=bzbarsky (356cbe6db7)
- Bug 1232732 - modify NS_WARNING in MOZ_WIN_MEM_TRY_CATCH; r=aklotz (e2be4d6919)
- Bug 1247658 - Expose a method to JS for find the shortest retaining paths of some nodes in a heap snapshot; r=bz r=jimb (2c82198808)
- Bug 1188115: Expose IDBCursorWithValue in workers. r=baku (e1c40aeb6e)
- Bug 1162680 - Notify Keyboard.jsm to send blur event when the message manager is closed first. r=timdream (53727ab300)
- Bug 1192986 Also mark Cache/CacheStorage as release interfaces on workers. r=ehsan a=bustage (25cf83c154)
- Bug 1159742. Get rid of the pref annotation from test_interfaces, since it basically corresponds to disabling the test. r=jst (c229e3f881)
- Bug 1203160 - Part 2: Fix the interfaces tests to allow SW interfaces for non-release Fennec; r=baku (072840db1f)
- Bug 1197700 - Correct mistakes in InputMethod.webidl. r=kanru, r=janjongboom, sr=smaug (4edb6f201f)
- Bug 1206970 - Stop expecting AnimationPlaybackEvent to be exposed on release branches, where it's disabled by pref, r=smaug (30ae2b13db)
- Bug 1177276 - Pref on canvas.captureStream by default. r=smaug,mt (0cfe0f72f2)
- Bug 1215147 - Enable VR API's on FF for Android by default. r=snorp, r=vlad, r=bz (5ff3725318)
- Bug 1218482 - Enable WebVR By Default,r=bz (f26111ed82)
- Bug 1159755. Stop forcing the media.eme.apiVisible preference to be true in our test harness. r=cpearce (09f7887917)
- Bug 1149312 - Obtain test coverage for the file-backed case of MediaRecorder. r=roc (bd2e7e40f0)
- Bug 1154559 - Remove flaky timeouts from manifest.js and register SimpleTest.registerCleanupFunction() to report unfinished tests. r=cpearce. (eb68db0fb2)
- Bug 1154564 - Add the ability to notify timeouts to MediaTestManager and remove flaky timeouts from test_playback.html. r=cpearce. (c89b4e58d9)
- Bug 1135170 - Fix up racey test_seek-1.html. rpending=mattwoodrow (b3a7d0dcd6)
- Bug 902686 - Change manifest.js to use SpecialPowers.pushPrefEnv. r=edwin (636b0edc1a)
- Bug 1183502 - give androidVersion a correct value in manifest.js. r=sotaro. (933e9ea712)
- Bug 1235588 - add null check to SimpleTest. r=bechen. (958ede68de)
- misspatch (c8922447ff)
- Bug 1151740 - pass the callback object as-is to SpecialPowers.exactGC(). r=edwin (99ca873bce)
- Bug 1197682 - InputMethodManager#setSupportsSwitchingTypes, r=janjongboom, sr=smaug (e7eb54e491)
- Bug 1201407 - Add input-manage-only events for InputMethod API. r=janjongboom, sr=smaug (776d064bd1)
- Bug 1234459 - Expose full text in the input box to InputMethod API, r=masayuki, sr=smaug (4fa0554356)
- Bug 1198163 - Workaround Mochitest app and assign frame proper permissions, r=kanru (c3bcf8ecc1)
- Bug 990250 - Fold nsIStyleSheet into CSSStyleSheet. r=dbaron (23579cb300)
This commit is contained in:
2024-01-16 11:25:53 +08:00
parent 5a3b3d60eb
commit 7f8ba9c1d7
328 changed files with 7184 additions and 4514 deletions
+17 -25
View File
@@ -414,14 +414,12 @@ nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
nsCOMPtr<nsIPresShell> shell = document->GetShell();
if (shell) {
// Reload only the chrome URL agent style sheets.
nsCOMArray<nsIStyleSheet> agentSheets;
nsTArray<RefPtr<CSSStyleSheet>> agentSheets;
rv = shell->GetAgentStyleSheets(agentSheets);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMArray<nsIStyleSheet> newAgentSheets;
for (int32_t l = 0; l < agentSheets.Count(); ++l) {
nsIStyleSheet *sheet = agentSheets[l];
nsTArray<RefPtr<CSSStyleSheet>> newAgentSheets;
for (CSSStyleSheet* sheet : agentSheets) {
nsIURI* uri = sheet->GetSheetURI();
if (IsChromeURI(uri)) {
@@ -431,12 +429,12 @@ nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
getter_AddRefs(newSheet));
if (NS_FAILED(rv)) return rv;
if (newSheet) {
rv = newAgentSheets.AppendObject(newSheet) ? NS_OK : NS_ERROR_FAILURE;
rv = newAgentSheets.AppendElement(newSheet) ? NS_OK : NS_ERROR_FAILURE;
if (NS_FAILED(rv)) return rv;
}
}
else { // Just use the same sheet.
rv = newAgentSheets.AppendObject(sheet) ? NS_OK : NS_ERROR_FAILURE;
rv = newAgentSheets.AppendElement(sheet) ? NS_OK : NS_ERROR_FAILURE;
if (NS_FAILED(rv)) return rv;
}
}
@@ -445,27 +443,22 @@ nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
NS_ENSURE_SUCCESS(rv, rv);
}
// Build an array of nsIURIs of style sheets we need to load.
nsCOMArray<nsIStyleSheet> oldSheets;
nsCOMArray<nsIStyleSheet> newSheets;
int32_t count = document->GetNumberOfStyleSheets();
// Iterate over the style sheets.
int32_t i;
for (i = 0; i < count; i++) {
// Get the style sheet
nsIStyleSheet *styleSheet = document->GetStyleSheetAt(i);
// Build an array of style sheets we need to reload.
nsTArray<RefPtr<CSSStyleSheet>> oldSheets(count);
nsTArray<RefPtr<CSSStyleSheet>> newSheets(count);
if (!oldSheets.AppendObject(styleSheet)) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Iterate over the style sheets.
for (int32_t i = 0; i < count; i++) {
// Get the style sheet
CSSStyleSheet* styleSheet = document->GetStyleSheetAt(i);
oldSheets.AppendElement(styleSheet);
}
// Iterate over our old sheets and kick off a sync load of the new
// sheet if and only if it's a chrome URL.
for (i = 0; i < count; i++) {
RefPtr<CSSStyleSheet> sheet = do_QueryObject(oldSheets[i]);
for (CSSStyleSheet* sheet : oldSheets) {
nsIURI* uri = sheet ? sheet->GetOriginalURI() : nullptr;
if (uri && IsChromeURI(uri)) {
@@ -475,11 +468,10 @@ nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow)
// only works by sheer dumb luck.
document->LoadChromeSheetSync(uri, false, getter_AddRefs(newSheet));
// Even if it's null, we put in in there.
newSheets.AppendObject(newSheet);
}
else {
newSheets.AppendElement(newSheet);
} else {
// Just use the same sheet.
newSheets.AppendObject(sheet);
newSheets.AppendElement(sheet);
}
}
+17 -2
View File
@@ -13,6 +13,7 @@
#include "nsIStreamTransportService.h"
#include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/dom/File.h"
@@ -315,11 +316,17 @@ FileReader::DoReadData(uint64_t aCount)
NS_ASSERTION(bytesRead == aCount, "failed to read data");
}
else {
CheckedInt<uint64_t> size = mDataLen;
size += aCount;
//Update memory buffer to reflect the contents of the file
if (mDataLen + aCount > UINT32_MAX) {
// PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
if (!size.isValid() ||
// PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
size.value() > UINT32_MAX ||
size.value() > mTotal) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (mDataFormat != FILE_AS_ARRAYBUFFER) {
mFileData = (char *) moz_realloc(mFileData, mDataLen + aCount);
NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
@@ -347,6 +354,14 @@ FileReader::ReadFileContent(Blob& aBlob,
Abort(error);
error.SuppressException();
if (mReadyState == LOADING) {
// A nested ReadAsSomething() as been called during one of the events
// dispatched by Abort(). We have to terminate this operation in order to
// continue the nested one.
aRv.Throw(NS_ERROR_ABORT);
return;
}
mError = nullptr;
SetDOMStringToNull(mResult);
mTransferred = 0;
+41 -30
View File
@@ -23,16 +23,17 @@ FormData::FormData(nsISupports* aOwner)
namespace {
already_AddRefed<Blob>
GetBlobForFormDataStorage(Blob& aBlob, const Optional<nsAString>& aFilename,
ErrorResult& aRv)
already_AddRefed<File>
GetOrCreateFileCalledBlob(Blob& aBlob, ErrorResult& aRv)
{
if (!aFilename.WasPassed()) {
RefPtr<Blob> blob = &aBlob;
return blob.forget();
// If this is file, we can just use it
RefPtr<File> file = aBlob.ToFile();
if (file) {
return file.forget();
}
RefPtr<File> file = aBlob.ToFile(aFilename.Value(), aRv);
// Forcing 'blob' as filename
file = aBlob.ToFile(NS_LITERAL_STRING("blob"), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@@ -40,6 +41,23 @@ GetBlobForFormDataStorage(Blob& aBlob, const Optional<nsAString>& aFilename,
return file.forget();
}
already_AddRefed<File>
GetBlobForFormDataStorage(Blob& aBlob, const Optional<nsAString>& aFilename,
ErrorResult& aRv)
{
// Forcing a filename
if (aFilename.WasPassed()) {
RefPtr<File> file = aBlob.ToFile(aFilename.Value(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return file.forget();
}
return GetOrCreateFileCalledBlob(aBlob, aRv);
}
} // namespace
// -------------------------------------------------------------------------
@@ -102,12 +120,12 @@ FormData::Append(const nsAString& aName, Blob& aBlob,
const Optional<nsAString>& aFilename,
ErrorResult& aRv)
{
RefPtr<Blob> blob = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
RefPtr<File> file = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
AddNameBlobPair(aName, blob);
AddNameBlobPair(aName, file);
}
void
@@ -165,8 +183,14 @@ FormData::AddNameBlobPair(const nsAString& aName, Blob* aBlob)
{
MOZ_ASSERT(aBlob);
ErrorResult rv;
RefPtr<File> file = GetOrCreateFileCalledBlob(*aBlob, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
FormDataTuple* data = mFormData.AppendElement();
SetNameBlobPair(data, aName, aBlob);
SetNameFilePair(data, aName, file);
return NS_OK;
}
@@ -199,12 +223,12 @@ FormData::Set(const nsAString& aName, Blob& aBlob,
{
FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
if (tuple) {
RefPtr<Blob> blob = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
RefPtr<File> file = GetBlobForFormDataStorage(aBlob, aFilename, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
SetNameBlobPair(tuple, aName, blob);
SetNameFilePair(tuple, aName, file);
} else {
Append(aName, aBlob, aFilename, aRv);
}
@@ -253,15 +277,15 @@ FormData::SetNameValuePair(FormDataTuple* aData,
}
void
FormData::SetNameBlobPair(FormDataTuple* aData,
FormData::SetNameFilePair(FormDataTuple* aData,
const nsAString& aName,
Blob* aBlob)
File* aFile)
{
MOZ_ASSERT(aData);
MOZ_ASSERT(aBlob);
MOZ_ASSERT(aFile);
aData->name = aName;
aData->value.SetAsBlob() = aBlob;
aData->value.SetAsBlob() = aFile;
}
// -------------------------------------------------------------------------
@@ -343,20 +367,7 @@ FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
if (mFormData[i].value.IsBlob()) {
RefPtr<File> file = mFormData[i].value.GetAsBlob()->ToFile();
if (file) {
fs.AddNameBlobPair(mFormData[i].name, file);
continue;
}
ErrorResult rv;
file =
mFormData[i].value.GetAsBlob()->ToFile(NS_LITERAL_STRING("blob"), rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
fs.AddNameBlobPair(mFormData[i].name, file);
fs.AddNameBlobPair(mFormData[i].name, mFormData[i].value.GetAsBlob());
} else if (mFormData[i].value.IsUSVString()) {
fs.AddNameValuePair(mFormData[i].name,
mFormData[i].value.GetAsUSVString());
+2 -2
View File
@@ -47,9 +47,9 @@ private:
const nsAString& aName,
const nsAString& aValue);
void SetNameBlobPair(FormDataTuple* aData,
void SetNameFilePair(FormDataTuple* aData,
const nsAString& aName,
Blob* aBlob);
File* aFile);
public:
explicit FormData(nsISupports* aOwner = nullptr);
-11
View File
@@ -2121,17 +2121,6 @@ public:
return true;
}
bool Suspend(JSContext* aCx) override
{
{
MutexAutoLock lock(mWebSocketImpl->mMutex);
mWebSocketImpl->mWorkerShuttingDown = true;
}
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
return true;
}
private:
WebSocketImpl* mWebSocketImpl;
};
+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
var a = new FileReader();
function f() {
a.removeEventListener("loadend", f);
g();
}
function g() {
a.readAsBinaryString(new Blob());
}
a.addEventListener("loadend", f);
try {
g();
g();
} catch(e) {}
</script>
</body>
</html>
+1
View File
@@ -204,3 +204,4 @@ load structured_clone_container_throws.html
HTTP(..) load xhr_abortinprogress.html
load xhr_empty_datauri.html
load xhr_html_nullresponse.html
load 1230422.html
+1 -2
View File
@@ -99,7 +99,6 @@
#include "mozilla/Preferences.h"
#include "nsIContentIterator.h"
#include "nsIDOMStyleSheet.h"
#include "nsIStyleSheet.h"
#include "nsIStyleSheetService.h"
#include "nsContentPermissionHelper.h"
#include "nsCSSPseudoElements.h" // for CSSPseudoElementType
@@ -3381,7 +3380,7 @@ nsDOMWindowUtils::AddSheet(nsIDOMStyleSheet *aSheet, uint32_t aSheetType)
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
if (sheet->GetOwningDocument()) {
return NS_ERROR_INVALID_ARG;
+89 -137
View File
@@ -716,15 +716,6 @@ nsDOMStyleSheetList::Length()
// been added or removed.
if (-1 == mLength) {
mLength = mDocument->GetNumberOfStyleSheets();
#ifdef DEBUG
int32_t i;
for (i = 0; i < mLength; i++) {
nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i);
nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(sheet));
NS_ASSERTION(domss, "All \"normal\" sheets implement nsIDOMStyleSheet");
}
#endif
}
return mLength;
}
@@ -738,7 +729,7 @@ nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
}
aFound = true;
nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(aIndex);
CSSStyleSheet* sheet = mDocument->GetStyleSheetAt(aIndex);
NS_ASSERTION(sheet, "Must have a sheet");
return static_cast<CSSStyleSheet*>(sheet);
@@ -751,26 +742,20 @@ nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
}
void
nsDOMStyleSheetList::StyleSheetAdded(nsIStyleSheet* aStyleSheet,
nsDOMStyleSheetList::StyleSheetAdded(CSSStyleSheet* aStyleSheet,
bool aDocumentSheet)
{
if (aDocumentSheet && -1 != mLength) {
nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
if (domss) {
mLength++;
}
mLength++;
}
}
void
nsDOMStyleSheetList::StyleSheetRemoved(nsIStyleSheet* aStyleSheet,
nsDOMStyleSheetList::StyleSheetRemoved(CSSStyleSheet* aStyleSheet,
bool aDocumentSheet)
{
if (aDocumentSheet && -1 != mLength) {
nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
if (domss) {
mLength--;
}
mLength--;
}
}
@@ -1333,7 +1318,7 @@ nsDOMStyleSheetSetList::EnsureFresh()
int32_t count = mDocument->GetNumberOfStyleSheets();
nsAutoString title;
for (int32_t index = 0; index < count; index++) {
nsIStyleSheet* sheet = mDocument->GetStyleSheetAt(index);
CSSStyleSheet* sheet = mDocument->GetStyleSheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
sheet->GetTitle(title);
if (!title.IsEmpty() && !mNames.Contains(title) && !Add(title)) {
@@ -1607,9 +1592,7 @@ nsDocument::~nsDocument()
nsAutoScriptBlocker scriptBlocker;
int32_t indx; // must be signed
uint32_t count = mChildren.ChildCount();
for (indx = int32_t(count) - 1; indx >= 0; --indx) {
for (uint32_t indx = mChildren.ChildCount(); indx-- != 0; ) {
mChildren.ChildAt(indx)->UnbindFromTree();
mChildren.RemoveChildAt(indx);
}
@@ -1617,9 +1600,8 @@ nsDocument::~nsDocument()
mCachedRootElement = nullptr;
// Let the stylesheets know we're going away
indx = mStyleSheets.Count();
while (--indx >= 0) {
mStyleSheets[indx]->SetOwningDocument(nullptr);
for (CSSStyleSheet* sheet : mStyleSheets) {
sheet->SetOwningDocument(nullptr);
}
if (mAttrStyleSheet) {
mAttrStyleSheet->SetOwningDocument(nullptr);
@@ -2297,9 +2279,7 @@ void
nsDocument::RemoveDocStyleSheetsFromStyleSets()
{
// The stylesheets should forget us
int32_t indx = mStyleSheets.Count();
while (--indx >= 0) {
nsIStyleSheet* sheet = mStyleSheets[indx];
for (CSSStyleSheet* sheet : Reversed(mStyleSheets)) {
sheet->SetOwningDocument(nullptr);
if (sheet->IsApplicable()) {
@@ -2313,12 +2293,12 @@ nsDocument::RemoveDocStyleSheetsFromStyleSets()
}
void
nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray<nsIStyleSheet>& aSheets, SheetType aType)
nsDocument::RemoveStyleSheetsFromStyleSets(
nsTArray<RefPtr<CSSStyleSheet>>& aSheets,
SheetType aType)
{
// The stylesheets should forget us
int32_t indx = aSheets.Count();
while (--indx >= 0) {
nsIStyleSheet* sheet = aSheets[indx];
for (CSSStyleSheet* sheet : Reversed(aSheets)) {
sheet->SetOwningDocument(nullptr);
if (sheet->IsApplicable()) {
@@ -2327,10 +2307,8 @@ nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray<nsIStyleSheet>& aSheets, S
shell->StyleSet()->RemoveStyleSheet(aType, sheet);
}
}
// XXX Tell observers?
}
}
void
@@ -2385,21 +2363,13 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
}
}
static bool
AppendAuthorSheet(nsIStyleSheet *aSheet, void *aData)
{
nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
styleSet->AppendStyleSheet(SheetType::Doc, aSheet);
return true;
}
static void
AppendSheetsToStyleSet(nsStyleSet* aStyleSet,
const nsCOMArray<nsIStyleSheet>& aSheets,
const nsTArray<RefPtr<CSSStyleSheet>>& aSheets,
SheetType aType)
{
for (int32_t i = aSheets.Count() - 1; i >= 0; --i) {
aStyleSet->AppendStyleSheet(aType, aSheets[i]);
for (CSSStyleSheet* sheet : Reversed(aSheets)) {
aStyleSet->AppendStyleSheet(aType, sheet);
}
}
@@ -2411,9 +2381,7 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
NS_PRECONDITION(aStyleSet->SheetCount(SheetType::Doc) == 0,
"Style set already has document sheets?");
int32_t i;
for (i = mStyleSheets.Count() - 1; i >= 0; --i) {
nsIStyleSheet* sheet = mStyleSheets[i];
for (CSSStyleSheet* sheet : Reversed(mStyleSheets)) {
if (sheet->IsApplicable()) {
aStyleSet->AddDocStyleSheet(sheet, this);
}
@@ -2421,13 +2389,13 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
if (sheetService) {
sheetService->AuthorStyleSheets()->EnumerateForwards(AppendAuthorSheet,
aStyleSet);
for (CSSStyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
}
}
// Iterate backwards to maintain order
for (i = mOnDemandBuiltInUASheets.Count() - 1; i >= 0; --i) {
nsIStyleSheet* sheet = mOnDemandBuiltInUASheets[i];
for (CSSStyleSheet* sheet : Reversed(mOnDemandBuiltInUASheets)) {
if (sheet->IsApplicable()) {
aStyleSet->PrependStyleSheet(SheetType::Agent, sheet);
}
@@ -4082,8 +4050,7 @@ nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify)
void
nsDocument::EnsureOnDemandBuiltInUASheet(CSSStyleSheet* aSheet)
{
// Contains() takes nsISupport*, so annoyingly we have to cast here
if (mOnDemandBuiltInUASheets.Contains(static_cast<nsIStyleSheet*>(aSheet))) {
if (mOnDemandBuiltInUASheets.Contains(aSheet)) {
return;
}
BeginUpdate(UPDATE_STYLE);
@@ -4094,8 +4061,7 @@ nsDocument::EnsureOnDemandBuiltInUASheet(CSSStyleSheet* aSheet)
void
nsDocument::AddOnDemandBuiltInUASheet(CSSStyleSheet* aSheet)
{
// Contains() takes nsISupport*, so annoyingly we have to cast here
MOZ_ASSERT(!mOnDemandBuiltInUASheets.Contains(static_cast<nsIStyleSheet*>(aSheet)));
MOZ_ASSERT(!mOnDemandBuiltInUASheets.Contains(aSheet));
// Prepend here so that we store the sheets in mOnDemandBuiltInUASheets in
// the same order that they should end up in the style set.
@@ -4119,24 +4085,23 @@ nsDocument::AddOnDemandBuiltInUASheet(CSSStyleSheet* aSheet)
int32_t
nsDocument::GetNumberOfStyleSheets() const
{
return mStyleSheets.Count();
return mStyleSheets.Length();
}
nsIStyleSheet*
CSSStyleSheet*
nsDocument::GetStyleSheetAt(int32_t aIndex) const
{
NS_ENSURE_TRUE(0 <= aIndex && aIndex < mStyleSheets.Count(), nullptr);
return mStyleSheets[aIndex];
return mStyleSheets.SafeElementAt(aIndex, nullptr);
}
int32_t
nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const
nsDocument::GetIndexOfStyleSheet(CSSStyleSheet* aSheet) const
{
return mStyleSheets.IndexOf(aSheet);
}
void
nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet)
nsDocument::AddStyleSheetToStyleSets(CSSStyleSheet* aSheet)
{
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
@@ -4146,15 +4111,10 @@ nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet)
#define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName) \
do { \
RefPtr<CSSStyleSheet> cssSheet = do_QueryObject(aSheet); \
if (!cssSheet) { \
return; \
} \
\
className##Init init; \
init.mBubbles = true; \
init.mCancelable = true; \
init.mStylesheet = cssSheet; \
init.mStylesheet = aSheet; \
init.memberName = argName; \
\
RefPtr<className> event = \
@@ -4168,7 +4128,7 @@ nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet)
} while (0);
void
nsDocument::NotifyStyleSheetAdded(nsIStyleSheet* aSheet, bool aDocumentSheet)
nsDocument::NotifyStyleSheetAdded(CSSStyleSheet* aSheet, bool aDocumentSheet)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (aSheet, aDocumentSheet));
@@ -4181,7 +4141,7 @@ nsDocument::NotifyStyleSheetAdded(nsIStyleSheet* aSheet, bool aDocumentSheet)
}
void
nsDocument::NotifyStyleSheetRemoved(nsIStyleSheet* aSheet, bool aDocumentSheet)
nsDocument::NotifyStyleSheetRemoved(CSSStyleSheet* aSheet, bool aDocumentSheet)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (aSheet, aDocumentSheet));
@@ -4194,10 +4154,10 @@ nsDocument::NotifyStyleSheetRemoved(nsIStyleSheet* aSheet, bool aDocumentSheet)
}
void
nsDocument::AddStyleSheet(nsIStyleSheet* aSheet)
nsDocument::AddStyleSheet(CSSStyleSheet* aSheet)
{
NS_PRECONDITION(aSheet, "null arg");
mStyleSheets.AppendObject(aSheet);
mStyleSheets.AppendElement(aSheet);
aSheet->SetOwningDocument(this);
if (aSheet->IsApplicable()) {
@@ -4208,7 +4168,7 @@ nsDocument::AddStyleSheet(nsIStyleSheet* aSheet)
}
void
nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet)
nsDocument::RemoveStyleSheetFromStyleSets(CSSStyleSheet* aSheet)
{
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
@@ -4217,12 +4177,12 @@ nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet)
}
void
nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
nsDocument::RemoveStyleSheet(CSSStyleSheet* aSheet)
{
NS_PRECONDITION(aSheet, "null arg");
nsCOMPtr<nsIStyleSheet> sheet = aSheet; // hold ref so it won't die too soon
RefPtr<CSSStyleSheet> sheet = aSheet; // hold ref so it won't die too soon
if (!mStyleSheets.RemoveObject(aSheet)) {
if (!mStyleSheets.RemoveElement(aSheet)) {
NS_ASSERTION(mInUnlinkOrDeletion, "stylesheet not found");
return;
}
@@ -4239,17 +4199,17 @@ nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
}
void
nsDocument::UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
nsCOMArray<nsIStyleSheet>& aNewSheets)
nsDocument::UpdateStyleSheets(nsTArray<RefPtr<CSSStyleSheet>>& aOldSheets,
nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
{
BeginUpdate(UPDATE_STYLE);
// XXX Need to set the sheet on the ownernode, if any
NS_PRECONDITION(aOldSheets.Count() == aNewSheets.Count(),
NS_PRECONDITION(aOldSheets.Length() == aNewSheets.Length(),
"The lists must be the same length!");
int32_t count = aOldSheets.Count();
int32_t count = aOldSheets.Length();
nsCOMPtr<nsIStyleSheet> oldSheet;
RefPtr<CSSStyleSheet> oldSheet;
int32_t i;
for (i = 0; i < count; ++i) {
oldSheet = aOldSheets[i];
@@ -4260,9 +4220,9 @@ nsDocument::UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
RemoveStyleSheet(oldSheet); // This does the right notifications
// Now put the new one in its place. If it's null, just ignore it.
nsIStyleSheet* newSheet = aNewSheets[i];
CSSStyleSheet* newSheet = aNewSheets[i];
if (newSheet) {
mStyleSheets.InsertObjectAt(newSheet, oldIndex);
mStyleSheets.InsertElementAt(oldIndex, newSheet);
newSheet->SetOwningDocument(this);
if (newSheet->IsApplicable()) {
AddStyleSheetToStyleSets(newSheet);
@@ -4276,10 +4236,11 @@ nsDocument::UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
}
void
nsDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, int32_t aIndex)
nsDocument::InsertStyleSheetAt(CSSStyleSheet* aSheet, int32_t aIndex)
{
NS_PRECONDITION(aSheet, "null ptr");
mStyleSheets.InsertObjectAt(aSheet, aIndex);
mStyleSheets.InsertElementAt(aIndex, aSheet);
aSheet->SetOwningDocument(this);
@@ -4292,13 +4253,13 @@ nsDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, int32_t aIndex)
void
nsDocument::SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
nsDocument::SetStyleSheetApplicableState(CSSStyleSheet* aSheet,
bool aApplicable)
{
NS_PRECONDITION(aSheet, "null arg");
// If we're actually in the document style sheet list
if (-1 != mStyleSheets.IndexOf(aSheet)) {
if (mStyleSheets.IndexOf(aSheet) != mStyleSheets.NoIndex) {
if (aApplicable) {
AddStyleSheetToStyleSets(aSheet);
} else {
@@ -4358,9 +4319,9 @@ ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType)
}
static int32_t
FindSheet(const nsCOMArray<nsIStyleSheet>& aSheets, nsIURI* aSheetURI)
FindSheet(const nsTArray<RefPtr<CSSStyleSheet>>& aSheets, nsIURI* aSheetURI)
{
for (int32_t i = aSheets.Count() - 1; i >= 0; i-- ) {
for (int32_t i = aSheets.Length() - 1; i >= 0; i-- ) {
bool bEqual;
nsIURI* uri = aSheets[i]->GetSheetURI();
@@ -4414,7 +4375,7 @@ nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType,
}
nsresult
nsDocument::AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aSheet)
nsDocument::AddAdditionalStyleSheet(additionalSheetType aType, CSSStyleSheet* aSheet)
{
if (mAdditionalSheets[aType].Contains(aSheet))
return NS_ERROR_INVALID_ARG;
@@ -4422,7 +4383,7 @@ nsDocument::AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aS
if (!aSheet->IsApplicable())
return NS_ERROR_INVALID_ARG;
mAdditionalSheets[aType].AppendObject(aSheet);
mAdditionalSheets[aType].AppendElement(aSheet);
BeginUpdate(UPDATE_STYLE);
nsCOMPtr<nsIPresShell> shell = GetShell();
@@ -4443,12 +4404,12 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet
{
MOZ_ASSERT(aSheetURI);
nsCOMArray<nsIStyleSheet>& sheets = mAdditionalSheets[aType];
nsTArray<RefPtr<CSSStyleSheet>>& sheets = mAdditionalSheets[aType];
int32_t i = FindSheet(mAdditionalSheets[aType], aSheetURI);
if (i >= 0) {
nsCOMPtr<nsIStyleSheet> sheetRef = sheets[i];
sheets.RemoveObjectAt(i);
RefPtr<CSSStyleSheet> sheetRef = sheets[i];
sheets.RemoveElementAt(i);
BeginUpdate(UPDATE_STYLE);
if (!mIsGoingAway) {
@@ -4469,10 +4430,10 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet
}
}
nsIStyleSheet*
CSSStyleSheet*
nsDocument::FirstAdditionalAuthorSheet()
{
return mAdditionalSheets[eAuthorSheet].SafeObjectAt(0);
return mAdditionalSheets[eAuthorSheet].SafeElementAt(0, nullptr);
}
nsIGlobalObject*
@@ -5212,7 +5173,7 @@ nsDocument::DocumentStatesChanged(EventStates aStateMask)
}
void
nsDocument::StyleRuleChanged(nsIStyleSheet* aSheet,
nsDocument::StyleRuleChanged(CSSStyleSheet* aSheet,
css::Rule* aStyleRule)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged, (aSheet));
@@ -5226,7 +5187,7 @@ nsDocument::StyleRuleChanged(nsIStyleSheet* aSheet,
}
void
nsDocument::StyleRuleAdded(nsIStyleSheet* aSheet,
nsDocument::StyleRuleAdded(CSSStyleSheet* aSheet,
css::Rule* aStyleRule)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded, (aSheet));
@@ -5241,7 +5202,7 @@ nsDocument::StyleRuleAdded(nsIStyleSheet* aSheet,
}
void
nsDocument::StyleRuleRemoved(nsIStyleSheet* aSheet,
nsDocument::StyleRuleRemoved(CSSStyleSheet* aSheet,
css::Rule* aStyleRule)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved, (aSheet));
@@ -6482,13 +6443,11 @@ nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
int32_t count = GetNumberOfStyleSheets();
nsAutoString title;
for (int32_t index = 0; index < count; index++) {
nsIStyleSheet* sheet = GetStyleSheetAt(index);
CSSStyleSheet* sheet = GetStyleSheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
nsCOMPtr<nsIDOMStyleSheet> domSheet = do_QueryInterface(sheet);
NS_ASSERTION(domSheet, "Sheet must QI to nsIDOMStyleSheet");
bool disabled;
domSheet->GetDisabled(&disabled);
sheet->GetDisabled(&disabled);
if (disabled) {
// Disabled sheets don't affect the currently selected set
continue;
@@ -6598,7 +6557,7 @@ nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
int32_t count = GetNumberOfStyleSheets();
nsAutoString title;
for (int32_t index = 0; index < count; index++) {
nsIStyleSheet* sheet = GetStyleSheetAt(index);
CSSStyleSheet* sheet = GetStyleSheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
sheet->GetTitle(title);
if (!title.IsEmpty()) {
@@ -10205,7 +10164,7 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
int32_t sheetsCount = GetNumberOfStyleSheets();
for (int32_t i = 0; i < sheetsCount; ++i) {
RefPtr<CSSStyleSheet> sheet = do_QueryObject(GetStyleSheetAt(i));
RefPtr<CSSStyleSheet> sheet = GetStyleSheetAt(i);
if (sheet) {
if (sheet->IsApplicable()) {
RefPtr<CSSStyleSheet> clonedSheet =
@@ -10218,11 +10177,8 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
}
}
sheetsCount = thisAsDoc->mOnDemandBuiltInUASheets.Count();
// Iterate backwards to maintain order
for (int32_t i = sheetsCount - 1; i >= 0; --i) {
RefPtr<CSSStyleSheet> sheet =
do_QueryObject(thisAsDoc->mOnDemandBuiltInUASheets[i]);
for (CSSStyleSheet* sheet : Reversed(thisAsDoc->mOnDemandBuiltInUASheets)) {
if (sheet) {
if (sheet->IsApplicable()) {
RefPtr<CSSStyleSheet> clonedSheet =
@@ -12360,7 +12316,7 @@ nsDocument::OnAppThemeChanged()
}
for (int32_t i = 0; i < GetNumberOfStyleSheets(); i++) {
RefPtr<CSSStyleSheet> sheet = do_QueryObject(GetStyleSheetAt(i));
RefPtr<CSSStyleSheet> sheet = GetStyleSheetAt(i);
if (!sheet) {
continue;
}
@@ -12727,15 +12683,19 @@ nsIDocument::DocAddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
}
static size_t
SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet* aStyleSheet,
MallocSizeOf aMallocSizeOf,
void* aData)
SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<CSSStyleSheet>>& aSheets,
MallocSizeOf aMallocSizeOf)
{
if (!aStyleSheet->GetOwningDocument()) {
// Avoid over-reporting shared sheets.
return 0;
size_t n = 0;
n += aSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (CSSStyleSheet* sheet : aSheets) {
if (!sheet->GetOwningDocument()) {
// Avoid over-reporting shared sheets.
continue;
}
n += sheet->SizeOfIncludingThis(aMallocSizeOf);
}
return aStyleSheet->SizeOfIncludingThis(aMallocSizeOf);
return n;
}
size_t
@@ -12786,26 +12746,18 @@ nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
}
aWindowSizes->mStyleSheetsSize +=
mStyleSheets.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
aWindowSizes->mMallocSizeOf);
SizeOfOwnedSheetArrayExcludingThis(mStyleSheets,
aWindowSizes->mMallocSizeOf);
// Note that we do not own the sheets pointed to by mOnDemandBuiltInUASheets
// (the nsLayoutStyleSheetCache singleton does) so pass nullptr as the
// aSizeOfElementIncludingThis callback argument.
// (the nsLayoutStyleSheetCache singleton does).
aWindowSizes->mStyleSheetsSize +=
mOnDemandBuiltInUASheets.SizeOfExcludingThis(nullptr,
aWindowSizes->mMallocSizeOf);
aWindowSizes->mStyleSheetsSize +=
mAdditionalSheets[eAgentSheet].
SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
aWindowSizes->mMallocSizeOf);
aWindowSizes->mStyleSheetsSize +=
mAdditionalSheets[eUserSheet].
SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
aWindowSizes->mMallocSizeOf);
aWindowSizes->mStyleSheetsSize +=
mAdditionalSheets[eAuthorSheet].
SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
aWindowSizes->mMallocSizeOf);
mOnDemandBuiltInUASheets.ShallowSizeOfExcludingThis(
aWindowSizes->mMallocSizeOf);
for (auto& sheetArray : mAdditionalSheets) {
aWindowSizes->mStyleSheetsSize +=
SizeOfOwnedSheetArrayExcludingThis(sheetArray,
aWindowSizes->mMallocSizeOf);
}
// Lumping in the loader with the style-sheets size is not ideal,
// but most of the things in there are in fact stylesheets, so it
// doesn't seem worthwhile to separate it out.
+30 -24
View File
@@ -775,24 +775,29 @@ public:
* These are ordered, highest priority last
*/
virtual int32_t GetNumberOfStyleSheets() const override;
virtual nsIStyleSheet* GetStyleSheetAt(int32_t aIndex) const override;
virtual int32_t GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const override;
virtual void AddStyleSheet(nsIStyleSheet* aSheet) override;
virtual void RemoveStyleSheet(nsIStyleSheet* aSheet) override;
virtual mozilla::CSSStyleSheet* GetStyleSheetAt(int32_t aIndex) const override;
virtual int32_t GetIndexOfStyleSheet(mozilla::CSSStyleSheet* aSheet) const override;
virtual void AddStyleSheet(mozilla::CSSStyleSheet* aSheet) override;
virtual void RemoveStyleSheet(mozilla::CSSStyleSheet* aSheet) override;
virtual void UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
nsCOMArray<nsIStyleSheet>& aNewSheets) override;
virtual void AddStyleSheetToStyleSets(nsIStyleSheet* aSheet);
virtual void RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet);
virtual void UpdateStyleSheets(
nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aOldSheets,
nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aNewSheets) override;
virtual void AddStyleSheetToStyleSets(mozilla::CSSStyleSheet* aSheet);
virtual void RemoveStyleSheetFromStyleSets(mozilla::CSSStyleSheet* aSheet);
virtual void InsertStyleSheetAt(nsIStyleSheet* aSheet, int32_t aIndex) override;
virtual void SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
virtual void InsertStyleSheetAt(mozilla::CSSStyleSheet* aSheet,
int32_t aIndex) override;
virtual void SetStyleSheetApplicableState(mozilla::CSSStyleSheet* aSheet,
bool aApplicable) override;
virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) override;
virtual nsresult AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aSheet) override;
virtual void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI) override;
virtual nsIStyleSheet* FirstAdditionalAuthorSheet() override;
virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType,
nsIURI* aSheetURI) override;
virtual nsresult AddAdditionalStyleSheet(additionalSheetType aType,
mozilla::CSSStyleSheet* aSheet) override;
virtual void RemoveAdditionalStyleSheet(additionalSheetType aType,
nsIURI* sheetURI) override;
virtual mozilla::CSSStyleSheet* FirstAdditionalAuthorSheet() override;
virtual nsIChannel* GetChannel() const override {
return mChannel;
@@ -852,11 +857,11 @@ public:
virtual void DocumentStatesChanged(
mozilla::EventStates aStateMask) override;
virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet,
virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) override;
virtual void StyleRuleAdded(nsIStyleSheet* aStyleSheet,
virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) override;
virtual void StyleRuleRemoved(nsIStyleSheet* aStyleSheet,
virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) override;
virtual void FlushPendingNotifications(mozFlushType aType) override;
@@ -1483,8 +1488,9 @@ protected:
nsStyleSet* aStyleSet);
void RemoveDocStyleSheetsFromStyleSets();
void RemoveStyleSheetsFromStyleSets(nsCOMArray<nsIStyleSheet>& aSheets,
mozilla::SheetType aType);
void RemoveStyleSheetsFromStyleSets(
nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aSheets,
mozilla::SheetType aType);
void ResetStylesheetsToURI(nsIURI* aURI);
void FillStyleSet(nsStyleSet* aStyleSet);
@@ -1532,9 +1538,9 @@ protected:
// EndLoad() has already happened.
nsWeakPtr mWeakSink;
nsCOMArray<nsIStyleSheet> mStyleSheets;
nsCOMArray<nsIStyleSheet> mOnDemandBuiltInUASheets;
nsCOMArray<nsIStyleSheet> mAdditionalSheets[AdditionalSheetTypeCount];
nsTArray<RefPtr<mozilla::CSSStyleSheet>> mStyleSheets;
nsTArray<RefPtr<mozilla::CSSStyleSheet>> mOnDemandBuiltInUASheets;
nsTArray<RefPtr<mozilla::CSSStyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
// Array of observers
nsTObserverArray<nsIDocumentObserver*> mObservers;
@@ -1713,8 +1719,8 @@ private:
friend class nsUnblockOnloadEvent;
// Recomputes the visibility state but doesn't set the new value.
mozilla::dom::VisibilityState GetVisibilityState() const;
void NotifyStyleSheetAdded(nsIStyleSheet* aSheet, bool aDocumentSheet);
void NotifyStyleSheetRemoved(nsIStyleSheet* aSheet, bool aDocumentSheet);
void NotifyStyleSheetAdded(mozilla::CSSStyleSheet* aSheet, bool aDocumentSheet);
void NotifyStyleSheetRemoved(mozilla::CSSStyleSheet* aSheet, bool aDocumentSheet);
void PostUnblockOnloadEvent();
void DoUnblockOnload();
+20 -16
View File
@@ -73,7 +73,6 @@ class nsIRequest;
class nsIRunnable;
class nsIStreamListener;
class nsIStructuredCloneContainer;
class nsIStyleSheet;
class nsIURI;
class nsIVariant;
class nsLocation;
@@ -946,7 +945,7 @@ public:
* @return the stylesheet at aIndex. Null if aIndex is out of range.
* @throws no exceptions
*/
virtual nsIStyleSheet* GetStyleSheetAt(int32_t aIndex) const = 0;
virtual mozilla::CSSStyleSheet* GetStyleSheetAt(int32_t aIndex) const = 0;
/**
* Insert a sheet at a particular spot in the stylesheet list (zero-based)
@@ -955,7 +954,8 @@ public:
* adjusted for the "special" sheets.
* @throws no exceptions
*/
virtual void InsertStyleSheetAt(nsIStyleSheet* aSheet, int32_t aIndex) = 0;
virtual void InsertStyleSheetAt(mozilla::CSSStyleSheet* aSheet,
int32_t aIndex) = 0;
/**
* Get the index of a particular stylesheet. This will _always_
@@ -963,7 +963,7 @@ public:
* @param aSheet the sheet to get the index of
* @return aIndex the index of the sheet in the full list
*/
virtual int32_t GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const = 0;
virtual int32_t GetIndexOfStyleSheet(mozilla::CSSStyleSheet* aSheet) const = 0;
/**
* Replace the stylesheets in aOldSheets with the stylesheets in
@@ -973,24 +973,25 @@ public:
* may be null; if so the corresponding sheets in the first list
* will simply be removed.
*/
virtual void UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
nsCOMArray<nsIStyleSheet>& aNewSheets) = 0;
virtual void UpdateStyleSheets(
nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aOldSheets,
nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aNewSheets) = 0;
/**
* Add a stylesheet to the document
*/
virtual void AddStyleSheet(nsIStyleSheet* aSheet) = 0;
virtual void AddStyleSheet(mozilla::CSSStyleSheet* aSheet) = 0;
/**
* Remove a stylesheet from the document
*/
virtual void RemoveStyleSheet(nsIStyleSheet* aSheet) = 0;
virtual void RemoveStyleSheet(mozilla::CSSStyleSheet* aSheet) = 0;
/**
* Notify the document that the applicable state of the sheet changed
* and that observers should be notified and style sets updated
*/
virtual void SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
virtual void SetStyleSheetApplicableState(mozilla::CSSStyleSheet* aSheet,
bool aApplicable) = 0;
enum additionalSheetType {
@@ -1000,10 +1001,13 @@ public:
AdditionalSheetTypeCount
};
virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) = 0;
virtual nsresult AddAdditionalStyleSheet(additionalSheetType aType, nsIStyleSheet* aSheet) = 0;
virtual void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI) = 0;
virtual nsIStyleSheet* FirstAdditionalAuthorSheet() = 0;
virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType,
nsIURI* aSheetURI) = 0;
virtual nsresult AddAdditionalStyleSheet(additionalSheetType aType,
mozilla::CSSStyleSheet* aSheet) = 0;
virtual void RemoveAdditionalStyleSheet(additionalSheetType aType,
nsIURI* sheetURI) = 0;
virtual mozilla::CSSStyleSheet* FirstAdditionalAuthorSheet() = 0;
/**
* Get this document's CSSLoader. This is guaranteed to not return null.
@@ -1306,11 +1310,11 @@ public:
// Observation hooks for style data to propagate notifications
// to document observers
virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet,
virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
virtual void StyleRuleAdded(nsIStyleSheet* aStyleSheet,
virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
virtual void StyleRuleRemoved(nsIStyleSheet* aStyleSheet,
virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
/**
+20 -19
View File
@@ -11,10 +11,10 @@
#include "nsIMutationObserver.h"
class nsIContent;
class nsIStyleSheet;
class nsIDocument;
namespace mozilla {
class CSSStyleSheet;
namespace css {
class Rule;
} // namespace css
@@ -100,7 +100,7 @@ public:
* @param aDocumentSheet True if sheet is in document's style sheet list,
* false if sheet is not (i.e., UA or user sheet)
*/
virtual void StyleSheetAdded(nsIStyleSheet* aStyleSheet,
virtual void StyleSheetAdded(mozilla::CSSStyleSheet* aStyleSheet,
bool aDocumentSheet) = 0;
/**
@@ -113,7 +113,7 @@ public:
* @param aDocumentSheet True if sheet is in document's style sheet list,
* false if sheet is not (i.e., UA or user sheet)
*/
virtual void StyleSheetRemoved(nsIStyleSheet* aStyleSheet,
virtual void StyleSheetRemoved(mozilla::CSSStyleSheet* aStyleSheet,
bool aDocumentSheet) = 0;
/**
@@ -125,7 +125,7 @@ public:
*
* @param aStyleSheet the StyleSheet that has changed state
*/
virtual void StyleSheetApplicableStateChanged(nsIStyleSheet* aStyleSheet) = 0;
virtual void StyleSheetApplicableStateChanged(mozilla::CSSStyleSheet* aStyleSheet) = 0;
/**
* A StyleRule has just been modified within a style sheet.
@@ -136,7 +136,7 @@ public:
*
* @param aStyleSheet the StyleSheet that contians the rule
*/
virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet) = 0;
virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet) = 0;
/**
* A StyleRule has just been added to a style sheet.
@@ -147,7 +147,7 @@ public:
*
* @param aStyleSheet the StyleSheet that has been modified
*/
virtual void StyleRuleAdded(nsIStyleSheet* aStyleSheet) = 0;
virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet) = 0;
/**
* A StyleRule has just been removed from a style sheet.
@@ -158,7 +158,7 @@ public:
*
* @param aStyleSheet the StyleSheet that has been modified
*/
virtual void StyleRuleRemoved(nsIStyleSheet* aStyleSheet) = 0;
virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
@@ -186,24 +186,25 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
mozilla::EventStates aStateMask) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED \
virtual void StyleSheetAdded(nsIStyleSheet* aStyleSheet, \
virtual void StyleSheetAdded(mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED \
virtual void StyleSheetRemoved(nsIStyleSheet* aStyleSheet, \
virtual void StyleSheetRemoved(mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETAPPLICABLESTATECHANGED \
virtual void StyleSheetApplicableStateChanged(nsIStyleSheet* aStyleSheet) override;
virtual void StyleSheetApplicableStateChanged( \
mozilla::CSSStyleSheet* aStyleSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED \
virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet) override;
virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED \
virtual void StyleRuleAdded(nsIStyleSheet* aStyleSheet) override;
virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED \
virtual void StyleRuleRemoved(nsIStyleSheet* aStyleSheet) override;
virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER \
NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE \
@@ -261,29 +262,29 @@ NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(_class)
#define NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(_class) \
void \
_class::StyleSheetAdded(nsIStyleSheet* aStyleSheet, \
_class::StyleSheetAdded(mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) \
{ \
} \
void \
_class::StyleSheetRemoved(nsIStyleSheet* aStyleSheet, \
_class::StyleSheetRemoved(mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) \
{ \
} \
void \
_class::StyleSheetApplicableStateChanged(nsIStyleSheet* aStyleSheet) \
_class::StyleSheetApplicableStateChanged(mozilla::CSSStyleSheet* aStyleSheet) \
{ \
} \
void \
_class::StyleRuleChanged(nsIStyleSheet* aStyleSheet) \
_class::StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet) \
{ \
} \
void \
_class::StyleRuleAdded(nsIStyleSheet* aStyleSheet) \
_class::StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet) \
{ \
} \
void \
_class::StyleRuleRemoved(nsIStyleSheet* aStyleSheet) \
_class::StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet) \
{ \
}
+2 -12
View File
@@ -285,17 +285,6 @@ UpdateIsElementInStyleScopeFlagOnSubtree(Element* aElement)
}
}
static Element*
GetScopeElement(nsIStyleSheet* aSheet)
{
RefPtr<CSSStyleSheet> cssStyleSheet = do_QueryObject(aSheet);
if (!cssStyleSheet) {
return nullptr;
}
return cssStyleSheet->GetScopeElement();
}
nsresult
nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
ShadowRoot* aOldShadowRoot,
@@ -327,7 +316,8 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
return NS_OK;
}
Element* oldScopeElement = GetScopeElement(mStyleSheet);
Element* oldScopeElement =
mStyleSheet ? mStyleSheet->GetScopeElement() : nullptr;
if (mStyleSheet && (aOldDocument || aOldShadowRoot)) {
MOZ_ASSERT(!(aOldDocument && aOldShadowRoot),
+2
View File
@@ -26,3 +26,5 @@ skip-if = true # Intermittent failures - bug 987493. Restore the skip-if above o
[browser_bug1058164.js]
skip-if = e10s # We need bug 918634 to land before this can be tested with e10s.
[browser_use_counters.js]
[browser_bug1238440.js]
skip-if = e10s
+76
View File
@@ -0,0 +1,76 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
waitForExplicitFinish();
const PAGE = "data:text/html,<html><body><input type=\"file\"/></body></html>";
function writeFile(file, text) {
return new Promise((resolve) => {
let converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let ostream = FileUtils.openSafeFileOutputStream(file);
let istream = converter.convertToInputStream(text);
NetUtil.asyncCopy(istream, ostream, function(status) {
if (!Components.isSuccessCode(status)) throw 'fail';
resolve();
});
});
}
function runFileReader(input, status) {
return new Promise((resolve) => {
let fr = new FileReader();
fr.onload = function() {
ok(status, "FileReader called onload");
resolve();
}
fr.onerror = function(e) {
e.preventDefault();
ok(!status, "FileReader called onerror");
resolve();
}
fr.readAsArrayBuffer(input);
});
}
add_task(function() {
info("Creating a temporary file...");
let file = FileUtils.getFile("TmpD", ["bug1238440.txt"]);
yield writeFile(file, "hello world");
info("Opening a tab...");
let tab = gBrowser.addTab(PAGE);
gBrowser.selectedTab = tab;
let browser = tab.linkedBrowser;
yield BrowserTestUtils.browserLoaded(browser);
info("Populating the form...");
let doc = browser.contentDocument;
let input = doc.querySelector('input');
input.value = file.path;
info("Running the FileReader...");
yield runFileReader(input.files[0], true);
info("Writing the temporary file again...");
yield writeFile(file, "hello world-----------------------------");
info("Running the FileReader again...");
yield runFileReader(input.files[0], false);
info("Closing the tab...");
gBrowser.removeTab(gBrowser.selectedTab);
ok(true, "we didn't crash.");
});
-17
View File
@@ -127,23 +127,6 @@ function testHasRun() {
}
}
function createFileWithData(fileData) {
var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"].getService(SpecialPowers.Ci.nsIProperties);
var testFile = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile);
testFile.append("fileAPItestfile2-" + fileNum);
fileNum++;
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();
var fileList = document.getElementById('fileList');
SpecialPowers.wrap(fileList).value = testFile.path;
return fileList.files[0];
}
function gc() {
window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIDOMWindowUtils)
+1 -2
View File
@@ -513,7 +513,6 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_bug433533.html]
[test_bug433662.html]
[test_bug435425.html]
[test_bug438519.html]
[test_bug444030.xhtml]
[test_bug444322.html]
[test_bug444722.html]
@@ -732,7 +731,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(bug 904183
[test_encodeToStringWithMaxLength.html]
[test_fileapi.html]
[test_fileapi_slice.html]
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s #bug 775227
skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 775227
[test_getElementById.html]
[test_html_colors_quirks.html]
[test_html_colors_standards.html]
-44
View File
@@ -1,44 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=438519
-->
<head>
<title>Test for Bug 438519</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="doTest()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=438519">Mozilla Bug 438519</a>
<p id="display"></p>
<div id="content" style="display:none">
<iframe id="empty" src="data:text/xml,<!DOCTYPE HTML []><html></html>"></iframe>
<iframe id="missing" src="data:text/xml,<!DOCTYPE HTML><html></html>"></iframe>
<iframe id="entity" src="data:text/xml,<!DOCTYPE HTML [ <!ENTITY foo 'foo'> ]><html></html>"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 218236 **/
SimpleTest.waitForExplicitFinish();
function doTest() {
function checkInternalSubset(id, expected) {
var e = document.getElementById(id);
is(e.contentDocument.doctype.internalSubset, expected, "checking '" + id + "'");
}
checkInternalSubset("empty", "");
checkInternalSubset("missing", null);
checkInternalSubset("entity", " <!ENTITY foo 'foo'> ");
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>
+1 -3
View File
@@ -24,7 +24,6 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
is(doc.doctype.name, "html");
is(doc.doctype.publicId, "");
is(doc.doctype.systemId, "");
is(doc.doctype.internalSubset, null, "internalSubset should be null!");
isElement(doc.documentElement, "html");
isElement(doc.documentElement.firstChild, "head");
if (title !== undefined) {
@@ -38,8 +37,7 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
}
isElement(doc.documentElement.lastChild, "body");
is(doc.documentElement.lastChild.childNodes.length, 0);
((!title || title.indexOf("\f") === -1) ? is : todo_is)
(doc.title, normalizedtitle);
is(doc.title, normalizedtitle);
doc.body.innerHTML = "foo";
is(doc.body.innerHTML, "foo", "innerHTML should work in HTML data documents!");
}
+85 -54
View File
@@ -54,31 +54,6 @@ cx.fill();
cx.closePath();
var fileData =
atob(cx.canvas.toDataURL("image/png").substring("data:text/png;base64,".length + 1));
var memFile = cx.canvas.mozGetAsFile("image/png");
var fileFile = createFileWithData(fileData);
var size = fileData.length;
// This might fail if we dramatically improve the png encoder. If that happens
// please increase the complexity or size of the image generated above to ensure
// that we're testing with files that are large enough.
ok(size > 65536, "test data sufficiently large");
// Test that basic properties work
testSlice(memFile, size, "image/png", fileData, "memFile");
testSlice(fileFile, size, "", fileData, "fileFile");
// Try loading directly from slice into an image
var testBinaryData = "";
for (var i = 0; i < 256; i++) {
testBinaryData += String.fromCharCode(i);
}
while (testBinaryData.length < 20000) {
testBinaryData += testBinaryData;
}
function imageLoadHandler(event) {
var origcanvas = $("canvas");
var testcanvas = $("testcanvas");
@@ -100,37 +75,93 @@ function imageLoadHandler(event) {
testHasRun();
}
// image in the middle
var imgfile = createFileWithData(testBinaryData + fileData + testBinaryData);
is(imgfile.size, size + testBinaryData.length * 2, "correct file size (middle)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
img.onload = imageLoadHandler;
expectedTestCount++;
var fileData =
atob(cx.canvas.toDataURL("image/png").substring("data:text/png;base64,".length + 1));
var size = fileData.length;
var testBinaryData = "";
// image at start
var imgfile = createFileWithData(fileData + testBinaryData);
is(imgfile.size, size + testBinaryData.length, "correct file size (start)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(0, size));
img.onload = imageLoadHandler;
expectedTestCount++;
// This might fail if we dramatically improve the png encoder. If that happens
// please increase the complexity or size of the image generated above to ensure
// that we're testing with files that are large enough.
ok(size > 65536, "test data sufficiently large");
// image at end
var imgfile = createFileWithData(testBinaryData + fileData);
is(imgfile.size, size + testBinaryData.length, "correct file size (end)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
img.onload = imageLoadHandler;
expectedTestCount++;
SpecialPowers.createFiles([{name: "basicTestFile", data: fileData}],
basicTest);
function basicTest(files) {
var fileFile = files[0];
// Test that basic properties work
var memFile = cx.canvas.mozGetAsFile("image/png");
testSlice(memFile, size, "image/png", fileData, "memFile");
testSlice(fileFile, size, "", fileData, "fileFile");
// Try loading directly from slice into an image
for (var i = 0; i < 256; i++) {
testBinaryData += String.fromCharCode(i);
}
while (testBinaryData.length < 20000) {
testBinaryData += testBinaryData;
}
// image in the middle
SpecialPowers.createFiles([{name: "middleTestFile",
data: testBinaryData + fileData + testBinaryData}],
imageMiddleTest);
}
function imageMiddleTest(files) {
var imgfile = files[0];
is(imgfile.size, size + testBinaryData.length * 2, "correct file size (middle)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
img.onload = imageLoadHandler;
expectedTestCount++;
// image at start
SpecialPowers.createFiles([{name: "startTestFile",
data: fileData + testBinaryData}],
imageStartTest);
}
function imageStartTest(files) {
var imgfile = files[0];
is(imgfile.size, size + testBinaryData.length, "correct file size (start)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(0, size));
img.onload = imageLoadHandler;
expectedTestCount++;
// image at end
SpecialPowers.createFiles([{name: "endTestFile",
data: testBinaryData + fileData}],
imageEndTest);
}
function imageEndTest(files) {
var imgfile = files[0];
is(imgfile.size, size + testBinaryData.length, "correct file size (end)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
img.onload = imageLoadHandler;
expectedTestCount++;
// image past end
SpecialPowers.createFiles([{name: "pastEndTestFile",
data: testBinaryData + fileData}],
imagePastEndTest);
}
function imagePastEndTest(files) {
var imgfile = files[0];
is(imgfile.size, size + testBinaryData.length, "correct file size (past end)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size + 1000));
img.onload = imageLoadHandler;
expectedTestCount++;
}
// image past end
var imgfile = createFileWithData(testBinaryData + fileData);
is(imgfile.size, size + testBinaryData.length, "correct file size (past end)");
var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size + 1000));
img.onload = imageLoadHandler;
expectedTestCount++;
</script>
</pre>
</body> </html>
</body>
</html>
+1
View File
@@ -89,3 +89,4 @@ MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")
MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer")
MSG_DEF(MSG_CACHE_ADD_FAILED_RESPONSE, 3, JSEXN_TYPEERR, "Cache got {0} response with bad status {1} while trying to add request {2}")
@@ -75,7 +75,7 @@ public:
return mDiscoverable;
}
BluetoothPairingListener* PairingReqs() const
BluetoothPairingListener* GetPairingReqs() const
{
return mPairingReqs;
}
@@ -75,15 +75,6 @@ const OBSERVED_EVENTS = [
'will-launch-app'
];
const COMMAND_MAP = {
'cut': 'cmd_cut',
'copy': 'cmd_copyAndCollapseToEnd',
'copyImage': 'cmd_copyImage',
'copyLink': 'cmd_copyLink',
'paste': 'cmd_paste',
'selectall': 'cmd_selectAll'
};
/**
* The BrowserElementChild implements one half of <iframe mozbrowser>.
* (The other half is, unsurprisingly, BrowserElementParent.)
@@ -269,7 +260,6 @@ BrowserElementChild.prototype = {
"activate-next-paint-listener": this._activateNextPaintListener.bind(this),
"set-input-method-active": this._recvSetInputMethodActive.bind(this),
"deactivate-next-paint-listener": this._deactivateNextPaintListener.bind(this),
"do-command": this._recvDoCommand,
"find-all": this._recvFindAll.bind(this),
"find-next": this._recvFindNext.bind(this),
"clear-match": this._recvClearMatch.bind(this),
@@ -419,15 +409,6 @@ BrowserElementChild.prototype = {
}
},
_isCommandEnabled: function(cmd) {
let command = COMMAND_MAP[cmd];
if (!command) {
return false;
}
return docShell.isCommandEnabled(command);
},
/**
* Spin in a nested event loop until we receive a unblock-modal-prompt message for
* this window.
@@ -1187,14 +1168,16 @@ BrowserElementChild.prototype = {
_recvFireCtxCallback: function(data) {
debug("Received fireCtxCallback message: (" + data.json.menuitem + ")");
let doCommandIfEnabled = (command) => {
if (docShell.isCommandEnabled(command)) {
docShell.doCommand(command);
}
};
if (data.json.menuitem == 'copy-image') {
// Set command
data.json.command = 'copyImage';
this._recvDoCommand(data);
doCommandIfEnabled('cmd_copyImage');
} else if (data.json.menuitem == 'copy-link') {
// Set command
data.json.command = 'copyLink';
this._recvDoCommand(data);
doCommandIfEnabled('cmd_copyLink');
} else if (data.json.menuitem in this._ctxHandlers) {
this._ctxHandlers[data.json.menuitem].click();
this._ctxHandlers = {};
@@ -1378,12 +1361,6 @@ BrowserElementChild.prototype = {
docShell.contentViewer.fullZoom = data.json.zoom;
},
_recvDoCommand: function(data) {
if (this._isCommandEnabled(data.json.command)) {
docShell.doCommand(COMMAND_MAP[data.json.command]);
}
},
_recvGetAudioChannelVolume: function(data) {
debug("Received getAudioChannelVolume message: (" + data.json.id + ")");
@@ -1871,6 +1848,7 @@ BrowserElementChild.prototype = {
case Cr.NS_BINDING_ABORTED :
// Ignoring NS_BINDING_ABORTED, which is set when loading page is
// stopped.
case Cr.NS_ERROR_PARSED_DATA_CACHED:
return;
// TODO See nsDocShell::DisplayLoadError to see what extra
@@ -30,7 +30,7 @@ var CopyPasteAssistent = {
switch (e.data.msg_name) {
case 'copypaste-do-command':
if (this._isCommandEnabled(e.data.command)) {
docShell.doCommand(COMMAND_MAP[e.data.command]);
docShell.doCommand(this.COMMAND_MAP[e.data.command]);
}
break;
}
+13 -36
View File
@@ -15,6 +15,7 @@ var Cr = Components.results;
*/
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
@@ -262,7 +263,6 @@ function BrowserElementParent() {
Services.obs.addObserver(this, 'ask-children-to-exit-fullscreen', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'ask-children-to-execute-copypaste-command', /* ownsWeak = */ true);
Services.obs.addObserver(this, 'back-docommand', /* ownsWeak = */ true);
@@ -470,6 +470,7 @@ BrowserElementParent.prototype = {
/* username and password */
let detail = {
host: authDetail.host,
path: authDetail.path,
realm: authDetail.realm,
isProxy: authDetail.isProxy
};
@@ -1008,36 +1009,17 @@ BrowserElementParent.prototype = {
Ci.nsIRequestObserver])
};
// If we have a URI we'll use it to get the triggering principal to use,
// if not available a null principal is acceptable.
let referrer = null;
let principal = null;
if (_options.referrer) {
// newURI can throw on malformed URIs.
try {
referrer = Services.io.newURI(_options.referrer, null, null);
}
catch(e) {
debug('Malformed referrer -- ' + e);
}
let referrer = Services.io.newURI(_options.referrer, null, null);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(
referrer, this._frameLoader.loadContext.originAttributes);
// This simply returns null if there is no principal available
// for the requested uri. This is an acceptable fallback when
// calling newChannelFromURI2.
principal =
Services.scriptSecurityManager.createCodebasePrincipal(
referrer, this._frameLoader.loadContext.originAttributes);
}
debug('Using principal? ' + !!principal);
let channel =
Services.io.newChannelFromURI2(url,
null, // No document.
principal, // Loading principal
principal, // Triggering principal
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_OTHER);
let channel = NetUtil.newChannel({
uri: url,
loadingPrincipal: principal,
securityFlags: SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
});
// XXX We would set private browsing information prior to calling this.
channel.notificationCallbacks = interfaceRequestor;
@@ -1062,7 +1044,7 @@ BrowserElementParent.prototype = {
}
// Set-up complete, let's get things started.
channel.asyncOpen(new DownloadListener(), null);
channel.asyncOpen2(new DownloadListener());
return req;
},
@@ -1292,11 +1274,6 @@ BrowserElementParent.prototype = {
this._sendAsyncMsg('exit-fullscreen');
}
break;
case 'copypaste-docommand':
if (this._isAlive() && this._frameElement.isEqualNode(subject.wrappedJSObject)) {
this._sendAsyncMsg('do-command', { command: data });
}
break;
case 'ask-children-to-execute-copypaste-command':
if (this._isAlive() && this._frameElement == subject.wrappedJSObject) {
this._sendAsyncMsg('copypaste-do-command', { command: data });
@@ -381,6 +381,7 @@ BrowserElementAuthPrompt.prototype = {
let [hostname, httpRealm] = this._getAuthTarget(channel, authInfo);
return {
host: hostname,
path: channel.URI.path,
realm: httpRealm,
username: authInfo.username,
isProxy: !!(authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY),
@@ -49,6 +49,9 @@ function testHttpAuthCancel(e) {
is(e.detail.realm, 'http_realm', 'expected realm matches');
is(e.detail.host, 'http://test', 'expected host matches');
is(e.detail.path,
'/tests/dom/browser-element/mochitest/file_http_401_response.sjs',
'expected path matches');
e.preventDefault();
SimpleTest.executeSoon(function() {
@@ -71,6 +74,9 @@ function testHttpAuth(e) {
is(e.detail.realm, 'http_realm', 'expected realm matches');
is(e.detail.host, 'http://test', 'expected host matches');
is(e.detail.path,
'/tests/dom/browser-element/mochitest/file_http_401_response.sjs',
'expected path matches');
is(e.detail.isProxy, false, 'expected isProxy is false');
e.preventDefault();
@@ -98,6 +104,9 @@ function testProxyAuth(e) {
is(e.detail.realm, 'http_realm', 'expected realm matches');
is(e.detail.host, mozproxy, 'expected host matches');
is(e.detail.path,
'/tests/dom/browser-element/mochitest/file_http_407_response.sjs',
'expected path matches');
is(e.detail.isProxy, true, 'expected isProxy is true');
e.preventDefault();
@@ -86,8 +86,14 @@ function runTest() {
}
function doCommand(cmd) {
Services.obs.notifyObservers({wrappedJSObject: SpecialPowers.unwrap(iframeInner)},
'copypaste-docommand', cmd);
var COMMAND_MAP = {
'cut': 'cmd_cut',
'copy': 'cmd_copyAndCollapseToEnd',
'paste': 'cmd_paste',
'selectall': 'cmd_selectAll'
};
var script = 'data:,docShell.doCommand("' + COMMAND_MAP[cmd] + '");';
mm.loadFrameScript(script, false);
}
function dispatchTest(e) {
@@ -9,6 +9,27 @@ SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
// We'll need to get the appId from the current document,
// it's either SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID when
// we are not running inside an app (e.g. Firefox Desktop),
// or the appId of Mochitest app when we are running inside that app
// (e.g. Emulator).
var currentAppId = SpecialPowers.wrap(document).nodePrincipal.appId;
var inApp =
currentAppId !== SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID;
// We will also need the manifest URL and set it on iframes.
var currentAppManifestURL;
if (inApp) {
let appsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"]
.getService(SpecialPowers.Ci.nsIAppsService);
currentAppManifestURL = appsService.getManifestURLByLocalId(currentAppId);
};
info('appId=' + currentAppId);
info('manifestURL=' + currentAppManifestURL);
function setup() {
let appInfo = SpecialPowers.Cc['@mozilla.org/xre/app-info;1']
.getService(SpecialPowers.Ci.nsIXULAppInfo);
@@ -27,110 +48,134 @@ function tearDown() {
}
function runTest() {
let path = location.pathname;
let imeUrl = location.protocol + '//' + location.host +
path.substring(0, path.lastIndexOf('/')) +
'/file_inputmethod.html';
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: {
url: imeUrl,
originAttributes: {inBrowser: true}
}
}], SimpleTest.waitForFocus.bind(SimpleTest, createFrames));
createFrames();
}
var gFrames = [];
var gInputMethodFrames = [];
var gInputFrame;
function createFrames() {
// Create two input method iframes.
let loadendCount = 0;
let countLoadend = function() {
if (this === gInputFrame) {
// The frame script running in the frame where the input is hosted.
let appFrameScript = function appFrameScript() {
let input = content.document.body.firstElementChild;
input.oninput = function() {
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
value: this.value
});
};
input.onblur = function() {
// "Expected" lost of focus since the test is finished.
if (input.value === '#0#1hello') {
return;
}
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
error: true,
value: 'Unexpected lost of focus on the input frame!'
});
};
input.focus();
}
// Inject frame script to receive input.
let mm = SpecialPowers.getBrowserFrameMessageManager(gInputFrame);
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
mm.addMessageListener("test:InputMethod:oninput", next);
} else {
ok(this.setInputMethodActive, 'Can access setInputMethodActive.');
// The frame script running in the input method frames.
let appFrameScript = function appFrameScript() {
content.addEventListener("message", function(evt) {
sendAsyncMessage('test:InputMethod:imFrameMessage', {
from: 'im',
value: evt.data
});
});
}
// Inject frame script to receive message.
let mm = SpecialPowers.getBrowserFrameMessageManager(this);
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
mm.addMessageListener("test:InputMethod:imFrameMessage", next);
}
loadendCount++;
if (loadendCount === 3) {
startTest();
setPermissions();
}
};
// Create an input field to receive string from input method iframes.
gInputFrame = document.createElement('iframe');
gInputFrame.setAttribute('mozbrowser', 'true');
gInputFrame.src =
'data:text/html,<input autofocus value="hello" />' +
'<p>This is targetted mozbrowser frame.</p>';
document.body.appendChild(gInputFrame);
gInputFrame.addEventListener('mozbrowserloadend', countLoadend);
for (let i = 0; i < 2; i++) {
let frame = gInputMethodFrames[i] = document.createElement('iframe');
frame.setAttribute('mozbrowser', 'true');
if (currentAppManifestURL) {
frame.setAttribute('mozapp', currentAppManifestURL);
}
};
frame.src = 'file_empty.html#' + i;
document.body.appendChild(frame);
frame.addEventListener('mozbrowserloadend', countLoadend);
}
}
// Create an input field to receive string from input method iframes.
gInputFrame = document.createElement('iframe');
gInputFrame.setAttribute('mozbrowser', 'true');
gInputFrame.src =
'data:text/html,<input autofocus value="hello" />' +
'<p>This is targetted mozbrowser frame.</p>';
document.body.appendChild(gInputFrame);
gInputFrame.addEventListener('mozbrowserloadend', countLoadend);
function setPermissions() {
let permissions = [{
type: 'input',
allow: true,
context: {
url: SimpleTest.getTestFileURL('/file_empty.html'),
originAttributes: {
appId: currentAppId,
inBrowser: true
}
}
}];
for (let i = 0; i < 2; i++) {
let frame = gFrames[i] = document.createElement('iframe');
gFrames[i].setAttribute('mozbrowser', 'true');
// When the input method iframe is activated, it will send the URL
// hash to current focused element. We set different hash to each
// iframe so that iframes can be differentiated by their hash.
frame.src = 'file_inputmethod.html#' + i;
document.body.appendChild(frame);
frame.addEventListener('mozbrowserloadend', countLoadend);
if (inApp) {
// The current document would also need to be given access for IPC to
// recognize our permission (why)?
permissions.push({
type: 'input', allow: true, context: document });
}
SpecialPowers.pushPermissions(permissions,
SimpleTest.waitForFocus.bind(SimpleTest, startTest));
}
function startTest() {
// Set focus to the input field and wait for input methods' inputting.
SpecialPowers.DOMWindowUtils.focus(gInputFrame);
function startTest() {
// The frame script running in the frame where the input is hosted.
let appFrameScript = function appFrameScript() {
let input = content.document.body.firstElementChild;
input.oninput = function() {
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
value: this.value
});
};
let req0 = gFrames[0].setInputMethodActive(true);
input.onblur = function() {
// "Expected" lost of focus since the test is finished.
if (input.value === '#0#1hello') {
return;
}
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
error: true,
value: 'Unexpected lost of focus on the input frame!'
});
};
input.focus();
};
// Inject frame script to receive input.
let mm = SpecialPowers.getBrowserFrameMessageManager(gInputFrame);
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
mm.addMessageListener("test:InputMethod:oninput", next);
gInputMethodFrames.forEach((frame) => {
ok(frame.setInputMethodActive, 'Can access setInputMethodActive.');
// The frame script running in the input method frames.
let appFrameScript = function appFrameScript() {
let im = content.navigator.mozInputMethod;
im.oninputcontextchange = function() {
let ctx = im.inputcontext;
// Report back to parent frame on status of ctx gotten.
// (A setTimeout() here to ensure this always happens after
// DOMRequest succeed.)
content.setTimeout(() => {
sendAsyncMessage('test:InputMethod:imFrameMessage', {
from: 'im',
value: content.location.hash + !!ctx
});
});
// If there is a context, send out the hash.
if (ctx) {
ctx.replaceSurroundingText(content.location.hash);
}
};
};
// Inject frame script to receive message.
let mm = SpecialPowers.getBrowserFrameMessageManager(frame);
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
mm.addMessageListener("test:InputMethod:imFrameMessage", next);
});
// Set focus to the input field and wait for input methods' inputting.
SpecialPowers.DOMWindowUtils.focus(gInputFrame);
let req0 = gInputMethodFrames[0].setInputMethodActive(true);
req0.onsuccess = function() {
ok(true, 'setInputMethodActive succeeded (0).');
};
@@ -203,14 +248,14 @@ function next(msg) {
gCount++;
let req0 = gFrames[0].setInputMethodActive(false);
let req0 = gInputMethodFrames[0].setInputMethodActive(false);
req0.onsuccess = function() {
ok(true, 'setInputMethodActive succeeded (0).');
};
req0.onerror = function() {
ok(false, 'setInputMethodActive failed (0): ' + this.error.name);
};
let req1 = gFrames[1].setInputMethodActive(true);
let req1 = gInputMethodFrames[1].setInputMethodActive(true);
req1.onsuccess = function() {
ok(true, 'setInputMethodActive succeeded (1).');
};
@@ -259,7 +304,7 @@ function next(msg) {
// Receive the second input from the second iframe.
// Deactive the second iframe.
let req3 = gFrames[1].setInputMethodActive(false);
let req3 = gInputMethodFrames[1].setInputMethodActive(false);
req3.onsuccess = function() {
ok(true, 'setInputMethodActive(false) succeeded (2).');
};
@@ -1,20 +0,0 @@
<!DOCTYPE HTML>
<html>
<body>
<script>
var im = navigator.mozInputMethod;
if (im) {
im.oninputcontextchange = function() {
var ctx = im.inputcontext;
// Report back to parent frame on status of ctx gotten.
window.postMessage(window.location.hash + !!ctx, '*');
// If there is a context, send out the hash.
if (ctx) {
ctx.replaceSurroundingText(location.hash);
}
};
}
</script>
<p>This frame represents the input method frame.</p>
</body>
</html>
@@ -75,8 +75,10 @@ skip-if = (toolkit == 'gonk') # Disabled on emulator. See bug 1144015 comment 8
[test_browserElement_oop_PrivateBrowsing.html]
[test_browserElement_oop_PromptCheck.html]
[test_browserElement_oop_PromptConfirm.html]
# Disabled on B2G Emulator because permission cannot be asserted in content process,
# need to fix either bug 1094055 or bug 1020135.
[test_browserElement_oop_Proxy.html]
skip-if = (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (toolkit == 'gonk')
[test_browserElement_oop_PurgeHistory.html]
[test_browserElement_oop_Reload.html]
[test_browserElement_oop_ReloadPostRequest.html]
@@ -86,7 +88,7 @@ skip-if = (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) #TIMED_OUT, bug 766586
[test_browserElement_oop_SendEvent.html]
[test_browserElement_oop_SetInputMethodActive.html]
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (os == "android")
[test_browserElement_oop_SetVisible.html]
[test_browserElement_oop_SetVisibleFrames.html]
[test_browserElement_oop_SetVisibleFrames2.html]
+4 -4
View File
@@ -129,12 +129,10 @@ support-files =
file_focus.html
file_http_401_response.sjs
file_http_407_response.sjs
file_inputmethod.html
file_microdata.html
file_microdata_bad_itemref.html
file_microdata_itemref.html
file_microformats.html
file_inputmethod.html
file_post_request.html
file_wyciwyg.html
file_audio.html
@@ -212,8 +210,10 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_inproc_PrivateBrowsing.html]
[test_browserElement_inproc_PromptCheck.html]
[test_browserElement_inproc_PromptConfirm.html]
# Disabled on B2G Emulator because permission cannot be asserted in content process,
# need to fix either bug 1094055 or bug 1020135.
[test_browserElement_inproc_Proxy.html]
skip-if = (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (toolkit == 'gonk')
[test_browserElement_inproc_PurgeHistory.html]
[test_browserElement_inproc_ReloadPostRequest.html]
[test_browserElement_inproc_RemoveBrowserElement.html]
@@ -223,7 +223,7 @@ skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) # android(TIMED_
[test_browserElement_inproc_SendEvent.html]
# The setInputMethodActive() tests will timed out on Android
[test_browserElement_inproc_SetInputMethodActive.html]
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (os == "android")
[test_browserElement_inproc_SetVisible.html]
[test_browserElement_inproc_SetVisibleFrames.html]
[test_browserElement_inproc_SetVisibleFrames2.html]
+38
View File
@@ -158,6 +158,26 @@ public:
return;
}
// Do not allow the convenience methods .add()/.addAll() to store failed
// responses. A consequence of this is that these methods cannot be
// used to store opaque or opaqueredirect responses since they always
// expose a 0 status value.
if (!response->Ok()) {
uint32_t t = static_cast<uint32_t>(response->Type());
NS_ConvertASCIItoUTF16 type(ResponseTypeValues::strings[t].value,
ResponseTypeValues::strings[t].length);
nsAutoString status;
status.AppendInt(response->Status());
nsAutoString url;
mRequestList[i]->GetUrl(url);
ErrorResult rv;
rv.ThrowTypeError<MSG_CACHE_ADD_FAILED_RESPONSE>(type, status, url);
// TODO: abort the fetch requests we have running (bug 1157434)
mPromise->MaybeReject(rv);
return;
}
responseList.AppendElement(Move(response));
}
@@ -234,6 +254,8 @@ Cache::Match(const RequestOrUSVString& aRequest,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@@ -261,6 +283,8 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
CacheQueryParams params;
ToCacheQueryParams(params, aOptions);
@@ -291,6 +315,8 @@ Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
if (!IsValidPutRequestMethod(aRequest, aRv)) {
return nullptr;
}
@@ -325,6 +351,8 @@ Cache::AddAll(JSContext* aContext,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
MOZ_ASSERT(!global.Failed());
@@ -371,6 +399,8 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
if (NS_WARN_IF(!IsValidPutRequestMethod(aRequest, aRv))) {
return nullptr;
}
@@ -400,6 +430,8 @@ Cache::Delete(const RequestOrUSVString& aRequest,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@@ -427,6 +459,8 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
CacheQueryParams params;
ToCacheQueryParams(params, aOptions);
@@ -529,6 +563,8 @@ Cache::~Cache()
already_AddRefed<Promise>
Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
{
MOZ_ASSERT(mActor);
RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (NS_WARN_IF(!promise)) {
return nullptr;
@@ -603,6 +639,8 @@ Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
return nullptr;
}
CacheChild::AutoLock actorLock(mActor);
AutoChildOpArgs args(this, CachePutAllArgs());
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
+29 -3
View File
@@ -34,6 +34,7 @@ CacheChild::CacheChild()
: mListener(nullptr)
, mNumChildActors(0)
, mDelayedDestroy(false)
, mLocked(false)
{
MOZ_COUNT_CTOR(cache::CacheChild);
}
@@ -44,6 +45,7 @@ CacheChild::~CacheChild()
NS_ASSERT_OWNINGTHREAD(CacheChild);
MOZ_ASSERT(!mListener);
MOZ_ASSERT(!mNumChildActors);
MOZ_ASSERT(!mLocked);
}
void
@@ -103,8 +105,9 @@ CacheChild::StartDestroy()
// If we have outstanding child actors, then don't destroy ourself yet.
// The child actors should be short lived and we should allow them to complete
// if possible. NoteDeletedActor() will call back into this Shutdown()
// method when the last child actor is gone.
if (mNumChildActors) {
// method when the last child actor is gone. Also, delay destruction if we
// have been explicitly locked by someone using us on the stack.
if (mNumChildActors || mLocked) {
mDelayedDestroy = true;
return;
}
@@ -175,11 +178,34 @@ void
CacheChild::NoteDeletedActor()
{
mNumChildActors -= 1;
if (!mNumChildActors && mDelayedDestroy) {
MaybeFlushDelayedDestroy();
}
void
CacheChild::MaybeFlushDelayedDestroy()
{
if (!mNumChildActors && !mLocked && mDelayedDestroy) {
StartDestroy();
}
}
void
CacheChild::Lock()
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
MOZ_ASSERT(!mLocked);
mLocked = true;
}
void
CacheChild::Unlock()
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
MOZ_ASSERT(mLocked);
mLocked = false;
MaybeFlushDelayedDestroy();
}
} // namespace cache
} // namespace dom
} // namespace mozilla
+30
View File
@@ -28,6 +28,24 @@ class CacheChild final : public PCacheChild
, public ActorChild
{
public:
class MOZ_RAII AutoLock final
{
CacheChild* mActor;
public:
explicit AutoLock(CacheChild* aActor)
: mActor(aActor)
{
MOZ_ASSERT(mActor);
mActor->Lock();
}
~AutoLock()
{
mActor->Unlock();
}
};
CacheChild();
~CacheChild();
@@ -74,12 +92,24 @@ private:
void
NoteDeletedActor();
void
MaybeFlushDelayedDestroy();
// Methods used to temporarily force the actor alive. Only called from
// AutoLock.
void
Lock();
void
Unlock();
// Use a weak ref so actor does not hold DOM object alive past content use.
// The Cache object must call ClearListener() to null this before its
// destroyed.
Cache* MOZ_NON_OWNING_REF mListener;
uint32_t mNumChildActors;
bool mDelayedDestroy;
bool mLocked;
NS_DECL_OWNINGTHREAD
};
-1
View File
@@ -119,7 +119,6 @@ IsTrusted(const PrincipalInfo& aPrincipalInfo, bool aTestingPrefEnabled)
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
if (scheme.LowerCaseEqualsLiteral("https") ||
scheme.LowerCaseEqualsLiteral("app") ||
scheme.LowerCaseEqualsLiteral("file")) {
return true;
}
+1 -2
View File
@@ -417,8 +417,7 @@ TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
if (aSchemeValidOut) {
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
*aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
scheme.LowerCaseEqualsLiteral("https") ||
scheme.LowerCaseEqualsLiteral("app");
scheme.LowerCaseEqualsLiteral("https");
}
uint32_t queryPos;
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>Test app for bug 1172562</title>
<script src='test.js'></script>
<script type='application/javascript;version=1.7'>
function runTests() {
return Promise.resolve()
.then(() => { return navigator.serviceWorker.ready })
.then((registration) => {
return new Promise((resolve) => {
var worker = registration.waiting || registration.active;
worker.postMessage('read');
navigator.serviceWorker.onmessage = (message) => {
if (message.data.type == 'done') {
ok(!message.data.cached, 'No cached data');
resolve();
}
};
});
})
.then(done);
}
</script>
</head>
<body onload='runTests()'>
</body>
</html>
+31
View File
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>Test app for bug 1172562</title>
<script src='test.js'></script>
<script type='application/javascript;version=1.7'>
function runTests() {
return Promise.resolve()
.then(() => { return navigator.serviceWorker.ready })
.then((registration) => {
return new Promise((resolve) => {
var worker = registration.waiting || registration.active;
worker.postMessage('write');
navigator.serviceWorker.onmessage = (message) => {
if (message.data.type == 'written') {
worker.postMessage('read');
} else if (message.data.type == 'done') {
ok(message.data.cached, 'Write success');
resolve();
}
};
});
})
.then(done);
}
</script>
</head>
<body onload='runTests()'>
</body>
</html>
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Test app for bug 1169249</title>
<title>Test app for bug 1172562</title>
<script type='application/javascript;version=1.7'>
function ok(aCondition, aMessage) {
if (aCondition) {
@@ -1,5 +1,5 @@
{
"name": "App",
"launch_path": "/index.html",
"description": "Test app for bug 1161684"
"description": "Test app for bug 1172562"
}
+19
View File
@@ -0,0 +1,19 @@
var url = 'index.html';
self.addEventListener('message', (message) => {
caches.open('acache').then((cache) => {
if(message.data == 'write') {
cache.add(url).then(() => {
message.source.postMessage({
type: 'written'
});
});
} else if (message.data == 'read') {
cache.match(url).then((result) => {
message.source.postMessage({
type: 'done',
cached: !!result
});
});
}
});
});
+15
View File
@@ -0,0 +1,15 @@
function ok(aCondition, aMessage) {
if (aCondition) {
alert('OK: ' + aMessage);
} else {
alert('KO: ' + aMessage);
}
}
function ready() {
alert('READY');
}
function done() {
alert('DONE');
}
+2
View File
@@ -0,0 +1,2 @@
<!DOCTYPE html>
<!-- This is only used to give us access to the caches global after setting the pref. -->
+4
View File
@@ -22,6 +22,8 @@ support-files =
test_cache_put_reorder.js
test_cache_https.js
large_url_list.js
empty.html
app/*
[test_cache.html]
[test_cache_add.html]
@@ -39,6 +41,8 @@ support-files =
skip-if = buildapp == 'b2g' # bug 1162353
[test_cache_restart.html]
[test_cache_shrink.html]
[test_cache_clear_on_app_uninstall.html]
skip-if = e10s || buildapp == 'b2g' # bug 1178685
[test_cache_orphaned_cache.html]
[test_cache_orphaned_body.html]
[test_cache_untrusted.html]
+2 -2
View File
@@ -1,7 +1,7 @@
var singleUrl = './test_cache_add.js';
var urlList = [
'./helloworld.txt',
'./foobar.txt',
'./empty.html',
'./frame.html',
'./test_cache.js'
];
var cache;
@@ -5,7 +5,7 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1161684 - Allow JAR channels to be intercepted by service workers</title>
<title>Bug 1172562 - Clear QuotaManager storage when uninstalling an app</title>
<script type='text/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css' />
</head>
@@ -17,8 +17,8 @@
SimpleTest.waitForExplicitFinish();
const appManifestURL =
'http://mochi.test:8888/tests/dom/workers/test/serviceworkers/app-protocol/update.webapp';
const gOrigin = 'http://mochi.test:8888/tests/dom/cache/test/mochitest/app';
const appManifestURL = gOrigin + '/manifest.webapp';
let gApp;
function setup() {
@@ -27,7 +27,6 @@ function setup() {
SpecialPowers.pushPrefEnv({'set': [
['dom.mozBrowserFramesEnabled', true],
['dom.serviceWorkers.exemptFromPerDomainMax', true],
["dom.serviceWorkers.interception.enabled", true],
['dom.serviceWorkers.enabled', true],
['dom.serviceWorkers.testing.enabled', true],
['dom.caches.enabled', true],
@@ -47,7 +46,7 @@ function setup() {
function installApp() {
return new Promise((resolve, reject) => {
let req = navigator.mozApps.installPackage(appManifestURL);
let req = navigator.mozApps.install(appManifestURL);
req.onsuccess = function() {
gApp = req.result;
is(req.result.manifestURL, appManifestURL, 'app installed');
@@ -90,11 +89,11 @@ function launchApp() {
let domParent = document.getElementById('container');
domParent.appendChild(iframe);
SpecialPowers.wrap(iframe.contentWindow).location =
gApp.origin + gApp.manifest.launch_path;
gOrigin + gApp.manifest.launch_path;
});
}
function loadControlled() {
function loadControlled(aUrl) {
return new Promise((resolve, reject) => {
let iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
@@ -105,18 +104,6 @@ function loadControlled() {
ok(true, "Message from app: " + message);
} else if (/KO/.exec(message)) {
ok(false, "Message from app: " + message);
} else if (/HTTPSIFRAMELOADED/.exec(message)) {
let doc = SpecialPowers.wrap(iframe).contentDocument;
let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected-https").contentDocument);
let innerLocation = innerDoc.defaultView.location;
is(innerDoc.domain, "example.org", "Correct domain expected (https)");
is(innerLocation.origin, "https://example.org", "Correct origin expected (https)");
} else if (/IFRAMELOADED/.exec(message)) {
let doc = SpecialPowers.wrap(iframe).contentDocument;
let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected").contentDocument);
let innerLocation = innerDoc.defaultView.location;
is(innerDoc.domain, "example.org", "Correct domain expected");
is(innerLocation.origin, "http://example.org", "Correct origin expected");
} else if (/DONE/.exec(message)) {
ok(true, "Messaging from app complete");
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
@@ -130,10 +117,18 @@ function loadControlled() {
let domParent = document.getElementById('container');
domParent.appendChild(iframe);
SpecialPowers.wrap(iframe.contentWindow).location =
gApp.origin + '/controlled.html';
gOrigin + aUrl;
});
}
function loadBeforeClear() {
return loadControlled('/before_clear.html');
}
function loadAfterClear() {
return loadControlled('/after_clear.html');
}
function uninstallApp() {
return new Promise((resolve, reject) => {
if (!gApp) {
@@ -149,11 +144,15 @@ function runTests() {
setup()
.then(installApp)
.then(launchApp)
.then(loadControlled)
.then(loadBeforeClear)
.then(uninstallApp)
.then(installApp)
.then(launchApp)
.then(loadAfterClear)
.then(uninstallApp)
.then(SimpleTest.finish)
.catch((e) => {
ok(false, 'Unexpected error ' + e);
ok(false, 'Unexpected error ' + e.target.error.name);
SimpleTest.finish();
});
}
+10 -2
View File
@@ -4,10 +4,18 @@ var urlBase = 'https://example.com/tests/dom/cache/test/mochitest';
var url1 = urlBase + '/test_cache.js';
var url2 = urlBase + '/test_cache_add.js';
function addOpaque(cache, url) {
return fetch(new Request(url, { mode: 'no-cors' })).then(function(response) {
return cache.put(url, response);
});
}
caches.open(name).then(function(c) {
cache = c;
return cache.addAll([new Request(url1, { mode: 'no-cors' }),
new Request(url2, { mode: 'no-cors' })]);
return Promise.all([
addOpaque(cache, url1),
addOpaque(cache, url2)
]);
}).then(function() {
return cache.delete(url1);
}).then(function(result) {
+1 -1
View File
@@ -59,7 +59,7 @@ SpecialPowers.pushPrefEnv({
var fullUsage = 0;
var resetUsage = 0;
var endUsage = 0;
var url = 'cache_add.js';
var url = 'test_cache_add.js';
// start from a fresh origin directory so other tests do not influence our
// results
+1 -1
View File
@@ -58,7 +58,7 @@ SpecialPowers.pushPrefEnv({
var fullUsage = 0;
var resetUsage = 0;
var endUsage = 0;
var url = 'cache_add.js';
var url = 'test_cache_add.js';
// start from a fresh origin directory so other tests do not influence our
// results
+15 -1
View File
@@ -9,6 +9,18 @@
</head>
<body>
<script class="testbody" type="text/javascript">
function setupTestIframe() {
return new Promise(function(resolve) {
var iframe = document.createElement("iframe");
iframe.src = "empty.html";
iframe.onload = function() {
window.caches = iframe.contentWindow.caches;
resolve();
};
document.body.appendChild(iframe);
});
}
function resetStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
@@ -24,7 +36,9 @@ SpecialPowers.pushPrefEnv({
var name = 'foo';
var url = './test_cache_add.js';
var cache;
caches.open(name).then(function(c) {
setupTestIframe().then(function() {
return caches.open(name);
}).then(function(c) {
cache = c;
return cache.add(url);
}).then(function() {
+15 -1
View File
@@ -10,6 +10,18 @@
</head>
<body>
<script class="testbody" type="text/javascript">
function setupTestIframe() {
return new Promise(function(resolve) {
var iframe = document.createElement("iframe");
iframe.src = "empty.html";
iframe.onload = function() {
window.caches = iframe.contentWindow.caches;
resolve();
};
document.body.appendChild(iframe);
});
}
function clearStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
@@ -47,7 +59,9 @@ SpecialPowers.pushPrefEnv({
var endUsage = 0;
// start from a fresh origin directory so other tests do not influence our
// results
clearStorage().then(function() {
setupTestIframe().then(function() {
return clearStorage();
}).then(function() {
return storageUsage();
}).then(function(usage) {
is(0, usage, 'disk usage should be zero to start');
+2 -2
View File
@@ -12,11 +12,11 @@ namespace mozilla {
namespace dom {
class BlobImpl;
}
} // namespace dom
namespace layers {
class Image;
}
} // namespace layers
class CameraControlListener
{
+1 -1
View File
@@ -1648,7 +1648,7 @@ nsDOMCameraControl::OnUserError(CameraControlListener::UserContext aContext, nsr
break;
case CameraControlListener::kInSetConfiguration:
if (mSetInitialConfig) {
if (mSetInitialConfig && mCameraControl) {
// If the SetConfiguration() call in the constructor fails, there
// is nothing we can do except release the camera hardware. This
// will trigger a hardware state change, and when the flag that
+3 -12
View File
@@ -2213,17 +2213,6 @@ nsGonkCameraControl::LoadRecorderProfiles()
return NS_OK;
}
/* static */ PLDHashOperator
nsGonkCameraControl::Enumerate(const nsAString& aProfileName,
RecorderProfile* aProfile,
void* aUserArg)
{
nsTArray<nsString>* profiles = static_cast<nsTArray<nsString>*>(aUserArg);
MOZ_ASSERT(profiles);
profiles->AppendElement(aProfileName);
return PL_DHASH_NEXT;
}
nsresult
nsGonkCameraControl::GetRecorderProfiles(nsTArray<nsString>& aProfiles)
{
@@ -2233,7 +2222,9 @@ nsGonkCameraControl::GetRecorderProfiles(nsTArray<nsString>& aProfiles)
}
aProfiles.Clear();
mRecorderProfiles.EnumerateRead(Enumerate, static_cast<void*>(&aProfiles));
for (auto iter = mRecorderProfiles.Iter(); !iter.Done(); iter.Next()) {
aProfiles.AppendElement(iter.Key());
}
return NS_OK;
}
-3
View File
@@ -156,9 +156,6 @@ protected:
void CreatePoster(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight, int32_t aRotation);
nsresult LoadRecorderProfiles();
static PLDHashOperator Enumerate(const nsAString& aProfileName,
RecorderProfile* aProfile,
void* aUserArg);
friend class SetPictureSize;
friend class SetThumbnailSize;
+65 -8
View File
@@ -28,6 +28,9 @@
#include "mozilla/layers/TextureClient.h"
#include "CameraPreferences.h"
#include "mozilla/RefPtr.h"
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
#include "GonkBufferQueueProducer.h"
#endif
#include "GonkCameraControl.h"
#include "CameraCommon.h"
@@ -50,6 +53,7 @@ GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, ui
, mTarget(aTarget)
, mRawSensorOrientation(0)
, mSensorOrientation(0)
, mEmulated(false)
{
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget);
}
@@ -191,6 +195,11 @@ GonkCameraHardware::Init()
}
DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation);
if (__system_property_get("ro.kernel.qemu", prop) > 0 && atoi(prop)) {
DOM_CAMERA_LOGI("Using emulated camera\n");
mEmulated = true;
}
// Disable shutter sound in android CameraService because gaia camera app will play it
mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);
@@ -198,6 +207,7 @@ GonkCameraHardware::Init()
sp<IGraphicBufferProducer> producer;
sp<IGonkGraphicBufferConsumer> consumer;
GonkBufferQueue::createBufferQueue(&producer, &consumer);
static_cast<GonkBufferQueueProducer*>(producer.get())->setSynchronousMode(false);
mNativeWindow = new GonkNativeWindow(consumer, GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
mCamera->setPreviewTarget(producer);
#elif ANDROID_VERSION >= 19
@@ -318,10 +328,19 @@ GonkCameraHardware::GetSensorOrientation(uint32_t aType)
}
}
bool
GonkCameraHardware::IsEmulated()
{
return mEmulated;
}
int
GonkCameraHardware::AutoFocus()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->autoFocus();
}
@@ -329,6 +348,9 @@ int
GonkCameraHardware::CancelAutoFocus()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->cancelAutoFocus();
}
@@ -336,8 +358,11 @@ int
GonkCameraHardware::StartFaceDetection()
{
DOM_CAMERA_LOGI("%s\n", __func__);
int rv = INVALID_OPERATION;
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
int rv = INVALID_OPERATION;
#if ANDROID_VERSION >= 15
rv = mCamera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0);
#endif
@@ -352,8 +377,11 @@ int
GonkCameraHardware::StopFaceDetection()
{
DOM_CAMERA_LOGI("%s\n", __func__);
int rv = INVALID_OPERATION;
if (mClosing) {
return DEAD_OBJECT;
}
int rv = INVALID_OPERATION;
#if ANDROID_VERSION >= 15
rv = mCamera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0);
#endif
@@ -367,6 +395,9 @@ GonkCameraHardware::StopFaceDetection()
int
GonkCameraHardware::TakePicture()
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->takePicture(CAMERA_MSG_SHUTTER | CAMERA_MSG_COMPRESSED_IMAGE);
}
@@ -379,6 +410,9 @@ GonkCameraHardware::CancelTakePicture()
int
GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
const String8 s = aParams.Flatten();
return mCamera->setParameters(s);
}
@@ -386,6 +420,9 @@ GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
nsresult
GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return NS_ERROR_NOT_AVAILABLE;
}
const String8 s = mCamera->getParameters();
return aParams.Unflatten(s);
}
@@ -394,6 +431,9 @@ GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
int
GonkCameraHardware::PushParameters(const CameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
String8 s = aParams.flatten();
return mCamera->setParameters(s);
}
@@ -401,8 +441,10 @@ GonkCameraHardware::PushParameters(const CameraParameters& aParams)
void
GonkCameraHardware::PullParameters(CameraParameters& aParams)
{
const String8 s = mCamera->getParameters();
aParams.unflatten(s);
if (!NS_WARN_IF(mClosing)) {
const String8 s = mCamera->getParameters();
aParams.unflatten(s);
}
}
#endif
@@ -410,6 +452,9 @@ int
GonkCameraHardware::StartPreview()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->startPreview();
}
@@ -417,16 +462,20 @@ void
GonkCameraHardware::StopPreview()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
mCamera->stopPreview();
if (!mClosing) {
mCamera->stopPreview();
}
}
int
GonkCameraHardware::StartRecording()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
int rv = OK;
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
rv = mCamera->startRecording();
int rv = mCamera->startRecording();
if (rv != OK) {
DOM_CAMERA_LOGE("mHardware->startRecording() failed with status %d", rv);
}
@@ -437,6 +486,9 @@ int
GonkCameraHardware::StopRecording()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (mClosing) {
return DEAD_OBJECT;
}
mCamera->stopRecording();
return OK;
}
@@ -452,12 +504,17 @@ GonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener)
void
GonkCameraHardware::ReleaseRecordingFrame(const sp<IMemory>& aFrame)
{
mCamera->releaseRecordingFrame(aFrame);
if (!NS_WARN_IF(mClosing)) {
mCamera->releaseRecordingFrame(aFrame);
}
}
#endif
int
GonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->storeMetaDataInBuffers(aEnabled);
}
+3
View File
@@ -99,6 +99,8 @@ public:
};
virtual int GetSensorOrientation(uint32_t aType = RAW_SENSOR_ORIENTATION);
virtual bool IsEmulated();
/**
* MIN_UNDEQUEUED_BUFFERS has increased to 4 since Android JB. For FFOS, more
* than 3 gralloc buffers are necessary between ImageHost and GonkBufferQueue
@@ -140,6 +142,7 @@ protected:
#endif
int mRawSensorOrientation;
int mSensorOrientation;
bool mEmulated;
private:
GonkCameraHardware(const GonkCameraHardware&) = delete;
+9 -17
View File
@@ -69,27 +69,19 @@ GonkCameraParameters::FindVendorSpecificKey(const char* aPotentialKeys[],
return nullptr;
}
/* static */ PLDHashOperator
GonkCameraParameters::EnumerateFlatten(const nsACString& aKey,
nsCString* aValue,
void* aUserArg)
{
nsCString* data = static_cast<nsCString*>(aUserArg);
if (!data->IsEmpty()) {
data->Append(';');
}
data->Append(aKey);
data->Append('=');
data->Append(*aValue);
return PL_DHASH_NEXT;
}
String8
GonkCameraParameters::Flatten() const
{
MutexAutoLock lock(mLock);
nsCString data;
mParams.EnumerateRead(EnumerateFlatten, static_cast<void*>(&data));
for (auto iter = mParams.ConstIter(); !iter.Done(); iter.Next()) {
if (!data.IsEmpty()) {
data.Append(';');
}
data.Append(iter.Key());
data.Append('=');
data.Append(*iter.UserData());
}
return String8(data.Data());
}
@@ -106,7 +98,7 @@ GonkCameraParameters::Unflatten(const String8& aFlatParameters)
break;
}
nsAutoCString key(data, pos - data);
nsDependentCSubstring key(data, pos - data);
data = pos + 1;
nsCString* value;
+14 -13
View File
@@ -93,18 +93,19 @@ protected:
nsClassHashtable<nsStringHashKey, nsCString> mIsoModeMap;
nsClassHashtable<nsCStringHashKey, nsCString> mParams;
static PLDHashOperator EnumerateFlatten(const nsACString& aKey, nsCString* aValue, void* aUserArg);
nsresult SetImpl(const char* aKey, const char* aValue)
{
nsCString key(aKey);
if (!aValue || strchr(aValue, ';') || strchr(aValue, '=')) {
return NS_ERROR_ILLEGAL_VALUE;
}
nsDependentCString key(aKey);
mParams.Put(key, new nsCString(aValue));
return NS_OK;
}
nsresult SetImpl(const char* aKey, int aValue)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value = new nsCString();
value->AppendInt(aValue);
mParams.Put(key, value);
@@ -113,7 +114,7 @@ protected:
nsresult SetImpl(const char* aKey, double aValue)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value = new nsCString();
value->AppendFloat(aValue);
mParams.Put(key, value);
@@ -122,7 +123,7 @@ protected:
nsresult SetImpl(const char* aKey, float aValue)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value = new nsCString();
value->AppendFloat(aValue);
mParams.Put(key, value);
@@ -131,14 +132,14 @@ protected:
nsresult SetImpl(const char* aKey, bool aValue)
{
nsCString key(aKey);
nsDependentCString key(aKey);
mParams.Put(key, new nsCString(aValue ? "true" : "false"));
return NS_OK;
}
nsresult GetImpl(const char* aKey, const char*& aRet)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value;
if (!mParams.Get(key, &value)) {
aRet = nullptr;
@@ -150,7 +151,7 @@ protected:
nsresult GetImpl(const char* aKey, float& aRet)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
@@ -163,7 +164,7 @@ protected:
nsresult GetImpl(const char* aKey, double& aRet)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
@@ -176,7 +177,7 @@ protected:
nsresult GetImpl(const char* aKey, int& aRet)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
@@ -189,7 +190,7 @@ protected:
nsresult GetImpl(const char* aKey, bool& aRet)
{
nsCString key(aKey);
nsDependentCString key(aKey);
nsCString* value;
if (!mParams.Get(key, &value)) {
aRet = false;
@@ -228,7 +229,7 @@ protected:
nsresult
ClearImpl(const char* aKey)
{
nsCString key(aKey);
nsDependentCString key(aKey);
mParams.Remove(key);
return NS_OK;
}
+3 -1
View File
@@ -1561,7 +1561,9 @@ status_t GonkRecorder::setupVideoEncoder(
// CHECK_EQ causes an abort if the given condition fails.
CHECK_EQ(client.connect(), (status_t)OK);
uint32_t encoder_flags = OMXCodec::kHardwareCodecsOnly;
uint32_t encoder_flags = mCameraHw->IsEmulated()
? 0
: OMXCodec::kHardwareCodecsOnly;
if (mIsMetaDataStoredInVideoBuffers) {
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
+3 -13
View File
@@ -269,18 +269,6 @@ GonkRecorderProfile::GonkRecorderProfile(uint32_t aCameraId,
mIsValid = isValid && mAudio.IsValid() && mVideo.IsValid();
}
/* static */ PLDHashOperator
GonkRecorderProfile::Enumerate(const nsAString& aProfileName,
GonkRecorderProfile* aProfile,
void* aUserArg)
{
nsTArray<RefPtr<ICameraControl::RecorderProfile>>* profiles =
static_cast<nsTArray<RefPtr<ICameraControl::RecorderProfile>>*>(aUserArg);
MOZ_ASSERT(profiles);
profiles->AppendElement(aProfile);
return PL_DHASH_NEXT;
}
/* static */
already_AddRefed<GonkRecorderProfile>
GonkRecorderProfile::CreateProfile(uint32_t aCameraId, int aQuality)
@@ -379,7 +367,9 @@ GonkRecorderProfile::GetAll(uint32_t aCameraId,
}
aProfiles.Clear();
profiles->EnumerateRead(Enumerate, static_cast<void*>(&aProfiles));
for (auto iter = profiles->Iter(); !iter.Done(); iter.Next()) {
aProfiles.AppendElement(iter.UserData());
}
return NS_OK;
}
-3
View File
@@ -142,9 +142,6 @@ protected:
static already_AddRefed<GonkRecorderProfile> CreateProfile(uint32_t aCameraId,
int aQuality);
static ProfileHashtable* GetProfileHashtable(uint32_t aCameraId);
static PLDHashOperator Enumerate(const nsAString& aProfileName,
GonkRecorderProfile* aProfile,
void* aUserArg);
uint32_t mCameraId;
int mQuality;
+6
View File
@@ -357,6 +357,12 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type));
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER:
if (IsWebGL2())
return JS::BooleanValue(mBoundVertexArray->mAttribs[index].integer);
break;
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
if (IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
+17 -10
View File
@@ -32,15 +32,17 @@ WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
fua->AllowUnsizedTexFormat(pi, usage);
};
const bool needSizedInternal = !gl->IsGLES();
MOZ_ASSERT_IF(needSizedInternal, gl->IsSupported(gl::GLFeature::texture_swizzle));
const bool needsSwizzle = gl->IsCoreProfile();
MOZ_ASSERT_IF(needsSwizzle, gl->IsSupported(gl::GLFeature::texture_swizzle));
const bool needsSizedFormat = !gl->IsGLES();
////////////////
pi = {LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_RGBA32F;
}
fnAdd(webgl::EffectiveFormat::RGBA32F);
@@ -50,7 +52,7 @@ WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
pi = {LOCAL_GL_RGB, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_RGB32F;
}
fnAdd(webgl::EffectiveFormat::RGB32F);
@@ -60,9 +62,11 @@ WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSwizzle) {
dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
} else if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_LUMINANCE32F_ARB;
}
fnAdd(webgl::EffectiveFormat::Luminance32F);
@@ -71,9 +75,11 @@ WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
pi = {LOCAL_GL_ALPHA, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSwizzle) {
dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
} else if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_ALPHA32F_ARB;
}
fnAdd(webgl::EffectiveFormat::Alpha32F);
@@ -82,9 +88,11 @@ WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSwizzle) {
dui = {LOCAL_GL_RG32F, LOCAL_GL_RG, LOCAL_GL_FLOAT};
swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
} else if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
}
fnAdd(webgl::EffectiveFormat::Luminance32FAlpha32F);
}
@@ -101,10 +109,9 @@ WebGLExtensionTextureFloat::IsSupported(const WebGLContext* webgl)
if (!gl->IsSupported(gl::GLFeature::texture_float))
return false;
const bool needSizedInternal = !gl->IsGLES();
const bool needsSwizzle = gl->IsCoreProfile();
const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle);
if (needSizedInternal && !hasSwizzle)
if (needsSwizzle && !hasSwizzle)
return false;
return true;
+17 -10
View File
@@ -30,8 +30,10 @@ WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* web
fua->AllowUnsizedTexFormat(pi, usage);
};
const bool needSizedInternal = !gl->IsGLES();
MOZ_ASSERT_IF(needSizedInternal, gl->IsSupported(gl::GLFeature::texture_swizzle));
const bool needsSwizzle = gl->IsCoreProfile();
MOZ_ASSERT_IF(needsSwizzle, gl->IsSupported(gl::GLFeature::texture_swizzle));
const bool needsSizedFormat = !gl->IsGLES();
GLenum driverUnpackType = LOCAL_GL_HALF_FLOAT;
if (!gl->IsSupported(gl::GLFeature::texture_half_float)) {
@@ -44,7 +46,7 @@ WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* web
pi = {LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_RGBA16F;
}
fnAdd(webgl::EffectiveFormat::RGBA16F);
@@ -54,7 +56,7 @@ WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* web
pi = {LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_RGB16F;
}
fnAdd(webgl::EffectiveFormat::RGB16F);
@@ -64,9 +66,11 @@ WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* web
pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSwizzle) {
dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
} else if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_LUMINANCE16F_ARB;
}
fnAdd(webgl::EffectiveFormat::Luminance16F);
@@ -75,9 +79,11 @@ WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* web
pi = {LOCAL_GL_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSwizzle) {
dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
} else if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_ALPHA16F_ARB;
}
fnAdd(webgl::EffectiveFormat::Alpha16F);
@@ -86,9 +92,11 @@ WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* web
pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
if (needsSwizzle) {
dui = {LOCAL_GL_RG16F, LOCAL_GL_RG, driverUnpackType};
swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
} else if (needsSizedFormat) {
dui.internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB;
}
fnAdd(webgl::EffectiveFormat::Luminance16FAlpha16F);
}
@@ -108,10 +116,9 @@ WebGLExtensionTextureHalfFloat::IsSupported(const WebGLContext* webgl)
return false;
}
const bool needSizedInternal = !gl->IsGLES();
const bool needsSwizzle = gl->IsCoreProfile();
const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle);
if (needSizedInternal && !hasSwizzle)
if (needsSwizzle && !hasSwizzle)
return false;
return true;
+13 -7
View File
@@ -560,11 +560,14 @@ FormatUsageAuthority::CreateForWebGL1(gl::GLContext* gl)
// RGBA8 is made renderable in WebGL 1.0, "Framebuffer Object Attachments"
// render filter
// able able
fnSet(EffectiveFormat::RGBA8 , true , true);
fnSet(EffectiveFormat::RGBA4 , true , true);
fnSet(EffectiveFormat::RGB5_A1, true , true);
fnSet(EffectiveFormat::RGB8 , false, true);
fnSet(EffectiveFormat::RGB565 , true , true);
fnSet(EffectiveFormat::RGBA8 , true, true);
fnSet(EffectiveFormat::RGBA4 , true, true);
fnSet(EffectiveFormat::RGB5_A1, true, true);
fnSet(EffectiveFormat::RGB565 , true, true);
// RGB8 is not guaranteed to be renderable, but we should allow it for web-compat.
// Min-capability mode should mark this as non-renderable.
fnSet(EffectiveFormat::RGB8, true, true);
fnSet(EffectiveFormat::Luminance8Alpha8, false, true);
fnSet(EffectiveFormat::Luminance8 , false, true);
@@ -803,7 +806,7 @@ FormatUsageAuthority::CreateForWebGL2(gl::GLContext* gl)
// GLES 3.0.4, p147, table 3.19
// GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
#if ALLOW_ES3_FORMATS
// Note that all compressed texture formats are filterable:
// GLES 3.0.4 p161:
// "[A] texture is complete unless any of the following conditions hold true:
@@ -823,7 +826,7 @@ FormatUsageAuthority::CreateForWebGL2(gl::GLContext* gl)
fnAllowES3TexFormat(FOO(COMPRESSED_SIGNED_RG11_EAC ), false, true);
fnAllowES3TexFormat(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ), false, true);
fnAllowES3TexFormat(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2), false, true);
#endif
#undef FOO
// GLES 3.0.4, p206, "Required Renderbuffer Formats":
@@ -840,6 +843,9 @@ FormatUsageAuthority::CreateForWebGL2(gl::GLContext* gl)
if (!AddUnsizedFormats(ptr, gl))
return nullptr;
ptr->AllowRBFormat(LOCAL_GL_DEPTH_STENCIL,
ptr->GetUsage(EffectiveFormat::DEPTH24_STENCIL8));
if (gfxPrefs::WebGL2CompatMode()) {
AddSimpleUnsized(ptr, LOCAL_GL_RGBA, LOCAL_GL_FLOAT, EffectiveFormat::RGBA32F);
AddSimpleUnsized(ptr, LOCAL_GL_RGB , LOCAL_GL_FLOAT, EffectiveFormat::RGB32F );
+7 -4
View File
@@ -172,10 +172,12 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
// Collect active locations:
GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
if (loc == -1)
MOZ_CRASH("Active attrib has no location.");
info->activeAttribLocs.insert(loc);
if (loc == -1) {
if (mappedName != "gl_InstanceID")
MOZ_CRASH("Active attrib has no location.");
} else {
info->activeAttribLocs.insert(loc);
}
}
// Uniforms
@@ -599,6 +601,7 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
if (mContext->IsWebGL2()) {
switch (pname) {
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
+24 -6
View File
@@ -133,7 +133,13 @@ WebGLContext::CreateShaderValidator(GLenum shaderType) const
return nullptr;
ShShaderSpec spec = IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC;
ShShaderOutput outputLanguage = ShaderOutput(gl);
ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT
: SH_GLSL_OUTPUT;
// If we're using WebGL2 we want a more specific version of GLSL
if (IsWebGL2())
outputLanguage = ShaderOutput(gl);
ShBuiltInResources resources;
memset(&resources, 0, sizeof(resources));
ShInitBuiltInResources(&resources);
@@ -147,18 +153,21 @@ WebGLContext::CreateShaderValidator(GLenum shaderType) const
resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
resources.MaxDrawBuffers = mGLMaxDrawBuffers;
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
const bool hasMRTs = (IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers));
resources.MaxDrawBuffers = (hasMRTs ? mGLMaxDrawBuffers : 1);
if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
resources.EXT_frag_depth = 1;
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
resources.OES_standard_derivatives = 1;
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
resources.EXT_draw_buffers = 1;
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
resources.EXT_shader_texture_lod = 1;
// Tell ANGLE to allow highp in frag shaders. (unless disabled)
@@ -247,6 +256,15 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
return false;
}
if (ShGetShaderVersion(prev->mHandle) != ShGetShaderVersion(mHandle)) {
nsPrintfCString error("Vertex shader version %d does not match"
" fragment shader version %d.",
ShGetShaderVersion(prev->mHandle),
ShGetShaderVersion(mHandle));
*out_log = error;
return false;
}
{
const std::vector<sh::Uniform>* vertPtr = ShGetUniforms(prev->mHandle);
const std::vector<sh::Uniform>* fragPtr = ShGetUniforms(mHandle);
+7 -7
View File
@@ -275,14 +275,14 @@ STRONG_GLENUM_BEGIN(TexCompareMode)
STRONG_GLENUM_END(TexCompareMode)
STRONG_GLENUM_BEGIN(TexCompareFunc)
STRONG_GLENUM_VALUE(LEQUAL),
STRONG_GLENUM_VALUE(GEQUAL),
STRONG_GLENUM_VALUE(LESS),
STRONG_GLENUM_VALUE(GREATER),
STRONG_GLENUM_VALUE(EQUAL),
STRONG_GLENUM_VALUE(NOTEQUAL),
STRONG_GLENUM_VALUE(ALWAYS),
STRONG_GLENUM_VALUE(NEVER),
STRONG_GLENUM_VALUE(LESS),
STRONG_GLENUM_VALUE(EQUAL),
STRONG_GLENUM_VALUE(LEQUAL),
STRONG_GLENUM_VALUE(GREATER),
STRONG_GLENUM_VALUE(NOTEQUAL),
STRONG_GLENUM_VALUE(GEQUAL),
STRONG_GLENUM_VALUE(ALWAYS),
STRONG_GLENUM_END(TexCompareFunc)
STRONG_GLENUM_BEGIN(TexFormat)
+30 -3
View File
@@ -164,9 +164,11 @@ WebGLTexture::MemoryUsage() const
if (IsDeleted())
return 0;
size_t result = 0;
MOZ_CRASH("todo");
return result;
size_t accum = 0;
for (const auto& cur : mImageInfoArr) {
accum += cur.MemoryUsage();
}
return accum;
}
void
@@ -740,6 +742,31 @@ WebGLTexture::GenerateMipmap(TexTarget texTarget)
return;
}
// OpenGL ES 3.0.4 p160:
// If the level base array was not specified with an unsized internal format from
// table 3.3 or a sized internal format that is both color-renderable and
// texture-filterable according to table 3.13, an INVALID_OPERATION error
// is generated.
const auto usage = baseImageInfo.mFormat;
bool canGenerateMipmap = (usage->isRenderable && usage->isFilterable);
switch (usage->format->effectiveFormat) {
case webgl::EffectiveFormat::Luminance8:
case webgl::EffectiveFormat::Alpha8:
case webgl::EffectiveFormat::Luminance8Alpha8:
// Non-color-renderable formats from Table 3.3.
canGenerateMipmap = true;
break;
default:
break;
}
if (!canGenerateMipmap) {
mContext->ErrorInvalidOperation("generateMipmap: Texture at base level is not unsized"
" internal format or is not"
" color-renderable or texture-filterable.");
return;
}
// Done with validation. Do the operation.
mContext->MakeContextCurrent();
+2 -1
View File
@@ -1784,7 +1784,8 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
GLenum error;
if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) {
error = DoCopyTexImage2D(gl, target, level, internalFormat, x, y, width, height,
MOZ_ASSERT(dstUsage->idealUnpack);
error = DoCopyTexImage2D(gl, target, level, dstUsage->idealUnpack->internalFormat, x, y, width, height,
border);
} else {
// 1. Zero the texture data.
+1 -1
View File
@@ -141,7 +141,7 @@ ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl, const char*
if (name.IsEmpty())
return false;
const uint32_t maxSize = 256;
const uint32_t maxSize = webgl->IsWebGL2() ? 1024 : 256;
if (name.Length() > maxSize) {
webgl->ErrorInvalidValue("%s: Identifier is %d characters long, exceeds the"
" maximum allowed length of %d characters.",
+7 -1
View File
@@ -52,12 +52,18 @@ struct WebGLVertexAttribData
case LOCAL_GL_UNSIGNED_SHORT:
return sizeof(GLushort);
case LOCAL_GL_INT:
return sizeof(GLint);
case LOCAL_GL_UNSIGNED_INT:
return sizeof(GLuint);
// case LOCAL_GL_FIXED:
case LOCAL_GL_FLOAT:
return sizeof(GLfloat);
default:
NS_ERROR("Should never get here!");
MOZ_ASSERT(false, "Should never get here!");
return 0;
}
}
@@ -205,11 +205,7 @@ function beginTest() {
}
}
var prefs = [
[ "canvas.capturestream.enabled", true ],
];
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
beginTest();
</script>
</pre>
</body>
@@ -211,13 +211,8 @@ function beginTest() {
document.manager.runTests(corsTests, startTest);
}
var prefs = [
[ "canvas.capturestream.enabled", true ],
];
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
beginTest();
</script>
</pre>
</body>
+2 -2
View File
@@ -20,7 +20,7 @@ pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback wrappe
== webgl-resize-test.html wrapper.html?green.png
# Check that captureStream() displays in a local video element
pref(canvas.capturestream.enabled,true) skip-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-capturestream-test.html?preserve wrapper.html?green.png
skip-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-capturestream-test.html?preserve wrapper.html?green.png
# Some of the failure conditions are a little crazy. I'm (jgilbert) setting these based on
# failures encountered when running on Try, and then targetting the Try config by
@@ -157,6 +157,6 @@ pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion
pref(canvas.customfocusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html
# Check that captureStream() displays in a local video element
pref(canvas.capturestream.enabled,true) skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png
skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png
fuzzy-if(Android,3,40) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html
+1 -4
View File
@@ -107,9 +107,6 @@ function beginTest() {
SimpleTest.waitForExplicitFinish();
var prefs = [
[ "canvas.capturestream.enabled", true ],
];
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
beginTest();
</script>
@@ -171,9 +171,6 @@ function beginTest() {
SimpleTest.waitForExplicitFinish();
var prefs = [
[ "canvas.capturestream.enabled", true ],
];
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
beginTest();
</script>
+86 -19
View File
@@ -21,6 +21,12 @@ XPCOMUtils.defineLazyServiceGetter(this, "volumeService",
"@mozilla.org/telephony/volume-service;1",
"nsIVolumeService");
/**
* The content process implementations of navigator.mozDownloadManager and its
* DOMDownload download objects. Uses DownloadsIPC.jsm to communicate with
* DownloadsAPI.jsm in the parent process.
*/
function debug(aStr) {
#ifdef MOZ_DEBUG
dump("-*- DownloadsAPI.js : " + aStr + "\n");
@@ -40,6 +46,15 @@ DOMDownloadManagerImpl.prototype = {
this.initDOMRequestHelper(aWindow,
["Downloads:Added",
"Downloads:Removed"]);
// Get the manifest URL if this is an installed app
let appsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
let principal = aWindow.document.nodePrincipal;
// This returns the empty string if we're not an installed app. Coerce to
// null.
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId) ||
null;
},
uninit: function() {
@@ -79,23 +94,8 @@ DOMDownloadManagerImpl.prototype = {
clearAllDone: function() {
debug("clearAllDone()");
return this.createPromise(function (aResolve, aReject) {
DownloadsIPC.clearAllDone().then(
function(aDownloads) {
// Turn the list of download objects into DOM objects and
// send them.
let array = new this._window.Array();
for (let id in aDownloads) {
let dom = createDOMDownloadObject(this._window, aDownloads[id]);
array.push(this._prepareForContent(dom));
}
aResolve(array);
}.bind(this),
function() {
aReject("ClearAllDoneError");
}
);
}.bind(this));
// This is a void function; we just kick it off. No promises, etc.
DownloadsIPC.clearAllDone();
},
remove: function(aDownload) {
@@ -121,6 +121,67 @@ DOMDownloadManagerImpl.prototype = {
}.bind(this));
},
adoptDownload: function(aAdoptDownloadDict) {
// Our AdoptDownloadDict only includes simple types, which WebIDL enforces.
// We have no object/any types so we do not need to worry about invoking
// JSON.stringify (and it inheriting our security privileges).
debug("adoptDownload");
return this.createPromise(function (aResolve, aReject) {
if (!aAdoptDownloadDict) {
debug("Download dictionary is required!");
aReject("InvalidDownload");
return;
}
if (!aAdoptDownloadDict.storageName || !aAdoptDownloadDict.storagePath ||
!aAdoptDownloadDict.contentType) {
debug("Missing one of: storageName, storagePath, contentType");
aReject("InvalidDownload");
return;
}
// Convert storageName/storagePath to a local filesystem path.
let volume;
// getVolumeByName throws if you give it something it doesn't like
// because XPConnect converts the NS_ERROR_NOT_AVAILABLE to an
// exception. So catch it.
try {
volume = volumeService.getVolumeByName(aAdoptDownloadDict.storageName);
} catch (ex) {}
if (!volume) {
debug("Invalid storage name: " + aAdoptDownloadDict.storageName);
aReject("InvalidDownload");
return;
}
let computedPath = volume.mountPoint + '/' +
aAdoptDownloadDict.storagePath;
// We validate that there is actually a file at the given path in the
// parent process in DownloadsAPI.js because that's where the file
// access would actually occur either way.
// Create a DownloadsAPI.jsm 'jsonDownload' style representation.
let jsonDownload = {
url: aAdoptDownloadDict.url,
path: computedPath,
contentType: aAdoptDownloadDict.contentType,
startTime: aAdoptDownloadDict.startTime.valueOf() || Date.now(),
sourceAppManifestURL: this._manifestURL
};
DownloadsIPC.adoptDownload(jsonDownload).then(
function(aResult) {
let domDownload = createDOMDownloadObject(this._window, aResult);
aResolve(this._prepareForContent(domDownload));
}.bind(this),
function(aResult) {
// This will be one of: AdoptError (generic catch-all),
// AdoptNoSuchFile, AdoptFileIsDirectory
aReject(aResult.error);
}
);
}.bind(this));
},
/**
* Turns a chrome download object into a content accessible one.
* When we have __DOM_IMPL__ available we just use that, otherwise
@@ -295,6 +356,11 @@ DOMDownloadImpl.prototype = {
}
},
/**
* Initialize a DOMDownload instance for the given window using the
* 'jsonDownload' serialized format of the download encoded by
* DownloadsAPI.jsm.
*/
_init: function(aWindow, aDownload) {
this._window = aWindow;
this.id = aDownload.id;
@@ -314,12 +380,13 @@ DOMDownloadImpl.prototype = {
}
let props = ["totalBytes", "currentBytes", "url", "path", "storageName",
"storagePath", "state", "contentType", "startTime"];
"storagePath", "state", "contentType", "startTime",
"sourceAppManifestURL"];
let changed = false;
let changedProps = {};
props.forEach((prop) => {
if (aDownload[prop] && (aDownload[prop] != this[prop])) {
if (prop in aDownload && (aDownload[prop] != this[prop])) {
this[prop] = aDownload[prop];
changedProps[prop] = changed = true;
}
+108 -11
View File
@@ -13,11 +13,19 @@ this.EXPORTED_SYMBOLS = [];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Downloads.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
/**
* Parent process logic that services download API requests from the
* DownloadAPI.js instances in content processeses. The actual work of managing
* downloads is done by Toolkit's Downloads.jsm. This module is loaded by B2G's
* shell.js
*/
function debug(aStr) {
#ifdef MOZ_DEBUG
dump("-*- DownloadsAPI.jsm : " + aStr + "\n");
@@ -49,7 +57,8 @@ let DownloadsAPI = {
"Downloads:ClearAllDone",
"Downloads:Remove",
"Downloads:Pause",
"Downloads:Resume"].forEach((msgName) => {
"Downloads:Resume",
"Downloads:Adopt"].forEach((msgName) => {
ppmm.addMessageListener(msgName, this);
});
@@ -92,7 +101,9 @@ let DownloadsAPI = {
url: aDownload.source.url,
path: aDownload.target.path,
contentType: aDownload.contentType,
startTime: aDownload.startTime.getTime()
startTime: aDownload.startTime.getTime(),
sourceAppManifestURL: aDownload._unknownProperties &&
aDownload._unknownProperties.sourceAppManifestURL
};
if (aDownload.error) {
@@ -165,6 +176,9 @@ let DownloadsAPI = {
case "Downloads:Resume":
this.resume(aMessage.data, aMessage.target);
break;
case "Downloads:Adopt":
this.adoptDownload(aMessage.data, aMessage.target);
break;
default:
debug("Invalid message: " + aMessage.name);
}
@@ -186,17 +200,9 @@ let DownloadsAPI = {
clearAllDone: function(aData, aMm) {
debug("clearAllDone called!");
let self = this;
Task.spawn(function () {
let list = yield Downloads.getList(Downloads.ALL);
yield list.removeFinished();
list = yield Downloads.getList(Downloads.ALL);
let downloads = yield list.getAll();
let res = [];
downloads.forEach((aDownload) => {
res.push(self.jsonDownload(aDownload));
});
aMm.sendAsyncMessage("Downloads:ClearAllDone:Return", res);
list.removeFinished();
}).then(null, Components.utils.reportError);
},
@@ -262,6 +268,97 @@ let DownloadsAPI = {
aData, "ResumeError");
}
);
},
/**
* Receive a download to adopt in the same representation we produce from
* our "jsonDownload" normalizer and add it to the list of downloads.
*/
adoptDownload: function(aData, aMm) {
let adoptJsonRep = aData.jsonDownload;
debug("adoptDownload " + uneval(adoptJsonRep));
Task.spawn(function* () {
// Verify that the file exists on disk. This will result in a rejection
// if the file does not exist. We will also use this information for the
// file size to avoid weird inconsistencies. We ignore the filesystem
// timestamp in favor of whatever the caller is telling us.
let fileInfo = yield OS.File.stat(adoptJsonRep.path);
// We also require that the file is not a directory.
if (fileInfo.isDir) {
throw new Error("AdoptFileIsDirectory");
}
// We need to create a Download instance to add to the list. Create a
// serialized representation and then from there the instance.
let serializedRep = {
// explicit initializations in toSerializable
source: {
url: adoptJsonRep.url
// This is where isPrivate would go if adoption supported private
// browsing.
},
target: {
path: adoptJsonRep.path,
},
startTime: adoptJsonRep.startTime,
// kPlainSerializableDownloadProperties propagations
succeeded: true, // (all adopted downloads are required to be completed)
totalBytes: fileInfo.size,
contentType: adoptJsonRep.contentType,
// unknown properties added/used by the DownloadsAPI
currentBytes: fileInfo.size,
sourceAppManifestURL: adoptJsonRep.sourceAppManifestURL
};
let download = yield Downloads.createDownload(serializedRep);
// The ALL list is a DownloadCombinedList instance that combines the
// PUBLIC (persisted to disk) and PRIVATE (ephemeral) download lists..
// When we call add on it, it dispatches to the appropriate list based on
// the 'isPrivate' field of the source. (Which we don't initialize and
// defaults to false.)
let allDownloadList = yield Downloads.getList(Downloads.ALL);
// This add will automatically notify all views of the added download,
// including DownloadsAPI instances and the DownloadAutoSaveView that's
// subscribed to the PUBLIC list and will save the download.
yield allDownloadList.add(download);
debug("download adopted");
// The notification above occurred synchronously, and so we will have
// already dispatched an added notification for our download to the child
// process in question. As such, we only need to relay the download id
// since the download will already have been cached.
return download;
}.bind(this)).then(
(download) => {
sendPromiseMessage(aMm, "Downloads:Adopt:Return",
{
id: this.downloadId(download),
promiseId: aData.promiseId
});
},
(ex) => {
let reportAs = "AdoptError";
// Provide better error codes for expected errors.
if (ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
reportAs = "AdoptNoSuchFile";
} else if (ex.message === "AdoptFileIsDirectory") {
reportAs = ex.message;
} else {
// Anything else is unexpected and should be reported to help track
// down what's going wrong.
debug("unexpected download error: " + ex);
Cu.reportError(ex);
}
sendPromiseMessage(aMm, "Downloads:Adopt:Return",
{
promiseId: aData.promiseId
},
reportAs);
});
}
};
+15 -14
View File
@@ -36,10 +36,10 @@ const ipcMessages = ["Downloads:Added",
"Downloads:Removed",
"Downloads:Changed",
"Downloads:GetList:Return",
"Downloads:ClearAllDone:Return",
"Downloads:Remove:Return",
"Downloads:Pause:Return",
"Downloads:Resume:Return"];
"Downloads:Resume:Return",
"Downloads:Adopt:Return"];
this.DownloadsIPC = {
downloads: {},
@@ -54,7 +54,6 @@ this.DownloadsIPC = {
// We need to get the list of current downloads.
this.ready = false;
this.getListPromises = [];
this.clearAllPromises = [];
this.downloadPromises = {};
cpmm.sendAsyncMessage("Downloads:GetList", {});
this._promiseId = 0;
@@ -93,12 +92,6 @@ this.DownloadsIPC = {
}
this.ready = true;
break;
case "Downloads:ClearAllDone:Return":
this._updateDownloadsArray(download);
this.clearAllPromises.forEach(aPromise =>
aPromise.resolve(this.downloads));
this.clearAllPromises.length = 0;
break;
case "Downloads:Added":
this.downloads[download.id] = download;
this.notifyChanges(download.id);
@@ -139,6 +132,7 @@ this.DownloadsIPC = {
case "Downloads:Remove:Return":
case "Downloads:Pause:Return":
case "Downloads:Resume:Return":
case "Downloads:Adopt:Return":
if (this.downloadPromises[download.promiseId]) {
if (!download.error) {
this.downloadPromises[download.promiseId].resolve(download);
@@ -167,14 +161,11 @@ this.DownloadsIPC = {
},
/**
* Returns a promise that is resolved with the list of current downloads.
*/
* Void function to trigger removal of completed downloads.
*/
clearAllDone: function() {
debug("clearAllDone");
let deferred = Promise.defer();
this.clearAllPromises.push(deferred);
cpmm.sendAsyncMessage("Downloads:ClearAllDone", {});
return deferred.promise;
},
promiseId: function() {
@@ -211,6 +202,16 @@ this.DownloadsIPC = {
return deferred.promise;
},
adoptDownload: function(aJsonDownload) {
debug("adoptDownload");
let deferred = Promise.defer();
let pId = this.promiseId();
this.downloadPromises[pId] = deferred;
cpmm.sendAsyncMessage("Downloads:Adopt",
{ jsonDownload: aJsonDownload, promiseId: pId });
return deferred.promise;
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == "xpcom-shutdown") {
ipcMessages.forEach((aMessage) => {
@@ -0,0 +1,67 @@
/**
* A helper to clear out the existing downloads known to the mozDownloadManager
* / downloads.js.
*
* It exists because previously mozDownloadManager.clearAllDone() thought that
* when it returned that all the completed downloads would be cleared out. It
* was wrong and this led to various intermittent test failurse. In discussion
* on https://bugzil.la/979446#c13 and onwards, it was decided that
* clearAllDone() was in the wrong and that the jsdownloads API it depends on
* was not going to change to make it be in the right.
*
* The existing uses of clearAllDone() in tests seemed to be about:
* - Exploding if there was somehow still a download in progress
* - Clearing out the download list at the start of a test so that calls to
* getDownloads() wouldn't have to worry about existing downloads, etc.
*
* From discussion, the right way to handle clearing is to wait for the expected
* removal events to occur for the existing downloads. So that's what we do.
* We still generate a test failure if there are any in-progress downloads.
*
* @param {Boolean} [getDownloads=false]
* If true, invoke getDownloads after clearing the download list and return
* its value.
*/
function clearAllDoneHelper(getDownloads) {
var clearedPromise = new Promise(function(resolve, reject) {
function gotDownloads(downloads) {
// If there are no downloads, we're already done.
if (downloads.length === 0) {
resolve();
return;
}
// Track the set of expected downloads that will be finalized.
var expectedIds = new Set();
function changeHandler(evt) {
var download = evt.download;
if (download.state === "finalized") {
expectedIds.delete(download.id);
if (expectedIds.size === 0) {
resolve();
}
}
}
downloads.forEach(function(download) {
if (download.state === "downloading") {
ok(false, "A download is still active: " + download.path);
reject("Active download");
}
download.onstatechange = changeHandler;
expectedIds.add(download.id);
});
navigator.mozDownloadManager.clearAllDone();
}
function gotBadNews(err) {
ok(false, "Problem clearing all downloads: " + err);
reject(err);
}
navigator.mozDownloadManager.getDownloads().then(gotDownloads, gotBadNews);
});
if (!getDownloads) {
return clearedPromise;
}
return clearedPromise.then(function() {
return navigator.mozDownloadManager.getDownloads();
});
}
+19
View File
@@ -0,0 +1,19 @@
function is(a, b, msg) {
alert((a === b ? 'OK' : 'KO') + ' ' + a + ' should equal ' + b + ': ' + msg);
}
function ok(a, msg) {
alert((a ? 'OK' : 'KO')+ ' ' + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function cbError() {
alert('KO error');
}
function finish() {
alert('DONE');
}
+55
View File
@@ -0,0 +1,55 @@
var gBasePath = "tests/dom/downloads/tests/";
var gTemplate = "file_app.template.webapp";
function handleRequest(request, response) {
var query = getQuery(request);
var testToken = query.testToken || '';
var appType = query.appType || 'web';
var template = gBasePath + gTemplate;
response.setHeader("Content-Type", "application/x-web-app-manifest+json", false);
var body = readTemplate(template)
.replace(/TESTTOKEN/g, testToken)
.replace(/APPTYPE/g, appType);
response.write();
}
// Copy-pasted incantations. There ought to be a better way to synchronously read
// a file into a string, but I guess we're trying to discourage that.
function readTemplate(path) {
var file = Components.classes["@mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("CurWorkD", Components.interfaces.nsILocalFile);
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
createInstance(Components.interfaces.nsIFileInputStream);
var cis = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Components.interfaces.nsIConverterInputStream);
var split = path.split("/");
for(var i = 0; i < split.length; ++i) {
file.append(split[i]);
}
fis.init(file, -1, -1, false);
cis.init(fis, "UTF-8", 0, 0);
var data = "";
let (str = {}) {
let read = 0;
do {
read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value
data += str.value;
} while (read != 0);
}
cis.close();
return data;
}
function getQuery(request) {
var query = {};
request.queryString.split('&').forEach(function (val) {
var [name, value] = val.split('=');
query[name] = unescape(value);
});
return query;
}
@@ -0,0 +1,7 @@
{
"name": "Really Rapid Release (hosted)",
"description": "Updated even faster than <a href='http://mozilla.org'>Firefox</a>, just to annoy slashdotters.",
"type": "APPTYPE",
"launch_path": "/tests/dom/downloads/tests/TESTTOKEN",
"icons": { "128": "default_icon" }
}
+14 -2
View File
@@ -1,12 +1,24 @@
[DEFAULT]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' # bug 979446, frequent failures
# The actual requirement for mozDownloadManager is MOZ_GONK because of
# the nsIVolumeService dependency. Until https://bugzil.la/1130264 is
# addressed, there is no way for mulet to run these tests.
run-if = toolkit == 'gonk'
support-files =
serve_file.sjs
clear_all_done_helper.js
file_app.template.webapp
file_app.sjs
common_app.js
shim_app_as_test.js
shim_app_as_test_chrome.js
testapp_downloads_adopt_download.html
testapp_downloads_adopt_download.js
testapp_downloads_adopt_download.manifest
[test_downloads_navigator_object.html]
[test_downloads_basic.html]
[test_downloads_large.html]
[test_downloads_adopt_download.html]
[test_downloads_bad_file.html]
[test_downloads_pause_remove.html]
[test_downloads_pause_resume.html]
skip-if = toolkit=='gonk' # b2g(bug 947167) b2g-debug(bug 947167)
+210
View File
@@ -0,0 +1,210 @@
/**
* Support logic to run a test file as an installed app. This file is derived
* from dom/requestsync/tests/test_basic_app.html but uses
* DOMApplicationRegistry in a chrome script (shim_app_as_test_chrome.js) to
* directly install the apps instead of mozApps.install because mozApps.install
* can't install privileged/certified apps. (This is the same mechanism used by
* the Firefox OS Gaia email app's backend test runner.)
*
* You really only want to do this if your test cares about the app's origin
* or you REALLY want to double-check AvailableIn and other WebIDL-provided
* security mechanisms.
*
* If you trust WebIDL, your life may be made significantly easier by just
* setting the pref "dom.ignore_webidl_scope_checks" to true, which makes
* BindingUtils.cpp's IsInPrivilegedApp and IsInCertifiedApp return true no
* matter what *on the main thread*. You are potentially out of luck on
* workers since at the time of writing this since the values stored on
* WorkerPrivateParent are based on the app status and ignore the pref.
*
* TO USE THIS:
*
* Make sure you have the usual header boilerplate:
* <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
* <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
*
* You also want to add this file!
* <script type="application/javascript" src="shim_app_as_test.js"></script>
*
* In your script body, issue a call like so:
* runAppTest({
* appFile: 'testapp_downloads_adopt_download.html',
* appManifest: 'testapp_downloads_adopt_download.manifest',
* appType: 'certified',
* extraPrefs: {
* set: [["dom.mozDownloads.enabled", true]]
* }
* });
*
* You shouldn't be adding other stuff to that file. Instead, you want
* everything in your testapp_*.html file. And you probably just want to copy
* and paste from an existing one of those...
*/
var gManifestURL;
var gApp;
var gOptions;
// Load the chrome script.
var gChromeHelper = SpecialPowers.loadChromeScript(
SimpleTest.getTestFileURL('shim_app_as_test_chrome.js'));
function installApp() {
info("installing app");
var useOrigin = document.location.origin;
gChromeHelper.sendAsyncMessage(
'install',
{
origin: useOrigin,
manifestURL: SimpleTest.getTestFileURL(gOptions.appManifest),
});
}
function installedApp(appInfo) {
gApp = appInfo;
ok(!!appInfo, 'installed app');
runTests();
}
gChromeHelper.addMessageListener('installed', installedApp);
function uninstallApp() {
info('uninstalling app');
gChromeHelper.sendAsyncMessage('uninstall', gApp);
}
function uninstalledApp(success) {
ok(success, 'uninstalled app');
runTests();
}
gChromeHelper.addMessageListener('uninstalled', uninstalledApp);
function testApp() {
var cleanupFrame;
var handleTestMessage = function(message) {
if (/^OK/.exec(message)) {
ok(true, "Message from app: " + message);
} else if (/^KO/.exec(message)) {
ok(false, "Message from app: " + message);
} else if (/^INFO/.exec(message)) {
info("Message from app: " + message.substring(5));
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from app complete");
cleanupFrame();
runTests();
}
};
// Bug 1097479 means that embed-webapps does not work if you are already
// OOP, as we are for b2g. So we need to have the chrome script run our
// app in a sibling iframe to the one we're living in. When that bug is
// fixed or we are run in a non-b2g context, we can set this value to false
// or otherwise conditionalize based on behaviour.
var needSiblingIframeHack = true;
if (needSiblingIframeHack) {
gChromeHelper.sendAsyncMessage('run', gApp);
gChromeHelper.addMessageListener('appMessage', handleTestMessage);
gChromeHelper.addMessageListener('appError', function(data) {
ok(false, "Error in app frame: " + data.message);
});
cleanupFrame = function() {
gChromeHelper.sendAsyncMessage('close', {});
};
} else {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', gApp.manifestURL);
cleanupFrame = function() {
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
domParent.removeChild(ifr);
};
// Set us up to listen for messages from the app.
var listener = function(e) {
var message = e.detail.message; // e.detail.message;
handleTestMessage(message);
};
// This event is triggered when the app calls "alert".
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
ifr.addEventListener('mozbrowsererror', function(evt) {
ok(false, "Error in app frame: " + evt.detail);
});
ifr.setAttribute('src', gApp.manifest.launch_path);
var domParent = document.getElementById('content');
if (!domParent) {
document.createElement('div');
document.body.insertBefore(domParent, document.body.firstChild);
}
domParent.appendChild(ifr);
}
}
var tests = [
// Permissions
function() {
info("pushing permissions");
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }
],
runTests);
},
// Preferences
function() {
info("pushing preferences: " + gOptions.extraPrefs.set);
SpecialPowers.pushPrefEnv({
"set": gOptions.extraPrefs.set
}, runTests);
},
function() {
info("enabling use of mozbrowser");
//SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
runTests();
},
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(function() {
SpecialPowers.autoConfirmAppUninstall(runTests);
});
},
// Installing the app
installApp,
// Run tests in app
testApp,
// Uninstall the app
uninstallApp,
];
function runTests() {
if (!tests.length) {
ok(true, 'DONE!');
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
function runAppTest(options) {
gOptions = options;
var href = document.location.href;
gManifestURL = href.substring(0, href.lastIndexOf('/') + 1) +
options.appManifest;
runTests();
}
@@ -0,0 +1,178 @@
/**
* This is the chrome helper for shim_app_as_test.js. Its load is triggered by
* shim_app_as_test.js by a call to SpecialPowers.loadChromeScript and runs
* in the parent process in a sandbox created with the system principal. (Which
* seems like it can never get collected because it's reachable via the
* apparently singleton SpecialPowersObserverAPI instance and there's no logic
* to support reaping. Wuh-oh.)
*
* It exists to help install fake privileged/certified applications. It needs
* to exist because:
* - We need to poke at DOMApplicationRegistry directly.
* - By using SpecialPowers.loadChromeScript we are able to ensure this file
* is run in the parent process. This is important because
* DOMApplicationRegistry only lives in the parent process!
* - By running entirely in a chrome privileged compartment, we avoid crazy
* wrapper problems that we would otherwise face with our shenanigans of
* directly meddling with DOMApplicationRegistry. (And hopefully save
* anyone changing DOMApplicationRegistry from frustration/hating us if
* things were just barely working.)
* - Bug 1097479 means that embed-webapps doesn't work when the content process
* that is telling us to do things is itself OOP. So it falls upon us to
* handle the running of the app by creating a sibling mozbrowser/mozapp
* iframe to the one running the mochitests.
*
* Note that in this file we try to do *only* those things that can't otherwise
* be cleanly done using SpecialPowers.
*
* Want to better understand our execution context? Check out
* SpecialPowersObserverAPI.js and search on SPLoadChromeScript.
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const CC = Components.Constructor;
Cu.import('resource://gre/modules/Webapps.jsm'); // for DOMApplicationRegistry
Cu.import('resource://gre/modules/AppsUtils.jsm'); // for AppUtils
Cu.import('resource://gre/modules/Services.jsm'); // for AppUtils
// Yes, you would think there was something like this already exposed easily
// in a JSM somewhere. No.
function fetchManifest(manifestURL) {
return new Promise(function(resolve, reject) {
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", manifestURL, true);
xhr.responseType = "json";
xhr.addEventListener("load", function() {
if (xhr.status == 200) {
resolve(xhr.response);
} else {
reject();
}
});
xhr.addEventListener("error", function() {
reject();
});
xhr.send(null);
});
}
/**
* Install an app using confirmInstall using pre-chewed data. This avoids the
* check in the normal installApp flow that gets all judgemental about the
* installation of privileged and certified apps.
*/
function installApp(req) {
fetchManifest(req.manifestURL).then(function(manifestObj) {
var data = {
// cloneAppObj normalizes the representation for us
app: AppsUtils.cloneAppObject({
installOrigin: req.origin,
origin: req.origin,
manifestURL: req.manifestURL,
appStatus: AppsUtils.getAppManifestStatus(manifestObj),
receipts: [],
categories: []
}),
from: req.origin, // unused?
oid: 0, // unused?
requestID: 0, // unused-ish
appId: 0, // unused
isBrowser: false,
isPackage: false, // used
// magic to auto-ack... don't think we care about this...
forceSuccessAck: false
// stuff that probably doesn't matter: 'mm', 'apkInstall',
};
// cloneAppObject does not propagate the manifest
data.app.manifest = manifestObj;
return DOMApplicationRegistry.confirmInstall(data).then(
function() {
var appId =
DOMApplicationRegistry.getAppLocalIdByManifestURL(req.manifestURL);
// act like this is a privileged app having all of its permissions
// authorized at first run.
DOMApplicationRegistry.updatePermissionsForApp(
appId,
/* preinstalled */ true,
/* system update? */ true);
sendAsyncMessage(
'installed',
{
appId: appId,
manifestURL: req.manifestURL,
manifest: manifestObj
});
},
function(err) {
sendAsyncMessage('installed', false);
});
});
}
function uninstallApp(appInfo) {
DOMApplicationRegistry.uninstall(appInfo.manifestURL).then(
function() {
sendAsyncMessage('uninstalled', true);
},
function() {
sendAsyncMessage('uninstalled', false);
});
}
var activeIframe = null;
/**
* Run our app in a sibling mozbrowser/mozapp iframe to the mochitest iframe.
* This is needed because we can't nest mozbrowser/mozapp iframes inside our
* already-OOP iframe until bug 1097479 is resolved.
*/
function runApp(appInfo) {
let shellDomWindow = Services.wm.getMostRecentWindow('navigator:browser');
let sysAppFrame = shellDomWindow.document.body.querySelector('#systemapp');
let sysAppDoc = sysAppFrame.contentDocument;
let siblingFrame = sysAppDoc.body.querySelector('#test-container');
let ifr = activeIframe = sysAppDoc.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('remote', 'true');
ifr.setAttribute('mozapp', appInfo.manifestURL);
ifr.addEventListener('mozbrowsershowmodalprompt', function(evt) {
var message = evt.detail.message;
// only send the message as long as we haven't been told to clean up.
if (activeIframe) {
sendAsyncMessage('appMessage', message);
}
}, false);
ifr.addEventListener('mozbrowsererror', function(evt) {
if (activeIframe) {
sendAsyncMessage('appError', { message: '' + evt.detail });
}
});
ifr.setAttribute('src', appInfo.manifest.launch_path);
siblingFrame.parentElement.appendChild(ifr);
}
function closeApp() {
if (activeIframe) {
activeIframe.parentElement.removeChild(activeIframe);
activeIframe = null;
}
}
addMessageListener('install', installApp);
addMessageListener('uninstall', uninstallApp);
addMessageListener('run', runApp);
addMessageListener('close', closeApp);
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=825318
-->
<head>
<title>Test for Bug 825318 mozDownloadManager.adoptDownload</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="shim_app_as_test.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=825318">Mozilla Bug 825318</a>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
runAppTest({
appFile: 'testapp_downloads_adopt_download.html',
appManifest: 'testapp_downloads_adopt_download.manifest',
appType: 'certified',
extraPrefs: {
set: [["dom.mozDownloads.enabled", true]]
}
});
</script>
</pre>
</body>
</html>
@@ -72,6 +72,10 @@ function downloadChange(evt) {
is(download.currentBytes, 1024, "Download current size is 1024 bytes");
SimpleTest.finish();
} else if (download.state === "downloading") {
// Note that this case may or may not trigger, depending on whether the
// download is initially reported with 0 bytes (we should happen) or with
// 1024 bytes (we should not happen). If we do happen, an additional 8
// TEST-PASS events should be logged.
ok(download.currentBytes > lastKnownCurrentBytes,
"Download current size is larger than last download change event");
lastKnownCurrentBytes = download.currentBytes;
@@ -84,7 +88,8 @@ function downloadStart(evt) {
var download = evt.download;
checkConsistentDownloadAttributes(download);
is(download.currentBytes, 0, "Download current size is zero");
// We used to check that the currentBytes was 0. This was incorrect. It
// is very common to first hear about the download already at 1024 bytes.
is(download.state, "downloading", "Download state is downloading");
download.onstatechange = downloadChange;
@@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=938023
<title>Test for Bug 938023 Downloads API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="clear_all_done_helper.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@@ -46,7 +47,7 @@ function error() {
function getDownloads(downloads) {
ok(downloads.length == 1, "One downloads after getDownloads");
navigator.mozDownloadManager.clearAllDone().then(clearAllDone, error);
clearAllDoneHelper(true).then(clearAllDone, error);
}
function clearAllDone(downloads) {
@@ -76,7 +77,7 @@ var steps = [
SpecialPowers.pushPermissions([
{type: "downloads", allow: true, context: document}
], function() {
navigator.mozDownloadManager.clearAllDone().then(next, error);
clearAllDoneHelper(true).then(next, error);
});
},
@@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=938023
<title>Test for Bug 938023 Downloads API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="clear_all_done_helper.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@@ -83,7 +84,7 @@ var steps = [
SpecialPowers.pushPermissions([
{type: "downloads", allow: true, context: document}
], function() {
navigator.mozDownloadManager.clearAllDone().then(next, error);
clearAllDoneHelper(true).then(next, error);
});
},
@@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=938023
<title>Test for Bug 938023 Downloads API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="clear_all_done_helper.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@@ -54,8 +55,7 @@ function checkDownloadList(downloads) {
function checkResumeSucceeded(download) {
ok(download.state == "succeeded", "Download resumed successfully.");
navigator.mozDownloadManager.clearAllDone()
.then(checkDownloadList, error);
clearAllDoneHelper(true).then(checkDownloadList, error);
}
function downloadChange(evt) {
@@ -88,7 +88,7 @@ var steps = [
SpecialPowers.pushPermissions([
{type: "downloads", allow: true, context: document}
], function() {
navigator.mozDownloadManager.clearAllDone().then(next, error);
clearAllDoneHelper(true).then(next, error);
});
},
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript" src="common_app.js"></script>
<meta charset="utf-8">
</head>
<body>
<div id="blah">initial text</div>
<pre id="test">
<!-- because of certified CSP, this code must NOT be inline -->
<script class="testbody" type="text/javascript;version=1.7" src="testapp_downloads_adopt_download.js"></script>
</pre>
</body>
</html>
@@ -0,0 +1,218 @@
/**
* Test the adoptDownload API. Specifically, we expect that when we call
* adoptDownload with a valid payload that:
* - The method will be resolved with a valid, fully populated DOMDownload
* instance, including an id.
* - An ondownloadstart notification will be generated and the DOMDownload
* instance it receives will be logically equivalent.
*
* We also explicitly verify that invalid adoptDownload payloads result in a
* rejection and that no download is added.
*
* This test explicitly does not test that the download is correctly persisted
* to the database. This is done because Downloads.jsm does not provide a means
* of safely restarting itself, so Firefox would need to be restarted. Because
* the adoptDownload code is using the Downloads API in a straightforward
* manner, it's not considered likely this would regress, and certainly not
* considered worth the automated testing overhead of a restart.
*/
function checkInvalidResult(dict, expectedErr, explanation) {
navigator.mozDownloadManager.ondownloadstart = function() {
ok(false, "No download should have been added!");
};
navigator.mozDownloadManager.adoptDownload(dict).then(
function() {
ok(false, "Invalid adoptDownload did not reject!");
runTests();
},
function(rejectedWith) {
is(rejectedWith, expectedErr, explanation + " rejection value");
runTests();
});
}
// Pick a date that Date.now() could not possibly return by picking a date in
// the past. (We want to make sure the date we provide works.)
var arbitraryDate = new Date(Date.now() - 60000);
var blobContents = new Uint8Array(256);
var memBlob = new Blob([blobContents], { type: 'application/octet-stream' });
var blobStorageName;
var blobStoragePath = 'blobby.blob';
function checkAdoptedDownload(download, validPayload) {
is(download.totalBytes, memBlob.size, 'size');
is(download.url, validPayload.url, 'url');
// The filesystem path is not practical to check since we can't hard-code it
// and the only way to check is to effectively duplicate the logic in
// DownloadsAPI.js. The good news, however, is that the value is
// round-tripped from storageName/storagePath to path and back again, and we
// also verify the file exists on disk, so we can be reasonably confident this
// is correct. We output it to aid in debugging if things should break,
// of course.
info('path (not checked): ' + download.path);
is(download.storageName, validPayload.storageName, 'storageName');
is(download.storagePath, validPayload.storagePath, 'storagePath');
is(download.state, 'succeeded', 'state');
is(download.contentType, validPayload.contentType, 'contentType');
is(download.startTime.valueOf(), arbitraryDate.valueOf(), 'startTime');
is(download.sourceAppManifestURL,
'http://mochi.test:8888/' +
'tests/dom/downloads/tests/testapp_downloads_adopt_download.manifest',
'app manifest');
};
var tests = [
function saveBlobToDeviceStorage() {
// Only sdcard can handle arbitrary MIME types and is guaranteed to be a
// thing.
var storage = navigator.getDeviceStorage('sdcard');
// We used the non-array helper, so the name we get may be different than
// what we asked for.
blobStorageName = storage.storageName;
ok(!!storage, 'have storage');
var req = storage.addNamed(memBlob, blobStoragePath);
req.onerror = function() {
ok(false, 'problem saving blob to storage: ' + req.error.name);
};
req.onsuccess = function(evt) {
ok(true, 'saved blob: ' + evt.target.result);
runTests();
};
},
function addValid() {
var validPayload = {
// All currently expected consumers are unable to provide a valid URL, and
// as a result need to provide an empty string.
url: "",
storageName: blobStorageName,
storagePath: blobStoragePath,
contentType: memBlob.type,
startTime: arbitraryDate
};
// Wrap the notification in a check so we can force our logic to be
// consistently ordered in the test even if it's not in reality.
var notifiedPromise = new Promise(function(resolve, reject) {
navigator.mozDownloadManager.ondownloadstart = function(evt) {
resolve(evt.download);
};
});
// Start the download
navigator.mozDownloadManager.adoptDownload(validPayload).then(
function(apiDownload) {
checkAdoptedDownload(apiDownload, validPayload);
ok(!!apiDownload.id, "Need a download id!");
notifiedPromise.then(function(notifiedDownload) {
checkAdoptedDownload(notifiedDownload, validPayload);
is(apiDownload.id, notifiedDownload.id,
"Notification should be for the download we adopted");
runTests();
});
},
function() {
ok(false, "adoptDownload should not have rejected");
runTests();
});
},
function dictionaryNotProvided() {
checkInvalidResult(undefined, "InvalidDownload");
},
// Missing fields immediately result in rejection with InvalidDownload
function missingStorageName() {
checkInvalidResult({
url: "",
// no storageName
storagePath: "relpath/filename.txt",
contentType: "text/plain",
startTime: arbitraryDate
}, "InvalidDownload", "missing storage name");
},
function nullStorageName() {
checkInvalidResult({
url: "",
storageName: null,
storagePath: "relpath/filename.txt",
contentType: "text/plain",
startTime: arbitraryDate
}, "InvalidDownload", "null storage name");
},
function missingStoragePath() {
checkInvalidResult({
url: "",
storageName: blobStorageName,
// no storagePath
contentType: "text/plain",
startTime: arbitraryDate
}, "InvalidDownload", "missing storage path");
},
function nullStoragePath() {
checkInvalidResult({
url: "",
storageName: blobStorageName,
storagePath: null,
contentType: "text/plain",
startTime: arbitraryDate
}, "InvalidDownload", "null storage path");
},
function missingContentType() {
checkInvalidResult({
url: "",
storageName: "sdcard",
storagePath: "relpath/filename.txt",
// no contentType
startTime: arbitraryDate
}, "InvalidDownload", "missing content type");
},
function nullContentType() {
checkInvalidResult({
url: "",
storageName: "sdcard",
storagePath: "relpath/filename.txt",
contentType: null,
startTime: arbitraryDate
}, "InvalidDownload", "null content type");
},
// Incorrect storage names are likewise immediately invalidated
function invalidStorageName() {
checkInvalidResult({
url: "",
storageName: "ALMOST CERTAINLY DOES NOT EXIST",
storagePath: "relpath/filename.txt",
contentType: "text/plain",
startTime: arbitraryDate
}, "InvalidDownload", "invalid storage name");
},
// The existence of the file is validated in the parent process
function legitStorageInvalidPath() {
checkInvalidResult({
url: "",
storageName: blobStorageName,
storagePath: "ALMOST CERTAINLY DOES NOT EXIST",
contentType: "text/plain",
startTime: arbitraryDate
}, "AdoptNoSuchFile", "invalid path");
},
function allDone() {
// Just in case, make sure no other mochitest could mess with us after we've
// finished.
navigator.mozDownloadManager.ondownloadstart = null;
runTests();
}
];
function runTests() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
if (test.name) {
info('starting test: ' + test.name);
}
test();
}
runTests();
@@ -0,0 +1,10 @@
{
"name": "Downloads certified test fake app",
"description": "Test",
"launch_path": "http://mochi.test:8888/tests/dom/downloads/tests/testapp_downloads_adopt_download.html",
"type": "certified",
"permissions": {
"device-storage:sdcard":{ "access": "readcreate" },
"downloads": {}
}
}
+30 -3
View File
@@ -484,6 +484,30 @@ EventStateManager::TryToFlushPendingNotificationsToIME()
}
}
static bool
IsMessageMouseUserActivity(EventMessage aMessage)
{
return aMessage == eMouseMove ||
aMessage == eMouseUp ||
aMessage == eMouseDown ||
aMessage == eMouseDoubleClick ||
aMessage == eMouseClick ||
aMessage == eMouseActivate ||
aMessage == eMouseLongTap;
}
static bool
IsMessageGamepadUserActivity(EventMessage aMessage)
{
#ifndef MOZ_GAMEPAD
return false;
#else
return aMessage == eGamepadButtonDown ||
aMessage == eGamepadButtonUp ||
aMessage == eGamepadAxisMove;
#endif
}
nsresult
EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
WidgetEvent* aEvent,
@@ -515,12 +539,12 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
if (aEvent->mFlags.mIsTrusted &&
((mouseEvent && mouseEvent->IsReal() &&
mouseEvent->mMessage != eMouseEnterIntoWidget &&
mouseEvent->mMessage != eMouseExitFromWidget) ||
IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
aEvent->mClass == eWheelEventClass ||
aEvent->mClass == ePointerEventClass ||
aEvent->mClass == eTouchEventClass ||
aEvent->mClass == eKeyboardEventClass)) {
aEvent->mClass == eKeyboardEventClass ||
IsMessageGamepadUserActivity(aEvent->mMessage))) {
if (gMouseOrKeyboardEventCounter == 0) {
nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService();
@@ -1992,6 +2016,7 @@ EventStateManager::GetContentViewer(nsIContentViewer** aCv)
nsCOMPtr<nsIDOMWindow> focusedWindow;
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
if (!focusedWindow) return NS_ERROR_FAILURE;
nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(focusedWindow);
if(!ourWindow) return NS_ERROR_FAILURE;
@@ -2577,6 +2602,8 @@ EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
case WidgetWheelEvent::SCROLL_DEFAULT:
if (isDeltaModePixel) {
mode = nsIScrollableFrame::NORMAL;
} else if (aEvent->mFlags.mHandledByAPZ) {
mode = nsIScrollableFrame::SMOOTH_MSD;
} else {
mode = nsIScrollableFrame::SMOOTH;
}
+14 -3
View File
@@ -958,7 +958,7 @@ IMEStateManager::SetInputContextForChildProcess(
GetActionFocusChangeName(aAction.mFocusChange),
sPresContext, sActiveTabParent.get()));
if (NS_WARN_IF(aTabParent != sActiveTabParent)) {
if (aTabParent != sActiveTabParent) {
MOZ_LOG(sISMLog, LogLevel::Error,
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
"because non-focused tab parent tries to set input context"));
@@ -1473,8 +1473,19 @@ IMEStateManager::NotifyIME(const IMENotification& aNotification,
return composition ?
composition->RequestToCommit(aWidget, true) : NS_OK;
case NOTIFY_IME_OF_COMPOSITION_UPDATE:
return composition && !isSynthesizedForTests ?
aWidget->NotifyIME(aNotification) : NS_OK;
if (!aOriginIsRemote && (!composition || isSynthesizedForTests)) {
MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::NotifyIME(), FAILED, received content "
"change notification from this process but there is no compostion"));
return NS_OK;
}
if (!sRemoteHasFocus && aOriginIsRemote) {
MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::NotifyIME(), received content change "
"notification from the remote but it's already lost focus"));
return NS_OK;
}
return aWidget->NotifyIME(aNotification);
default:
MOZ_CRASH("Unsupported notification");
}

Some files were not shown because too many files have changed in this diff Show More