OLD | NEW |
---|---|
(Empty) | |
1 PDF Theory of Operation | |
2 ======================= | |
3 | |
4 <!-- | |
5 PRE-GIT DOCUMENT VERSION HISTORY | |
6 2012-06-25 Steve VanDeBogart | |
7 * Original version | |
8 2015-01-14 Hal Canary. | |
9 * Add section "Using the PDF backend" | |
10 * Markdown formatting | |
11 --> | |
12 | |
13 | |
14 Using the PDF backend | |
15 --------------------- | |
16 | |
17 Here is an example of a C++ function that makes use of Skia's PDF backend | |
18 in the recommended way: using the SkDocument API. | |
19 | |
20 #include "SkDocument.h" | |
21 | |
22 class DocumentSource { | |
23 public: | |
24 virtual int pageCount() const = 0; | |
25 virtual void draw(int page, SkCanvas* dst) const = 0; | |
26 virtual SkScalar width(int page) const = 0; | |
27 virtual SkScalar height(int page) const = 0; | |
28 }; | |
29 | |
30 bool WritePDF(const DocumentSource& src, | |
31 SkWStream* outputStream) { | |
32 SkAutoTUnref<SkDocument> pdfDocument( | |
33 SkDocument::CreatePDF(outputStream)); | |
34 | |
35 for (int page = 0; page < src.pageCount(); ++page) { | |
36 SkCanvas* canvas = pdfDocument->beginPage( | |
37 src.width(page), src.height(page)); | |
38 src.draw(page, canvas); | |
39 pdfDocument->endPage(); | |
40 } | |
41 | |
42 return pdfDocument->close(); | |
43 } | |
44 | |
45 Internally, Skia uses SkPDFDocument and SkPDFDevice to represent PDF | |
46 documents and pages. This document describes how the backend | |
47 operates, but **these interfaces are not part of the public API and | |
48 are subject to perpetual change.** | |
49 | |
50 * * * | |
51 | |
52 ### Contents ### | |
53 | |
54 * [Typical usage of the PDF backend](#Typical_usage_of_the_PDF_backend) | |
55 * [PDF Objects and Document Structure](#PDF_Objects_and_Document_Structure) | |
56 * [PDF drawing](#PDF_drawing) | |
57 * [Interned objects](#Interned_objects) | |
58 * [Graphic States](#Graphic_States) | |
59 * [Clip and Transform](#Clip_and_Transform) | |
60 * [Generating a content stream](#Generating_a_content_stream) | |
61 * [Margins and content area](#Margins_and_content_area) | |
62 * [Drawing details](#Drawing_details) | |
63 + [Layers](#Layers) | |
64 + [Fonts](#Fonts) | |
65 + [Shaders](#Shaders) | |
66 + [Xfer modes](#Xfer_modes) | |
67 * [Known issues](#Known_issues) | |
68 | |
69 <a name="Typical_usage_of_the_PDF_backend"></a> | |
70 Typical usage of the PDF backend | |
71 -------------------------------- | |
72 | |
73 SkPDFDevice is the main interface to the PDF backend. This child of | |
74 SkDevice can be set on an SkCanvas and drawn to. It requires no more | |
75 care and feeding than SkDevice. Once drawing is complete, the device | |
76 should be added to an SkPDFDocument as a page of the desired PDF. A | |
77 new SkPDFDevice should be created for each page desired in the | |
78 document. After all the pages have been added to the document, | |
79 `SkPDFDocument::emitPDF()` can be called to get a PDF file. One of the | |
80 special features of the PDF backend is that the same device can be | |
81 added to multiple documents. This for example, would let you generate | |
82 a PDF with the single page you just drew as well as adding it to a | |
83 longer document with a bunch of other pages. | |
84 | |
85 SkAutoUnref<SkPDFDevice> pdfDevice( | |
86 new SkPDFDevice(width, height, initial_transform)); | |
87 | |
88 SkCanvas canvas(pdfDevice); | |
89 draw_content(&canvas); | |
90 | |
91 SkPDFDocument doc; | |
92 doc.appendPage(dev); | |
93 doc.emitPDF(&pdf_stream); | |
94 | |
95 <a name="PDF_Objects_and_Document_Structure"></a> | |
96 PDF Objects and Document Structure | |
97 ---------------------------------- | |
98 | |
99 **Background**: The PDF file format has a header, a set of objects and | |
100 then a footer that contains a table of contents for all of the objects | |
101 in the document (the cross-reference table). The table of contents | |
102 lists the specific byte position for each object. The objects may have | |
103 references to other objects and the ASCII size of those references is | |
104 dependent on the object number assigned to the referenced object; | |
105 therefore we can’t calculate the table of contents until the size of | |
106 objects is known, which requires assignment of object | |
107 numbers. | |
108 | |
109 Furthermore, PDF files can support a *linearized* mode, where objects | |
110 are in a specific order so that pdf-viewers can more easily retrieve | |
111 just the objects they need to display a specific page, i.e. by | |
112 byte-range requests over the web. Linearization also requires that all | |
113 objects used or referenced on the first page of the PDF have object | |
114 numbers before the rest of the objects. Consequently, before | |
115 generating a linearized PDF, all objects, their sizes, and object | |
116 references must be known. Skia has no plans to implement linearized | |
117 PDFs. | |
118 | |
119 <!-- <del>At this point, linearized PDFs are not generated. The | |
120 framework to generate them is in place, but the final bits of code | |
121 have not been written.</del> --> | |
122 | |
123 %PDF-1.4 | |
124 …objects... | |
125 xref | |
126 0 31 % Total number of entries in the table of contents. | |
127 0000000000 65535 f | |
128 0000210343 00000 n | |
129 … | |
130 0000117055 00000 n | |
131 trailer | |
132 <</Size 31 /Root 1 0 R>> | |
133 startxref | |
134 210399 % Byte offset to the start of the table of contents. | |
135 %%EOF | |
136 | |
137 The class SkPDFCatalog and the virtual class SkPDFObject are used to | |
138 manage the needs of the file format. Any object that will represent a | |
139 PDF object must inherit from SkPDFObject and implement the methods to | |
140 generate the binary representation and report any other SkPDFObjects | |
141 used as resources. SkPDFTypes.h defines most of the basic PDF objects | |
142 types: bool, int, scalar, string, name, array, dictionary, and object | |
143 reference. The stream type is defined in SkPDFStream.h. A stream is a | |
144 dictionary containing at least a Length entry followed by the data of | |
145 the stream. All of these types except the stream type can be used in | |
146 both a direct and an indirect fashion, i.e. an array can have an int | |
147 or a dictionary as an inline entry, which does not require an object | |
148 number. The stream type, cannot be inlined and must be referred to | |
149 with an object reference. Most of the time, other objects types can be | |
150 referred to with an object reference, but there are specific rules in | |
151 the PDF specification that requires an inline reference in some place | |
152 or an indirect reference in other places. All indirect objects must | |
153 have an object number assigned. | |
154 | |
155 * **bools**: `true` `false` | |
156 * **ints**: `42` `0` `-1` | |
157 * **scalars**: `0.001` | |
158 * **strings**: `(strings are in parentheses or byte encoded)` `<74657374>` | |
159 * **name**: `/Name` `/Name#20with#20spaces` | |
160 * **array**: `[/Foo 42 (arrays can contain multiple types)]` | |
161 * **dictionary**: `<</Key1 (value1) /key2 42>>` | |
162 * **indirect object**: | |
163 `5 0 obj | |
164 (An indirect string. Indirect objects have an object number and a | |
165 generation number, Skia always uses generation 0 objects) | |
166 endobj` | |
167 * **object reference**: `5 0 R` | |
168 * **stream**: `<</Length 56>> | |
169 stream | |
170 ...stream contents can be arbitrary, including binary... | |
171 endstream` | |
172 | |
173 The PDF backend requires all indirect objects used in a PDF to be | |
174 added to the SkPDFCatalog of the SkPDFDocument. The catalog is | |
175 responsible for assigning object numbers and generating the table of | |
176 contents required at the end of PDF files. In some sense, generating a | |
177 PDF is a three step process. In the first step all the objects and | |
178 references among them are created (mostly done by SkPDFDevice). In the | |
179 second step, object numbers are assigned and SkPDFCatalog is informed | |
180 of the file offset of each indirect object. Finally, in the third | |
181 step, the header is printed, each object is printed, and then the | |
182 table of contents and trailer are printed. SkPDFDocument takes care of | |
183 collecting all the objects from the various SkPDFDevice instances, | |
184 adding them to an SkPDFCatalog, iterating through the objects once to | |
185 set their file positions, and iterating again to generate the final | |
186 PDF. | |
187 | |
188 %PDF-1.4 | |
189 2 0 obj << | |
190 /Type /Catalog | |
191 /Pages 1 0 R | |
192 >> | |
193 endobj | |
194 3 0 obj << | |
195 /Type /Page | |
196 /Parent 1 0 R | |
197 /Resources <> | |
198 /MediaBox [0 0 612 792] | |
199 /Contents 4 0 R | |
200 >> | |
201 endobj | |
202 4 0 obj <> stream | |
203 endstream | |
204 endobj | |
205 1 0 obj << | |
206 /Type /Pages | |
207 /Kids [3 0 R] | |
208 /Count 1 | |
209 >> | |
210 endobj | |
211 xref | |
212 0 5 | |
213 0000000000 65535 f | |
214 0000000236 00000 n | |
215 0000000009 00000 n | |
216 0000000062 00000 n | |
217 0000000190 00000 n | |
218 trailer | |
219 <</Size 5 /Root 2 0 R>> | |
220 startxref | |
221 299 | |
222 %%EOF | |
223 | |
224 <a name="PDF_drawing"></a> | |
225 PDF drawing | |
226 ----------- | |
227 | |
228 Most drawing in PDF is specified by the text of a stream, referred to | |
229 as a content stream. The syntax of the content stream is different | |
230 than the syntax of the file format described above and is much closer | |
231 to PostScript in nature. The commands in the content stream tell the | |
232 PDF interpreter to draw things, like a rectangle (`x y w h re`), an | |
233 image, or text, or to do meta operations like set the drawing color, | |
234 apply a transform to the drawing coordinates, or clip future drawing | |
235 operations. The page object that references a content stream has a | |
236 list of resources that can be used in the content stream using the | |
237 dictionary name to reference the resources. Resources are things like | |
238 font objects, images objects, graphic state objects (a set of meta | |
239 operations like miter limit, line width, etc). Because of a mismatch | |
240 between Skia and PDF’s support for transparency (which will be | |
241 explained later), SkPDFDevice records each drawing operation into an | |
242 internal structure (ContentEntry) and only when the content stream is | |
243 needed does it flatten that list of structures into the final content | |
244 stream. | |
245 | |
246 4 0 obj << | |
247 /Type /Page | |
248 /Resources << | |
249 /Font <</F1 9 0 R>> | |
250 /XObject <</Image1 22 0 R /Image2 73 0 R>> | |
251 >> | |
252 /Content 5 0 R | |
253 >> endobj | |
254 | |
255 5 0 obj <</Length 227>> stream | |
256 % In the font specified in object 9 and a height | |
257 % of 12 points, at (72, 96) draw ‘Hello World.’ | |
258 BT | |
259 /F1 12 Tf | |
260 72 96 Td | |
261 (Hello World) Tj | |
262 ET | |
263 % Draw a filled rectange. | |
264 200 96 72 72 re B | |
265 ... | |
266 endstream | |
267 endobj | |
268 | |
269 <a name="Interned_objects"></a> | |
270 Interned objects | |
271 ---------------- | |
272 | |
273 There are a number of high level PDF objects (like fonts, graphic | |
274 states, etc) that are likely to be referenced multiple times in a | |
275 single PDF. To ensure that there is only one copy of each object | |
276 instance these objects an implemented with an | |
277 [interning pattern](http://en.wikipedia.org/wiki/String_interning). | |
278 As such, the classes representing these objects (like | |
279 SkPDFGraphicState) have private constructors and static methods to | |
280 retrieve an instance of the class. Internally, the class has a list of | |
281 unique instances that it consults before returning a new instance of | |
282 the class. If the requested instance already exists, the existing one | |
283 is returned. For obvious reasons, the returned instance should not be | |
284 modified. A mechanism to ensure that interned classes are immutable is | |
285 needed. See [issue 2683](http://skbug.com/2683). | |
286 | |
287 <a name="Graphic_States"></a> | |
288 Graphic States | |
289 -------------- | |
290 | |
291 PDF has a number of parameters that affect how things are drawn. The | |
292 ones that correspond to drawing options in Skia are: color, alpha, | |
293 line cap, line join type, line width, miter limit, and xfer/blend mode | |
294 (see later section for xfer modes). With the exception of color, these | |
295 can all be specified in a single pdf object, represented by the | |
296 SkPDFGraphicState class. A simple command in the content stream can | |
297 then set the drawing parameters to the values specified in that | |
298 graphic state object. PDF does not allow specifying color in the | |
299 graphic state object, instead it must be specified directly in the | |
300 content stream. Similarly the current font and font size are set | |
301 directly in the content stream. | |
302 | |
303 6 0 obj << | |
304 /Type /ExtGState | |
305 /CA 1 % Opaque - alpha = 1 | |
306 /LC 0 % Butt linecap | |
307 /LJ 0 % Miter line-join | |
308 /LW 2 % Line width of 2 | |
309 /ML 6 % Miter limit of 6 | |
310 /BM /Normal % Blend mode is normal i.e. source over | |
311 >> | |
312 endobj | |
313 | |
314 <a name="Clip_and_Transform"></a> | |
315 Clip and Transform | |
316 ------------------ | |
317 | |
318 Similar to Skia, PDF allows drawing to be clipped or | |
319 transformed. However, there are a few caveats that affect the design | |
320 of the PDF backend. PDF does not support perspective transforms | |
321 (perspective transform are treated as identity transforms). Clips, | |
322 however, have more issues to cotend with. PDF clips cannot be directly | |
323 unapplied or expanded. i.e. once an area has been clipped off, there | |
324 is no way to draw to it. However, PDF provides a limited depth stack | |
325 for the PDF graphic state (which includes the drawing parameters | |
326 mentioned above in the Graphic States section as well as the clip and | |
327 transform). Therefore to undo a clip, the PDF graphic state must be | |
328 pushed before the clip is applied, then popped to revert to the state | |
329 of the graphic state before the clip was applied. Along these lines, | |
330 PDF only supports clip intersection, so Skia’s other modes | |
331 (Difference, Union, Xor, ReverseDifference, Replace) have to be | |
332 checked and simulated using SkRegion. A general purpose geometry | |
333 library ([issue 221](http://skbug.com/221)) would make the simulation | |
334 more accurate and produce smaller PDFs. | |
335 | |
336 <!-- TODO(halcanary): update this documentation. --> | |
337 | |
338 As the canvas makes drawing calls into SkPDFDevice, the active | |
339 transform, clip region, and clip stack are stored in a ContentEntry | |
340 structure. Later, when the ContentEntry structures are flattened into | |
341 a valid PDF content stream, the transforms and clips are compared to | |
342 decide on an efficient set of operations to transition between the | |
343 states needed. Currently, a local optimization is used, to figure out | |
344 the best transition from one state to the next. A global optimization | |
345 could improve things by more effectively using the graphics state | |
346 stack provided in the PDF format. | |
347 | |
348 <a name="Generating_a_content_stream"></a> | |
349 Generating a content stream | |
350 --------------------------- | |
351 | |
352 For each draw call on an SkPDFDevice, a new ContentEntry is created, | |
353 which stores the matrix, clip region, and clip stack as well as the | |
354 paint parameters. Most of the paint parameters are bundled into an | |
355 SkPDFGraphicState (interned) with the rest (color, font size, etc) | |
356 explicitly stored in the ContentEntry. After populating the | |
357 ContentEntry with all the relevant context, it is compared to the the | |
358 most recently used ContentEntry. If the context matches, then the | |
359 previous one is appended to instead of using the new one. In either | |
360 case, with the context populated into the ContentEntry, the | |
361 appropriate draw call is allowed to append to the content stream | |
362 snippet in the ContentEntry to affect the core of the drawing call, | |
363 i.e. drawing a shape, an image, text, etc. | |
364 | |
365 When all drawing is complete, SkPDFDocument::emitPDF() will call | |
366 SkPDFDevice::content() to request the complete content stream for the | |
367 page. The first thing done is to apply the initial transform specified | |
368 in part in the constructor, this transform takes care of changing the | |
369 coordinate space from an origin in the lower left (PDF default) to the | |
370 upper left (Skia default) as well as any translation or scaling | |
371 requested by the user (i.e. to achieve a margin or scale the | |
372 canvas). Next (well almost next, see the next section), a clip is | |
373 applied to restrict drawing to the content area (the part of the page | |
374 inside the margins) of the page. Then, each ContentEntry is applied to | |
375 the content stream with the help of a helper class, GraphicStackState, | |
376 which tracks the state of the PDF graphics stack and optimizes the | |
377 output. For each ContentEntry, commands are emitted to the final | |
378 content entry to update the clip from its current state to the state | |
379 specified in the ContentEntry, similarly the Matrix and drawing state | |
380 (color, line joins, etc) are updated, then the content entry fragment | |
381 (the actual drawing operation) is appended. | |
382 | |
383 <a name="Margins_and_content_area"></a> | |
384 Margins and content area | |
385 ------------------------ | |
386 | |
387 The above procedure does not permit drawing in the margins. This is | |
388 done in order to contain any rendering problems in WebKit. In order to | |
389 support headers and footers, which are drawn in the margin, a second | |
390 set of ContentEntry’s are maintained. The | |
391 methodSkPDFDevice::setDrawingArea() selects which set of | |
392 ContentEntry’s are drawn into. Then, in the SkPDFDevice::content() | |
393 method, just before the clip to the content area is applied the margin | |
394 ContentEntry's are played back. | |
395 | |
396 <!-- TODO(halcanary): update this documentation. --> | |
397 | |
398 <a name="Drawing_details"></a> | |
399 Drawing details | |
400 --------------- | |
401 | |
402 Certain objects have specific properties that need to be dealt | |
403 with. Images, layers (see below), and fonts assume the standard PDF | |
404 coordinate system, so we have to undo any flip to the Skia coordinate | |
405 system before drawing these entities. We don’t currently support | |
406 inverted paths, so filling an inverted path will give the wrong result | |
407 ([issue 221](http://skbug.com/221)). PDF doesn’t draw zero length | |
408 lines that have butt of square caps, so that is emulated. | |
409 | |
410 <a name="Layers"></a> | |
411 ### Layers ### | |
412 | |
413 PDF has a higher level object called a form x-object (form external | |
414 object) that is basically a PDF page, with resources and a content | |
415 stream, but can be transformed and drawn on an existing page. This is | |
416 used to implement layers. SkDevice has a method, | |
417 createFormXObjectFromDevice, which uses the SkPDFDevice::content() | |
418 method to construct a form x-object from the the | |
419 device. SkPDFDevice::drawDevice() works by creating a form x-object of | |
420 the passed device and then drawing that form x-object in the root | |
421 device. There are a couple things to be aware of in this process. As | |
422 noted previously, we have to be aware of any flip to the coordinate | |
423 system - flipping it an even number of times will lead to the wrong | |
424 result unless it is corrected for. The SkClipStack passed to drawing | |
425 commands includes the entire clip stack, including the clipping | |
426 operations done on the base layer. Since the form x-object will be | |
427 drawn as a single operation onto the base layer, we can assume that | |
428 all of those clips are in effect and need not apply them within the | |
429 layer. | |
430 | |
431 <a name="Fonts"></a> | |
432 ### Fonts ### | |
433 | |
434 There are many details for dealing with fonts, so this document will | |
435 only talk about some of the more important ones. A couple short | |
436 details: | |
437 | |
438 * We can’t assume that an arbitrary font will be available at PDF view | |
439 time, so we embed all fonts in accordance with modern PDF | |
440 guidelines. | |
441 * Most fonts these days are TrueType fonts, so this is where most of | |
442 the effort has been concentrated. | |
443 * Because Skia may only be given a glyph-id encoding of the text to | |
444 render and there is no perfect way to reverse the encoding, the | |
445 PDF backend always uses the glyph-id encoding of the text. | |
446 | |
447 #### *Type1/Type3 fonts* #### | |
448 | |
449 Linux supports Type1 fonts, but Windows and Mac seem to lack the | |
450 functionality required to extract the required information from the | |
451 font without parsing the font file. When a non TrueType font is used | |
452 any any platform (except for Type1 on Linux), it is encoded as a Type3 | |
453 font. In this context, a Type3 font is an array of form x-objects | |
454 (content streams) that draw each glyph of the font. No hinting or | |
455 kerning information is included in a Type3 font, just the shape of | |
456 each glyph. Any font that has the do-not embed copy protection bit set | |
457 will also get embedded as a Type3 font. From what I understand, shapes | |
458 are not copyrightable, but programs are, so by stripping all the | |
459 programmatic information and only embedding the shape of the glyphs we | |
460 are honoring the do-not embed bit as much as required by law. | |
461 | |
462 PDF only supports an 8-bit encoding for Type1 or Type3 fonts. However, | |
463 they can contain more than 256 glyphs. The PDF backend handles this by | |
464 segmenting the glyphs into groups of 255 (glyph id 0 is always the | |
465 unknown glyph) and presenting the font as multiple fonts, each with up | |
466 to 255 glyphs. | |
467 | |
468 #### *Font subsetting* #### | |
469 | |
470 Many fonts, especially fonts with CJK support are fairly large, so it | |
471 is desirable to subset them. Chrome uses the SFNTLY package to provide | |
472 subsetting support to Skia for TrueType fonts. However, there is a | |
473 conflict between font subsetting and interned objects. If the object | |
474 is immutable, how can it be subsetted? This conflict is resolved by | |
475 using a substitution mechanism in SkPDFCatalog. Font objects are still | |
476 interned, but the interned objects aren’t internally | |
477 populated. Subsetting starts while drawing text to an SkPDFDevice; a | |
478 bit set indicating which glyphs have been used is maintained. Later, | |
479 when SkPDFDocument::emitPDF() is rendering the PDF, it queries each | |
480 device (each page) for the set of fonts used and the glyphs used from | |
481 each font and combines the information. It then asks the interned | |
482 (unpopulated) font objects to create a populated instance with the | |
483 calculated subset of the font - this instance is not interned. The | |
484 subsetted instance is then set as a substitute for the interned font | |
485 object in the SkPDFCatalog. All future references to those fonts | |
486 within that document will refer to the subsetted instances, resulting | |
487 in a final PDF with exactly one instance of each used font that | |
488 includes only the glyphs used. | |
489 | |
490 The substitution mechanism is a little complicated, but is needed to | |
491 support the use case of an SkPDFDevice being added to multiple | |
492 documents. If fonts were subsetted in-situ, concurrent PDF generation | |
493 would have to be explicitly handled. Instead, by giving each document | |
494 its own subsetted instance, there is no need to worry about concurrent | |
495 PDF generation. The substitution method is also used to support | |
496 optional stream compression. A stream can used by different documents | |
497 in both a compressed and uncompressed form, leading to the same | |
498 potential difficulties faced by the concurrent font use case. | |
499 | |
500 <a name="Shaders"></a> | |
501 ### Shaders ### | |
502 | |
503 Skia has two types of predefined shaders, image shaders and gradient | |
504 shaders. In both cases, shaders are effectively positioned absolutely, | |
505 so the initial position and bounds of where they are visible is part | |
506 of the immutable state of the shader object. Each of the Skia’s tile | |
507 modes needs to be considered and handled explicitly. The image shader | |
508 we generate will be tiled, so tiling is handled by default. To support | |
509 mirroring, we draw the image, reversed, on the appropriate axis, or on | |
510 both axes plus a fourth in the vacant quadrant. For clamp mode, we | |
511 extract the pixels along the appropriate edge and stretch the single | |
512 pixel wide/long image to fill the bounds. For both x and y in clamp | |
513 mode, we fill the corners with a rectangle of the appropriate | |
514 color. The composed shader is then rotated or scaled as appropriate | |
515 for the request. | |
516 | |
517 Gradient shaders are handled purely mathematically. First, the matrix | |
518 is transformed so that specific points in the requested gradient are | |
519 at pre-defined locations, for example, the linear distance of the | |
520 gradient is always normalized to one. Then, a type 4 PDF function is | |
521 created that achieves the desired gradient. A type 4 function is a | |
522 function defined by a resticted postscript language. The generated | |
523 functions clamp at the edges so if the desired tiling mode is tile or | |
524 mirror, we hav to add a bit more postscript code to map any input | |
525 parameter into the 0-1 range appropriately. The code to generate the | |
526 postscript code is somewhat obtuse, since it is trying to generate | |
527 optimized (for space) postscript code, but there is a significant | |
528 number of comments to explain the intent. | |
529 | |
530 <a name="Xfer_modes"></a> | |
531 ### Xfer modes ### | |
532 | |
533 PDF supports some of the xfer modes used in Skia directly. For those, | |
534 it is simply a matter of setting the blend mode in the graphic state | |
535 to the appropriate value (Normal/SrcOver, Multiply, Screen, Overlay, | |
536 Darken, Lighten, !ColorDOdge, ColorBurn, HardLight, SoftLight, | |
537 Difference, Exclusion). Aside from the standard SrcOver mode, PDF does | |
538 not directly support the porter-duff xfer modes though. Most of them | |
539 (Clear, SrcMode, DstMode, DstOver, SrcIn, DstIn, SrcOut, DstOut) can | |
540 be emulated by various means, mostly by creating form x-objects out of | |
541 part of the content and drawing it with a another form x-object as a | |
542 mask. I have not figured out how to emulate the following modes: | |
543 SrcATop, DstATop, Xor, Plus. | |
544 | |
545 At the time of writing [2012-06-25], I have a [CL outstanding to fix a | |
546 misunderstanding I had about the meaning of some of the emulated | |
547 modes](https://codereview.appspot.com/4631078/). | |
548 I will describe the system with this change applied. | |
549 | |
550 First, a bit of terminology and definition. When drawing something | |
551 with an emulated xfer mode, what’s already drawn to the device is | |
552 called the destination or Dst, and what’s about to be drawn is the | |
553 source or Src. Src (and Dst) can have regions where it is transparent | |
554 (alpha equals zero), but it also has an inherent shape. For most kinds | |
555 of drawn objects, the shape is the same as where alpha is not | |
556 zero. However, for things like images and layers, the shape is the | |
557 bounds of the item, not where the alpha is non-zero. For example, a | |
558 10x10 image, that is transparent except for a 1x1 dot in the center | |
559 has a shape that is 10x10. The xfermodes gm test demonstrates the | |
560 interaction between shape and alpha in combination with the port-duff | |
561 xfer modes. | |
562 | |
563 The clear xfer mode removes any part of Dst that is within Src’s | |
564 shape. This is accomplished by bundling the current content of the | |
565 device (Dst) into a single entity and then drawing that with the | |
566 inverse of Src’s shape used as a mask (we want Dst where Src | |
567 isn’t). The implementation of that takes a couple more steps. You may | |
568 have to refer back to [the content stream section](#Generating_a_content_stream) . For any draw call, a | |
569 ContentEntry is created through a method called | |
570 SkPDFDevice::setUpContentEntry(). This method examines the xfer modes | |
571 in effect for that drawing operation and if it is an xfer mode that | |
572 needs emulation, it creates a form x-object from the device, | |
573 i.e. creates Dst, and stores it away for later use. This also clears | |
574 all of that existing ContentEntry's on that device. The drawing | |
575 operation is then allowed to proceed as normal (in most cases, see | |
576 note about shape below), but into the now empty device. Then, when the | |
577 drawing operation in done, a complementary method is | |
578 called,SkPDFDevice::finishContentEntry(), which takes action if the | |
579 current xfer mode is emulated. In the case of Clear, it packages what | |
580 was just drawn into another form x-object, and then uses the Src form | |
581 x-object, an invert function, and the Dst form x-object to draw Dst | |
582 with the inverse shape of Src as a mask. This works well when the | |
583 shape of Src is the same as the opaque part of the drawing, since PDF | |
584 uses the alpha channel of the mask form x-object to do masking. When | |
585 shape doesn’t match the alpha channel, additional action is | |
586 required. The drawing routines where shape and alpha don’t match, set | |
587 state to indicate the shape (always rectangular), which | |
588 finishContentEntry uses. The clear xfer mode is a special case; if | |
589 shape is needed, then Src isn’t used, so there is code to not bother | |
590 drawing Src if shape is required and the xfer mode is clear. | |
591 | |
592 SrcMode is clear plus Src being drawn afterward. DstMode simply omits | |
593 drawing Src. DstOver is the same as SrcOver with Src and Dst swapped - | |
594 this is accomplished by inserting the new ContentEntry at the | |
595 beginning of the list of ContentEntry’s in setUpContentEntry instead | |
596 of at the end. SrcIn, SrcOut, DstIn, DstOut are similar to each, the | |
597 difference being an inverted or non-inverted mask and swapping Src and | |
598 Dst (or not). SrcIn is SrcMode with Src drawn with Dst as a | |
599 mask. SrcOut is like SrcMode, but with Src drawn with an inverted Dst | |
600 as a mask. DstIn is SrcMode with Dst drawn with Src as a | |
601 mask. Finally, DstOut is SrcMode with Dst draw with an inverted Src as | |
602 a mask. | |
603 | |
604 <a name="Known_issues"></a> | |
605 Known issues | |
606 ------------ | |
607 | |
608 * [issue 221](http://skbug.com/221), | |
jcgregorio
2015/01/14 21:19:11
Have the bugs been reviewed? For example, 221 is m
hal.canary
2015/01/20 18:02:05
Updated.
| |
609 [issue 241](http://skbug.com/241) | |
610 As previously noted, a boolean geometry library | |
611 would improve clip fidelity in some places, add supported for | |
612 inverted fill types, as well as simplify code. | |
613 * [issue 237](http://skbug.com/237) | |
614 SkMaskFilter is not supported. | |
615 * [issue 238](http://skbug.com/238) | |
616 SkColorFilter is not supported. | |
617 * [issue 242](http://skbug.com/242) | |
618 perspective transforms are not supported. | |
619 * [issue 249](http://skbug.com/249) | |
620 SrcAtop DstAtop, Xor, and Plus xfer modes are not supported. | |
621 * [issue 240](http://skbug.com/240) | |
622 drawVerticies is not implemented. | |
623 * [issue 236](http://skbug.com/236) | |
624 SkPDFImage doesn’t unpremultiply colors. | |
625 * [issue 248](http://skbug.com/248) | |
626 Linearized PDFs are not generated, though support for them | |
627 is built in. | |
628 * [issue 244](http://skbug.com/244) | |
629 Mostly, only TTF fonts are directly supported. | |
630 * [issue 260](http://skbug.com/260) | |
631 Page rotation is accomplished by specifying a different | |
632 size page instead of including the appropriate rotation | |
633 annotation. | |
634 | |
635 * * * | |
636 | |
OLD | NEW |