Support beforeprint and afterprint events

RESOLVED FIXED in mozilla6



Printing: Output
12 years ago
5 months ago


(Reporter: Darin Fisher, Assigned: smaug)


(Depends on: 2 bugs, {dev-doc-complete})

Dependency tree / graph

Firefox Tracking Flags

(Not tracked)



(4 attachments, 5 obsolete attachments)



12 years ago
Support onbeforeprint and onafterprint events

IE generates these events, which can be very useful for webapps that wish to
have greater control over printing.  @media style sheets are great, but the
requested DOM events give webapps more options.

Comment 1

12 years ago
I think this is a great idea, but it's important to make sure that it's easy to
avoid onbeforeprint handlers to foil attempts by web page authors to make pages
unprintable.  Perhaps the Print dialog could have a checkbox to disable
onbeforeprint if the web page traps it?

Comment 2

12 years ago
I would hope turning JavaScript off would foil any such handlers.
it may or may not be of interest to people that this topic was/is recently
discussed on the whatwg mailing list...

Comment 4

12 years ago
Taking.  I've been working on this and have something functional.
Assignee: printing → mark

Comment 5

12 years ago
*** Bug 283329 has been marked as a duplicate of this bug. ***

Comment 6

12 years ago
Created attachment 208379 [details] [diff] [review]
Initial implementation

This isn't doing anyone any good sitting around in my $HOME.  Here's my first cut.

Comment 7

12 years ago
I'm taking this bug and un-bitrotting Mark's patch; to be posted shortly.
Assignee: mark → pkasting

Comment 8

12 years ago
Created attachment 219808 [details] [diff] [review]
Un-bitrotted version of previous patch

OK, here's a cleaned-up version of Mark's patch.  I moved a few bits around as seems appropriate.  The key file to review here is nsDocumentViewer.cpp, which is where the events actually get fired; I'd like to make sure I'm doing things in the right places.

In my tests, onbeforeprint gets fired before the print dialog/preview come up (same as IE), while onafterprint gets fired after we close the preview/dismiss the dialog (whereas IE fires it before any dialogs appear, so right after onbeforeprint gets fired).  Presumably IE renders the page to somewhere in memory before pulling up the preview/dialog.  I don't think it's important to match this behavior.
Attachment #208379 - Attachment is obsolete: true
Attachment #219808 - Flags: review?(bzbarsky)
FWIW, the print-preview version of after-print with this patch is probably firing at an unsafe time...
Past that, I'm not the right reviewer for this patch; you want someone familiar with the guts of the event code.

Comment 11

12 years ago
Comment on attachment 219808 [details] [diff] [review]
Un-bitrotted version of previous patch

OK, changing review request to jst.  I hope that's an appropriate target; please advise if not.

As to "unsafe place", can you clarify?  There's two different places onafterprint fires for the preview case, and I'm not sure which (both?) you're referring to or what you mean, exactly.
Attachment #219808 - Flags: review?(bzbarsky) → review?(jst)
For the event guts parts of this bug, I'd think you want either bryner or smaug.  For the actual document viewer changes, jst is probably good...

As for the other, I mean both, though the first time around I was looking at the Destroy() callsite.

