blitz-pdf 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +266 -12
  2. package/THIRD_PARTY_NOTICES.md +4 -2
  3. package/dist/browser.d.ts +1 -1
  4. package/dist/browser.d.ts.map +1 -1
  5. package/dist/document-options.d.ts +36 -0
  6. package/dist/document-options.d.ts.map +1 -0
  7. package/dist/document-options.js +236 -0
  8. package/dist/document-options.js.map +1 -0
  9. package/dist/node.d.ts +1 -1
  10. package/dist/node.d.ts.map +1 -1
  11. package/dist/options.d.ts +35 -1
  12. package/dist/options.d.ts.map +1 -1
  13. package/dist/options.js +21 -14
  14. package/dist/options.js.map +1 -1
  15. package/dist/types.d.ts +71 -1
  16. package/dist/types.d.ts.map +1 -1
  17. package/dist/validation.d.ts +2 -0
  18. package/dist/validation.d.ts.map +1 -0
  19. package/dist/validation.js +7 -0
  20. package/dist/validation.js.map +1 -0
  21. package/examples/zugferd.mjs +41 -0
  22. package/licenses/RUST_DEPENDENCIES.txt +27 -0
  23. package/package.json +3 -2
  24. package/src/browser.ts +1 -1
  25. package/src/document-options.ts +218 -0
  26. package/src/node.ts +1 -1
  27. package/src/options.ts +18 -13
  28. package/src/types.ts +76 -1
  29. package/src/validation.ts +6 -0
  30. package/vendor/README.md +27 -2
  31. package/vendor/krilla/.cargo-ok +1 -0
  32. package/vendor/krilla/.cargo_vcs_info.json +6 -0
  33. package/vendor/krilla/Cargo.lock +1357 -0
  34. package/vendor/krilla/Cargo.toml +165 -0
  35. package/vendor/krilla/LICENSE_APACHE +202 -0
  36. package/vendor/krilla/LICENSE_MIT +21 -0
  37. package/vendor/krilla/README.md +156 -0
  38. package/vendor/krilla/examples/basic.rs +117 -0
  39. package/vendor/krilla/examples/empty_document.rs +25 -0
  40. package/vendor/krilla/examples/parley.rs +174 -0
  41. package/vendor/krilla/examples/simple_text.rs +118 -0
  42. package/vendor/krilla/examples/stream_builder.rs +93 -0
  43. package/vendor/krilla/icc/LICENSE +116 -0
  44. package/vendor/krilla/icc/README.md +1 -0
  45. package/vendor/krilla/icc/sGrey-v2-magic.icc +0 -0
  46. package/vendor/krilla/icc/sGrey-v4.icc +0 -0
  47. package/vendor/krilla/icc/sRGB-v2-magic.icc +0 -0
  48. package/vendor/krilla/icc/sRGB-v4.icc +0 -0
  49. package/vendor/krilla/src/chunk_container.rs +503 -0
  50. package/vendor/krilla/src/configure/PDF_A1.md +227 -0
  51. package/vendor/krilla/src/configure/PDF_A2.md +269 -0
  52. package/vendor/krilla/src/configure/PDF_A3.md +31 -0
  53. package/vendor/krilla/src/configure/PDF_A4.md +211 -0
  54. package/vendor/krilla/src/configure/PDF_UA1.md +202 -0
  55. package/vendor/krilla/src/configure/README.md +23 -0
  56. package/vendor/krilla/src/configure/mod.rs +197 -0
  57. package/vendor/krilla/src/configure/validate.rs +1244 -0
  58. package/vendor/krilla/src/configure/version.rs +134 -0
  59. package/vendor/krilla/src/content.rs +1352 -0
  60. package/vendor/krilla/src/data.rs +49 -0
  61. package/vendor/krilla/src/document.rs +156 -0
  62. package/vendor/krilla/src/error.rs +170 -0
  63. package/vendor/krilla/src/geom.rs +341 -0
  64. package/vendor/krilla/src/graphics/blend.rs +46 -0
  65. package/vendor/krilla/src/graphics/color.rs +552 -0
  66. package/vendor/krilla/src/graphics/graphic.rs +30 -0
  67. package/vendor/krilla/src/graphics/graphics_state.rs +251 -0
  68. package/vendor/krilla/src/graphics/icc.rs +218 -0
  69. package/vendor/krilla/src/graphics/image.rs +835 -0
  70. package/vendor/krilla/src/graphics/mask.rs +128 -0
  71. package/vendor/krilla/src/graphics/mod.rs +14 -0
  72. package/vendor/krilla/src/graphics/paint.rs +434 -0
  73. package/vendor/krilla/src/graphics/separation.rs +86 -0
  74. package/vendor/krilla/src/graphics/shading_function.rs +865 -0
  75. package/vendor/krilla/src/graphics/shading_pattern.rs +60 -0
  76. package/vendor/krilla/src/graphics/tiling_pattern.rs +119 -0
  77. package/vendor/krilla/src/graphics/xobject.rs +150 -0
  78. package/vendor/krilla/src/interactive/action.rs +68 -0
  79. package/vendor/krilla/src/interactive/annotation.rs +283 -0
  80. package/vendor/krilla/src/interactive/destination.rs +289 -0
  81. package/vendor/krilla/src/interactive/mod.rs +3 -0
  82. package/vendor/krilla/src/interchange/embed.rs +240 -0
  83. package/vendor/krilla/src/interchange/metadata.rs +564 -0
  84. package/vendor/krilla/src/interchange/mod.rs +4 -0
  85. package/vendor/krilla/src/interchange/outline.rs +263 -0
  86. package/vendor/krilla/src/interchange/tagging/fmt.rs +733 -0
  87. package/vendor/krilla/src/interchange/tagging/generate.toml +474 -0
  88. package/vendor/krilla/src/interchange/tagging/generated.rs +4754 -0
  89. package/vendor/krilla/src/interchange/tagging/mod.rs +1324 -0
  90. package/vendor/krilla/src/interchange/tagging/tag.rs +686 -0
  91. package/vendor/krilla/src/lib.rs +179 -0
  92. package/vendor/krilla/src/num.rs +26 -0
  93. package/vendor/krilla/src/page.rs +612 -0
  94. package/vendor/krilla/src/pdf.rs +313 -0
  95. package/vendor/krilla/src/resource.rs +436 -0
  96. package/vendor/krilla/src/serialize.rs +1101 -0
  97. package/vendor/krilla/src/stream.rs +368 -0
  98. package/vendor/krilla/src/surface.rs +664 -0
  99. package/vendor/krilla/src/text/cid.rs +488 -0
  100. package/vendor/krilla/src/text/font.rs +351 -0
  101. package/vendor/krilla/src/text/glyph/bitmap.rs +81 -0
  102. package/vendor/krilla/src/text/glyph/colr.rs +581 -0
  103. package/vendor/krilla/src/text/glyph/mod.rs +205 -0
  104. package/vendor/krilla/src/text/glyph/outline.rs +72 -0
  105. package/vendor/krilla/src/text/glyph/svg.rs +34 -0
  106. package/vendor/krilla/src/text/group.rs +463 -0
  107. package/vendor/krilla/src/text/mod.rs +232 -0
  108. package/vendor/krilla/src/text/shape.rs +102 -0
  109. package/vendor/krilla/src/text/type3.rs +514 -0
  110. package/vendor/krilla/src/util.rs +286 -0
  111. package/vendor/stylo/properties/longhands.toml +0 -1
  112. package/vendor/stylo/stylesheets/rule_parser.rs +1 -1
  113. package/wasm/blitz_pdf.js +10 -5
  114. package/wasm/blitz_pdf_bg.wasm +0 -0
