[skpdf] PDFs generated from pdf.js (via MozPrintCallback) are missing selectable text
Categories
(Core :: Printing: Output, defect, P3)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox154 | --- | verified |
People
(Reporter: calixte, Assigned: emilio, NeedInfo)
References
Details
Attachments
(2 files, 1 obsolete file)
STR:
- Set about:config pref
print.experimental.skpdftotrue - Print, and choose the Save to PDF backend.
- Open the resulting file in Firefox
- Try to select any text in the document.
ACTUAL RESULTS:
The text is unselectable.
EXPECTED RESULTS:
Text should be selectable.
Each page is rendered as an image.
Comment 1•5 months ago
|
||
Jamie, Emilio, can you take a look?
| Assignee | ||
Comment 2•5 months ago
|
||
Happens on Linux as well afaict.
| Assignee | ||
Comment 3•5 months ago
|
||
Calixte, how does pdf.js draw the text for printing? Just .drawText from the mozPrintCallback?
| Reporter | ||
Comment 4•5 months ago
|
||
(In reply to Emilio Cobos Álvarez [:emilio] from comment #3)
Calixte, how does pdf.js draw the text for printing? Just
.drawTextfrom themozPrintCallback?
Yes just drawText.
I don't know if it matters but we call drawText for each char.
| Assignee | ||
Comment 5•5 months ago
|
||
Yeah so I think I understand what's going on. What happens is that for MozPrintCallback, we call CreateSimilarDrawTarget for each <canvas> element (for each page, effectively):
That basically causes it to get a raster surface here:
Lee, I'm not sure what the best way to go about this is, here's what I've tried:
I first tried the obvious "implement CreateSimilarDrawTarget without a raster surface". I don't see a particularly trivial way of doing that tho. SkPDFDocument::makeSurface just returns a raster surface, and reusing the SkCanvas seems like asking for trouble. Of course that works in this particular case because we only have one canvas per page, but still.
I tried to use the recording surface stuff with something like the diff below:
diff --git a/layout/generic/nsPageSequenceFrame.cpp b/layout/generic/nsPageSequenceFrame.cpp
index 7d1e0c27bff7..3cc894d849a3 100644
--- a/layout/generic/nsPageSequenceFrame.cpp
+++ b/layout/generic/nsPageSequenceFrame.cpp
@@ -12,6 +12,8 @@
#include "mozilla/PrintedSheetFrame.h"
#include "mozilla/StaticPresData.h"
#include "mozilla/dom/HTMLCanvasElement.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/intl/AppDateTimeFormat.h"
#include "nsCOMPtr.h"
@@ -659,16 +661,18 @@ nsresult nsPageSequenceFrame::PrePrintNextSheet(nsITimerCallback* aCallback,
UniquePtr<gfxContext> renderingContext = dc->CreateRenderingContext();
NS_ENSURE_TRUE(renderingContext, NS_ERROR_OUT_OF_MEMORY);
- DrawTarget* drawTarget = renderingContext->GetDrawTarget();
- if (NS_WARN_IF(!drawTarget)) {
+ DrawTarget* referenceDt = renderingContext->GetDrawTarget();
+ if (NS_WARN_IF(!referenceDt)) {
return NS_ERROR_FAILURE;
}
for (HTMLCanvasElement* canvas : Reversed(mCurrentCanvasList)) {
CSSIntSize size = canvas->GetSize();
-
- RefPtr<DrawTarget> canvasTarget = drawTarget->CreateSimilarDrawTarget(
- size.ToUnknownSize(), drawTarget->GetFormat());
+ RefPtr recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>(nullptr);
+ RefPtr<DrawTarget> canvasTarget =
+ gfx::Factory::CreateRecordingDrawTarget(
+ recorder, referenceDt,
+ gfx::IntRect(gfx::IntPoint(), size.ToUnknownSize()));
if (!canvasTarget) {
continue;
}
But this hits this warning. With that diff, I get there with a mozilla::gfx::SourceSurfaceRecording, which I think it's just not handled. Should it?
Another potential approach would be to maybe use the DrawDependentSurface mechanism that iframes use, instead of CreateSimilarDrawTarget. I haven't tried that yet but it should work as well...
Lee, any suggestion on the preferred approach?
| Assignee | ||
Comment 6•5 months ago
|
||
The good thing is that this is just related to pdf.js / MozPrintCallback and not a more general problem
| Assignee | ||
Updated•5 months ago
|
| Assignee | ||
Updated•5 months ago
|
Updated•5 months ago
|
| Assignee | ||
Updated•5 months ago
|
| Assignee | ||
Comment 7•5 months ago
|
||
This seems to do the trick, but I'm not super-happy about it:
-
SourceSurfaceSkia generally assumes non-null mImage, and we are
adding this mPicture codepath, should I add a SourceSurfaceSkPicture
or something? -
Similarly, having to null out mCanvas and such after calling
Snapshot() is a bit hacky, but it works for our purposes.
Updated•5 months ago
|
| Assignee | ||
Updated•5 months ago
|
| Assignee | ||
Comment 8•5 months ago
|
||
By teaching DrawTargetRecording to draw a SourceSurfaceRecording
properly.
| Assignee | ||
Comment 9•4 months ago
|
||
Calixte do you know where / how could / should we add some tests for this?
Comment 10•4 months ago
|
||
Comment 11•4 months ago
|
||
Comment 12•4 months ago
•
|
||
Reverted this because it was causing webdriver failures.
- Revert link
- Push with failures
- Failure Log
- Failure line: TEST-UNEXPECTED-FAIL | /webdriver/tests/classic/print/printcmd.py | test_large_html_document - AssertionError: unknown error (500): [Exception... "Unexpected error" nsresult: "0x8000ffff (NS_ERROR_UNEXPECTED)" location: "JS frame :: resource:///modules/sessionstore/SessionStore.sys.mjs :: ssi_onQuitApplicationGranted :: line 2910" data: no]
Also, please check ths wpt failure.
Comment 13•4 months ago
|
||
| Assignee | ||
Updated•4 months ago
|
Comment 14•4 months ago
|
||
Comment 15•4 months ago
|
||
Backed out for causing wpt failures @ mozilla/html/canvas/mozPrintCallback-rect-001-print.html
Backout link: https://hg.mozilla.org/integration/autoland/rev/de4a613bc2881b79bd28b85bce3881907dd914ea
Failures log ->TEST-UNEXPECTED-FAIL | /_mozilla/html/canvas/mozPrintCallback-rect-00x-print.html
| Reporter | ||
Comment 16•4 months ago
|
||
(In reply to Emilio Cobos Álvarez [:emilio] from comment #9)
Calixte do you know where / how could / should we add some tests for this?
I'd say in test directory for printing stuff.
You can use something like:
https://searchfox.org/firefox-main/source/layout/tools/reftest/reftest.sys.mjs#2240
Once you've a document from getDocument, you can call getPage(1) to get the first page and then call getTextContent in order to make sure that isn't not just an image and assert on the text content.
Jamie did something similar:
https://searchfox.org/firefox-main/source/accessible/tests/browser/pdfOutput/head.js#109-127
| Assignee | ||
Comment 17•4 months ago
|
||
(In reply to Sandor Molnar[:smolnar] from comment #15)
Backed out for causing wpt failures @ mozilla/html/canvas/mozPrintCallback-rect-001-print.html
Was missing a setTransform call.
Updated•4 months ago
|
Comment 18•4 months ago
|
||
Comment 19•4 months ago
|
||
| bugherder | ||
| Assignee | ||
Comment 20•3 months ago
|
||
sheriffs: Can we back this out of beta for causing bug 2045512? We can leave it on Nightly.
Updated•3 months ago
|
Comment 21•3 months ago
|
||
(In reply to Emilio Cobos Álvarez [:emilio] from comment #20)
sheriffs: Can we back this out of beta for causing bug 2045512? We can leave it on Nightly.
Pascal is current release owner for beta
Comment 22•3 months ago
|
||
| uplift | ||
Updated•3 months ago
|
Updated•3 months ago
|
Comment 23•3 months ago
|
||
Reproducible on a 2026-04-23 Firefox Nightly build on Windows 10.
Verified as fixed on Firefox Nightly 154.0a1 on Windows 10, Ubuntu 22, macOS 13.
Description
•