As to what I mean by unsafe....  Consider the code in DocumentViewerImpl::ReturnToGalleyPresentation.  When you call DispatchDOMEvent, arbitrary script can run.  In particular, it can possibly cause the DocumentViewerImpl object to be destroyed.  It can _definitely_ cause the mViewManager pointer to become null (which will cause us to crash).  It can also definitely cause Close() to be called, which will fire a second afterprint event (since we haven't called SetIsPrintPreview(PR_FALSE) yet.

Basically, any time you fire a DOM event arbitrary parts of Gecko can be reentered from the resulting JS.  So if you're "in the middle of something" (whatever that may mean), you don't want to be firing DOM events.

Comment 13

12 years ago
Hmm.  I think I can probably just move the ReturnToGalleyPresentation() onafterprint firing to ExitPrintPreview(), which should be safer (I think) and makes more logical sense anyway.

However, the code in Close() has me more worried.  I'm assuming this code gets reached if, say, some page's script calls close() while we're trying to print?  Or something?  If so,
(a) Why did Mark's patch (and therefore my patch) only fire onafterprint in the Print Preview case, and not in the Print case?  Seems like both (or neither) should get the event.
(b) Speaking of "both or neither" -- does it even make sense to fire an onafterprint() event here at all?  Do we need to guarantee that every onbeforeprint gets paired with an onafterprint, or is it OK to just never fire a "finished printing" event if we were closed while printing?  Because if we have to fire one here, I don't see how we can possibly do it safely.

Comment 14

12 years ago
Created attachment 220417 [details] [diff] [review]
Safer version

OK, hopefully this will fire events at safer times.  I moved the onafterprint firing for Print Preview into the ExitPrintPreview() routine, and stripped the stuff in Close() entirely.  I think this means if someone calls Close() while we're trying to print, no onafterprint events get fired, but I think that's probably OK.

I'm also requesting review from bryner since he told me he'd be willing to take a look at this.
Attachment #219808 - Attachment is obsolete: true
Attachment #220417 - Flags: review?(bryner)
Attachment #219808 - Flags: review?(jst)
For what it's called ExitPrintPreview is called somewhere about the middle of the actual print preview teardown process (as far as the UI is concerned).  Please do test carefully what happens if malicious event handlers (ones that close windows, throw exceptions, load new web pages, etc) are set for that event.
Comment on attachment 220417 [details] [diff] [review]
Safer version

This should be ok, but I'd also like to see a couple of testcases for the situations Boris mentioned.
Attachment #220417 - Flags: review?(bryner) → review+

Comment 17

11 years ago
Created attachment 223458 [details]
Window close testcase

Here's a quick-and-dirty testcase for the window closing case.  Open a popup window via the link in the page, then go to the popup window and hit ctrl-p.

Now watch the browser crash :(

So, clearly, as Boris suspected, something isn't safe here.  I haven't looked into what; maybe I need to move the event firing outward more somehow, or maybe I just need to null-check and abort things.

Comment 18

11 years ago
I can make this not crash by actually checking the return value of the call to initialize the print engine, which seems like a good thing to do anyway.

However, Darin has made me worry that perhaps some result of the before/after print calls could delete the window or this pointers, which would lead to weird crashes.

We discussed a couple of possible solutions, including making printing asynchronous.  Dunno how much work that would be.

Interestingly, I've just run some tests in IE and discovered two things:
(1) IE disallows self.close() (at least) in the onbeforeprint/onafterprint handlers.  Thus my testcase above does not cause the window to be closed when it is printed.
(2) In IE, printing is "sort of" asynchronous... when window.print() is called, onbeforeprint fires, then the entire page is somehow scraped, then onafterprint() fires, then the script continues executing.  Now, asynchronously, a print setup/preview/whatever window will pop up with the scraped contents.  So the DOM is read synchronously with the before/after print events and script execution, but the actual printing _itself_ is asynchronous.  This might prevent the browser from hanging when interacting with a slow network printer, which Darin said is currently an issue in Firefox...

Comment 19

11 years ago
Created attachment 223509 [details]
Window navigate testcase

This tests what happens when onbeforeprint/onafterprint navigates somewhere (mainly onbeforeprint).

In Firefox (w/patch), this results in an error box about how "the page you were trying to print was replaced, please try again" (paraphrase).

In IE, onbeforeprint _does_ actually replace the location with another page, but (crazily), printing prints the old page anyway.

Comment 20

11 years ago
Created attachment 226570 [details] [diff] [review]
Less crashable version

This fixes a crash bug by properly checking return values more, which maybe we should have been doing anyway.

I'm not sure this solves the larger questions around this feature, but at this point it probably needs someone more willing to think hard about how printing does and should work.
Attachment #220417 - Attachment is obsolete: true

Comment 21

11 years ago
Created attachment 226572 [details] [diff] [review]
Less crashable version v2

Sigh, I meant to use more context in my diff there
Attachment #226570 - Attachment is obsolete: true

Comment 22

11 years ago
Now that this is out of my checkout, I'm going to go ahead and dump this back to nobody, in accordance with my comment #20.
Assignee: pkasting → nobody

Comment 23

11 years ago
I recommend making this bug WONTFIX for the following reasons:

1) The events alter pages at the semantic level to achieve a presentational effect.

2) You can use CSS for the vast majority of use cases for these events.

