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( already_AddRefed<Document> Document::CreateStaticClone(
nsIDocShell* aCloneContainer) { nsIDocShell* aCloneContainer, nsIContentViewer* aViewer,
bool* aOutHasInProcessPrintCallbacks) {
MOZ_ASSERT(!mCreatingStaticClone); MOZ_ASSERT(!mCreatingStaticClone);
MOZ_ASSERT(!GetProperty(nsGkAtoms::adoptedsheetclones)); MOZ_ASSERT(!GetProperty(nsGkAtoms::adoptedsheetclones));
MOZ_DIAGNOSTIC_ASSERT(aViewer);
mCreatingStaticClone = true; mCreatingStaticClone = true;
SetProperty(nsGkAtoms::adoptedsheetclones, new AdoptedStyleSheetCloneCache(), SetProperty(nsGkAtoms::adoptedsheetclones, new AdoptedStyleSheetCloneCache(),
nsINode::DeleteProperty<AdoptedStyleSheetCloneCache>); nsINode::DeleteProperty<AdoptedStyleSheetCloneCache>);
@ -12295,50 +12298,75 @@ already_AddRefed<Document> Document::CreateStaticClone(
} }
nsCOMPtr<Document> clonedDoc = do_QueryInterface(clonedNode); nsCOMPtr<Document> clonedDoc = do_QueryInterface(clonedNode);
if (clonedDoc) { if (!clonedDoc) {
size_t sheetsCount = SheetCount(); return nullptr;
for (size_t i = 0; i < sheetsCount; ++i) { }
RefPtr<StyleSheet> sheet = SheetAt(i);
if (sheet) { size_t sheetsCount = SheetCount();
if (sheet->IsApplicable()) { for (size_t i = 0; i < sheetsCount; ++i) {
RefPtr<StyleSheet> clonedSheet = RefPtr<StyleSheet> sheet = SheetAt(i);
sheet->Clone(nullptr, nullptr, clonedDoc, nullptr); if (sheet) {
NS_WARNING_ASSERTION(clonedSheet, if (sheet->IsApplicable()) {
"Cloning a stylesheet didn't work!"); RefPtr<StyleSheet> clonedSheet =
if (clonedSheet) { sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
clonedDoc->AddStyleSheet(clonedSheet); 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) { for (int t = 0; t < AdditionalSheetTypeCount; ++t) {
auto& sheets = mAdditionalSheets[additionalSheetType(t)]; auto& sheets = mAdditionalSheets[additionalSheetType(t)];
for (StyleSheet* sheet : sheets) { for (StyleSheet* sheet : sheets) {
if (sheet->IsApplicable()) { if (sheet->IsApplicable()) {
RefPtr<StyleSheet> clonedSheet = RefPtr<StyleSheet> clonedSheet =
sheet->Clone(nullptr, nullptr, clonedDoc, nullptr); sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
NS_WARNING_ASSERTION(clonedSheet, NS_WARNING_ASSERTION(clonedSheet, "Cloning a stylesheet didn't work!");
"Cloning a stylesheet didn't work!"); if (clonedSheet) {
if (clonedSheet) { clonedDoc->AddAdditionalStyleSheet(additionalSheetType(t),
clonedDoc->AddAdditionalStyleSheet(additionalSheetType(t), clonedSheet);
clonedSheet);
}
} }
} }
} }
}
// Font faces created with the JS API will not be reflected in the // Font faces created with the JS API will not be reflected in the
// stylesheets and need to be copied over to the cloned document. // stylesheets and need to be copied over to the cloned document.
if (const FontFaceSet* set = GetFonts()) { if (const FontFaceSet* set = GetFonts()) {
set->CopyNonRuleFacesTo(clonedDoc->Fonts()); 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 = clone.mElement->SetFrameLoader(frameLoader);
static_cast<dom::ReferrerInfo*>(mReferrerInfo.get())->Clone();
clonedDoc->mPreloadReferrerInfo = clonedDoc->mReferrerInfo; nsresult rv = frameLoader->FinishStaticClone(
CachePrintSelectionRanges(*this, *clonedDoc); clone.mStaticCloneOf, aOutHasInProcessPrintCallbacks);
Unused << NS_WARN_IF(NS_FAILED(rv));
} }
return clonedDoc.forget(); return clonedDoc.forget();
@ -16776,13 +16804,6 @@ bool Document::HasRecentlyStartedForegroundLoads() {
return false; 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, void Document::AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement,
nsFrameLoader* aStaticCloneOf) { nsFrameLoader* aStaticCloneOf) {
PendingFrameStaticClone* clone = mPendingFrameStaticClones.AppendElement(); PendingFrameStaticClone* clone = mPendingFrameStaticClones.AppendElement();

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

@ -55,7 +55,7 @@
#include "mozilla/SegmentedVector.h" #include "mozilla/SegmentedVector.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include <bitset> // for member #include <bitset> // for member
#include "js/friend/DOMProxy.h" // JS::ExpandoAndGeneration #include "js/friend/DOMProxy.h" // JS::ExpandoAndGeneration
// XXX We need to include this here to ensure that DefaultDeleter for Servo // 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). * and replace the cloned resources).
* *
* @param aCloneContainer The container for the clone document. * @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 * If this document is a static clone, this returns the original
@ -3934,7 +3940,6 @@ class Document : public nsINode,
RefPtr<nsFrameLoaderOwner> mElement; RefPtr<nsFrameLoaderOwner> mElement;
RefPtr<nsFrameLoader> mStaticCloneOf; RefPtr<nsFrameLoader> mStaticCloneOf;
}; };
nsTArray<PendingFrameStaticClone> TakePendingFrameStaticClones();
void AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement, void AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement,
nsFrameLoader* aStaticCloneOf); nsFrameLoader* aStaticCloneOf);

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

@ -2754,9 +2754,8 @@ void nsFrameLoader::ActivateFrameEvent(const nsAString& aType, bool aCapture,
} }
} }
nsresult nsFrameLoader::FinishStaticClone(nsFrameLoader* aStaticCloneOf, nsresult nsFrameLoader::FinishStaticClone(
nsIDocShell** aCloneDocShell, nsFrameLoader* aStaticCloneOf, bool* aOutHasInProcessPrintCallbacks) {
Document** aCloneDocument) {
MOZ_DIAGNOSTIC_ASSERT( MOZ_DIAGNOSTIC_ASSERT(
!nsContentUtils::IsSafeToRunScript(), !nsContentUtils::IsSafeToRunScript(),
"A script blocker should be on the stack while FinishStaticClone is run"); "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())) { if (NS_WARN_IF(IsDead())) {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
if (NS_WARN_IF(aStaticCloneOf->IsRemoteFrame())) { if (NS_WARN_IF(aStaticCloneOf->IsRemoteFrame())) {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
@ -2793,12 +2793,9 @@ nsresult nsFrameLoader::FinishStaticClone(nsFrameLoader* aStaticCloneOf,
nsCOMPtr<Document> doc = origDocShell->GetDocument(); nsCOMPtr<Document> doc = origDocShell->GetDocument();
NS_ENSURE_STATE(doc); 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; 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 // After the parent document has been fully cloned, a new frameloader will be
// created for the cloned iframe, and `FinishStaticClone` will be called on // created for the cloned iframe, and `FinishStaticClone` will be called on
// it, which will clone the inner document of the source nsFrameLoader. // 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, nsresult FinishStaticClone(nsFrameLoader* aStaticCloneOf,
nsIDocShell** aCloneDocShell, bool* aOutHasInProcessPrintCallbacks);
Document** aCloneDocument);
// WebIDL methods // WebIDL methods

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

@ -5284,36 +5284,6 @@ void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
#endif #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( Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
nsIPrintSettings* aPrintSettings, nsIWebProgressListener* aListener, nsIPrintSettings* aPrintSettings, nsIWebProgressListener* aListener,
nsIDocShell* aDocShellToCloneInto, IsPreview aIsPreview, nsIDocShell* aDocShellToCloneInto, IsPreview aIsPreview,
@ -5431,23 +5401,12 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
auto dispatchAfterPrint = MakeScopeExit( auto dispatchAfterPrint = MakeScopeExit(
[&] { DispatchPrintEventToWindowTree(*docToPrint, u"afterprint"_ns); }); [&] { DispatchPrintEventToWindowTree(*docToPrint, u"afterprint"_ns); });
RefPtr<Document> clone; nsAutoScriptBlocker blockScripts;
{ RefPtr<Document> clone =
nsAutoScriptBlocker blockScripts; docToPrint->CreateStaticClone(cloneDocShell, cv, &hasPrintCallbacks);
clone = docToPrint->CreateStaticClone(cloneDocShell); if (!clone) {
if (!clone) { aError.ThrowNotSupportedError("Clone operation for printing failed");
aError.ThrowNotSupportedError("Clone operation for printing failed"); return nullptr;
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);
} }
} }