Backed out 6 changesets (bug 1648064) for wp failures on test_printpreview.xhtml . CLOSED TREE

Backed out changeset 8ac892c60eda (bug 1648064)
Backed out changeset 189401f7b6e8 (bug 1648064)
Backed out changeset 2598e2706bd0 (bug 1648064)
Backed out changeset 4ec12eb9788c (bug 1648064)
Backed out changeset f735d4f6b21f (bug 1648064)
Backed out changeset 0fed6928b53d (bug 1648064)
This commit is contained in:
Narcis Beleuzu 2020-07-22 21:28:10 +03:00
parent 6a99a110b2
commit 46367e2f7d
27 changed files with 222 additions and 417 deletions

View File

@ -7564,44 +7564,26 @@ Element* Document::GetAnonRootIfInAnonymousContentContainer(
}
Maybe<ClientInfo> Document::GetClientInfo() const {
if (const Document* orig = GetOriginalDocument()) {
if (Maybe<ClientInfo> info = orig->GetClientInfo()) {
return info;
}
}
if (nsPIDOMWindowInner* inner = GetInnerWindow()) {
nsPIDOMWindowInner* inner = GetInnerWindow();
if (inner) {
return inner->GetClientInfo();
}
return Maybe<ClientInfo>();
}
Maybe<ClientState> Document::GetClientState() const {
if (const Document* orig = GetOriginalDocument()) {
if (Maybe<ClientState> state = orig->GetClientState()) {
return state;
}
}
if (nsPIDOMWindowInner* inner = GetInnerWindow()) {
nsPIDOMWindowInner* inner = GetInnerWindow();
if (inner) {
return inner->GetClientState();
}
return Maybe<ClientState>();
}
Maybe<ServiceWorkerDescriptor> Document::GetController() const {
if (const Document* orig = GetOriginalDocument()) {
if (Maybe<ServiceWorkerDescriptor> controller = orig->GetController()) {
return controller;
}
}
if (nsPIDOMWindowInner* inner = GetInnerWindow()) {
nsPIDOMWindowInner* inner = GetInnerWindow();
if (inner) {
return inner->GetController();
}
return Maybe<ServiceWorkerDescriptor>();
}
@ -10783,8 +10765,6 @@ void Document::DoUnblockOnload() {
if (mAsyncOnloadBlockCount != 0) {
// We need to wait until the async onload block has been handled.
//
// FIXME(emilio): Shouldn't we return here??
PostUnblockOnloadEvent();
}
@ -11123,14 +11103,6 @@ nsresult Document::CloneDocHelper(Document* clone) const {
NS_ENSURE_SUCCESS(rv, rv);
if (mCreatingStaticClone) {
if (mOriginalDocument) {
clone->mOriginalDocument = mOriginalDocument;
} else {
clone->mOriginalDocument = const_cast<Document*>(this);
}
clone->mOriginalDocument->mLatestStaticClone = clone;
clone->mOriginalDocument->mStaticCloneCount++;
nsCOMPtr<nsILoadGroup> loadGroup;
// |mDocumentContainer| is the container of the document that is being
@ -11162,7 +11134,6 @@ nsresult Document::CloneDocHelper(Document* clone) const {
RefPtr<nsDOMNavigationTiming> timing =
mTiming->CloneNavigationTime(nsDocShell::Cast(clone->GetDocShell()));
clone->SetNavigationTiming(timing);
clone->SetCsp(mCSP);
}
// Now ensure that our clone has the same URI, base URI, and principal as us.
@ -12143,6 +12114,16 @@ already_AddRefed<Document> Document::CreateStaticClone(
nsCOMPtr<Document> clonedDoc = do_QueryInterface(clonedNode);
if (clonedDoc) {
if (IsStaticDocument()) {
clonedDoc->mOriginalDocument = mOriginalDocument;
mOriginalDocument->mLatestStaticClone = clonedDoc;
} else {
clonedDoc->mOriginalDocument = this;
mLatestStaticClone = clonedDoc;
}
clonedDoc->mOriginalDocument->mStaticCloneCount++;
size_t sheetsCount = SheetCount();
for (size_t i = 0; i < sheetsCount; ++i) {
RefPtr<StyleSheet> sheet = SheetAt(i);

View File

@ -2627,8 +2627,7 @@ class Document : public nsINode,
bool ShouldLoadImages() const {
// We check IsBeingUsedAsImage() so that SVG documents loaded as
// images can themselves have data: URL image references.
return IsCurrentActiveDocument() || IsBeingUsedAsImage() ||
IsStaticDocument();
return IsCurrentActiveDocument() || IsBeingUsedAsImage();
}
/**
@ -2809,7 +2808,7 @@ class Document : public nsINode,
* If this document is a static clone, this returns the original
* document.
*/
Document* GetOriginalDocument() const {
Document* GetOriginalDocument() {
MOZ_ASSERT(!mOriginalDocument || !mOriginalDocument->GetOriginalDocument());
return mOriginalDocument;
}

View File

@ -3298,19 +3298,13 @@ bool nsContentUtils::IsInPrivateBrowsing(nsILoadGroup* aLoadGroup) {
return isPrivate;
}
// FIXME(emilio): This is (effectively) almost but not quite the same as
// Document::ShouldLoadImages(), which one is right?
bool nsContentUtils::DocumentInactiveForImageLoads(Document* aDocument) {
if (!aDocument) {
return false;
if (aDocument && !IsChromeDoc(aDocument) && !aDocument->IsResourceDoc()) {
nsCOMPtr<nsPIDOMWindowInner> win =
do_QueryInterface(aDocument->GetScopeObject());
return !win || !win->GetDocShell();
}
if (IsChromeDoc(aDocument) || aDocument->IsResourceDoc() ||
aDocument->IsStaticDocument()) {
return false;
}
nsCOMPtr<nsPIDOMWindowInner> win =
do_QueryInterface(aDocument->GetScopeObject());
return !win || !win->GetDocShell();
return false;
}
imgLoader* nsContentUtils::GetImgLoaderForDocument(Document* aDoc) {
@ -3448,6 +3442,15 @@ already_AddRefed<imgIContainer> nsContentUtils::GetImageFromContent(
return imgContainer.forget();
}
// static
already_AddRefed<imgRequestProxy> nsContentUtils::GetStaticRequest(
Document* aLoadingDocument, imgRequestProxy* aRequest) {
NS_ENSURE_TRUE(aRequest, nullptr);
RefPtr<imgRequestProxy> retval;
aRequest->GetStaticRequest(aLoadingDocument, getter_AddRefs(retval));
return retval.forget();
}
// static
bool nsContentUtils::ContentIsDraggable(nsIContent* aContent) {
MOZ_ASSERT(aContent);

View File

@ -936,6 +936,12 @@ class nsContentUtils {
static already_AddRefed<imgIContainer> GetImageFromContent(
nsIImageLoadingContent* aContent, imgIRequest** aRequest = nullptr);
/**
* Helper method to call imgIRequest::GetStaticRequest.
*/
static already_AddRefed<imgRequestProxy> GetStaticRequest(
Document* aLoadingDocument, imgRequestProxy* aRequest);
/**
* Method that decides whether a content node is draggable
*

View File

@ -75,29 +75,11 @@ nsDataDocumentContentPolicy::ShouldLoad(nsIURI* aContentLocation,
return NS_OK;
}
// Nothing else is OK to load for data documents
if (doc->IsLoadedAsData()) {
bool allowed = [&] {
if (!doc->IsStaticDocument()) {
// If not a print/print preview doc, then nothing else is allowed for
// data documents.
return false;
}
// Let static (print/print preview) documents to load fonts and
// images.
switch (contentType) {
case nsIContentPolicy::TYPE_IMAGE:
case nsIContentPolicy::TYPE_IMAGESET:
case nsIContentPolicy::TYPE_FONT:
// This one is a bit sketchy, but nsObjectLoadingContent takes care of
// only getting here if it is an image.
case nsIContentPolicy::TYPE_OBJECT:
return true;
default:
return false;
}
}();
if (!allowed) {
// ...but let static (print/print preview) documents to load fonts.
if (!doc->IsStaticDocument() ||
contentType != nsIContentPolicy::TYPE_FONT) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
return NS_OK;
}

View File

@ -5476,12 +5476,6 @@ CallState nsGlobalWindowInner::CallOnInProcessChildren(Method aMethod,
Maybe<ClientInfo> nsGlobalWindowInner::GetClientInfo() const {
MOZ_ASSERT(NS_IsMainThread());
if (mDoc && mDoc->IsStaticDocument()) {
if (Maybe<ClientInfo> info = mDoc->GetOriginalDocument()->GetClientInfo()) {
return info;
}
}
Maybe<ClientInfo> clientInfo;
if (mClientSource) {
clientInfo.emplace(mClientSource->Info());
@ -5491,13 +5485,6 @@ Maybe<ClientInfo> nsGlobalWindowInner::GetClientInfo() const {
Maybe<ClientState> nsGlobalWindowInner::GetClientState() const {
MOZ_ASSERT(NS_IsMainThread());
if (mDoc && mDoc->IsStaticDocument()) {
if (Maybe<ClientState> state =
mDoc->GetOriginalDocument()->GetClientState()) {
return state;
}
}
Maybe<ClientState> clientState;
if (mClientSource) {
Result<ClientState, ErrorResult> res = mClientSource->SnapshotState();
@ -5512,13 +5499,6 @@ Maybe<ClientState> nsGlobalWindowInner::GetClientState() const {
Maybe<ServiceWorkerDescriptor> nsGlobalWindowInner::GetController() const {
MOZ_ASSERT(NS_IsMainThread());
if (mDoc && mDoc->IsStaticDocument()) {
if (Maybe<ServiceWorkerDescriptor> controller =
mDoc->GetOriginalDocument()->GetController()) {
return controller;
}
}
Maybe<ServiceWorkerDescriptor> controller;
if (mClientSource) {
controller = mClientSource->GetController();

View File

@ -976,8 +976,8 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
// Do the load.
RefPtr<imgRequestProxy>& req = PrepareNextRequest(eImageLoadType_Normal);
nsresult rv = loader->LoadImageWithChannel(aChannel, this, doc,
aListener, getter_AddRefs(req));
nsresult rv = loader->LoadImageWithChannel(aChannel, this, doc, aListener,
getter_AddRefs(req));
if (NS_SUCCEEDED(rv)) {
CloneScriptedRequests(req);
TrackImage(req);
@ -1103,12 +1103,7 @@ nsresult nsImageLoadingContent::LoadImage(nsIURI* aNewURI, bool aForce,
// Data documents, or documents from DOMParser shouldn't perform image
// loading.
//
// FIXME(emilio): Shouldn't this check be part of
// Document::ShouldLoadImages()? Or alternatively check ShouldLoadImages here
// instead? (It seems we only check ShouldLoadImages in HTMLImageElement,
// which seems wrong...)
if (aDocument->IsLoadedAsData() && !aDocument->IsStaticDocument()) {
if (aDocument->IsLoadedAsData()) {
// This is the only codepath on which we can reach SetBlockedRequest while
// our pending request exists. Just clear it out here if we do have one.
ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DiscardImages));
@ -1739,6 +1734,26 @@ void nsImageLoadingContent::UntrackImage(
}
}
void nsImageLoadingContent::CreateStaticImageClone(
nsImageLoadingContent* aDest) const {
aDest->ClearScriptedRequests(CURRENT_REQUEST, NS_BINDING_ABORTED);
aDest->mCurrentRequest = nsContentUtils::GetStaticRequest(
aDest->GetOurOwnerDoc(), mCurrentRequest);
if (aDest->mCurrentRequest) {
aDest->CloneScriptedRequests(aDest->mCurrentRequest);
}
aDest->TrackImage(aDest->mCurrentRequest);
aDest->mForcedImageState = mForcedImageState;
aDest->mImageBlockingStatus = mImageBlockingStatus;
aDest->mLoadingEnabled = mLoadingEnabled;
aDest->mStateChangerDepth = mStateChangerDepth;
aDest->mIsImageStateForced = mIsImageStateForced;
aDest->mLoading = mLoading;
aDest->mBroken = mBroken;
aDest->mUserDisabled = mUserDisabled;
aDest->mSuppressed = mSuppressed;
}
CORSMode nsImageLoadingContent::GetCORSMode() { return CORS_NONE; }
nsImageLoadingContent::ImageObserver::ImageObserver(
@ -1839,7 +1854,6 @@ Element* nsImageLoadingContent::FindImageMap() {
nsLoadFlags nsImageLoadingContent::LoadFlags() {
auto* image = HTMLImageElement::FromNode(AsContent());
if (image && image->OwnerDoc()->IsScriptEnabled() &&
!image->OwnerDoc()->IsStaticDocument() &&
image->LoadingState() == HTMLImageElement::Loading::Lazy) {
// Note that LOAD_BACKGROUND is not about priority of the load, but about
// whether it blocks the load event (by bypassing the loadgroup).

View File

@ -373,6 +373,8 @@ class nsImageLoadingContent : public nsIImageLoadingContent {
nsresult StringToURI(const nsAString& aSpec,
mozilla::dom::Document* aDocument, nsIURI** aURI);
void CreateStaticImageClone(nsImageLoadingContent* aDest) const;
/**
* Prepare and returns a reference to the "next request". If there's already
* a _usable_ current request (one with SIZE_AVAILABLE), this request is

View File

@ -1837,21 +1837,10 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
// XXX(johns): In these cases, we refuse to touch our content and just
// remain unloaded, as per legacy behavior. It would make more sense to
// load fallback content initially and refuse to ever change state again.
if (doc->IsBeingUsedAsImage()) {
if (doc->IsBeingUsedAsImage() || doc->IsLoadedAsData()) {
return NS_OK;
}
if (doc->IsLoadedAsData() && !doc->IsStaticDocument()) {
return NS_OK;
}
if (doc->IsStaticDocument()) {
// We only allow image loads in static documents, but we need to let the
// eType_Loading state go through too while we do so.
if (mType != eType_Image && mType != eType_Loading) {
return NS_OK;
}
}
LOG(("OBJLC [%p]: LoadObject called, notify %u, forceload %u, channel %p",
this, aNotify, aForceLoad, aLoadingChannel));
@ -2601,6 +2590,8 @@ nsPluginFrame* nsObjectLoadingContent::GetExistingFrame() {
void nsObjectLoadingContent::CreateStaticClone(
nsObjectLoadingContent* aDest) const {
nsImageLoadingContent::CreateStaticImageClone(aDest);
aDest->mType = mType;
nsObjectLoadingContent* thisObj = const_cast<nsObjectLoadingContent*>(this);
if (thisObj->mPrintFrame.IsAlive()) {

View File

@ -735,25 +735,32 @@ uint32_t HTMLImageElement::NaturalWidth() {
}
nsresult HTMLImageElement::CopyInnerTo(HTMLImageElement* aDest) {
bool destIsStatic = aDest->OwnerDoc()->IsStaticDocument();
if (destIsStatic) {
CreateStaticImageClone(aDest);
}
nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
if (NS_FAILED(rv)) {
return rv;
}
// In SetAttr (called from nsGenericHTMLElement::CopyInnerTo), aDest skipped
// doing the image load because we passed in false for aNotify. But we
// really do want it to do the load, so set it up to happen once the cloning
// reaches a stable state.
if (!aDest->InResponsiveMode() &&
aDest->HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
aDest->ShouldLoadImage()) {
// Mark channel as urgent-start before load image if the image load is
// initaiated by a user interaction.
mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput();
if (!destIsStatic) {
// In SetAttr (called from nsGenericHTMLElement::CopyInnerTo), aDest skipped
// doing the image load because we passed in false for aNotify. But we
// really do want it to do the load, so set it up to happen once the cloning
// reaches a stable state.
if (!aDest->InResponsiveMode() &&
aDest->HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
aDest->ShouldLoadImage()) {
// Mark channel as urgent-start before load image if the image load is
// initaiated by a user interaction.
mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput();
nsContentUtils::AddScriptRunner(NewRunnableMethod<bool>(
"dom::HTMLImageElement::MaybeLoadImage", aDest,
&HTMLImageElement::MaybeLoadImage, false));
nsContentUtils::AddScriptRunner(NewRunnableMethod<bool>(
"dom::HTMLImageElement::MaybeLoadImage", aDest,
&HTMLImageElement::MaybeLoadImage, false));
}
}
return NS_OK;
@ -1256,10 +1263,7 @@ void HTMLImageElement::SetLazyLoading() {
// If scripting is disabled don't do lazy load.
// https://whatpr.org/html/3752/images.html#updating-the-image-data
//
// Same for printing.
Document* doc = OwnerDoc();
if (!doc->IsScriptEnabled() || doc->IsStaticDocument()) {
if (!OwnerDoc()->IsScriptEnabled()) {
return;
}

View File

@ -1088,6 +1088,9 @@ nsresult HTMLInputElement::Clone(dom::NodeInfo* aNodeInfo,
}
break;
case VALUE_MODE_DEFAULT:
if (mType == NS_FORM_INPUT_IMAGE && it->OwnerDoc()->IsStaticDocument()) {
CreateStaticImageClone(it);
}
break;
}

View File

@ -306,5 +306,12 @@ SVGElement::StringAttributesInfo SVGImageElement::GetStringInfo() {
ArrayLength(sStringInfo));
}
nsresult SVGImageElement::CopyInnerTo(Element* aDest) {
if (aDest->OwnerDoc()->IsStaticDocument()) {
CreateStaticImageClone(static_cast<SVGImageElement*>(aDest));
}
return SVGImageElementBase::CopyInnerTo(aDest);
}
} // namespace dom
} // namespace mozilla

View File

@ -83,6 +83,8 @@ class SVGImageElement : public SVGImageElementBase,
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
void MaybeLoadSVGImage();
// WebIDL

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Undefine windows version of LoadImage because our code uses that name.
#include "mozilla/ScopeExit.h"
#undef LoadImage
#include "imgLoader.h"
@ -1698,7 +1697,7 @@ bool imgLoader::ValidateRequestWithNewChannel(
validator->AddProxy(proxy);
}
return true;
return NS_SUCCEEDED(rv);
}
// We will rely on Necko to cache this request when it's possible, and to
// tell imgCacheValidator::OnStartRequest whether the request came from its
@ -2126,29 +2125,6 @@ imgLoader::LoadImageXPCOM(
return rv;
}
static void MakeRequestStaticIfNeeded(
Document* aLoadingDocument,
imgRequestProxy** aProxyAboutToGetReturned) {
if (!aLoadingDocument || !aLoadingDocument->IsStaticDocument()) {
return;
}
if (!*aProxyAboutToGetReturned) {
return;
}
RefPtr<imgRequestProxy> proxy = dont_AddRef(*aProxyAboutToGetReturned);
*aProxyAboutToGetReturned = nullptr;
RefPtr<imgRequestProxy> staticProxy =
proxy->GetStaticRequest(aLoadingDocument);
if (staticProxy != proxy) {
proxy->CancelAndForgetObserver(NS_BINDING_ABORTED);
proxy = std::move(staticProxy);
}
proxy.forget(aProxyAboutToGetReturned);
}
nsresult imgLoader::LoadImage(
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIReferrerInfo* aReferrerInfo,
nsIPrincipal* aTriggeringPrincipal, uint64_t aRequestContextID,
@ -2165,10 +2141,6 @@ nsresult imgLoader::LoadImage(
return NS_ERROR_NULL_POINTER;
}
auto makeStaticIfNeeded = mozilla::MakeScopeExit([&] {
MakeRequestStaticIfNeeded(aLoadingDocument, _retval);
});
#ifdef MOZ_GECKO_PROFILER
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("imgLoader::LoadImage", NETWORK,
aURI->GetSpecOrDefault());
@ -2527,10 +2499,6 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
MOZ_ASSERT(NS_UsePrivateBrowsing(channel) == mRespectPrivacy);
auto makeStaticIfNeeded = mozilla::MakeScopeExit([&] {
MakeRequestStaticIfNeeded(aLoadingDocument, _retval);
});
LOG_SCOPE(gImgLog, "imgLoader::LoadImageWithChannel");
RefPtr<imgRequest> request;

View File

@ -1053,21 +1053,29 @@ void imgRequestProxy::NullOutListener() {
NS_IMETHODIMP
imgRequestProxy::GetStaticRequest(imgIRequest** aReturn) {
RefPtr<imgRequestProxy> proxy =
GetStaticRequest(static_cast<Document*>(nullptr));
proxy.forget(aReturn);
return NS_OK;
imgRequestProxy* proxy;
nsresult result = GetStaticRequest(nullptr, &proxy);
*aReturn = proxy;
return result;
}
already_AddRefed<imgRequestProxy> imgRequestProxy::GetStaticRequest(
Document* aLoadingDocument) {
MOZ_DIAGNOSTIC_ASSERT(!aLoadingDocument || aLoadingDocument->IsStaticDocument());
nsresult imgRequestProxy::GetStaticRequest(Document* aLoadingDocument,
imgRequestProxy** aReturn) {
*aReturn = nullptr;
RefPtr<Image> image = GetImage();
bool animated;
if (!image || (NS_SUCCEEDED(image->GetAnimated(&animated)) && !animated)) {
// Early exit - we're not animated, so we don't have to do anything.
return do_AddRef(this);
NS_ADDREF(*aReturn = this);
return NS_OK;
}
// Check for errors in the image. Callers code rely on GetStaticRequest
// failing in this case, though with FrozenImage there's no technical reason
// for it anymore.
if (image->HasError()) {
return NS_ERROR_FAILURE;
}
// We are animated. We need to create a frozen version of this image.
@ -1082,7 +1090,9 @@ already_AddRefed<imgRequestProxy> imgRequestProxy::GetStaticRequest(
frozenImage, currentPrincipal, hadCrossOriginRedirects);
req->Init(nullptr, nullptr, aLoadingDocument, mURI, nullptr);
return req.forget();
NS_ADDREF(*aReturn = req);
return NS_OK;
}
void imgRequestProxy::NotifyListener() {

View File

@ -123,7 +123,8 @@ class imgRequestProxy : public mozilla::PreloaderBase,
Document* aLoadingDocument, imgRequestProxy** aClone);
nsresult Clone(imgINotificationObserver* aObserver,
Document* aLoadingDocument, imgRequestProxy** aClone);
already_AddRefed<imgRequestProxy> GetStaticRequest(Document* aLoadingDocument);
nsresult GetStaticRequest(Document* aLoadingDocument,
imgRequestProxy** aReturn);
imgRequest* GetOwner() const;

View File

@ -22,11 +22,6 @@ support-files =
printpreview_font_mozprintcallback_ref.html
printpreview_quirks.html
printpreview_quirks_ref.html
printpreview_images.html
printpreview_images_ref.html
printpreview_images_sw.html
printpreview_images_sw_ref.html
printpreview_images_sw.js
test_document_adopted_styles.html
test_document_adopted_styles_ref.html
test_shadow_root_adopted_styles.html

View File

@ -16,7 +16,6 @@ var is = window.arguments[0].is;
var isnot = window.arguments[0].isnot;
var ok = window.arguments[0].ok;
var todo = window.arguments[0].todo;
var info = window.arguments[0].info;
var SimpleTest = window.arguments[0].SimpleTest;
var gWbp;
var ctx1;
@ -30,28 +29,15 @@ filePath = file.path;
function printpreview(hasMozPrintCallback) {
gWbp = frameElts[1].docShell.initOrReusePrintPreviewViewer();
let resolve;
let promise = new Promise(r => { resolve = r });
var listener = {
onLocationChange: function(webProgress, request, location, flags) { },
onProgressChange: function(webProgress, request, curSelfProgress,
maxSelfProgress, curTotalProgress,
maxTotalProgress) {
info("onProgressChange", [...arguments].join(", "));
},
maxTotalProgress) { },
onSecurityChange: function(webProgress, request, state) { },
onStateChange: function(webProgress, request, stateFlags, status) {
info("onStateChange", [...arguments].join(", "));
if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
setTimeout(resolve, 0);
}
},
onStatusChange: function(webProgress, request, status, message) {
info("onStatusChange", [...arguments].join(", "));
},
onContentBlockingEvent: function(webProgress, request, event) {
info("onContentBlockingEvent", [...arguments].join(", "));
},
onStateChange: function(webProgress, request, stateFlags, status) { },
onStatusChange: function(webProgress, request, status, message) { },
onContentBlockingEvent: function(webProgress, request, event) { },
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIWebProgressListener) ||
iid.equals(Ci.nsISupportsWeakReference))
@ -62,7 +48,6 @@ function printpreview(hasMozPrintCallback) {
var settings = Cc["@mozilla.org/gfx/printsettings-service;1"]
.getService(Ci.nsIPrintSettingsService).globalPrintSettings;
settings.showPrintProgress = false;
settings.printBGColors = true;
var before = 0;
var after = 0;
function beforeprint() { ++before; }
@ -78,7 +63,6 @@ function printpreview(hasMozPrintCallback) {
}
frameElts[0].contentWindow.removeEventListener("beforeprint", beforeprint, true);
frameElts[0].contentWindow.removeEventListener("afterprint", afterprint, true);
return promise;
}
function exitprintpreview() {
@ -103,20 +87,15 @@ function runTests()
}
}
function compareCanvases(options = {}) {
function compareCanvases() {
const canvas1 = document.getElementsByTagName("canvas")[0];
const canvas2 = document.getElementsByTagName("canvas")[1];
let maxDifference = {};
const differingPixels = window.windowUtils.compareCanvases(canvas1, canvas2, maxDifference);
if (differingPixels) {
todo(false, "different: " + differingPixels + ", maxDifference: " + maxDifference.value);
const result = window.windowUtils.compareCanvases(canvas1, canvas2, {}) == 0;
if (!result) {
todo(false, "TEST CASE: " + canvas1.toDataURL());
todo(false, "REFERENCE: " + canvas2.toDataURL());
}
let maxAllowedDifferent = options.maxDifferent || 0;
let maxAllowedDifference = options.maxDifference || 0;
return differingPixels <= maxAllowedDifferent && maxDifference.value <= maxAllowedDifference;
return result;
}
function addHTMLContent(parent) {
@ -144,7 +123,7 @@ function startTest1() {
frameElts[0].contentWindow.setTimeout(frameElts[0].contentWindow.counterTimeout, 0);
frameElts[0].contentDocument.body.firstChild.innerHTML = "Print preview";
let ppfinished = printpreview();
printpreview();
ctx1.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(256,256,256)");
frameElts[0].contentDocument.body.firstChild.innerHTML = "Galley presentation";
@ -155,13 +134,10 @@ function startTest1() {
// And readd.
addHTMLContent(frameElts[0].contentDocument.body.lastChild);
setTimeout(function() {
finalizeTest1(ppfinished)
}, 1000);
setTimeout(finalizeTest1, 1000);
}
async function finalizeTest1(ppfinished) {
await ppfinished;
function finalizeTest1() {
ctx2.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(256,256,256)");
exitprintpreview();
ok(compareCanvases(), "Canvas should be the same!");
@ -227,17 +203,17 @@ function runTest3() {
setTimeout(runTest4, 0)
}
async function compareFormElementPrint(el1, el2, equals) {
function compareFormElementPrint(el1, el2, equals) {
frameElts[0].contentDocument.body.innerHTML = el1;
frameElts[0].contentDocument.body.firstChild.value =
frameElts[0].contentDocument.body.firstChild.getAttribute('value');
await printpreview();
printpreview();
ctx1.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(256,256,256)");
exitprintpreview();
frameElts[0].contentDocument.body.innerHTML = el2;
frameElts[0].contentDocument.body.firstChild.value =
frameElts[0].contentDocument.body.firstChild.getAttribute('value');
await printpreview();
printpreview();
ctx2.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(256,256,256)");
exitprintpreview();
is(compareCanvases(), equals,
@ -252,19 +228,19 @@ function runTest4() {
setTimeout(runTest4end, 500);
}
async function runTest4end() {
await printpreview();
function runTest4end() {
printpreview();
exitprintpreview();
runTest5();
}
// This is a crash test for bug 595337
async function runTest5() {
function runTest5() {
frameElts[0].contentDocument.body.innerHTML =
'<iframe style="position: fixed; visibility: hidden; bottom: 10em;"></iframe>' +
'<input contenteditable="true" style="display: table; page-break-before: left; width: 10000px;">';
await printpreview();
printpreview();
exitprintpreview();
setTimeout(runTest6, 0);
@ -279,28 +255,28 @@ function runTest6() {
setTimeout(runTest6end, 500);
}
async function runTest6end() {
await printpreview();
function runTest6end() {
printpreview();
exitprintpreview();
requestAnimationFrame(function() { setTimeout(runTest7); } );
}
async function runTest7() {
function runTest7() {
var contentText = "<a href='#'>mozilla</a><input>test<select><option>option1</option></select>";
// Create normal content
frameElts[0].contentDocument.body.innerHTML =
"<div>" + contentText + "</div>";
frameElts[0].contentDocument.body.firstChild.value =
frameElts[0].contentDocument.body.firstChild.getAttribute('value');
await printpreview();
printpreview();
ctx1.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
frameElts[0].contentDocument.body.innerHTML = "<div></div>";
var sr = frameElts[0].contentDocument.body.firstChild.attachShadow({mode: "open"});
sr.innerHTML = contentText;
await printpreview();
printpreview();
ctx2.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
ok(compareCanvases(), "Printing light DOM and shadow DOM should create same output");
@ -317,7 +293,7 @@ async function runTest8() {
iframeElement.addEventListener("load", resolve, { capture: true, once: true });
iframeElement.setAttribute("src", "printpreview_font_api_ref.html");
});
await printpreview();
printpreview();
ctx1.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
@ -326,7 +302,7 @@ async function runTest8() {
iframeElement.addEventListener("message", resolve, { capture: true, once: true });
iframeElement.setAttribute("src", "printpreview_font_api.html");
});
await printpreview();
printpreview();
ctx2.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
ok(compareCanvases(), "Printing pages with fonts loaded from CSS and JS should be the same.");
@ -342,7 +318,7 @@ async function runTest9() {
</svg>
`;
await printpreview();
printpreview();
ctx1.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
@ -364,7 +340,7 @@ async function runTest9() {
// Ensure the <use> shadow tree is created so we test what we want to test.
frameElts[0].contentDocument.body.offsetTop;
await printpreview();
printpreview();
ctx2.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
ok(compareCanvases(), "Printing <use> subtrees should create same output");
@ -386,7 +362,7 @@ async function runTest10() {
let mozPrintCallbackDone = new Promise((resolve) => {
iframeElement.addEventListener("message", resolve, { capture: true, once: true });
});
await printpreview(true);
printpreview(true);
await mozPrintCallbackDone;
ctx1.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
@ -399,7 +375,7 @@ async function runTest10() {
mozPrintCallbackDone = new Promise((resolve) => {
iframeElement.addEventListener("message", resolve, { capture: true, once: true });
});
await printpreview(true);
printpreview(true);
// Wait for the mozprintcallback to finish.
await mozPrintCallbackDone;
ctx2.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
@ -410,43 +386,26 @@ async function runTest10() {
requestAnimationFrame(function() { setTimeout(runTest11); } );
}
async function compareFiles(src1, src2, options = {}) {
const BASE = "https://example.org/chrome/layout/base/tests/chrome/";
info(`Comparing ${src1} with ${src2}`);
async function compareFiles(src1, src2) {
const iframeElement = document.getElementsByTagName("iframe")[0];
let messagePromise = null;
if (options.waitForMessage) {
messagePromise = new Promise(resolve => {
iframeElement.addEventListener("message", resolve, { capture: true, once: true });
});
}
await new Promise((resolve) => {
iframeElement.addEventListener("load", resolve, { capture: true, once: true });
iframeElement.setAttribute("src", BASE + src1);
iframeElement.setAttribute("src", src1);
});
if (messagePromise) {
info("awaiting for message to arrive");
await messagePromise;
}
await printpreview();
printpreview();
ctx1.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
await new Promise((resolve) => {
iframeElement.addEventListener("load", resolve, { capture: true, once: true });
iframeElement.setAttribute("src", BASE + src2);
iframeElement.setAttribute("src", src2);
});
await printpreview();
printpreview();
ctx2.drawWindow(frameElts[1].contentWindow, 0, 0, 400, 400, "rgb(255,255,255)");
exitprintpreview();
ok(compareCanvases(options), `Printing ${src1} and ${src2} should produce the same results`);
ok(compareCanvases(), `Printing ${src1} and ${src2} should produce the same results`);
}
// bug 1567105
@ -476,28 +435,14 @@ async function runTest14() {
// Crash test for bug 1615261
async function runTest15() {
frameElts[0].contentDocument.body.innerHTML =
'<style>div { width: 100px; height: 100px; background-image: url("animated.gif"); } </style>' +
'<style> div { width: 100px; height: 100px; background-image: url("animated.gif"); } </style>' +
'<div>Firefox will crash if you try and print this page</div>';
// XXX Is there a more reliable way to wait for the background-image to load?
await new Promise(resolve => setTimeout(resolve, 500));
await printpreview();
await exitprintpreview();
requestAnimationFrame(function() { setTimeout(runTest16); } );
}
// Various image tests.
async function runTest16() {
// fuzzy: SVG image in the test pixel-snaps different than <div> in the ref.
await compareFiles("printpreview_images.html", "printpreview_images_ref.html", { maxDifferent: 118, maxDifference: 177 });
requestAnimationFrame(function() { setTimeout(runTest17); } );
}
async function runTest17() {
// fuzzy: SVG image in the test pixel-snaps different than <div> in the ref.
await compareFiles("printpreview_images_sw.html", "printpreview_images_sw_ref.html", { waitForMessage: true, maxDifferent: 118, maxDifference: 177 });
printpreview();
exitprintpreview();
finish();
}

View File

@ -1,25 +0,0 @@
<!doctype html>
<style>
img, object, svg, input { display: block }
div {
content: url(blue-32x32.png);
width: 32px;
height: 32px;
}
</style>
<div></div>
<picture>
<source srcset="blue-32x32.png">
<img width=32 height=32>
</picture>
<picture>
<source srcset="blue-32x32.png" media="print">
<source srcset="animated.gif" media="not print">
<img width=32 height=32>
</picture>
<img src="blue-32x32.png" width=32 height=32>
<object data="blue-32x32.png" width=32 height=32></object>
<svg width="32" height="32">
<image x=0 y=0 href="blue-32x32.png" width=32 height=32></image>
</svg>
<input type="image" src="blue-32x32.png" width=32 height=32>

View File

@ -1,15 +0,0 @@
<!doctype html>
<style>
div {
width: 32px;
height: 32px;
background-color: blue;
}
</style>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

View File

@ -1,46 +0,0 @@
<!doctype html>
<style>
img, object, svg, input { display: block }
div {
content: url(nonexistent.png?1);
width: 32px;
height: 32px;
}
</style>
<script>
const WORKER = "printpreview_images_sw.js";
if (location.href.includes("registered")) {
console.log("REGISTERED");
onload = function() {
postMessage("ready", "*");
}
onbeforeunload = function() {
navigator.serviceWorker.getRegistrations().then(function(registrations) {
for(let registration of registrations) {
registration.unregister()
}
})
navigator.serviceWorker.unregister(WORKER);
}
} else {
navigator.serviceWorker.oncontrollerchange = function() {
location.href = location.href + "?registered";
};
navigator.serviceWorker.register(WORKER);
}
</script>
<div></div>
<picture>
<source srcset="nonexistent.png?2">
<img width=32 height=32>
</picture>
<picture>
<source srcset="nonexistent.png?3" media="print">
<source srcset="animated.gif" media="not print">
<img width=32 height=32>
</picture>
<img src="nonexistent.png?4" width=32 height=32>
<svg width="32" height="32">
<image x=0 y=0 href="nonexistent.png?7" width=32 height=32></image>
</svg>
<input type="image" src="nonexistent.png?6" width=32 height=32>

View File

@ -1,11 +0,0 @@
self.addEventListener("fetch", event => {
if (event.request.url.includes("nonexistent.png")) {
event.respondWith(
fetch(event.request.url.replace("nonexistent.png", "blue-32x32.png"))
);
}
});
self.addEventListener("activate", event => {
event.waitUntil(clients.claim());
});

View File

@ -1,14 +0,0 @@
<!doctype html>
<style>
div {
width: 32px;
height: 32px;
background-color: blue;
}
</style>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

View File

@ -6,7 +6,6 @@
#include "nsPrintJob.h"
#include "nsDebug.h"
#include "nsDocShell.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
@ -17,7 +16,6 @@
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/CustomEvent.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/StaticPrefs_print.h"
#include "mozilla/Telemetry.h"
@ -26,8 +24,6 @@
#include "nsIScriptGlobalObject.h"
#include "nsIStringBundle.h"
#include "nsPIDOMWindow.h"
#include "nsPrintData.h"
#include "nsPrintObject.h"
#include "nsIDocShell.h"
#include "nsIURI.h"
#include "nsITextToSubURI.h"
@ -914,13 +910,14 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
}
// Attach progressListener to catch network requests.
mDidLoadDataForPrinting = false;
nsCOMPtr<nsIWebProgress> webProgress =
do_QueryInterface(printData->mPrintObject->mDocShell);
webProgress->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
nsIWebProgress::NOTIFY_STATE_REQUEST);
mLoadCounter = 0;
mDidLoadDataForPrinting = false;
if (mIsCreatingPrintPreview) {
bool notifyOnInit = false;
ShowPrintProgress(false, notifyOnInit);
@ -1684,33 +1681,18 @@ nsresult nsPrintJob::InitPrintDocConstruction(bool aHandleError) {
// Guarantee that mPrt->mPrintObject won't be deleted. It's owned by mPrt.
// So, we should grab it with local variable.
RefPtr<nsPrintData> printData = mPrt;
rv = ReflowDocList(printData->mPrintObject, DoSetPixelScale());
NS_ENSURE_SUCCESS(rv, rv);
FirePrintPreviewUpdateEvent();
MaybeResumePrintAfterResourcesLoaded(aHandleError);
if (mLoadCounter == 0) {
ResumePrintAfterResourcesLoaded(aHandleError);
}
return rv;
}
bool nsPrintJob::ShouldResumePrint() const {
Document* doc = mPrt->mPrintObject->mDocument;
MOZ_ASSERT(doc);
NS_ENSURE_TRUE(doc, true);
nsCOMPtr<nsILoadGroup> lg = doc->GetDocumentLoadGroup();
NS_ENSURE_TRUE(lg, true);
bool pending = false;
nsresult rv = lg->IsPending(&pending);
NS_ENSURE_SUCCESS(rv, true);
return !pending;
}
nsresult nsPrintJob::MaybeResumePrintAfterResourcesLoaded(bool aCleanupOnError) {
if (!ShouldResumePrint()) {
mDidLoadDataForPrinting = true;
return NS_OK;
}
nsresult nsPrintJob::ResumePrintAfterResourcesLoaded(bool aCleanupOnError) {
// If Destroy() has already been called, mPtr is nullptr. Then, the instance
// needs to do nothing anymore in this method.
// Note: it shouldn't be possible for mPrt->mPrintObject to be null; we
@ -1751,9 +1733,22 @@ nsresult nsPrintJob::MaybeResumePrintAfterResourcesLoaded(bool aCleanupOnError)
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
nsPrintJob::OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) {
if (aStateFlags & STATE_STOP) {
// If all resources are loaded, then finish and reflow.
MaybeResumePrintAfterResourcesLoaded(/* aCleanupOnError */ true);
nsAutoCString name;
aRequest->GetName(name);
if (name.EqualsLiteral("about:document-onload-blocker")) {
return NS_OK;
}
if (aStateFlags & STATE_START) {
++mLoadCounter;
} else if (aStateFlags & STATE_STOP) {
mDidLoadDataForPrinting = true;
--mLoadCounter;
// If all resources are loaded, then do a small timeout and if there
// are still no new requests, then another reflow.
if (mLoadCounter == 0) {
ResumePrintAfterResourcesLoaded(/* aCleanupOnError */ true);
}
}
return NS_OK;
}

View File

@ -243,9 +243,7 @@ class nsPrintJob final : public nsIObserver,
* (if it has a 'print' style sheet, for example).
*/
MOZ_CAN_RUN_SCRIPT nsresult
MaybeResumePrintAfterResourcesLoaded(bool aCleanupOnError);
bool ShouldResumePrint() const;
ResumePrintAfterResourcesLoaded(bool aCleanupOnError);
nsresult SetRootView(nsPrintObject* aPO, bool& aDoReturn,
bool& aDocumentIsTopLevel, nsSize& aAdjSize);
@ -289,6 +287,7 @@ class nsPrintJob final : public nsIObserver,
nsPagePrintTimer* mPagePrintTimer = nullptr;
float mScreenDPI = 115.0f;
int32_t mLoadCounter = 0;
bool mIsCreatingPrintPreview = false;
bool mIsDoingPrinting = false;

View File

@ -402,15 +402,46 @@ already_AddRefed<imgRequestProxy> ImageLoader::LoadImage(
const URLExtraData& data = aImage.ExtraData();
// NB: If aDocument is not the original document, we may not be able to load
// images from aDocument. Instead we do the image load from the original
// doc and clone it to aDocument.
Document* loadingDoc = aDocument.GetOriginalDocument();
const bool isPrint = !!loadingDoc;
if (!loadingDoc) {
loadingDoc = &aDocument;
}
RefPtr<imgRequestProxy> request;
nsresult rv = nsContentUtils::LoadImage(
uri, &aDocument, &aDocument, data.Principal(), 0, data.ReferrerInfo(),
sImageObserver, loadFlags, u"css"_ns,
getter_AddRefs(request));
uri, loadingDoc, loadingDoc, data.Principal(), 0, data.ReferrerInfo(),
sImageObserver, loadFlags, u"css"_ns, getter_AddRefs(request));
if (NS_FAILED(rv) || !request) {
return nullptr;
}
if (isPrint) {
RefPtr<imgRequestProxy> ret;
request->GetStaticRequest(&aDocument, getter_AddRefs(ret));
// Now we have a static image. If it is different from the one from the
// loading doc (that is, `request` is an animated image, and `ret` is a
// frozen version of it), we can forget about notifications from the
// animated image (assuming nothing else cares about it already).
//
// This is not technically needed for correctness, but helps keep the
// invariant that we only receive notifications for images that are in
// `sImages`.
if (ret != request) {
if (!sImages->Contains(request)) {
request->CancelAndForgetObserver(NS_BINDING_ABORTED);
}
if (!ret) {
return nullptr;
}
request = std::move(ret);
}
}
sImages->LookupForAdd(request).OrInsert([] { return new ImageTableEntry(); });
return request.forget();
}

View File

@ -1,2 +0,0 @@
[table-background-print.html]
fuzzy: maxDifference=84;totalPixels=132