OLD | NEW |
(Empty) | |
| 1 # Introduction |
| 2 The common approach used in printing on Linux is to use Gtk+ and Cairo libraries
. The [Gtk+ documentation](http://library.gnome.org/devel/gtk/stable/Printing.ht
ml) describes both high-level and low-level APIs for us to do printing. In an ap
plication program, the easiest way to do printing is to use [GtkPrintOperation](
http://library.gnome.org/devel/gtk/stable/gtk-High-level-Printing-API.html) to g
et the Cairo context in `draw-page`'s callback, and render **each** page's conte
nts on this specific context, the rest is easy and trivial. |
| 3 |
| 4 However, in Chromium's multi-process architecture, we hope that all rendering sh
ould be done in the renderer process, and I/O should be done in the browser proc
ess. The problem is that we are unable to pass the Cairo context we obtained in
the browser process to the renderer via IPC and/or shared memory, and later get
it back after the rendering is done. Hence, we have to find something which we c
an _pickle_ and pass between processes. |
| 5 |
| 6 # Possible Solutions |
| 7 1. **Bitmap**: This seems easy because we have already passed bitmaps for disp
laying web pages. It is also pretty easy to _dump_ this bitmap on the printing c
ontext. However, the bitmap takes lots of memory space even when you print a bla
nk page. You might wonder why it can be a critical problem, since we've used bit
maps for displaying. The critical part is that the screen DPI is around 72~110,
at least lower than 150. However, the DPI for printing is usually above 150, and
maybe 1200 or 2400 for high-end printers. The 72-DPI bitmap actually looks terr
ible on the paper and reminds us the old time when we used dot-matrix printers.
A 72-DPI bitmap will take ~7MB memory (assume we are using US letter paper), hen
ce, it will take ~500MB memory per page when we would like to print with a 600-D
PI laser printer. By the way, even we would like to do so, we still have the pro
blem that WebKit seems not to take the DPI factor into account when rendering th
e web page. |
| 8 1. **Rendering records** (scripts): We might be able to record every operation
which is going to be performed on canvas, and later pass all these records to t
he browser side to playback. We can define our own format (or script), or we can
use CairoScript. Unfortunately, CairoScript is still in the snapshot (it is und
er development and we can hardly find its detailed and useful documentation), no
t in the stable release. Even it is in a stable release, we still cannot assume
that the user will install the latest version of Cairo library. If we would like
to create our own format/script and use it, we have to replay these records in
the browser process, which seems to be another kind of rendering action (it is a
ctually). By the way, one thing we need to take care of would be, for example, w
hen we have to composite multiple semi-transparent bitmaps, we also have to embe
d these bitmaps along with other skia objects into our records. This implies tha
t we have to be able to _pickle_ `SkBitmap`, `SkPaint`, and other related skia o
bjects. This sucks. |
| 9 1. **Metafile approach 1**: We can use Cairo to create the PDF (or PS) file in
the renderer (one file per page) and pass it to the browser process. We can the
n use [libpoppler](http://poppler.freedesktop.org/) to render the page content o
n the printing context (it is pretty easy to use and we just need to add few lin
es to use it). This sounds better, but this also means that we have to bring [li
bpoppler](http://poppler.freedesktop.org/) into our dependency. Moreover, we sti
ll have to do _rendering_ in the browser process, which we should really avoid i
f possible. |
| 10 1. **Metafile approach 2**: Again, we use Cairo to create the PDF (or PS) file
in the renderer. However, this time we have to generate the PDF/PS file for all
pages. Unlike other approaches we mentioned earlier, all rendering tasks are do
ne in the renderer, including transformation for setting up the page, and render
ing of the header and footer. Since we do not want to do rendering in the browse
r process, this means that we cannot use the [GtkPrintOperation](http://library.
gnome.org/devel/gtk/stable/gtk-High-level-Printing-API.html) approach, which doe
s require rendering. Instead, we can use [GtkPrintUnixDialog](http://library.gno
me.org/devel/gtk/stable/GtkPrintUnixDialog.html) to get printing parameters and
generate the [GtkPrintJob](http://library.gnome.org/devel/gtk/stable/GtkPrintJob
.html) accordingly. Then, we use `gtk_print_job_set_source_file()` and `gtk_prin
t_job_send ()` to send our PDF/PS file directly to the printing system (CUPS). O
ne bad part is that `gtk_print_job_set_source_file()` only takes a file on the d
isk, so we have to create a temporary file on the disk before we use it. This fi
le might be pretty large if the user is printing a long web page. |
| 11 |
| 12 # Our Choice |
| 13 We currently are using Metafile approach 2, since we really like to avoid any re
ndering in the browser process if possible. By the way, we are using a two-pass
rendering in `PdfPsmetafile` right now. Because in the first pass, we need to ge
t the shrink factor from WebKit so that we can scale and center the page in the
second pass. If we later we can have the shrink factor from Preview, we might be
able to use single-pass rendering. However, using two-pass rendering might stil
l have some advantages. For example, we can actually do Preview and the first pa
ss at the same time if we use the bitmap object in the `VectorPlatformDevice` as
Preview. (Not very sure if it works or not now, since Previewing is also a comp
licated issue.) Once we have the page settings (margins, scaling, etc), we can e
asily apply the first-pass results to generate our final output by copying Cairo
surfaces. |
| 14 |
| 15 (Please NOTE the approach used here might be changed in the future.) |
| 16 |
| 17 # Current Status |
| 18 We now can generate a PDF file for the web page and save it under user's default
download directory. The function is still very basic. Please see ideal Goal, Kn
own Issues, and Bugs below. |
| 19 |
| 20 |
| 21 --- |
| 22 |
| 23 |
| 24 # Ideal Goal |
| 25 Design a better printing flow for Linux: |
| 26 > Ideally, when we print the web page, we should get the _snapshot_ of that page
. In the current architecture, we cannot halt JavaScript from running when we pr
int the web page. This is not good since the script might close the page we are
printing. Things could be worse if plug-ins are involved. When we print, the ren
derer sends a sync message to the browser, so the renderer must wait for the bro
wser. We potentially may have deadlocks when the plug-in talks to the renderer.
Please see [here](http://dev.chromium.org/developers/design-documents/printing)
for further detail. This might be avoided if we could copy the entire DOM tree b
efore we print. It seems that WebKit does not support this directly right now. B
efore we can entirely solve this issue, we might need to reduce the time and cha
nce we block the renderer. For example, unlike the windows version, we always ha
ve at least one printer (print to file). Hence, we can put "Page Setup" in the b
rowser menu, so that we don't need to ask the user each time before we print (Yo
u can see this in Firefox and many other Linux applications). |
| 27 > Another issue is that we might need different mechanisms for different platfor
ms. Obviously, the ways how we do printing on Windows and on Linux are quite dif
ferent. The printing flow on Linux might be something like this one: |
| 28 * Print on a low-resolution bitmap canvas to generate Previews. (Believe it
or not! It's actually much more difficult/tedious than it sounds.) |
| 29 * We use the preview to do Page Setup: Paper size, margins, page range, and
maybe also the header and the footer. |
| 30 * Generate the PDF file. |
| 31 * Save the resulting PDF as a temporary file. |
| 32 * Use GTK+ APIs in the browser to ask the user which printer to use, then di
rectly send the temporary file to CUPS. |
| 33 > These steps look simple, but we actually need to consider and design more deta
ils before we can make it happen. (For example, do we have to support all option
s shown in the GTK+ printing dialog?) |
| 34 |
| 35 # Known Issues |
| 36 1. For some reason, if we send the resulting PDF files directly to CUPS, we of
ten get nothing without any error message. The CUPS I was using is version 1.3.1
1. This might be a bug in Cairo 1.6.0, and/or a bug in the PDF filter (pdftopdf?
pdftops?) in CUPS. Actually, if we use Firefox and print to file, we will somet
imes have this problem, too. Nevertheless, the resulting PDF can be viewed in al
l PDF viewers without any error. However, you won't see the embedded font inform
ation in some PDF viewers, such as evince. If the printer supports PDF natively
and has the HTTP interface, we can get the printout by sending the PDF file via
printer's HTTP interface. [Issue# 21599](http://code.google.com/p/chromium/issue
s/detail?id=21599) |
| 37 1. WebKit does not pass original text information to skia. Hence, we only have
glyphs in the resulting PDF. This implies that we cannot do text selection in t
he resulting PDF. [Issue# 21602](http://code.google.com/p/chromium/issues/detail
?id=21602) |
| 38 1. The vector canvas used for printing in skia still has a bitmap within it [I
ssue# 21604](http://code.google.com/p/chromium/issues/detail?id=21604). This was
tes lots of memory and does nothing. Maybe we can use this bitmap to do previewi
ng, or use it as a thumbnail. of course, another possibility might be implementi
ng PDF generating capabilities in skia. |
| 39 1. To let Cairo use correct font information, we use FreeType to load the font
again in `PdfPsMetafile`. This again wastes lots of memory when printing. It wo
uld be nice if we can find a way to share font information with/from skia. [Issu
e# 21608](http://code.google.com/p/chromium/issues/detail?id=21608) |
| 40 1. Since we ask the browser open a temporary file for us. This might potential
ly be a security hole for DoS attack. We should find a way to limit the size of
temporary files and the frequency of creation. (Do we have this now?) [Issue# 21
610](http://code.google.com/p/chromium/issues/detail?id=21610) |
| 41 1. In Cairo 1.6.0, the library opens a temporary file when creating a PostScri
pt surface. Hence, our only choice is the PDF surface, which does not require an
y temporary file in the renderer. |
| 42 1. In Cairo 1.6.0, we cannot output multiple glyphs at the same time. (we have
to do it one by one). Newer version does support multiple glyphs output. We can
use it in the future. |
| 43 1. I did not have enough time to write good unit tests for classes related to
printing on Linux. We definitely need those unit tests in the future. [Issue# 21
611](http://code.google.com/p/chromium/issues/detail?id=21611) |
| 44 1. I did not have enough time to compare our results with other competitors. A
nyway, in the future, we should always compare quality, correctness, size, and m
aybe also resources and time in printing. |
| 45 1. We do not supports all APIs in `SkCanvas` now ([Issue# 21612](http://code.g
oogle.com/p/chromium/issues/detail?id=21612)). By the way, when we need to do al
pha composition in canvas, the result generated by Cairo is not perfect(buggy).
For example, the resulting color might be wrong, and sometimes we will have roun
d-off error in images' layout. You can try to print `third_party/WebKit/LayoutTe
sts/svg/W3C-SVG-1.1/filters-blend-01-b.svg` and compare the result with your scr
een. If you print it out with a printer using CYMK, you might have incorrect col
ors. |
| 46 1. We should find a way to do layout tests for printing. [Issue# 21613](http:/
/code.google.com/p/chromium/issues/detail?id=21613) For example, it looks not qu
ite right when you print this [page](http://code.google.com/p/chromium/issues/de
tail?id=8551&colspec=ID%20Stars%20Pri%20Area%20Type%20Status%20Summary%20Modifie
d%20Owner%20Mstone). |
| 47 |
| 48 # Bugs |
| 49 1. There are still many bugs in vector canvas. I did not implement path effect
, so it prints dashed lines as solid lines. [Issue# 21614](http://code.google.co
m/p/chromium/issues/detail?id=21614) |
| 50 1. When you print the "new-tab-page", the rounded boxes look strange. [Issue#
21616](http://code.google.com/p/chromium/issues/detail?id=21616) |
| 51 1. The button is shown as a black rectangle. We should print it with a bitmap.
Of course, we have to get the correct button according to the user's theme. [Is
sue# 21617](http://code.google.com/p/chromium/issues/detail?id=21617) |
| 52 1. The font cache in `PdfPsMetafile` might not be thread-safe. [Issue# 21618](
http://code.google.com/p/chromium/issues/detail?id=21618) |
| 53 1. The file descriptor map used in the browser might not be thread safe. (Howe
ver, it is just used at this moment as a quick ugly hack. We should be able to g
et rid of it when we implement all other printing classes.) |
| 54 1. Since we save the resulting PDF file in the renderer, this might not be a g
ood thing and might freeze the renderer for a while. We should find a way to get
around it. By the way, maybe we should also show the printing progress? [Issue#
21619](http://code.google.com/p/chromium/issues/detail?id=21619) |
| 55 |
| 56 |
| 57 --- |
| 58 |
| 59 |
| 60 # Reference |
| 61 [Issue# 9847](http://code.google.com/p/chromium/issues/detail?id=9847) |
| 62 > It is blocked on [Issue# 19223](http://code.google.com/p/chromium/issues/detai
l?id=19223) |
| 63 | Revision# | Code review# | |
| 64 |:----------|:-------------| |
| 65 | `r22522` | `160347` | |
| 66 | `r23032` | `164025` | |
| 67 | `r24243` | `174042` | |
| 68 | `r24376` | `173368` | |
| 69 | `r24474` | `174468` | |
| 70 | `r24533` | `173516` | |
| 71 | `r25615` | `172115` | |
| 72 | `r25974` | `196071` | |
| 73 | `r26308` | `203062` | |
| 74 | `r26400` | `200138` | |
OLD | NEW |