3) A bug in the scripting (or an intentional feature of the scripting) may result in a failure to restore the document to its original state when printing is complete.

Comment 24

9 years ago
I was hoping to optimize web applications (a la Yahoo! YSlow #1 tip, less HTTPRequests) by _NOT_ including my "print.css" stylesheet, _UNTIL_ the user actually attempts to print, since I'm guessing that 95% of the time, loading such styles (with media=screen) is redundant (even if cached, gzipped, minified, etc.)

I realize the caveats of JS turned off, etc. but in most cases (I ever deal with) I have minimum requirements for application usage, which include a modern browser, with JS and CSS turned on)

I can currently (for IE users), avoid loading special CSS styles, but for Mozilla/Firefox users I can't.  The best I can achieve is "wrapping" the print() method with my own... this lets me intercept the print event when called from JS, but attempts to intercept a CTRL+P event happen too late, and as we all know, the UI chrome print and printpreview commands are not affected by this.

I read the WHATG thread on this too, but I thought "my" scenario was a bit different.  E.g. I'm not trying to create a business plan out of blocking printing, nor am I doing something that can be handled with CSS, since I'm already at that point... I'm now trying to only load the CSS "on-demand".

Personally, I have no interest in "halting" the print... I just want a < 3 second opportunity to do some tweaking.  Also, I would be quite happy if only the before event was hookable, I see little advantages in the after event.
Steve, it's not clear how these events would help with your use case.  The user wants to print the document _now_, and we'll print it "now", not wait for the stylesheet to load before printing.  If loading were somehow synchronous that might work, but in practice it's not (and that's a good thing, given possible connection issues).

Comment 26

9 years ago

Understood, but I would expect (from my IE tests), that this would take less than a second... and would be cached on the 2nd - Nth loads.

I'm certainly not interested in stopping them printing, I just want to provide a *better* printing experience... removing ads/sidebars of content they don't need, tweaking colors (if necs) for a better B&W print.
> that this would take less than a second

That depends on the user's network connection, does it not?

Seriously, I think you should just send the stylesheets...

Comment 28

9 years ago
   Steve, removing adds can be done with "display: none" in a print style sheet. Same for tweaking colors and so forth. With support for CSS 3 content replacement, you could also replace images with improved versions:

   #bwimage1 { content: url(enhanced-BW-image.jpg); }

   As for the proper time to load a print style sheet, I see that as a caching issue, not an issue that every webmaster should have control over. If you do caching of the print style sheet in the background after page load, the user can theoretically still be reading the page by the time the caching is complete, and even if it isn't, you've at least saved yourself part of the download. By contrast, an event before printing would just load all the content at once, causing a very obvious lag for those with slower connections (especially if there are hi-res images to load from the style sheet).

   I will reiterate that I believe |onbeforeprint| and |onafterprint| are user hostile and increasing irrelevant as CSS and HTML continue to improve. While I think it might be useful to have a customized printing experience, I feel that standard printing methods should be the default and that user should have a choice of whether or not to use author print customizations. Events that can make permanently alter the DOM don't really provide such flexibility.

Comment 29

9 years ago
@Matthew, thanks for the comments.  I guess I can keep the external CSS stylesheet just for printing... and let it cache.

Can I presume that internally Firefox is "smart" enough to read in a CSS sylesheet marked for "print" (only) from the web server... but do nothing with it until a print request is made?

Gecko will read and parse the stylesheet, but nothing else.

Comment 31

9 years ago
Here's another use case that I don't think can be acheived without these functions:

