FileSystemDirectoryReader / FileSystemEntry should not prevent entering the back/forward cache
https://bugs.webkit.org/show_bug.cgi?id=203090
<rdar://problem/56550805>
Reviewed by Geoffrey Garen.
Source/WebCore:
FileSystemDirectoryReader / FileSystemEntry no longer prevent entering the back/forward cache.
We now dispatch tasks to the window event loop whenever we need to call a JS callback since the
window event loop takes care of suspending tasks while in the back/forward cache.
Tests: editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache.html
editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache.html
* Modules/entriesapi/FileSystemDirectoryEntry.cpp:
(WebCore::FileSystemDirectoryEntry::getEntry):
* Modules/entriesapi/FileSystemDirectoryReader.cpp:
(WebCore::FileSystemDirectoryReader::document const):
(WebCore::FileSystemDirectoryReader::readEntries):
* Modules/entriesapi/FileSystemDirectoryReader.h:
* Modules/entriesapi/FileSystemEntry.cpp:
(WebCore::FileSystemEntry::document const):
(WebCore::FileSystemEntry::getParent):
* Modules/entriesapi/FileSystemEntry.h:
* Modules/entriesapi/FileSystemFileEntry.cpp:
(WebCore::FileSystemFileEntry::file):
LayoutTests:
Add layout test coverage.
* editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache-expected.txt: Added.
* editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache.html: Added.
* editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache-expected.txt: Added.
* editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251509 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 1099e072..dd4ce27 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,18 @@
+2019-10-23 Chris Dumez <cdumez@apple.com>
+
+ FileSystemDirectoryReader / FileSystemEntry should not prevent entering the back/forward cache
+ https://bugs.webkit.org/show_bug.cgi?id=203090
+ <rdar://problem/56550805>
+
+ Reviewed by Geoffrey Garen.
+
+ Add layout test coverage.
+
+ * editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache-expected.txt: Added.
+ * editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache.html: Added.
+ * editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache-expected.txt: Added.
+ * editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache.html: Added.
+
2019-10-23 Truitt Savell <tsavell@apple.com>
update expectations for inspector/heap/getRemoteObject.html
diff --git a/LayoutTests/editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache-expected.txt b/LayoutTests/editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache-expected.txt
new file mode 100644
index 0000000..97af183
--- /dev/null
+++ b/LayoutTests/editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache-expected.txt
@@ -0,0 +1,15 @@
+Make sure that fileSystemDirectoryEntry.getFile() does not prevent a page from entering the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the page cache
+PASS Success callback was called
+PASS restoredFromPageCache is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache.html b/LayoutTests/editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache.html
new file mode 100644
index 0000000..0d6aee8
--- /dev/null
+++ b/LayoutTests/editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache.html
@@ -0,0 +1,60 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+<script src="../../editing.js"></script>
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Make sure that fileSystemDirectoryEntry.getFile() does not prevent a page from entering the back/forward cache.");
+jsTestIsAsync = true;
+restoredFromPageCache = false;
+
+window.addEventListener("pageshow", function(event) {
+ debug("pageshow - " + (event.persisted ? "" : "not ") + "from cache");
+ if (event.persisted) {
+ testPassed("Page did enter and was restored from the page cache");
+ restoredFromPageCache = true;
+ }
+}, false);
+
+window.addEventListener("pagehide", function(event) {
+ debug("pagehide - " + (event.persisted ? "" : "not ") + "entering cache");
+ if (!event.persisted) {
+ testFailed("Page did not enter the page cache.");
+ finishJSTest();
+ } else {
+ entry.getFile('/testFiles/subfolder1/file3.txt', {}, function(file) {
+ testPassed("Success callback was called");
+ shouldBeTrue("restoredFromPageCache");
+ finishJSTest();
+ }, function(e) {
+ testFailed("Error callback was called");
+ finishJSTest();
+ });
+ }
+}, false);
+
+var dropzone = document.getElementById('dropzone');
+dropzone.ondrop = function(e) {
+ e.preventDefault();
+ dataTransfer = e.dataTransfer;
+
+ entry = dataTransfer.items[0].webkitGetAsEntry();
+ window.location.href = "../../../fast/history/resources/page-cache-helper.html";
+};
+
+dropzone.ondragover = function(ev) {
+ ev.preventDefault();
+}
+
+onload = function() {
+ setTimeout(() => {
+ dragFilesOntoElement(dropzone, ['../../../fast/forms/file/entries-api/resources/testFiles']);
+ }, 0);
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache-expected.txt b/LayoutTests/editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache-expected.txt
new file mode 100644
index 0000000..4954288
--- /dev/null
+++ b/LayoutTests/editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache-expected.txt
@@ -0,0 +1,15 @@
+Basic test coverage for fileSystemDirectoryReader.readEntries()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the page cache
+PASS Success callback was called
+PASS restoredFromPageCache is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache.html b/LayoutTests/editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache.html
new file mode 100644
index 0000000..1d60279
--- /dev/null
+++ b/LayoutTests/editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache.html
@@ -0,0 +1,84 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+<script src="../../editing.js"></script>
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Basic test coverage for fileSystemDirectoryReader.readEntries()");
+jsTestIsAsync = true;
+restoredFromPageCache = false;
+
+function getEntriesAsPromise(dirEntry) {
+ return new Promise((resolve, reject) => {
+ let result = [];
+ reader = dirEntry.createReader();
+ let doBatch = () => {
+ reader.readEntries(entries => {
+ if (entries.length > 0) {
+ entries.forEach(e => result.push(e));
+ doBatch();
+ } else {
+ resolve(result.sort(function (a, b) {
+ if (a.name > b.name)
+ return 1;
+ else if (a.name < b.name)
+ return -1;
+ return 0;
+ }));
+ }
+ }, reject);
+ };
+ doBatch();
+ });
+}
+
+window.addEventListener("pageshow", function(event) {
+ debug("pageshow - " + (event.persisted ? "" : "not ") + "from cache");
+ if (event.persisted) {
+ testPassed("Page did enter and was restored from the page cache");
+ restoredFromPageCache = true;
+ }
+}, false);
+
+window.addEventListener("pagehide", function(event) {
+ debug("pagehide - " + (event.persisted ? "" : "not ") + "entering cache");
+ if (!event.persisted) {
+ testFailed("Page did not enter the page cache.");
+ finishJSTest();
+ } else {
+ getEntriesAsPromise(entry).then(function(entries) {
+ testPassed("Success callback was called");
+ shouldBeTrue("restoredFromPageCache");
+ finishJSTest();
+ }, function(e) {
+ testFailed("Error callback was called");
+ finishJSTest();
+ });
+ }
+}, false);
+
+var dropzone = document.getElementById('dropzone');
+dropzone.ondrop = function(e) {
+ e.preventDefault();
+ dataTransfer = e.dataTransfer;
+
+ entry = dataTransfer.items[0].webkitGetAsEntry();
+ window.location.href = "../../../fast/history/resources/page-cache-helper.html";
+};
+
+dropzone.ondragover = function(ev) {
+ ev.preventDefault();
+}
+
+onload = function() {
+ setTimeout(() => {
+ dragFilesOntoElement(dropzone, ['../../../fast/forms/file/entries-api/resources/testFiles']);
+ }, 0);
+}
+</script>
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 7b19857..1bd257c 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,31 @@
+2019-10-23 Chris Dumez <cdumez@apple.com>
+
+ FileSystemDirectoryReader / FileSystemEntry should not prevent entering the back/forward cache
+ https://bugs.webkit.org/show_bug.cgi?id=203090
+ <rdar://problem/56550805>
+
+ Reviewed by Geoffrey Garen.
+
+ FileSystemDirectoryReader / FileSystemEntry no longer prevent entering the back/forward cache.
+ We now dispatch tasks to the window event loop whenever we need to call a JS callback since the
+ window event loop takes care of suspending tasks while in the back/forward cache.
+
+ Tests: editing/pasteboard/entries-api/DirectoryEntry-getFile-back-forward-cache.html
+ editing/pasteboard/entries-api/DirectoryReader-readEntries-back-forward-cache.html
+
+ * Modules/entriesapi/FileSystemDirectoryEntry.cpp:
+ (WebCore::FileSystemDirectoryEntry::getEntry):
+ * Modules/entriesapi/FileSystemDirectoryReader.cpp:
+ (WebCore::FileSystemDirectoryReader::document const):
+ (WebCore::FileSystemDirectoryReader::readEntries):
+ * Modules/entriesapi/FileSystemDirectoryReader.h:
+ * Modules/entriesapi/FileSystemEntry.cpp:
+ (WebCore::FileSystemEntry::document const):
+ (WebCore::FileSystemEntry::getParent):
+ * Modules/entriesapi/FileSystemEntry.h:
+ * Modules/entriesapi/FileSystemFileEntry.cpp:
+ (WebCore::FileSystemFileEntry::file):
+
2019-10-23 Myles C. Maxfield <mmaxfield@apple.com>
[iOS] Remove Hiragino Sans site-specific quirk for Yahoo Japan
diff --git a/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp b/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp
index 02130a4..0aa21da 100644
--- a/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp
+++ b/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp
@@ -33,6 +33,7 @@
#include "FileSystemEntryCallback.h"
#include "FileSystemFileEntry.h"
#include "ScriptExecutionContext.h"
+#include "WindowEventLoop.h"
namespace WebCore {
@@ -51,20 +52,30 @@
if (!successCallback && !errorCallback)
return;
- filesystem().getEntry(context, *this, path, flags, [pendingActivity = makePendingActivity(*this), matches = WTFMove(matches), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) {
+ filesystem().getEntry(context, *this, path, flags, [this, pendingActivity = makePendingActivity(*this), matches = WTFMove(matches), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) mutable {
+ auto* document = this->document();
if (result.hasException()) {
- if (errorCallback)
- errorCallback->handleEvent(DOMException::create(result.releaseException()));
+ if (errorCallback && document) {
+ document->eventLoop().queueTask(TaskSource::Networking, *document, [errorCallback = WTFMove(errorCallback), exception = result.releaseException(), pendingActivity = WTFMove(pendingActivity)]() mutable {
+ errorCallback->handleEvent(DOMException::create(WTFMove(exception)));
+ });
+ }
return;
}
auto entry = result.releaseReturnValue();
if (!matches(entry)) {
- if (errorCallback)
- errorCallback->handleEvent(DOMException::create(Exception { TypeMismatchError, "Entry at given path does not match expected type"_s }));
+ if (errorCallback && document) {
+ document->eventLoop().queueTask(TaskSource::Networking, *document, [errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)]() mutable {
+ errorCallback->handleEvent(DOMException::create(Exception { TypeMismatchError, "Entry at given path does not match expected type"_s }));
+ });
+ }
return;
}
- if (successCallback)
- successCallback->handleEvent(WTFMove(entry));
+ if (successCallback && document) {
+ document->eventLoop().queueTask(TaskSource::Networking, *document, [successCallback = WTFMove(successCallback), entry = WTFMove(entry), pendingActivity = WTFMove(pendingActivity)]() mutable {
+ successCallback->handleEvent(WTFMove(entry));
+ });
+ }
});
}
diff --git a/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp b/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp
index 63aa0fe..5dddcf5 100644
--- a/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp
+++ b/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp
@@ -28,10 +28,12 @@
#include "DOMException.h"
#include "DOMFileSystem.h"
+#include "Document.h"
#include "ErrorCallback.h"
#include "FileSystemDirectoryEntry.h"
#include "FileSystemEntriesCallback.h"
#include "ScriptExecutionContext.h"
+#include "WindowEventLoop.h"
#include <wtf/IsoMallocInlines.h>
#include <wtf/MainThread.h>
@@ -53,10 +55,9 @@
return "FileSystemDirectoryReader";
}
-// FIXME: This should never prevent entering the back/forward cache.
-bool FileSystemDirectoryReader::shouldPreventEnteringBackForwardCache_DEPRECATED() const
+Document* FileSystemDirectoryReader::document() const
{
- return hasPendingActivity();
+ return downcast<Document>(scriptExecutionContext());
}
// https://wicg.github.io/entries-api/#dom-filesystemdirectoryentry-readentries
@@ -83,15 +84,23 @@
auto pendingActivity = makePendingActivity(*this);
callOnMainThread([this, context = makeRef(context), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)]() mutable {
m_isReading = false;
- m_directory->filesystem().listDirectory(context, m_directory, [this, successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)](ExceptionOr<Vector<Ref<FileSystemEntry>>>&& result) {
+ m_directory->filesystem().listDirectory(context, m_directory, [this, successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)](ExceptionOr<Vector<Ref<FileSystemEntry>>>&& result) mutable {
+ auto* document = this->document();
if (result.hasException()) {
m_error = result.releaseException();
- if (errorCallback)
- errorCallback->handleEvent(DOMException::create(*m_error));
+ if (errorCallback && document) {
+ document->eventLoop().queueTask(TaskSource::Networking, *document, [this, errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)]() mutable {
+ errorCallback->handleEvent(DOMException::create(*m_error));
+ });
+ }
return;
}
m_isDone = true;
- successCallback->handleEvent(result.releaseReturnValue());
+ if (document) {
+ document->eventLoop().queueTask(TaskSource::Networking, *document, [successCallback = WTFMove(successCallback), pendingActivity = WTFMove(pendingActivity), result = result.releaseReturnValue()]() mutable {
+ successCallback->handleEvent(WTFMove(result));
+ });
+ }
});
});
}
diff --git a/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.h b/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.h
index b900de7..1a0998a 100644
--- a/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.h
+++ b/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.h
@@ -54,7 +54,7 @@
FileSystemDirectoryReader(ScriptExecutionContext&, FileSystemDirectoryEntry&);
const char* activeDOMObjectName() const final;
- bool shouldPreventEnteringBackForwardCache_DEPRECATED() const final;
+ Document* document() const;
Ref<FileSystemDirectoryEntry> m_directory;
Optional<Exception> m_error;
diff --git a/Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp b/Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp
index d2516a3..a86db76 100644
--- a/Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp
+++ b/Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp
@@ -32,6 +32,7 @@
#include "FileSystemDirectoryEntry.h"
#include "FileSystemEntryCallback.h"
#include "ScriptExecutionContext.h"
+#include "WindowEventLoop.h"
#include <wtf/FileSystem.h>
#include <wtf/IsoMallocInlines.h>
@@ -60,10 +61,9 @@
return "FileSystemEntry";
}
-// FIXME: This should never prevent entering the back/forward cache.
-bool FileSystemEntry::shouldPreventEnteringBackForwardCache_DEPRECATED() const
+Document* FileSystemEntry::document() const
{
- return hasPendingActivity();
+ return downcast<Document>(scriptExecutionContext());
}
void FileSystemEntry::getParent(ScriptExecutionContext& context, RefPtr<FileSystemEntryCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
@@ -71,14 +71,20 @@
if (!successCallback && !errorCallback)
return;
- filesystem().getParent(context, *this, [pendingActivity = makePendingActivity(*this), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) {
- if (result.hasException()) {
- if (errorCallback)
- errorCallback->handleEvent(DOMException::create(result.releaseException()));
+ filesystem().getParent(context, *this, [this, pendingActivity = makePendingActivity(*this), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) mutable {
+ auto* document = this->document();
+ if (!document)
return;
- }
- if (successCallback)
- successCallback->handleEvent(result.releaseReturnValue());
+
+ document->eventLoop().queueTask(TaskSource::Networking, *document, [successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), result = WTFMove(result), pendingActivity = WTFMove(pendingActivity)]() mutable {
+ if (result.hasException()) {
+ if (errorCallback)
+ errorCallback->handleEvent(DOMException::create(result.releaseException()));
+ return;
+ }
+ if (successCallback)
+ successCallback->handleEvent(result.releaseReturnValue());
+ });
});
}
diff --git a/Source/WebCore/Modules/entriesapi/FileSystemEntry.h b/Source/WebCore/Modules/entriesapi/FileSystemEntry.h
index d9763ef..af28ce0 100644
--- a/Source/WebCore/Modules/entriesapi/FileSystemEntry.h
+++ b/Source/WebCore/Modules/entriesapi/FileSystemEntry.h
@@ -52,10 +52,10 @@
protected:
FileSystemEntry(ScriptExecutionContext&, DOMFileSystem&, const String& virtualPath);
+ Document* document() const;
private:
const char* activeDOMObjectName() const final;
- bool shouldPreventEnteringBackForwardCache_DEPRECATED() const final;
Ref<DOMFileSystem> m_filesystem;
String m_name;
diff --git a/Source/WebCore/Modules/entriesapi/FileSystemFileEntry.cpp b/Source/WebCore/Modules/entriesapi/FileSystemFileEntry.cpp
index e8c9ef3..40f4724 100644
--- a/Source/WebCore/Modules/entriesapi/FileSystemFileEntry.cpp
+++ b/Source/WebCore/Modules/entriesapi/FileSystemFileEntry.cpp
@@ -28,8 +28,10 @@
#include "DOMException.h"
#include "DOMFileSystem.h"
+#include "Document.h"
#include "ErrorCallback.h"
#include "FileCallback.h"
+#include "WindowEventLoop.h"
namespace WebCore {
@@ -40,13 +42,19 @@
void FileSystemFileEntry::file(Ref<FileCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
{
- filesystem().getFile(*this, [successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) {
- if (result.hasException()) {
- if (errorCallback)
- errorCallback->handleEvent(DOMException::create(result.releaseException()));
+ filesystem().getFile(*this, [this, pendingActivity = makePendingActivity(*this), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) mutable {
+ auto* document = this->document();
+ if (!document)
return;
- }
- successCallback->handleEvent(result.releaseReturnValue());
+
+ document->eventLoop().queueTask(TaskSource::Networking, *document, [successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), result = WTFMove(result), pendingActivity = WTFMove(pendingActivity)]() mutable {
+ if (result.hasException()) {
+ if (errorCallback)
+ errorCallback->handleEvent(DOMException::create(result.releaseException()));
+ return;
+ }
+ successCallback->handleEvent(result.releaseReturnValue());
+ });
});
}