Last Comment Bug 307258 - Support beforeprint and afterprint events
: Support beforeprint and afterprint events
: dev-doc-complete
Product: Core
Classification: Components
Component: Printing: Output (show other bugs)
: Trunk
: All All
: -- enhancement with 7 votes (vote)
: mozilla6
Assigned To: Olli Pettay [:smaug]
: 283329 (view as bug list)
Depends on: 669895 811776 667092 669084
  Show dependency treegraph
Reported: 2005-09-06 13:37 PDT by Darin Fisher
Modified: 2012-11-14 12:09 PST (History)
21 users (show)
See Also:
Crash Signature:
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---

Initial implementation (27.52 KB, patch)
2006-01-13 07:33 PST, Mark Mentovai
no flags Details | Diff | Review
Un-bitrotted version of previous patch (29.67 KB, patch)
2006-04-25 16:23 PDT, Peter Kasting
no flags Details | Diff | Review
Safer version (29.23 KB, patch)
2006-05-01 11:29 PDT, Peter Kasting
bryner: review+
Details | Diff | Review
Window close testcase (723 bytes, text/html)
2006-05-26 10:38 PDT, Peter Kasting
no flags Details
Window navigate testcase (832 bytes, text/html)
2006-05-26 16:07 PDT, Peter Kasting
no flags Details
Less crashable version (21.05 KB, patch)
2006-06-21 17:35 PDT, Peter Kasting
no flags Details | Diff | Review
Less crashable version v2 (31.40 KB, patch)
2006-06-21 17:38 PDT, Peter Kasting
no flags Details | Diff | Review
patch (13.69 KB, patch)
2011-05-06 15:01 PDT, Olli Pettay [:smaug]
no flags Details | Diff | Review
patch (13.69 KB, patch)
2011-05-06 15:08 PDT, Olli Pettay [:smaug]
mats: review+
roc: superreview+
Details | Diff | Review

Description Darin Fisher 2005-09-06 13:37:45 PDT
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 Seth LaForge 2005-09-06 15:48:11 PDT
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 James Ross 2005-09-06 15:50:59 PDT
I would hope turning JavaScript off would foil any such handlers.
Comment 3 Christian :Biesinger (don't email me, ping me on IRC) 2005-09-06 16:40:57 PDT
it may or may not be of interest to people that this topic was/is recently
discussed on the whatwg mailing list...
Comment 4 Mark Mentovai 2005-10-03 13:41:34 PDT
Taking.  I've been working on this and have something functional.
Comment 5 Nickolay_Ponomarev 2005-12-09 03:19:12 PST
*** Bug 283329 has been marked as a duplicate of this bug. ***
Comment 6 Mark Mentovai 2006-01-13 07:33:57 PST
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 Peter Kasting 2006-04-25 15:59:04 PDT
I'm taking this bug and un-bitrotting Mark's patch; to be posted shortly.
Comment 8 Peter Kasting 2006-04-25 16:23:24 PDT
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.
Comment 9 Boris Zbarsky [:bz] 2006-04-25 16:30:41 PDT
FWIW, the print-preview version of after-print with this patch is probably firing at an unsafe time...
Comment 10 Boris Zbarsky [:bz] 2006-04-25 16:31:28 PDT
Past that, I'm not the right reviewer for this patch; you want someone familiar with the guts of the event code.
Comment 11 Peter Kasting 2006-04-25 16:52:39 PDT
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.
Comment 12 Boris Zbarsky [:bz] 2006-04-25 17:15:51 PDT
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 Peter Kasting 2006-04-25 18:14:43 PDT
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 Peter Kasting 2006-05-01 11:29:29 PDT
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.
Comment 15 Boris Zbarsky [:bz] 2006-05-01 11:46:58 PDT
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 16 Brian Ryner (not reading) 2006-05-10 14:54:04 PDT
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.
Comment 17 Peter Kasting 2006-05-26 10:38:23 PDT
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 Peter Kasting 2006-05-26 15:13:48 PDT
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 Peter Kasting 2006-05-26 16:07:33 PDT
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 Peter Kasting 2006-06-21 17:35:27 PDT
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.
Comment 21 Peter Kasting 2006-06-21 17:38:04 PDT
Created attachment 226572 [details] [diff] [review]
Less crashable version v2

Sigh, I meant to use more context in my diff there
Comment 22 Peter Kasting 2006-06-21 17:39:13 PDT
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.
Comment 23 Matthew Raymond 2006-07-17 10:35:13 PDT
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 Steve 2008-07-25 11:52:54 PDT
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.
Comment 25 Boris Zbarsky [:bz] 2008-07-25 12:34:33 PDT
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 Steve 2008-07-25 12:41:07 PDT

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.
Comment 27 Boris Zbarsky [:bz] 2008-07-25 13:08:03 PDT
> 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 Matthew Raymond 2008-09-15 04:57:04 PDT
   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 Steve 2008-09-15 06:51:49 PDT
@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?

Comment 30 Boris Zbarsky [:bz] 2008-09-15 07:20:36 PDT
Gecko will read and parse the stylesheet, but nothing else.
Comment 31 Mark Clements 2008-11-24 04:36:17 PST
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 sashimka 2009-07-21 14:49:07 PDT
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?

Comment 33 Boris Zbarsky [:bz] 2009-07-21 19:03:37 PDT
> 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.
Comment 34 Nelson Menezes 2010-03-29 06:42:54 PDT
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 Matthew Raymond 2010-06-15 05:29:57 PDT
(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 Chris Griego 2010-06-16 04:52:18 PDT
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 Mark Clements 2010-06-16 05:43:20 PDT
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 Olli Pettay [:smaug] 2011-05-06 14:22:36 PDT
Patch coming.
Comment 39 Olli Pettay [:smaug] 2011-05-06 15:01:21 PDT
Created attachment 530750 [details] [diff] [review]

Uploaded to tryserver.
Comment 40 Olli Pettay [:smaug] 2011-05-06 15:08:00 PDT
Created attachment 530751 [details] [diff] [review]
Comment 41 Olli Pettay [:smaug] 2011-05-07 02:20:37 PDT
Tryserver builds for anyone who want to test the patch
Comment 42 Olli Pettay [:smaug] 2011-05-07 06:52:47 PDT
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 43 Mats Palmgren (:mats) 2011-05-13 12:33:09 PDT
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.
Comment 44 Olli Pettay [:smaug] 2011-05-13 12:37:45 PDT
Comment on attachment 530751 [details] [diff] [review]

I think roc has looked more printing patches.
Comment 45 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2011-05-14 02:22:34 PDT
Comment on attachment 530751 [details] [diff] [review]

I sure wish we could add events with less boilerplate code!
Comment 46 Olli Pettay [:smaug] 2011-05-14 04:12:38 PDT
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 Olli Pettay [:smaug] 2011-05-14 07:03:34 PDT
Comment 48 Eric Shepherd [:sheppy] 2011-05-17 14:33:21 PDT
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.
Comment 49 Rahly 2011-05-31 12:21:55 PDT
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 Olli Pettay [:smaug] 2011-05-31 12:49:33 PDT
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 Rahly 2011-06-01 11:10:24 PDT
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.
Comment 52 Martijn Wargers [:mwargers] (gone per 2016-05-31 :-( ) 2011-07-17 23:12:40 PDT
I'm just wondering why beforeprint and afterprint events are not listed in this list:
Comment 53 Olli Pettay [:smaug] 2011-07-18 03:38:35 PDT
Because the events are dispatched using normal DOM createEvent/dispatchEvent
way. I'd like to get rid of that list eventually.

Note You need to log in before you can comment on or make changes to this bug.