I have a form that uses JS to perform an error check at the point of submission.  If it fails, I use JS to mark the failing items in red (by adding the InputError class).  I also want the error check to happen at the point of printing, so that they are highlighted on the print-out.  However, the form is pretty large, and the checks are quite complex, so the JS code is too slow to run constantly in reaction to every keystroke/mouseclick.

Currently I have a 'print' button that runs the check and then calls print(), but this obviously only works when the button is clicked, not when the user prints from the chrome.

onBeforePrint would allow me to capture the print event and run my checks beforehand.

Bascially, style sheets are fine for visual stuff, but the event handlers allow JS to react to these events for any non-visual changes, and whilst it is not useful in the above example, I can equally see a need for onAfterPrint (for example, in a corporate intranet environment you may wish to log instances of a document being printed, which should only happen if the print took place, not if it was cancelled).

Comment 32

8 years ago
Just saw a reference saying FireFox 3.5 Supports HTML5,and another one saying HTML5 supports the "onbeforeprint" and "onafterprint" events.
Does this mean we can finally use these events in FF?

> Just saw a reference saying FireFox 3.5 Supports HTML5,

Wherever you saw this is confused.  Firefox 3.5 has support for some parts of the HTML5 draft.
QA Contact: printing

Comment 34

8 years ago
One more use case: I have a paged, JS-driven data table, which shows 25 rows per "page" on the screen (see an example here: When printing I want all pages to be printed. The JS would be exceedingly simple ("paginator.setRowsPerPage(99999)"), but there's no way to trigger it automatically, so I'd have to have a "print" button on the page to do that. Most users will miss that button and instead print the table one page at a time using the browser print command, wasting loads of paper and ink with the extra page furniture. Think of the trees!  :)

Comment 35

