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