flypig.co.uk

List items

Items from the current list are shown below.

Blog

31 Dec 2023 : Day 124 #
Here in the UK as I write this it's verging on 2024. From the fireworks outside I can tell that new year celebrations have already started for some. But I still have just enough time to squeeze in a final Gecko Dev Diary for 2023.


 

What I'm really looking forward to in 2024 is not having to worry about the printing pipeline any more. And thankfully we're reaching the end game for this particular issue. But there are still plenty more things to work on to get this ESR 91 version of the engine working as well as ESR 78, so this is far from being close to my final post on the topic.

So please expect posts to continue as we fly headlong into the new year. To everyone who has been following along over the last 124 days, thank you so much for your time, commitment, Mastodon favourites, boosts, generous comments and generally hugely motivational interactions. It's been a wonderful experience for me.

But I mustn't get carried away when there's development to be done, so let's continue with today's post.

Following the plan I cooked up to suspend rendering when the "hidden" window is created, yesterday I attempted to avoid the flicker at the point when the user selects the "Save page to PDF" option. The approach failed, so I'm dropping the idea. It doesn't change the functionality and, in retrospect, suspending rendering was always likely to leave the display showing the background colour rather than the last thing rendered, so without a fair bit more engineering it was always likely to fail.

That means I'm moving on to refactoring the QML and DownloadPDFSaver code today.

To kick things off I've worked through all the changes I made to gecko-dev to expose the isForPrinting flag, converting it to a hidden flag in the process. All of these changes live in the EmbedLite portion of the code, which is ideally what we want because it avoids having to patch the upstream gecko-dev code itself.

I've also committed the changes to qtmozembed and sailfish-browser that are needed to support this too.

The next step is to backtrack and take another look at the changes made to gecko-dev that we inserted in order to support printing. This is covered by two commits the first of which, now I look at it, I made right at the start of December. It makes me think that I've been stalled on these printing changes for far too long.
$ git log -2
commit 2fb912372c0475c1ca84c381cf9927f75fe32595
    (HEAD -> FIREFOX_ESR_91_9_X_RELBRANCH_patches)
Author: David Llewellyn-Jones <david@flypig.co.uk>
Date:   Tue Dec 19 20:22:51 2023 +0000

    Call Print from the CanonicalBrowingContext
    
    Call Print from the CanonicalBrowsingContext rather than on the
    Ci.nsIWebBrowserPrint of the current window.

commit 26259399358f14e9695d7b9497aeb3a8577285a9
Author: David Llewellyn-Jones <david@flypig.co.uk>
Date:   Tue Dec 5 22:29:55 2023 +0000

    Reintroduce PDF printing code
    
    Reintroduces code to allow printing of a window. This essentially
    reverts the following three upstream commits:
    
    https://phabricator.services.mozilla.com/D84012
    
    https://phabricator.services.mozilla.com/D84137
    
    https://phabricator.services.mozilla.com/D83264
The plan was always to try to move the reverted changes in the "Reintroduce PDF printing code" from the gecko-dev code and into the EmbedLite code. More specifically, moving the changes in DownloadCore.jsm to EmbedLiteDownloadManager.js. This may turn out not to be practical, but I'd like to give it a go.

The DownloadPDFSaver class prototype itself looks pretty self-contained, so moving that to EmbedliteDownloadManager.js looks plausible. However there's also deserialisation code which looks a bit more baked in. In order to move the code, we'd have to perform the deserialisation in EmbedliteDownloadManager.js as well.

Thankfully I looked through this code quite carefully already on Day 99 at the start of December. It's these situations in which I'm glad to have recorded these notes, because reading through the post means I don't have to dig through the code all over again.

The flow is the following:
  1. EmbedliteDownloadManager.observe() in EmbedliteDownloadManager.js.
  2. Downloads.createDownload() in Downloads.jsm.
  3. Download.fromSerializable() in DownloadCore.jsm.
  4. DownloadSource.fromSerializable() and DownloadTarget.fromSerializable() in DownloadCore.jsm.
  5. DownloadSaver.fromSerializable() in DownloadCore.jsm.
  6. DownloadPDFSaver.fromSerializable() in DownloadCore.jsm.
The aim is to move DownloadPDFSaver into EmbedliteDownloadManager.js. But in order for this to work all of the steps between will need moving there too. In practice most of the logic in the intermediate fromSerializable() methods are conditions on the contents of the data passed in. If we're moving DownloadPDFSaver into EmbedliteDownloadManager.js then most of the logic becomes redundant because we'll only have to cover the one case. Moreover we don't really need to perform any deserialisation: we can just configure the DownloadPDFSaver class with the values we have directly.

So it looks like it should be straightforward, but will need a little care and testing.

I've hatched a plan for how to proceed that will start with me moving the DownloadPDFSaver code, then collecting together the data to be configured into this, all of which comes from the following "serialised" data structure that's created in EmbedliteDownloadManager.js:
{
  source: Services.ww.activeWindow,
  target: data.to,
  saver: "pdf",
  contentType: "application/pdf"
}
Thankfully that's not a lot of data to have to deal with. We'll need to end up with a promise that resolves to a Download structure that will look like this:
download = Download
{
	source: {
	    url: Services.ww.activeWindow.location.href,
	    isPrivate: PrivateBrowsingUtils.isContentWindowPrivate(
	        Services.ww.activeWindow
	    ),
	    windowRef: Cu.getWeakReference(Services.ww.activeWindow),
	},
	target: {
	    path: data.to,
	},
	saver: DownloadPDFSaver(
	    download: download,
	),
	contentType: "application/pdf",
	saveAsPdf: true,
}
That's simply the structure you get when you follow all of the fromSerializable() steps through the code. Once DownloadPDFSaver has been moved it doesn't look like there's anything else there that can't be accessed from the EmbedliteDownloadManager.js code.

But we'll find that out tomorrow when I actually try to implement this. Roll on 2024!

If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.

Comments

Uncover Disqus comments