Bug 160860 - backface-visibility style not applied when printing
Summary: backface-visibility style not applied when printing
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Printing (show other bugs)
Version: WebKit Nightly Build
Hardware: Mac OS X 10.11
: P2 Minor
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-08-15 13:10 PDT by Nathan Perkins
Modified: 2018-02-14 10:34 PST (History)
12 users (show)

See Also:


Attachments
HTML and CSS to reproduce issue (627 bytes, text/html)
2016-08-15 13:10 PDT, Nathan Perkins
no flags Details
Patch (1.97 KB, patch)
2016-08-25 14:01 PDT, Nathan Perkins
no flags Details | Formatted Diff | Diff
Patch (7.20 KB, patch)
2016-08-28 06:33 PDT, Nathan Perkins
beidson: review-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Nathan Perkins 2016-08-15 13:10:41 PDT
Created attachment 286081 [details]
HTML and CSS to reproduce issue

The backface-visibility option does not affect the rendering of the page when printed.

I originally found this issue while trying to print search results from DuckDuckGo that include places:

https://duckduckgo.com/?q=boston+restaurants&ia=places

Through some subsequent digging, I found that the -webkit-backface-visibility property was no longer hiding content when printing the page. As a result, this causes text that is hidden on screen to appear when printing, and to appear after undergoing the specified transformation (e.g., in the attached example, the 3D rotation causes the text to horizontally be mirrored).

I was able to create a simple HTML page reduction that illustrates this error. No content appears on screen, but when printing, the content of the DIV is visible. Using the HTML file, I confirmed that the issue appears in the current nightly build (Version 9.1.2 (11601.7.7, r204466)).

The attached file provides an HTML file with sufficient CSS to demonstrate the issue.
Comment 1 Nathan Perkins 2016-08-15 13:24:44 PDT
One small addition: I do not think this bug just affects printing, although that is the easiest way to reproduce it. On Mac OS X, using Cocoa APIs such as those to capture an image of a view [NSView cacheDisplayInRect:toBitmapImageRep:] have the same rendering issue as the printed version.
Comment 2 Nathan Perkins 2016-08-25 13:59:21 PDT
After finding this bug, I thought this might be an interesting introduction to the WebKit project and have done some digging and think I found the underlying issue. This is a  dauntingly complex open source project, far beyond what I have worked on in the past, but hopefully my investigations and findings will be of some use. I am happy to iterate on improving the solution or revising, or just handing it off to someone more experienced.

It appears that when printing (or when capturing a view as an image using Cocoa APIs on Mac), a separating painting code path is used. Normally, the 3D-transformed elements are rendered using a PlatformCALayer and backface-visibility is achieved through the PlatformCALayer::setDoubleSided method to hide elements when the backface is visible.

When printing, the 3D transform is achieved at paint time using the RenderLayer::paintLayerByApplyingTransform function, which does not take into account backface visibility.

I have added code to the beginning of that function that checks the backface visibility and uses the existing TransformationMatrix::isBackFaceVisible to abort painting if the backface is visible.

Given my limited knowledge of WebKit, I am not sure if aborting painting can lead to other problems, but in my test case and a few variations, it all produced the expected results.

I have not tried to create tests, as I am not sure how to force a 3D transformed element to be rendered using the alternative path described above. If anyone can provide some guidance on that, I am happy to take a stab at adding tests.
Comment 3 Nathan Perkins 2016-08-25 14:01:54 PDT
Created attachment 287011 [details]
Patch
Comment 4 Simon Fraser (smfr) 2016-08-25 14:05:17 PDT
Comment on attachment 287011 [details]
Patch

Good investigation, but this isn't quite correct. Backface visibility needs to be computed relative to the ancestor most non-preserve3D layer (the spec at https://drafts.csswg.org/css-transforms/ talks about this in terms of "3d rendering contexts").

For testing I think we have a way to do printing tests (see LayoutTests/printing).
Comment 5 Nathan Perkins 2016-08-28 06:33:44 PDT
Created attachment 287229 [details]
Patch
Comment 6 Nathan Perkins 2016-08-28 06:40:22 PDT
I tried to address the feedback form smfr, and have reworked the approach:

* The backface visibility check is only assessed when the flatten compositing layers flag is set for the paint behavior.
* The approach recalculates the accumulated transform matrix, which can be relatively slow, but this should only effect printing and snapshotting. I am not fully confident that this approach covers all scenarios. There may be other details that should cause the accumulation to stop when it reaches an element that fully determines the 3D rendering context.

In addition, I have added a test case in the printing folder based off some of the other backface visibility tests.

PS: A slightly more clever approach occurred to me and may be worthwhile. Using the GraphicsContext CTM combined with the current elements affine transform, it is possible to assess whether or not the element is being flipped. That being said, it is less obvious what such an implementation is doing and there may be platform specific details to the graphics context that make such an approach less functional.
Comment 7 Darin Adler 2016-09-03 13:03:31 PDT
Hyatt, Simon, what do you think of this new version?
Comment 8 Brady Eidson 2018-02-14 10:34:00 PST
Comment on attachment 287229 [details]
Patch

Patches that have been up for review since 2016 are almost certainly too stale to be relevant to trunk in their current form.

If this patch is still important please rebase it and post it for review again.