@@ -0,0 +1,686 @@
1
+ use std::marker::PhantomData;
2
+ use std::num::{NonZeroU16, NonZeroU32};
3
+
4
+ use smallvec::SmallVec;
5
+
6
+ use crate::geom::Rect;
7
+ use crate::surface::Location;
8
+
9
+ include!("generated.rs");
10
+
11
+ impl TagKind {
12
+ /// Get the location.
13
+ pub fn location(&self) -> Option<Location> {
14
+ self.as_any().location
15
+ }
16
+
17
+ /// Set the location.
18
+ pub fn set_location(&mut self, location: Option<Location>) {
19
+ self.as_any_mut().location = location;
20
+ }
21
+
22
+ /// Set the location.
23
+ pub fn with_location(mut self, location: Option<Location>) -> Self {
24
+ self.as_any_mut().location = location;
25
+ self
26
+ }
27
+ }
28
+
29
+ /// A specific tag which allows accessing attributes specific to this [`TagKind`].
30
+ ///
31
+ /// # Example
32
+ /// ```
33
+ /// use std::num::NonZeroU32;
34
+ /// use krilla::tagging::{TagGroup, TagTree, TableHeaderScope, Tag, TagId};
35
+ ///
36
+ /// let tag = Tag::TH(TableHeaderScope::Row)
37
+ /// .with_id(Some(TagId::from(*b"this id")))
38
+ /// .with_col_span(Some(NonZeroU32::new(3).unwrap()))
39
+ /// .with_headers(Some([TagId::from(*b"parent id")]))
40
+ /// .with_width(Some(250.0))
41
+ /// .with_height(Some(100.0));
42
+ /// let group = TagGroup::new(tag);
43
+ ///
44
+ /// let mut tree = TagTree::new();
45
+ /// tree.push(group);
46
+ /// ```
47
+ #[derive(Clone, Debug, PartialEq)]
48
+ pub struct Tag<T> {
49
+ inner: AnyTag,
50
+ /// Compile time marker for a type-safe API.
51
+ pub(crate) ty: PhantomData<T>,
52
+ }
53
+
54
+ impl<T> Tag<T> {
55
+ /// This can't be public, otherwise tags could be constructed without
56
+ /// providing required attributes.
57
+ pub(crate) const fn new() -> Self {
58
+ Self {
59
+ inner: AnyTag::new(),
60
+ ty: PhantomData,
61
+ }
62
+ }
63
+
64
+ /// A raw tag, which allows reading all attributes.
65
+ pub fn as_any(&self) -> &AnyTag {
66
+ &self.inner
67
+ }
68
+
69
+ /// A raw tag, which allows reading all attributes and additionally writing
70
+ /// all global ones.
71
+ pub fn as_any_mut(&mut self) -> &mut AnyTag {
72
+ &mut self.inner
73
+ }
74
+
75
+ /// Get the location.
76
+ pub fn location(&self) -> Option<Location> {
77
+ self.as_any().location
78
+ }
79
+
80
+ /// Set the location.
81
+ pub fn set_location(&mut self, location: Option<Location>) {
82
+ self.as_any_mut().location = location;
83
+ }
84
+
85
+ /// Set the location.
86
+ pub fn with_location(mut self, location: Option<Location>) -> Self {
87
+ self.as_any_mut().location = location;
88
+ self
89
+ }
90
+ }
91
+
92
+ /// A raw tag, which allows reading all attributes and additionally writing all
93
+ /// global ones.
94
+ #[derive(Clone, Debug, PartialEq)]
95
+ pub struct AnyTag {
96
+ /// The location of the tag.
97
+ pub location: Option<Location>,
98
+ pub(crate) attrs: OrdinalSet<Attr>,
99
+ }
100
+
101
+ impl AnyTag {
102
+ pub(crate) const fn new() -> Self {
103
+ Self {
104
+ attrs: OrdinalSet::new(),
105
+ location: None,
106
+ }
107
+ }
108
+ }
109
+
110
+ /// An ordered set using ordinal numbers to sort and identify elements.
111
+ #[derive(Clone, Debug, PartialEq)]
112
+ pub(crate) struct OrdinalSet<A> {
113
+ items: SmallVec<[A; 1]>,
114
+ }
115
+
116
+ impl<A> OrdinalSet<A> {
117
+ pub(crate) const fn new() -> Self {
118
+ Self {
119
+ items: SmallVec::new_const(),
120
+ }
121
+ }
122
+ }
123
+
124
+ impl<A: Ordinal> OrdinalSet<A> {
125
+ pub(crate) fn iter(&self) -> impl Iterator<Item = &A> {
126
+ self.items.iter()
127
+ }
128
+
129
+ pub(crate) fn set(&mut self, attr: A) {
130
+ for (i, item) in self.items.iter().enumerate() {
131
+ if item.ordinal() == attr.ordinal() {
132
+ self.items[i] = attr;
133
+ return;
134
+ }
135
+ if item.ordinal() > attr.ordinal() {
136
+ self.items.insert(i, attr);
137
+ return;
138
+ }
139
+ }
140
+ self.items.push(attr);
141
+ }
142
+
143
+ pub(crate) fn remove(&mut self, ordinal: usize) {
144
+ for (i, item) in self.items.iter().enumerate() {
145
+ if item.ordinal() == ordinal {
146
+ self.items.remove(i);
147
+ return;
148
+ }
149
+ if item.ordinal() > ordinal {
150
+ break;
151
+ }
152
+ }
153
+ }
154
+
155
+ pub(crate) fn get(&self, ordinal: usize) -> Option<&A> {
156
+ for item in self.items.iter() {
157
+ if item.ordinal() == ordinal {
158
+ return Some(item);
159
+ }
160
+ if item.ordinal() > ordinal {
161
+ break;
162
+ }
163
+ }
164
+ None
165
+ }
166
+
167
+ pub(crate) fn set_or_remove(&mut self, ordinal: usize, attr: Option<A>) {
168
+ match attr {
169
+ Some(attr) => self.set(attr),
170
+ None => self.remove(ordinal),
171
+ }
172
+ }
173
+ }
174
+
175
+ /// Identifies elements using an ordinal number.
176
+ pub(crate) trait Ordinal {
177
+ fn ordinal(&self) -> usize;
178
+ }
179
+
180
+ /// An identifier of a [`Tag`].
181
+ #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
182
+ pub struct TagId(pub(crate) SmallVec<[u8; 16]>);
183
+
184
+ impl<I: IntoIterator<Item = u8>> From<I> for TagId {
185
+ fn from(value: I) -> Self {
186
+ // Disambiguate ids provided by the user from ids automatically assigned
187
+ // to notes by prefixing them with a `U`.
188
+ let bytes = std::iter::once(b'U').chain(value).collect();
189
+ TagId(bytes)
190
+ }
191
+ }
192
+
193
+ impl TagId {
194
+ /// Returns the identifier as a byte slice.
195
+ pub fn as_bytes(&self) -> &[u8] {
196
+ self.0.as_slice()
197
+ }
198
+ }
199
+
200
+ /// The list numbering type.
201
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
202
+ pub enum ListNumbering {
203
+ /// No numbering.
204
+ None,
205
+ /// Solid circular bullets.
206
+ Disc,
207
+ /// Open circular bullets.
208
+ Circle,
209
+ /// Solid square bullets.
210
+ Square,
211
+ /// Decimal numbers.
212
+ Decimal,
213
+ /// Lowercase Roman numerals.
214
+ LowerRoman,
215
+ /// Uppercase Roman numerals.
216
+ UpperRoman,
217
+ /// Lowercase letters.
218
+ LowerAlpha,
219
+ /// Uppercase letters.
220
+ UpperAlpha,
221
+ }
222
+
223
+ impl ListNumbering {
224
+ pub(crate) fn to_pdf(self) -> pdf_writer::types::ListNumbering {
225
+ match self {
226
+ ListNumbering::None => pdf_writer::types::ListNumbering::None,
227
+ ListNumbering::Disc => pdf_writer::types::ListNumbering::Disc,
228
+ ListNumbering::Circle => pdf_writer::types::ListNumbering::Circle,
229
+ ListNumbering::Square => pdf_writer::types::ListNumbering::Square,
230
+ ListNumbering::Decimal => pdf_writer::types::ListNumbering::Decimal,
231
+ ListNumbering::LowerRoman => pdf_writer::types::ListNumbering::LowerRoman,
232
+ ListNumbering::UpperRoman => pdf_writer::types::ListNumbering::UpperRoman,
233
+ ListNumbering::LowerAlpha => pdf_writer::types::ListNumbering::LowerAlpha,
234
+ ListNumbering::UpperAlpha => pdf_writer::types::ListNumbering::UpperAlpha,
235
+ }
236
+ }
237
+ }
238
+
239
+ /// The scope of a table header cell.
240
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
241
+ pub enum TableHeaderScope {
242
+ /// The header cell refers to the row.
243
+ Row,
244
+ /// The header cell refers to the column.
245
+ Column,
246
+ /// The header cell refers to both the row and the column.
247
+ Both,
248
+ }
249
+
250
+ impl TableHeaderScope {
251
+ pub(crate) fn to_pdf(self) -> pdf_writer::types::TableHeaderScope {
252
+ match self {
253
+ TableHeaderScope::Row => pdf_writer::types::TableHeaderScope::Row,
254
+ TableHeaderScope::Column => pdf_writer::types::TableHeaderScope::Column,
255
+ TableHeaderScope::Both => pdf_writer::types::TableHeaderScope::Both,
256
+ }
257
+ }
258
+ }
259
+
260
+ /// The positioning of the element with respect to the enclosing reference area
261
+ /// and other content.
262
+ /// When applied to an ILSE, any value except Inline shall cause the element to
263
+ /// be treated as a BLSE instead.
264
+ ///
265
+ /// Default value: [`Placement::Inline`].
266
+ #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
267
+ pub enum Placement {
268
+ /// Stacked in the block-progression direction within an enclosing reference
269
+ /// area or parent BLSE.
270
+ Block,
271
+ /// Packed in the inline-progression direction within an enclosing BLSE.
272
+ #[default]
273
+ Inline,
274
+ /// Placed so that the before edge of the element’s allocation rectangle.
275
+ /// (see “Content and Allocation Rectangles” in 14.8.5.4, “Layout Attributes”)
276
+ /// coincides with that of the nearest enclosing reference area. The element
277
+ /// may float, if necessary, to achieve the specified placement. The element
278
+ /// shall be treated as a block occupying the full extent of the enclosing
279
+ /// reference area in the inline direction. Other content shall be stacked
280
+ /// so as to begin at the after edge of the element’s allocation rectangle.
281
+ Before,
282
+ /// Placed so that the start edge of the element’s allocation rectangle
283
+ /// (see “Content and Allocation Rectangles” in 14.8.5.4, “Layout Attributes”)
284
+ /// coincides with that of the nearest enclosing reference area. The element
285
+ /// may float, if necessary, to achieve the specified placement. Other
286
+ /// content that would intrude into the element’s allocation rectangle
287
+ /// shall be laid out as a runaround.
288
+ Start,
289
+ /// Placed so that the end edge of the element’s allocation rectangle
290
+ /// (see “Content and Allocation Rectangles” in 14.8.5.4, “Layout Attributes”)
291
+ /// coincides with that of the nearest enclosing reference area. The element
292
+ /// may float, if necessary, to achieve the specified placement. Other
293
+ /// content that would intrude into the element’s allocation rectangle
294
+ /// shall be laid out as a runaround.
295
+ End,
296
+ }
297
+
298
+ impl Placement {
299
+ pub(crate) fn to_pdf(self) -> pdf_writer::types::Placement {
300
+ match self {
301
+ Placement::Block => pdf_writer::types::Placement::Block,
302
+ Placement::Inline => pdf_writer::types::Placement::Inline,
303
+ Placement::Before => pdf_writer::types::Placement::Before,
304
+ Placement::Start => pdf_writer::types::Placement::Start,
305
+ Placement::End => pdf_writer::types::Placement::End,
306
+ }
307
+ }
308
+ }
309
+
310
+ /// The directions of layout progression for packing of ILSEs (inline progression)
311
+ /// and stacking of BLSEs (block progression).
312
+ /// The specified layout directions shall apply to the given structure element
313
+ /// and all of its descendants to any level of nesting.
314
+ ///
315
+ /// Default value: [`WritingMode::LrTb`].
316
+ #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
317
+ pub enum WritingMode {
318
+ /// Inline progression from left to right; block progression from top to
319
+ /// bottom. This is the typical writing mode for Western writing systems.
320
+ #[default]
321
+ LrTb,
322
+ /// Inline progression from right to left; block progression from top to
323
+ /// bottom. This is the typical writing mode for Arabic and Hebrew writing
324
+ /// systems.
325
+ RlTb,
326
+ /// Inline progression from top to bottom; block progression from right to
327
+ /// left. This is the typical writing mode for Chinese and Japanese writing
328
+ /// systems.
329
+ TbRl,
330
+ }
331
+
332
+ impl WritingMode {
333
+ pub(crate) fn to_pdf(self) -> pdf_writer::types::WritingMode {
334
+ match self {
335
+ WritingMode::LrTb => pdf_writer::types::WritingMode::LtrTtb,
336
+ WritingMode::RlTb => pdf_writer::types::WritingMode::RtlTtb,
337
+ WritingMode::TbRl => pdf_writer::types::WritingMode::TtbRtl,
338
+ }
339
+ }
340
+ }
341
+
342
+ /// The bounding box of a tag that encloses its visible content.
343
+ /// If the content spans multiple pages, this should be omitted.
344
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
345
+ pub struct BBox {
346
+ /// The page index of the bounding box.
347
+ pub page_idx: usize,
348
+ /// The rectangle that encloses the content.
349
+ pub rect: Rect,
350
+ }
351
+
352
+ impl BBox {
353
+ /// Create a new bounding box.
354
+ pub fn new(page_idx: usize, rect: Rect) -> Self {
355
+ Self { page_idx, rect }
356
+ }
357
+ }
358
+
359
+ /// An RGB color within the tag tree. The color space of this color is not
360
+ /// specified. Each component is in the range [0.0, 1.0].
361
+ #[derive(Clone, Copy, Debug, PartialEq)]
362
+ pub struct NaiveRgbColor {
363
+ /// The red component of the color.
364
+ pub red: u8,
365
+ /// The green component of the color.
366
+ pub green: u8,
367
+ /// The blue component of the color.
368
+ pub blue: u8,
369
+ }
370
+
371
+ impl NaiveRgbColor {
372
+ /// Create a new RGB color.
373
+ pub fn new(red: u8, green: u8, blue: u8) -> Self {
374
+ Self { red, green, blue }
375
+ }
376
+
377
+ /// Create a new RGB color from normalized floating point values.
378
+ pub fn new_f32(red: f32, green: f32, blue: f32) -> Self {
379
+ if !(0.0..=1.0).contains(&red)
380
+ || !(0.0..=1.0).contains(&green)
381
+ || !(0.0..=1.0).contains(&blue)
382
+ {
383
+ panic!("RGB color components must be in the range [0.0, 1.0]");
384
+ }
385
+ Self {
386
+ red: (255.0 * red).round() as u8,
387
+ green: (255.0 * green).round() as u8,
388
+ blue: (255.0 * blue).round() as u8,
389
+ }
390
+ }
391
+
392
+ /// Convert the color into an array of f32 components for PDF serialization.
393
+ pub fn into_f32_array(self) -> [f32; 3] {
394
+ let normalize = |n| n as f32 / 255.0;
395
+ [self.red, self.green, self.blue].map(normalize)
396
+ }
397
+ }
398
+
399
+ impl From<NaiveRgbColor> for crate::graphics::color::rgb::Color {
400
+ fn from(color: NaiveRgbColor) -> Self {
401
+ crate::graphics::color::rgb::Color::new(color.red, color.green, color.blue)
402
+ }
403
+ }
404
+
405
+ impl From<NaiveRgbColor> for [f32; 3] {
406
+ fn from(color: NaiveRgbColor) -> Self {
407
+ color.into_f32_array()
408
+ }
409
+ }
410
+
411
+ /// The border style of an element.
412
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
413
+ pub enum BorderStyle {
414
+ /// No border.
415
+ None,
416
+ /// Hidden border.
417
+ Hidden,
418
+ /// Solid border.
419
+ Solid,
420
+ /// Dashed border.
421
+ Dashed,
422
+ /// Dotted border.
423
+ Dotted,
424
+ /// Double border.
425
+ Double,
426
+ /// Groove border.
427
+ Groove,
428
+ /// Ridge border.
429
+ Ridge,
430
+ /// Inset border.
431
+ Inset,
432
+ /// Outset border.
433
+ Outset,
434
+ }
435
+
436
+ impl BorderStyle {
437
+ pub(super) fn to_pdf(self) -> pdf_writer::types::LayoutBorderStyle {
438
+ match self {
439
+ BorderStyle::None => pdf_writer::types::LayoutBorderStyle::None,
440
+ BorderStyle::Hidden => pdf_writer::types::LayoutBorderStyle::Hidden,
441
+ BorderStyle::Solid => pdf_writer::types::LayoutBorderStyle::Solid,
442
+ BorderStyle::Dashed => pdf_writer::types::LayoutBorderStyle::Dashed,
443
+ BorderStyle::Dotted => pdf_writer::types::LayoutBorderStyle::Dotted,
444
+ BorderStyle::Double => pdf_writer::types::LayoutBorderStyle::Double,
445
+ BorderStyle::Groove => pdf_writer::types::LayoutBorderStyle::Groove,
446
+ BorderStyle::Ridge => pdf_writer::types::LayoutBorderStyle::Ridge,
447
+ BorderStyle::Inset => pdf_writer::types::LayoutBorderStyle::Inset,
448
+ BorderStyle::Outset => pdf_writer::types::LayoutBorderStyle::Outset,
449
+ }
450
+ }
451
+ }
452
+
453
+ /// The text alignment.
454
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
455
+ pub enum TextAlign {
456
+ /// At the start of the inline advance direction.
457
+ Start,
458
+ /// Centered.
459
+ Center,
460
+ /// At the end of the inline advance direction.
461
+ End,
462
+ /// Justified.
463
+ Justify,
464
+ }
465
+
466
+ impl TextAlign {
467
+ pub(super) fn to_pdf(self) -> pdf_writer::types::TextAlign {
468
+ match self {
469
+ TextAlign::Start => pdf_writer::types::TextAlign::Start,
470
+ TextAlign::Center => pdf_writer::types::TextAlign::Center,
471
+ TextAlign::End => pdf_writer::types::TextAlign::End,
472
+ TextAlign::Justify => pdf_writer::types::TextAlign::Justify,
473
+ }
474
+ }
475
+ }
476
+
477
+ /// The block alignment.
478
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
479
+ pub enum BlockAlign {
480
+ /// At the start of the block advance direction.
481
+ Begin,
482
+ /// Centered.
483
+ Middle,
484
+ /// At the end of the block advance direction.
485
+ After,
486
+ /// Justified.
487
+ Justify,
488
+ }
489
+
490
+ impl BlockAlign {
491
+ pub(super) fn to_pdf(self) -> pdf_writer::types::BlockAlign {
492
+ match self {
493
+ BlockAlign::Begin => pdf_writer::types::BlockAlign::Before,
494
+ BlockAlign::Middle => pdf_writer::types::BlockAlign::Middle,
495
+ BlockAlign::After => pdf_writer::types::BlockAlign::After,
496
+ BlockAlign::Justify => pdf_writer::types::BlockAlign::Justify,
497
+ }
498
+ }
499
+ }
500
+
501
+ /// The inline alignment.
502
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
503
+ pub enum InlineAlign {
504
+ /// At the start of the inline advance direction.
505
+ Start,
506
+ /// Centered.
507
+ Center,
508
+ /// At the end of the inline advance direction.
509
+ End,
510
+ }
511
+
512
+ impl InlineAlign {
513
+ pub(super) fn to_pdf(self) -> pdf_writer::types::InlineAlign {
514
+ match self {
515
+ InlineAlign::Start => pdf_writer::types::InlineAlign::Start,
516
+ InlineAlign::Center => pdf_writer::types::InlineAlign::Center,
517
+ InlineAlign::End => pdf_writer::types::InlineAlign::End,
518
+ }
519
+ }
520
+ }
521
+
522
+ /// The height of a line.
523
+ #[derive(Debug, Copy, Clone, PartialEq)]
524
+ pub enum LineHeight {
525
+ /// Adjust the line height automatically, taking `/BaselineShift` into
526
+ /// account.
527
+ Normal,
528
+ /// Adjust the line height automatically.
529
+ Auto,
530
+ /// Set a fixed line height.
531
+ Custom(f32),
532
+ }
533
+
534
+ impl LineHeight {
535
+ pub(super) fn to_pdf(self) -> pdf_writer::types::LineHeight {
536
+ match self {
537
+ LineHeight::Auto => pdf_writer::types::LineHeight::Auto,
538
+ LineHeight::Normal => pdf_writer::types::LineHeight::Normal,
539
+ LineHeight::Custom(height) => pdf_writer::types::LineHeight::Custom(height),
540
+ }
541
+ }
542
+ }
543
+
544
+ /// The text decoration type (over- and underlines).
545
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
546
+ pub enum TextDecorationType {
547
+ /// No decoration.
548
+ None,
549
+ /// Underlined.
550
+ Underline,
551
+ /// Line over the text.
552
+ Overline,
553
+ /// Strike the text.
554
+ LineThrough,
555
+ }
556
+
557
+ impl TextDecorationType {
558
+ pub(super) fn to_pdf(self) -> pdf_writer::types::TextDecorationType {
559
+ match self {
560
+ Self::None => pdf_writer::types::TextDecorationType::None,
561
+ Self::Underline => pdf_writer::types::TextDecorationType::Underline,
562
+ Self::Overline => pdf_writer::types::TextDecorationType::Overline,
563
+ Self::LineThrough => pdf_writer::types::TextDecorationType::LineThrough,
564
+ }
565
+ }
566
+ }
567
+
568
+ /// The rotation of glyphs in vertical writing modes.
569
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
570
+ pub enum GlyphOrientationVertical {
571
+ /// Determine the rotation based on whether the text is full-width.
572
+ Auto,
573
+ /// No rotation.
574
+ None,
575
+ /// Rotate 90 degrees clockwise.
576
+ Clockwise90,
577
+ /// Rotate 90 degrees counter-clockwise.
578
+ CounterClockwise90,
579
+ /// Rotate 180 degrees clockwise.
580
+ Clockwise180,
581
+ /// Rotate 180 degrees counter-clockwise.
582
+ CounterClockwise180,
583
+ /// Rotate 270 degrees clockwise.
584
+ Clockwise270,
585
+ }
586
+
587
+ impl GlyphOrientationVertical {
588
+ /// Convert the rotation to a number. If the rotation is `Auto`, returns
589
+ /// `None`.
590
+ pub(super) fn to_pdf(self) -> pdf_writer::types::GlyphOrientationVertical {
591
+ let angle = match self {
592
+ GlyphOrientationVertical::Auto => {
593
+ return pdf_writer::types::GlyphOrientationVertical::Auto
594
+ }
595
+ GlyphOrientationVertical::None => 0,
596
+ GlyphOrientationVertical::Clockwise90 => 90,
597
+ GlyphOrientationVertical::CounterClockwise90 => -90,
598
+ GlyphOrientationVertical::Clockwise180 => 180,
599
+ GlyphOrientationVertical::CounterClockwise180 => -180,
600
+ GlyphOrientationVertical::Clockwise270 => 270,
601
+ };
602
+ pdf_writer::types::GlyphOrientationVertical::Angle(angle)
603
+ }
604
+ }
605
+
606
+ /// An attribute value that can apply to all sides of the element, or have a specific value for each side.
607
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
608
+ pub struct Sides<T> {
609
+ /// The start of the element on the block axis.
610
+ pub before: T,
611
+ /// The end of the element on the block axis.
612
+ pub after: T,
613
+ /// The start of the element on the inline axis.
614
+ pub start: T,
615
+ /// The end of the element on the inline axis.
616
+ pub end: T,
617
+ }
618
+
619
+ impl<T> Sides<T> {
620
+ /// Construct a new `Sides` value with specific values for each side.
621
+ pub fn new(before: T, after: T, start: T, end: T) -> Self {
622
+ Self {
623
+ before,
624
+ after,
625
+ start,
626
+ end,
627
+ }
628
+ }
629
+
630
+ /// Construct a new `Sides` value with the same value for all sides.
631
+ pub fn uniform(value: T) -> Self
632
+ where
633
+ T: Copy,
634
+ {
635
+ Sides {
636
+ before: value,
637
+ after: value,
638
+ start: value,
639
+ end: value,
640
+ }
641
+ }
642
+
643
+ pub(crate) fn is_uniform(&self) -> bool
644
+ where
645
+ T: PartialEq,
646
+ {
647
+ self.before == self.after && self.before == self.start && self.before == self.end
648
+ }
649
+
650
+ /// Returns an array for all sides.
651
+ pub(super) fn into_array(self) -> [T; 4] {
652
+ [self.before, self.after, self.start, self.end]
653
+ }
654
+
655
+ /// Convert into [`pdf_writer::types::Sides`].
656
+ pub(super) fn into_pdf(self) -> pdf_writer::types::Sides<T> {
657
+ pdf_writer::types::Sides::from_array(self.into_array())
658
+ }
659
+
660
+ /// Convert into [`pdf_writer::types::Sides`] by each side value.
661
+ pub(super) fn map_pdf<P>(self, to_pdf: impl Fn(T) -> P) -> pdf_writer::types::Sides<P> {
662
+ pdf_writer::types::Sides::from_array(self.into_array().map(to_pdf))
663
+ }
664
+ }
665
+
666
+ /// Widths related to columns, either for all columns or
667
+ /// with specific values for each.
668
+ #[derive(Debug, Clone, PartialEq)]
669
+ pub enum ColumnDimensions {
670
+ /// The same value applies to all columns.
671
+ All(f32),
672
+ /// The value varies for each column or column gap.
673
+ Specific(Vec<f32>),
674
+ }
675
+
676
+ impl ColumnDimensions {
677
+ /// Construct a new `ColumnDimensions` with the same value for all columns.
678
+ pub fn all(value: f32) -> Self {
679
+ ColumnDimensions::All(value)
680
+ }
681
+
682
+ /// Construct a new `ColumnDimensions` with specific values for each column.
683
+ pub fn specific(values: Vec<f32>) -> Self {
684
+ ColumnDimensions::Specific(values)
685
+ }
686
+ }