7 years ago
(In reply to comment #34)

   Nelson, that's not a good use case. In your example, the ability to print all rows at once is hidden from the user until they print, so if they don't do a print preview before printing each page, they may print all of the rows multiple times. Also, they may wish to print only the rows that are currently visible on the page, so printing all 99999 rows would be a real pain. "Think of the trees!"

   By contrast, simply providing a link or button for a print version would give the user far greater control over what they print and how much. For example, the user may wish to print the current document to a PDF or some other format to use in a presentation as an example of what the website looks like. You may want to load a separate full print version of the page so you can hack the page to remove what you don't want without damaging the original page. Heck, you may simply want to print a single row from the original page to get an address or phone number. As the Internet proves, a stable, predictable platform is the best environment for innovation. Creating results that are inconsistent or unpredictable harms innovation. Let users innovate.

   I think it's worth noting that the issues I raised were regarding a use case from someone who genuinely wants to help the user. The problem is that you can't help someone without their consent. That's called _MEDDLING_. Stop this Old Media(tm) hubris and accept that we no longer live in a world of content-provider-knows-best.

Comment 36

7 years ago
Matthew, by your logic print stylesheet support should be removed.

I use these events for analytics to help determine which pages earn more effort put into their print stylesheets.

Comment 37

7 years ago
I agree.  Matthew, your argument is a bit of a straw man.  Whether or not you agree with Nelson's specific use-case (and I would argue that without knowing the details about his user-base, you are not in a position to make this judgement), it is not an argument against adding this functionality to Firefox.

You are assuming that Firefox is only used as a web-browser (i.e. the content-provider/consumer model) where in practice it is just as common for it to be used as a host for web-based applications (i.e. the application/user model).  As someone who develops business tools, it is vital to be able to control the printing process with the same level of control that we use for on-screen display (for example, see my comment 31).

Whilst I agree that there are some situations where the designer will only end up frustrating their users if they try to 'help' them in a way that gives unexpected results, this is a problem that affects nearly all HTML/CSS/JS features* and is not a reason to block this otherwise useful functionality.

* A classic example being a Bugzilla hack I encountered where the 'commit' button was disabled after being clicked, to stop people accidentally submitting new bugs twice.  The result being that it was no longer possible to enter a second similar bug using the back button from the 'bug submitted' page and simply changing the summary/description.  You instead had to refresh the page (to re-enable the button) and fill in all the fields every time.  It was a good idea in principle, but there were other implications that the designer hadn't considered, which made it very frustrating for a lot of users until we convinced them to remove the hack and to deal with the occasional dupe manually.  However, I would never hold this up as a reason to remove the functionality that allows the submit button to be disabled.

Comment 38

6 years ago
Patch coming.
Assignee: nobody → Olli.Pettay

Comment 39

6 years ago
Created attachment 530750 [details] [diff] [review]

Uploaded to tryserver.
Attachment #530750 - Flags: review?(matspal)

Comment 40

6 years ago
Created attachment 530751 [details] [diff] [review]
Attachment #530750 - Attachment is obsolete: true
Attachment #530751 - Flags: review?(matspal)
Attachment #530750 - Flags: review?(matspal)

Comment 41

6 years ago
Tryserver builds for anyone who want to test the patch

Comment 42

6 years ago
I tested also a case when loading the page takes some time and
window.print() is called before the page is loaded.
beforeprint is correctly dispatched right before printing (which happens after 
page has been loaded.)
Comment on attachment 530751 [details] [diff] [review]

Looks fine to me.  r=mats

I'm not a peer for much of this code though (as far as I know)...
so you should probably get jst or bz to rubber stamp.
Attachment #530751 - Flags: review?(matspal) → review+

Comment 44

6 years ago
Comment on attachment 530751 [details] [diff] [review]

I think roc has looked more printing patches.
Attachment #530751 - Flags: superreview?(roc)
Comment on attachment 530751 [details] [diff] [review]

I sure wish we could add events with less boilerplate code!
Attachment #530751 - Flags: superreview?(roc) → superreview+

Comment 46

6 years ago
Well, just adding new events is nothing more than
calling nsContentUtils::DispathTrustedEvents.
But to add support for <element onfoo> needs the change to nsContentUtils
and to add support for element.onfoo requires the changes to nsDOMClassInfo.
Especially the latter one should be easier.

Comment 47

6 years ago
Last Resolved: 6 years ago
Resolution: --- → FIXED


6 years ago
Keywords: dev-doc-needed


6 years ago
Summary: Support onbeforeprint and onafterprint events → Support beforeprint and afterprint events
Target Milestone: --- → mozilla6
The two events are added to the admittedly sketchy list of DOM events here:

Also, an actual example of their use is here:

And mentioned on Firefox 6 for developers.
Keywords: dev-doc-needed → dev-doc-complete

Comment 49

6 years ago
Although I love this, the more work on the printing the better.  I think it would be more useful if the afterprint event actually had a field that returned you either that it printed, or if they okay/cancel -ed the window.  Like a property, event.mozPrinted true/false, or have getPreventDefault() returns true for a cancelled event, false if it wasn't cancelled.

Comment 50

6 years ago
I implemented what is specified in HTML spec. So, if you want to add
new features, please bring up the ideas in WhatWG mailing.

Also, what would mozPrinted mean for print preview?

Comment 51

6 years ago
Personally, I would like to see almost the complete details of the dialog be passed in.  For some web apps, its important to know say, how many copies were made, esp if it contained sensitive information.  But simplified, mozPrinted would be true, since it was sent to a "print device", just because its being printed to the screen, shouldn't make a difference.  After/beforeprint should fire for every time they click the print button in the preview.  Logically, the after/beforeprint, should fire for every time the contents are printed.  I understand that the preview is a separate window, but you are still contents from the original window.  Although, I can see what I'd like to be huge in code changes.  I can't see how a simple flag of the print being cancelled to be an insane request.


6 years ago
Depends on: 667092


6 years ago
Depends on: 669084


6 years ago
Depends on: 669895
I'm just wondering why beforeprint and afterprint events are not listed in this list:

Comment 53

6 years ago
Because the events are dispatched using normal DOM createEvent/dispatchEvent
way. I'd like to get rid of that list eventually.


5 years ago
Depends on: 811776
You need to log in before you can comment on or make changes to this bug.