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