Bug 1557645 - Unify in-process document cloning a bit more. r=jwatt

By passing the content viewer to CreateStaticClone we can do this fairly
easily. I'm going to add another entry-point to the clone process and
it'd be good if we avoid repeating the SetDocument dance and so on.

Differential Revision: https://phabricator.services.mozilla.com/D90315
This commit is contained in:
Emilio Cobos Álvarez 2020-09-15 23:03:23 +00:00
Родитель b769c92faf
Коммит 3464071d3d
5 изменённых файлов: 83 добавлений и 105 удалений

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

@ -12270,9 +12270,12 @@ static void CachePrintSelectionRanges(const Document& aSourceDoc,
}
already_AddRefed<Document> Document::CreateStaticClone(
nsIDocShell* aCloneContainer) {
nsIDocShell* aCloneContainer, nsIContentViewer* aViewer,
bool* aOutHasInProcessPrintCallbacks) {
MOZ_ASSERT(!mCreatingStaticClone);
MOZ_ASSERT(!GetProperty(nsGkAtoms::adoptedsheetclones));
MOZ_DIAGNOSTIC_ASSERT(aViewer);
mCreatingStaticClone = true;
SetProperty(nsGkAtoms::adoptedsheetclones, new AdoptedStyleSheetCloneCache(),
nsINode::DeleteProperty<AdoptedStyleSheetCloneCache>);
@ -12295,50 +12298,75 @@ already_AddRefed<Document> Document::CreateStaticClone(
}
nsCOMPtr<Document> clonedDoc = do_QueryInterface(clonedNode);
if (clonedDoc) {
size_t sheetsCount = SheetCount();
for (size_t i = 0; i < sheetsCount; ++i) {
RefPtr<StyleSheet> sheet = SheetAt(i);
if (sheet) {
if (sheet->IsApplicable()) {
RefPtr<StyleSheet> clonedSheet =
sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
NS_WARNING_ASSERTION(clonedSheet,
"Cloning a stylesheet didn't work!");
if (clonedSheet) {
clonedDoc->AddStyleSheet(clonedSheet);
}
if (!clonedDoc) {
return nullptr;
}
size_t sheetsCount = SheetCount();
for (size_t i = 0; i < sheetsCount; ++i) {
RefPtr<StyleSheet> sheet = SheetAt(i);
if (sheet) {
if (sheet->IsApplicable()) {
RefPtr<StyleSheet> clonedSheet =
sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
NS_WARNING_ASSERTION(clonedSheet, "Cloning a stylesheet didn't work!");
if (clonedSheet) {
clonedDoc->AddStyleSheet(clonedSheet);
}
}
}
clonedDoc->CloneAdoptedSheetsFrom(*this);
}
clonedDoc->CloneAdoptedSheetsFrom(*this);
for (int t = 0; t < AdditionalSheetTypeCount; ++t) {
auto& sheets = mAdditionalSheets[additionalSheetType(t)];
for (StyleSheet* sheet : sheets) {
if (sheet->IsApplicable()) {
RefPtr<StyleSheet> clonedSheet =
sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
NS_WARNING_ASSERTION(clonedSheet,
"Cloning a stylesheet didn't work!");
if (clonedSheet) {
clonedDoc->AddAdditionalStyleSheet(additionalSheetType(t),
clonedSheet);
}
for (int t = 0; t < AdditionalSheetTypeCount; ++t) {
auto& sheets = mAdditionalSheets[additionalSheetType(t)];
for (StyleSheet* sheet : sheets) {
if (sheet->IsApplicable()) {
RefPtr<StyleSheet> clonedSheet =
sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
NS_WARNING_ASSERTION(clonedSheet, "Cloning a stylesheet didn't work!");
if (clonedSheet) {
clonedDoc->AddAdditionalStyleSheet(additionalSheetType(t),
clonedSheet);
}
}
}
}
// Font faces created with the JS API will not be reflected in the
// stylesheets and need to be copied over to the cloned document.
if (const FontFaceSet* set = GetFonts()) {
set->CopyNonRuleFacesTo(clonedDoc->Fonts());
// Font faces created with the JS API will not be reflected in the
// stylesheets and need to be copied over to the cloned document.
if (const FontFaceSet* set = GetFonts()) {
set->CopyNonRuleFacesTo(clonedDoc->Fonts());
}
clonedDoc->mReferrerInfo =
static_cast<dom::ReferrerInfo*>(mReferrerInfo.get())->Clone();
clonedDoc->mPreloadReferrerInfo = clonedDoc->mReferrerInfo;
CachePrintSelectionRanges(*this, *clonedDoc);
// We're done with the clone, embed ourselves into the document viewer and
// clone our children. The order here is pretty important, because our
// document our document needs to have an owner global before we can create
// the frame loaders for subdocuments.
aViewer->SetDocument(clonedDoc);
*aOutHasInProcessPrintCallbacks |= clonedDoc->HasPrintCallbacks();
auto pendingClones = std::move(clonedDoc->mPendingFrameStaticClones);
for (const auto& clone : pendingClones) {
RefPtr<Element> element = do_QueryObject(clone.mElement);
RefPtr<nsFrameLoader> frameLoader =
nsFrameLoader::Create(element, /* aNetworkCreated */ false);
if (NS_WARN_IF(!frameLoader)) {
continue;
}
clonedDoc->mReferrerInfo =
static_cast<dom::ReferrerInfo*>(mReferrerInfo.get())->Clone();
clonedDoc->mPreloadReferrerInfo = clonedDoc->mReferrerInfo;
CachePrintSelectionRanges(*this, *clonedDoc);
clone.mElement->SetFrameLoader(frameLoader);
nsresult rv = frameLoader->FinishStaticClone(
clone.mStaticCloneOf, aOutHasInProcessPrintCallbacks);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
return clonedDoc.forget();
@ -16776,13 +16804,6 @@ bool Document::HasRecentlyStartedForegroundLoads() {
return false;
}
nsTArray<Document::PendingFrameStaticClone>
Document::TakePendingFrameStaticClones() {
MOZ_ASSERT(mIsStaticDocument,
"Cannot have pending frame static clones in non-static documents");
return std::move(mPendingFrameStaticClones);
}
void Document::AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement,
nsFrameLoader* aStaticCloneOf) {
PendingFrameStaticClone* clone = mPendingFrameStaticClones.AppendElement();

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

@ -55,7 +55,7 @@
#include "mozilla/SegmentedVector.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include <bitset> // for member
#include <bitset> // for member
#include "js/friend/DOMProxy.h" // JS::ExpandoAndGeneration
// XXX We need to include this here to ensure that DefaultDeleter for Servo
@ -2830,8 +2830,14 @@ class Document : public nsINode,
* and replace the cloned resources).
*
* @param aCloneContainer The container for the clone document.
* @param aContentViewer The viewer for the clone document. Must be the viewer
* of aCloneContainer, but callers must have a reference
* to it already and ensure it's not null.
* @param aOutHasInProcessPrintCallbacks Self-descriptive.
*/
already_AddRefed<Document> CreateStaticClone(nsIDocShell* aCloneContainer);
already_AddRefed<Document> CreateStaticClone(
nsIDocShell* aCloneContainer, nsIContentViewer* aContentViewer,
bool* aOutHasInProcessPrintCallbacks);
/**
* If this document is a static clone, this returns the original
@ -3934,7 +3940,6 @@ class Document : public nsINode,
RefPtr<nsFrameLoaderOwner> mElement;
RefPtr<nsFrameLoader> mStaticCloneOf;
};
nsTArray<PendingFrameStaticClone> TakePendingFrameStaticClones();
void AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement,
nsFrameLoader* aStaticCloneOf);

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

@ -2754,9 +2754,8 @@ void nsFrameLoader::ActivateFrameEvent(const nsAString& aType, bool aCapture,
}
}
nsresult nsFrameLoader::FinishStaticClone(nsFrameLoader* aStaticCloneOf,
nsIDocShell** aCloneDocShell,
Document** aCloneDocument) {
nsresult nsFrameLoader::FinishStaticClone(
nsFrameLoader* aStaticCloneOf, bool* aOutHasInProcessPrintCallbacks) {
MOZ_DIAGNOSTIC_ASSERT(
!nsContentUtils::IsSafeToRunScript(),
"A script blocker should be on the stack while FinishStaticClone is run");
@ -2772,6 +2771,7 @@ nsresult nsFrameLoader::FinishStaticClone(nsFrameLoader* aStaticCloneOf,
if (NS_WARN_IF(IsDead())) {
return NS_ERROR_UNEXPECTED;
}
if (NS_WARN_IF(aStaticCloneOf->IsRemoteFrame())) {
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -2793,12 +2793,9 @@ nsresult nsFrameLoader::FinishStaticClone(nsFrameLoader* aStaticCloneOf,
nsCOMPtr<Document> doc = origDocShell->GetDocument();
NS_ENSURE_STATE(doc);
nsCOMPtr<Document> clonedDoc = doc->CreateStaticClone(docShell);
nsCOMPtr<Document> clonedDoc =
doc->CreateStaticClone(docShell, viewer, aOutHasInProcessPrintCallbacks);
viewer->SetDocument(clonedDoc);
docShell.forget(aCloneDocShell);
clonedDoc.forget(aCloneDocument);
return NS_OK;
}

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

@ -146,12 +146,8 @@ class nsFrameLoader final : public nsStubMutationObserver,
// After the parent document has been fully cloned, a new frameloader will be
// created for the cloned iframe, and `FinishStaticClone` will be called on
// it, which will clone the inner document of the source nsFrameLoader.
//
// The `aCloneDocShell` and `aCloneDocument` outparameters will be filled with
// the values from the newly cloned subframe.
nsresult FinishStaticClone(nsFrameLoader* aStaticCloneOf,
nsIDocShell** aCloneDocShell,
Document** aCloneDocument);
bool* aOutHasInProcessPrintCallbacks);
// WebIDL methods

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

@ -5284,36 +5284,6 @@ void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
#endif
}
// Returns whether there's any print callback.
static bool BuildNestedClones(Document& aJustClonedDoc) {
bool hasPrintCallbacks = aJustClonedDoc.HasPrintCallbacks();
auto pendingFrameClones = aJustClonedDoc.TakePendingFrameStaticClones();
for (const auto& clone : pendingFrameClones) {
RefPtr<Element> element = do_QueryObject(clone.mElement);
RefPtr<nsFrameLoader> frameLoader =
nsFrameLoader::Create(element, /* aNetworkCreated */ false);
if (NS_WARN_IF(!frameLoader)) {
continue;
}
clone.mElement->SetFrameLoader(frameLoader);
nsCOMPtr<nsIDocShell> docshell;
RefPtr<Document> doc;
nsresult rv = frameLoader->FinishStaticClone(
clone.mStaticCloneOf, getter_AddRefs(docshell), getter_AddRefs(doc));
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
if (doc) {
hasPrintCallbacks |= BuildNestedClones(*doc);
}
}
return hasPrintCallbacks;
}
Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
nsIPrintSettings* aPrintSettings, nsIWebProgressListener* aListener,
nsIDocShell* aDocShellToCloneInto, IsPreview aIsPreview,
@ -5431,23 +5401,12 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
auto dispatchAfterPrint = MakeScopeExit(
[&] { DispatchPrintEventToWindowTree(*docToPrint, u"afterprint"_ns); });
RefPtr<Document> clone;
{
nsAutoScriptBlocker blockScripts;
clone = docToPrint->CreateStaticClone(cloneDocShell);
if (!clone) {
aError.ThrowNotSupportedError("Clone operation for printing failed");
return nullptr;
}
// Do this now so that we get a script handling object, and thus can
// create our clones.
aError = cv->SetDocument(clone);
if (aError.Failed()) {
return nullptr;
}
hasPrintCallbacks |= BuildNestedClones(*clone);
nsAutoScriptBlocker blockScripts;
RefPtr<Document> clone =
docToPrint->CreateStaticClone(cloneDocShell, cv, &hasPrintCallbacks);
if (!clone) {
aError.ThrowNotSupportedError("Clone operation for printing failed");
return nullptr;
}
}