idml 0.9.1 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a82b32708ab694d0d794c39f33d74de7b39a9bdc38b7a6315b99a2156dcef271
4
- data.tar.gz: 7eee074d6ecf3a46798139fa6ed6fc36c975bcaf93059c52e68e597e7b1a87f3
3
+ metadata.gz: eb1bde51604723b865996a34842c6a5216b3c0ce4f55947902aa9dd92358ed25
4
+ data.tar.gz: a1e6ed580c3d0fee769287d3619c33fa6e18ed79ee332d1aa0a7976b1352b760
5
5
  SHA512:
6
- metadata.gz: 6c561f3cd1a83d7688291a2ef3dc23d42616bce723b5ff82a77a641104fae0731247c4cbc50cae2d9d5d5aa979c31ac8e90ff0b38f107235793bdfd7fda4019a
7
- data.tar.gz: e42f707ec01db8ce171244e95ba378420bdf44c4a195c1f2f285ac7d56e91777c4750f5d5f4b05dc6ac60fb2f59beebaa50755f6c1ee3bb2de13957a7b44edab
6
+ metadata.gz: 989af27c2ad974dac8d370e335e923b70727a0c32991fe67011c2231cd5b526fdf59e73d571df8423ae69e9e27a5fa03dd69cf94a732ec76138cb34188af0792
7
+ data.tar.gz: d3daaccd0d51e4a78b825f5ea2f7baf6a3c23c11df1c33eb793b649c23b18bac2255de8e3fc3e3e7d62addac871b77f20879931dac73d6f14fec6fe54c10caea
@@ -1,5 +1,8 @@
1
- # Auto-generated by Cimas: Do not edit it manually!
2
- # See https://github.com/metanorma/cimas
1
+ # Managed by Cimas; trusted-publishing change is intentional (2026-08-18):
2
+ # publish via RubyGems OIDC Trusted Publishing instead of the API key
3
+ # (the API-key path is blocked by rubygems.org MFA OTP demands).
4
+ # See https://github.com/metanorma/ci — the reusable workflow uses its
5
+ # OIDC path whenever the rubygems-api-key secret is not passed.
3
6
  name: release
4
7
 
5
8
  on:
@@ -20,6 +23,5 @@ jobs:
20
23
  with:
21
24
  next_version: ${{ github.event.inputs.next_version }}
22
25
  secrets:
23
- rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
24
26
  pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
25
27
 
@@ -1,11 +1,21 @@
1
1
  # TODO PDF 104: Schema-faithful Table model completion
2
2
 
3
- ## Status: PARTIALadded the rendering-relevant subset (column_count,
4
- single_column_width, header/body/footer row counts, table_direction,
5
- outer-border strokes). The remaining ~150 schema attributes (alternating
6
- stroke rows, column rules, table-flavor bits) aren't needed for
7
- rendering and would be pure model bloat. Add incrementally as use
8
- cases demand.
3
+ ## Status: COMPLETEimplemented 2026-08-18
4
+
5
+ All 171 Table_Object attributes from
6
+ `reference-docs/schemas/package/Stories/Story.rnc` are declared on
7
+ `Elements::Table` (the prior rendering-relevant subset plus the 155
8
+ remaining: border tints/gaps/overprints, default row/column strokes,
9
+ alternating fills, cell insets, diagonal lines, caption settings,
10
+ …), generated with `scripts/rnc_to_lutaml.rb` in schema order.
11
+
12
+ Drift defense: `spec/idml/elements/table_spec.rb` reads the RNC at
13
+ spec time and asserts a Table built with every schema attribute
14
+ round-trips every attribute — any attribute dropped from the model
15
+ fails the spec.
16
+
17
+ The renderer still consults only the rendering-relevant subset; the
18
+ rest are carried for round-trip and downstream-tool fidelity.
9
19
 
10
20
  ## Problem
11
21
 
@@ -0,0 +1,31 @@
1
+ # TODO PDF 116: Justified-text last-line handling
2
+
3
+ ## Status: COMPLETE — implemented 2026-08-18
4
+
5
+ ## Problem
6
+
7
+ `TextEngine::Justifier` spread slack across inter-word spaces for
8
+ `:justified` paragraphs on EVERY line, including each paragraph's
9
+ final line — InDesign (and standard typography) leaves the last line
10
+ of a justified paragraph ragged. Every fully-justified paragraph
11
+ rendered with its final line stretched across the full column width.
12
+
13
+ ## What was done
14
+
15
+ - `Justifier.justify` takes `last_line:`; when true, a `:justified`
16
+ line falls back to left alignment (no space stretching). All other
17
+ alignments unchanged.
18
+ - `TextFrameRenderer.layout_run` passes `last_line:` true for the
19
+ final line of the paragraph's FINAL run (`paragraph_last:` flag
20
+ threaded from `render_runs_for_paragraph`, which knows the run
21
+ list). Mid-paragraph run breaks still justify — only the true
22
+ paragraph-final line goes ragged.
23
+ - Footnote layout (`Render::Footnote.layout_paragraph`) applies the
24
+ same rule for the final line of the final run.
25
+
26
+ ## Known limitations
27
+
28
+ - Justification adjusts inter-word spaces only; letter spacing and
29
+ glyph scaling (Minimum/Maximum/DesiredGlyphScaling, tracking) are
30
+ not applied. ToBinding / RTL binding alignment remains mapped to
31
+ left.
@@ -0,0 +1,45 @@
1
+ # TODO PDF 117: Endnote support
2
+
3
+ ## Status: OPEN (modeling COMPLETE 2026-08-18; rendering OPEN pending
4
+ a real fixture)
5
+
6
+ ## Problem
7
+
8
+ IDML endnotes use a reference architecture unlike footnotes: the
9
+ main story carries `<Endnote Self="..." EndnoteTextRange="..."/>`
10
+ plus `<EndnoteRange SourceEndnote="..."/>` markers (both at Story
11
+ level, per Story.rnc), while the endnote TEXT lives in a separate
12
+ story flagged `IsEndnoteStory="true"`. Documents with endnotes
13
+ (scholarly publishing) currently drop endnote text entirely.
14
+
15
+ ## What is done (2026-08-18)
16
+
17
+ - `Elements::Endnote` (Self, EndnoteTextRange) and
18
+ `Elements::EndnoteRange` (Self, SourceEndnote) — schema-faithful
19
+ models, wired into `StoryInner` (`endnote`, `endnote_range`
20
+ collections). Round-trip + parse specs.
21
+ - `StoryInner#is_endnote_story` already parsed, so endnote stories
22
+ are identifiable.
23
+
24
+ ## Design for rendering (needs a real InDesign fixture to validate)
25
+
26
+ 1. Marker: story-level `Endnote`/`EndnoteRange` pairs delimit the
27
+ anchor range; marker position requires story text-offset
28
+ bookkeeping the extraction layer doesn't currently track (unlike
29
+ footnotes, which sit inside a CSR). A range-aware extraction is
30
+ the prerequisite.
31
+ 2. Endnote text: resolve `EndnoteTextRange` → the endnote story
32
+ (IsEndnoteStory) → its paragraphs.
33
+ 3. Placement: per EndnoteOption Scope — end of story / end of
34
+ section / end of document; end-of-story is the tractable default
35
+ (append after the referencing story's last paragraph).
36
+ 4. Numbering: endnotes number separately from footnotes
37
+ (FootnoteOption vs EndnoteOption StartAt/Prefix/Suffix — the
38
+ Endnote preference object is not yet modeled in Preferences).
39
+
40
+ ## Why rendering is deferred
41
+
42
+ The marker-position machinery (text-range resolution) cannot be
43
+ validated without a real fixture; blind implementation risks wrong
44
+ anchor placement on production files. Schema modeling + round-trip
45
+ is complete and verified.
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Idml
4
+ module Elements
5
+ # `<Endnote>` — a story-level endnote reference. The endnote's
6
+ # TEXT lives in a separate story flagged `IsEndnoteStory="true"`;
7
+ # this element points at it via `EndnoteTextRange` (schema:
8
+ # Endnote_Object in Stories/Story.rnc — Self plus the range
9
+ # reference; no inline content). Rendering design in
10
+ # TODO.pdf/117-endnote-support.md.
11
+ class Endnote < Lutaml::Model::Serializable
12
+ attribute :self_attr, :string
13
+ attribute :endnote_text_range, :string
14
+
15
+ xml do
16
+ root "Endnote"
17
+ map_attribute "Self", to: :self_attr
18
+ map_attribute "EndnoteTextRange", to: :endnote_text_range
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Idml
4
+ module Elements
5
+ # `<EndnoteRange>` — marks the text range in the main story that
6
+ # an endnote references, linking back via `SourceEndnote`
7
+ # (schema: EndnoteRange_Object in Stories/Story.rnc). Pairs with
8
+ # Elements::Endnote; rendering design in
9
+ # TODO.pdf/117-endnote-support.md.
10
+ class EndnoteRange < Lutaml::Model::Serializable
11
+ attribute :self_attr, :string
12
+ attribute :source_endnote, :string
13
+
14
+ xml do
15
+ root "EndnoteRange"
16
+ map_attribute "Self", to: :self_attr
17
+ map_attribute "SourceEndnote", to: :source_endnote
18
+ end
19
+ end
20
+ end
21
+ end
@@ -313,6 +313,9 @@ module Idml
313
313
  attribute :content, Idml::Elements::Content, collection: true
314
314
  attribute :xml_element, Idml::Elements::XmlElement, collection: true
315
315
  attribute :footnote, Idml::Elements::Footnote, collection: true
316
+ attribute :endnote, Idml::Elements::Endnote, collection: true
317
+ attribute :endnote_range, Idml::Elements::EndnoteRange,
318
+ collection: true
316
319
 
317
320
  xml do
318
321
  root "Story"
@@ -678,6 +681,8 @@ module Idml
678
681
  map_element "Content", to: :content
679
682
  map_element "XMLElement", to: :xml_element
680
683
  map_element "Footnote", to: :footnote
684
+ map_element "Endnote", to: :endnote
685
+ map_element "EndnoteRange", to: :endnote_range
681
686
  end
682
687
 
683
688
  def text_content
@@ -3,7 +3,9 @@
3
3
  module Idml
4
4
  module Elements
5
5
  # `<Table>` — a table page item. Carries geometry, body/header
6
- # row counts, column layout, and border styling. Two child
6
+ # row counts, column layout, and border styling. Declares every
7
+ # attribute of Table_Object in Stories/Story.rnc (171 schema
8
+ # attributes). Two child
7
9
  # collections hold the table's content:
8
10
  #
9
11
  # - `row` — schema-faithful `<Row>` siblings (real IDML).
@@ -43,6 +45,167 @@ module Idml
43
45
  attribute :right_border_stroke_weight, :float
44
46
  attribute :right_border_stroke_color, :string
45
47
 
48
+ # The remaining Table_Object attributes (border tints/gaps/
49
+ # overprints, default row/column strokes, alternating fills,
50
+ # cell insets, diagonal lines, caption settings, …) in schema
51
+ # order — generated by `scripts/rnc_to_lutaml.rb` from
52
+ # reference-docs/schemas/package/Stories/Story.rnc.
53
+ attribute :top_border_stroke_type, :string
54
+ attribute :top_border_stroke_tint, :float
55
+ attribute :top_border_stroke_overprint, :boolean
56
+ attribute :top_border_stroke_gap_color, :string
57
+ attribute :top_border_stroke_gap_tint, :float
58
+ attribute :top_border_stroke_gap_overprint, :boolean
59
+ attribute :left_border_stroke_type, :string
60
+ attribute :left_border_stroke_tint, :float
61
+ attribute :left_border_stroke_overprint, :boolean
62
+ attribute :left_border_stroke_gap_color, :string
63
+ attribute :left_border_stroke_gap_tint, :float
64
+ attribute :left_border_stroke_gap_overprint, :boolean
65
+ attribute :bottom_border_stroke_type, :string
66
+ attribute :bottom_border_stroke_tint, :float
67
+ attribute :bottom_border_stroke_overprint, :boolean
68
+ attribute :bottom_border_stroke_gap_color, :string
69
+ attribute :bottom_border_stroke_gap_tint, :float
70
+ attribute :bottom_border_stroke_gap_overprint, :boolean
71
+ attribute :right_border_stroke_type, :string
72
+ attribute :right_border_stroke_tint, :float
73
+ attribute :right_border_stroke_overprint, :boolean
74
+ attribute :right_border_stroke_gap_color, :string
75
+ attribute :right_border_stroke_gap_tint, :float
76
+ attribute :right_border_stroke_gap_overprint, :boolean
77
+ attribute :space_before, :float
78
+ attribute :space_after, :float
79
+ attribute :skip_first_alternating_stroke_rows, :integer
80
+ attribute :skip_last_alternating_stroke_rows, :integer
81
+ attribute :start_row_stroke_count, :integer
82
+ attribute :start_row_stroke_color, :string
83
+ attribute :start_row_stroke_weight, :float
84
+ attribute :start_row_stroke_type, :string
85
+ attribute :start_row_stroke_tint, :float
86
+ attribute :start_row_stroke_gap_overprint, :boolean
87
+ attribute :start_row_stroke_gap_color, :string
88
+ attribute :start_row_stroke_gap_tint, :float
89
+ attribute :start_row_stroke_overprint, :boolean
90
+ attribute :end_row_stroke_count, :integer
91
+ attribute :end_row_stroke_color, :string
92
+ attribute :end_row_stroke_weight, :float
93
+ attribute :end_row_stroke_type, :string
94
+ attribute :end_row_stroke_tint, :float
95
+ attribute :end_row_stroke_overprint, :boolean
96
+ attribute :end_row_stroke_gap_color, :string
97
+ attribute :end_row_stroke_gap_tint, :float
98
+ attribute :end_row_stroke_gap_overprint, :boolean
99
+ attribute :skip_first_alternating_stroke_columns, :integer
100
+ attribute :skip_last_alternating_stroke_columns, :integer
101
+ attribute :start_column_stroke_count, :integer
102
+ attribute :start_column_stroke_color, :string
103
+ attribute :start_column_stroke_weight, :float
104
+ attribute :start_column_stroke_type, :string
105
+ attribute :start_column_stroke_tint, :float
106
+ attribute :start_column_stroke_overprint, :boolean
107
+ attribute :start_column_stroke_gap_color, :string
108
+ attribute :start_column_stroke_gap_tint, :float
109
+ attribute :start_column_stroke_gap_overprint, :boolean
110
+ attribute :end_column_stroke_count, :integer
111
+ attribute :end_column_stroke_color, :string
112
+ attribute :end_column_stroke_weight, :float
113
+ attribute :end_column_line_style, :string
114
+ attribute :end_column_stroke_tint, :float
115
+ attribute :end_column_stroke_overprint, :boolean
116
+ attribute :end_column_stroke_gap_color, :string
117
+ attribute :end_column_stroke_gap_tint, :float
118
+ attribute :end_column_stroke_gap_overprint, :boolean
119
+ attribute :column_fills_priority, :boolean
120
+ attribute :skip_first_alternating_fill_rows, :integer
121
+ attribute :skip_last_alternating_fill_rows, :integer
122
+ attribute :start_row_fill_color, :string
123
+ attribute :start_row_fill_count, :integer
124
+ attribute :start_row_fill_tint, :float
125
+ attribute :start_row_fill_overprint, :boolean
126
+ attribute :end_row_fill_count, :integer
127
+ attribute :end_row_fill_color, :string
128
+ attribute :end_row_fill_tint, :float
129
+ attribute :end_row_fill_overprint, :boolean
130
+ attribute :skip_first_alternating_fill_columns, :integer
131
+ attribute :skip_last_alternating_fill_columns, :integer
132
+ attribute :start_column_fill_count, :integer
133
+ attribute :start_column_fill_color, :string
134
+ attribute :start_column_fill_tint, :float
135
+ attribute :start_column_fill_overprint, :boolean
136
+ attribute :end_column_fill_count, :integer
137
+ attribute :end_column_fill_color, :string
138
+ attribute :end_column_fill_tint, :float
139
+ attribute :end_column_fill_overprint, :boolean
140
+ attribute :break_headers, :string
141
+ attribute :break_footers, :string
142
+ attribute :skip_first_header, :boolean
143
+ attribute :skip_last_footer, :boolean
144
+ attribute :stroke_order, :string
145
+ attribute :default_row_stroke_weight, :float
146
+ attribute :default_row_stroke_type, :string
147
+ attribute :default_row_stroke_color, :string
148
+ attribute :default_row_stroke_tint, :float
149
+ attribute :default_row_stroke_overprint, :boolean
150
+ attribute :default_row_stroke_gap_color, :string
151
+ attribute :default_row_stroke_gap_tint, :float
152
+ attribute :default_row_stroke_gap_overprint, :boolean
153
+ attribute :default_column_stroke_weight, :float
154
+ attribute :default_column_stroke_type, :string
155
+ attribute :default_column_stroke_color, :string
156
+ attribute :default_column_stroke_tint, :float
157
+ attribute :default_column_stroke_overprint, :boolean
158
+ attribute :default_column_stroke_gap_color, :string
159
+ attribute :default_column_stroke_gap_tint, :float
160
+ attribute :default_column_stroke_gap_overprint, :boolean
161
+ attribute :top_inset, :float
162
+ attribute :left_inset, :float
163
+ attribute :bottom_inset, :float
164
+ attribute :right_inset, :float
165
+ attribute :fill_tint, :float
166
+ attribute :overprint_fill, :boolean
167
+ attribute :top_left_diagonal_line, :boolean
168
+ attribute :top_right_diagonal_line, :boolean
169
+ attribute :diagonal_line_in_front, :boolean
170
+ attribute :diagonal_line_stroke_weight, :float
171
+ attribute :diagonal_line_stroke_type, :string
172
+ attribute :diagonal_line_stroke_color, :string
173
+ attribute :diagonal_line_stroke_tint, :float
174
+ attribute :diagonal_line_stroke_overprint, :boolean
175
+ attribute :diagonal_line_stroke_gap_color, :string
176
+ attribute :diagonal_line_stroke_gap_tint, :float
177
+ attribute :diagonal_line_stroke_gap_overprint, :boolean
178
+ attribute :clip_content_to_cell, :boolean
179
+ attribute :first_baseline_offset, :string
180
+ attribute :vertical_justification, :string
181
+ attribute :paragraph_spacing_limit, :float
182
+ attribute :minimum_first_baseline_offset, :float
183
+ attribute :rotation_angle, :float
184
+ attribute :writing_direction, :boolean
185
+ attribute :minimum_height, :float
186
+ attribute :maximum_height, :float
187
+ attribute :keep_with_next_row, :boolean
188
+ attribute :start_row, :string
189
+ attribute :auto_grow, :boolean
190
+ attribute :num_header_columns, :integer
191
+ attribute :header_columns_position, :string
192
+ attribute :caption_paragraph_count, :integer
193
+ attribute :caption_position, :string
194
+ attribute :graphic_left_inset, :float
195
+ attribute :graphic_top_inset, :float
196
+ attribute :graphic_right_inset, :float
197
+ attribute :graphic_bottom_inset, :float
198
+ attribute :clip_content_to_graphic_cell, :boolean
199
+ attribute :text_top_inset, :float
200
+ attribute :text_left_inset, :float
201
+ attribute :text_bottom_inset, :float
202
+ attribute :text_right_inset, :float
203
+ attribute :clip_content_to_text_cell, :boolean
204
+ attribute :single_row_height, :float
205
+ attribute :applied_table_style, :string
206
+ attribute :display_collapsed, :boolean
207
+ attribute :display_order, :string
208
+
46
209
  attribute :table_row, Idml::Elements::TableRow, collection: true
47
210
  attribute :cell, Idml::Elements::Cell, collection: true
48
211
  attribute :row, Idml::Elements::Row, collection: true
@@ -75,6 +238,211 @@ module Idml
75
238
  to: :bottom_border_stroke_color
76
239
  map_attribute "RightBorderStrokeWeight", to: :right_border_stroke_weight
77
240
  map_attribute "RightBorderStrokeColor", to: :right_border_stroke_color
241
+ map_attribute "TopBorderStrokeType", to: :top_border_stroke_type
242
+ map_attribute "TopBorderStrokeTint", to: :top_border_stroke_tint
243
+ map_attribute "TopBorderStrokeOverprint",
244
+ to: :top_border_stroke_overprint
245
+ map_attribute "TopBorderStrokeGapColor",
246
+ to: :top_border_stroke_gap_color
247
+ map_attribute "TopBorderStrokeGapTint", to: :top_border_stroke_gap_tint
248
+ map_attribute "TopBorderStrokeGapOverprint",
249
+ to: :top_border_stroke_gap_overprint
250
+ map_attribute "LeftBorderStrokeType", to: :left_border_stroke_type
251
+ map_attribute "LeftBorderStrokeTint", to: :left_border_stroke_tint
252
+ map_attribute "LeftBorderStrokeOverprint",
253
+ to: :left_border_stroke_overprint
254
+ map_attribute "LeftBorderStrokeGapColor",
255
+ to: :left_border_stroke_gap_color
256
+ map_attribute "LeftBorderStrokeGapTint",
257
+ to: :left_border_stroke_gap_tint
258
+ map_attribute "LeftBorderStrokeGapOverprint",
259
+ to: :left_border_stroke_gap_overprint
260
+ map_attribute "BottomBorderStrokeType", to: :bottom_border_stroke_type
261
+ map_attribute "BottomBorderStrokeTint", to: :bottom_border_stroke_tint
262
+ map_attribute "BottomBorderStrokeOverprint",
263
+ to: :bottom_border_stroke_overprint
264
+ map_attribute "BottomBorderStrokeGapColor",
265
+ to: :bottom_border_stroke_gap_color
266
+ map_attribute "BottomBorderStrokeGapTint",
267
+ to: :bottom_border_stroke_gap_tint
268
+ map_attribute "BottomBorderStrokeGapOverprint",
269
+ to: :bottom_border_stroke_gap_overprint
270
+ map_attribute "RightBorderStrokeType", to: :right_border_stroke_type
271
+ map_attribute "RightBorderStrokeTint", to: :right_border_stroke_tint
272
+ map_attribute "RightBorderStrokeOverprint",
273
+ to: :right_border_stroke_overprint
274
+ map_attribute "RightBorderStrokeGapColor",
275
+ to: :right_border_stroke_gap_color
276
+ map_attribute "RightBorderStrokeGapTint",
277
+ to: :right_border_stroke_gap_tint
278
+ map_attribute "RightBorderStrokeGapOverprint",
279
+ to: :right_border_stroke_gap_overprint
280
+ map_attribute "SpaceBefore", to: :space_before
281
+ map_attribute "SpaceAfter", to: :space_after
282
+ map_attribute "SkipFirstAlternatingStrokeRows",
283
+ to: :skip_first_alternating_stroke_rows
284
+ map_attribute "SkipLastAlternatingStrokeRows",
285
+ to: :skip_last_alternating_stroke_rows
286
+ map_attribute "StartRowStrokeCount", to: :start_row_stroke_count
287
+ map_attribute "StartRowStrokeColor", to: :start_row_stroke_color
288
+ map_attribute "StartRowStrokeWeight", to: :start_row_stroke_weight
289
+ map_attribute "StartRowStrokeType", to: :start_row_stroke_type
290
+ map_attribute "StartRowStrokeTint", to: :start_row_stroke_tint
291
+ map_attribute "StartRowStrokeGapOverprint",
292
+ to: :start_row_stroke_gap_overprint
293
+ map_attribute "StartRowStrokeGapColor", to: :start_row_stroke_gap_color
294
+ map_attribute "StartRowStrokeGapTint", to: :start_row_stroke_gap_tint
295
+ map_attribute "StartRowStrokeOverprint", to: :start_row_stroke_overprint
296
+ map_attribute "EndRowStrokeCount", to: :end_row_stroke_count
297
+ map_attribute "EndRowStrokeColor", to: :end_row_stroke_color
298
+ map_attribute "EndRowStrokeWeight", to: :end_row_stroke_weight
299
+ map_attribute "EndRowStrokeType", to: :end_row_stroke_type
300
+ map_attribute "EndRowStrokeTint", to: :end_row_stroke_tint
301
+ map_attribute "EndRowStrokeOverprint", to: :end_row_stroke_overprint
302
+ map_attribute "EndRowStrokeGapColor", to: :end_row_stroke_gap_color
303
+ map_attribute "EndRowStrokeGapTint", to: :end_row_stroke_gap_tint
304
+ map_attribute "EndRowStrokeGapOverprint",
305
+ to: :end_row_stroke_gap_overprint
306
+ map_attribute "SkipFirstAlternatingStrokeColumns",
307
+ to: :skip_first_alternating_stroke_columns
308
+ map_attribute "SkipLastAlternatingStrokeColumns",
309
+ to: :skip_last_alternating_stroke_columns
310
+ map_attribute "StartColumnStrokeCount", to: :start_column_stroke_count
311
+ map_attribute "StartColumnStrokeColor", to: :start_column_stroke_color
312
+ map_attribute "StartColumnStrokeWeight", to: :start_column_stroke_weight
313
+ map_attribute "StartColumnStrokeType", to: :start_column_stroke_type
314
+ map_attribute "StartColumnStrokeTint", to: :start_column_stroke_tint
315
+ map_attribute "StartColumnStrokeOverprint",
316
+ to: :start_column_stroke_overprint
317
+ map_attribute "StartColumnStrokeGapColor",
318
+ to: :start_column_stroke_gap_color
319
+ map_attribute "StartColumnStrokeGapTint",
320
+ to: :start_column_stroke_gap_tint
321
+ map_attribute "StartColumnStrokeGapOverprint",
322
+ to: :start_column_stroke_gap_overprint
323
+ map_attribute "EndColumnStrokeCount", to: :end_column_stroke_count
324
+ map_attribute "EndColumnStrokeColor", to: :end_column_stroke_color
325
+ map_attribute "EndColumnStrokeWeight", to: :end_column_stroke_weight
326
+ map_attribute "EndColumnLineStyle", to: :end_column_line_style
327
+ map_attribute "EndColumnStrokeTint", to: :end_column_stroke_tint
328
+ map_attribute "EndColumnStrokeOverprint",
329
+ to: :end_column_stroke_overprint
330
+ map_attribute "EndColumnStrokeGapColor",
331
+ to: :end_column_stroke_gap_color
332
+ map_attribute "EndColumnStrokeGapTint", to: :end_column_stroke_gap_tint
333
+ map_attribute "EndColumnStrokeGapOverprint",
334
+ to: :end_column_stroke_gap_overprint
335
+ map_attribute "ColumnFillsPriority", to: :column_fills_priority
336
+ map_attribute "SkipFirstAlternatingFillRows",
337
+ to: :skip_first_alternating_fill_rows
338
+ map_attribute "SkipLastAlternatingFillRows",
339
+ to: :skip_last_alternating_fill_rows
340
+ map_attribute "StartRowFillColor", to: :start_row_fill_color
341
+ map_attribute "StartRowFillCount", to: :start_row_fill_count
342
+ map_attribute "StartRowFillTint", to: :start_row_fill_tint
343
+ map_attribute "StartRowFillOverprint", to: :start_row_fill_overprint
344
+ map_attribute "EndRowFillCount", to: :end_row_fill_count
345
+ map_attribute "EndRowFillColor", to: :end_row_fill_color
346
+ map_attribute "EndRowFillTint", to: :end_row_fill_tint
347
+ map_attribute "EndRowFillOverprint", to: :end_row_fill_overprint
348
+ map_attribute "SkipFirstAlternatingFillColumns",
349
+ to: :skip_first_alternating_fill_columns
350
+ map_attribute "SkipLastAlternatingFillColumns",
351
+ to: :skip_last_alternating_fill_columns
352
+ map_attribute "StartColumnFillCount", to: :start_column_fill_count
353
+ map_attribute "StartColumnFillColor", to: :start_column_fill_color
354
+ map_attribute "StartColumnFillTint", to: :start_column_fill_tint
355
+ map_attribute "StartColumnFillOverprint",
356
+ to: :start_column_fill_overprint
357
+ map_attribute "EndColumnFillCount", to: :end_column_fill_count
358
+ map_attribute "EndColumnFillColor", to: :end_column_fill_color
359
+ map_attribute "EndColumnFillTint", to: :end_column_fill_tint
360
+ map_attribute "EndColumnFillOverprint", to: :end_column_fill_overprint
361
+ map_attribute "BreakHeaders", to: :break_headers
362
+ map_attribute "BreakFooters", to: :break_footers
363
+ map_attribute "SkipFirstHeader", to: :skip_first_header
364
+ map_attribute "SkipLastFooter", to: :skip_last_footer
365
+ map_attribute "StrokeOrder", to: :stroke_order
366
+ map_attribute "DefaultRowStrokeWeight", to: :default_row_stroke_weight
367
+ map_attribute "DefaultRowStrokeType", to: :default_row_stroke_type
368
+ map_attribute "DefaultRowStrokeColor", to: :default_row_stroke_color
369
+ map_attribute "DefaultRowStrokeTint", to: :default_row_stroke_tint
370
+ map_attribute "DefaultRowStrokeOverprint",
371
+ to: :default_row_stroke_overprint
372
+ map_attribute "DefaultRowStrokeGapColor",
373
+ to: :default_row_stroke_gap_color
374
+ map_attribute "DefaultRowStrokeGapTint",
375
+ to: :default_row_stroke_gap_tint
376
+ map_attribute "DefaultRowStrokeGapOverprint",
377
+ to: :default_row_stroke_gap_overprint
378
+ map_attribute "DefaultColumnStrokeWeight",
379
+ to: :default_column_stroke_weight
380
+ map_attribute "DefaultColumnStrokeType", to: :default_column_stroke_type
381
+ map_attribute "DefaultColumnStrokeColor",
382
+ to: :default_column_stroke_color
383
+ map_attribute "DefaultColumnStrokeTint", to: :default_column_stroke_tint
384
+ map_attribute "DefaultColumnStrokeOverprint",
385
+ to: :default_column_stroke_overprint
386
+ map_attribute "DefaultColumnStrokeGapColor",
387
+ to: :default_column_stroke_gap_color
388
+ map_attribute "DefaultColumnStrokeGapTint",
389
+ to: :default_column_stroke_gap_tint
390
+ map_attribute "DefaultColumnStrokeGapOverprint",
391
+ to: :default_column_stroke_gap_overprint
392
+ map_attribute "TopInset", to: :top_inset
393
+ map_attribute "LeftInset", to: :left_inset
394
+ map_attribute "BottomInset", to: :bottom_inset
395
+ map_attribute "RightInset", to: :right_inset
396
+ map_attribute "FillTint", to: :fill_tint
397
+ map_attribute "OverprintFill", to: :overprint_fill
398
+ map_attribute "TopLeftDiagonalLine", to: :top_left_diagonal_line
399
+ map_attribute "TopRightDiagonalLine", to: :top_right_diagonal_line
400
+ map_attribute "DiagonalLineInFront", to: :diagonal_line_in_front
401
+ map_attribute "DiagonalLineStrokeWeight",
402
+ to: :diagonal_line_stroke_weight
403
+ map_attribute "DiagonalLineStrokeType", to: :diagonal_line_stroke_type
404
+ map_attribute "DiagonalLineStrokeColor", to: :diagonal_line_stroke_color
405
+ map_attribute "DiagonalLineStrokeTint", to: :diagonal_line_stroke_tint
406
+ map_attribute "DiagonalLineStrokeOverprint",
407
+ to: :diagonal_line_stroke_overprint
408
+ map_attribute "DiagonalLineStrokeGapColor",
409
+ to: :diagonal_line_stroke_gap_color
410
+ map_attribute "DiagonalLineStrokeGapTint",
411
+ to: :diagonal_line_stroke_gap_tint
412
+ map_attribute "DiagonalLineStrokeGapOverprint",
413
+ to: :diagonal_line_stroke_gap_overprint
414
+ map_attribute "ClipContentToCell", to: :clip_content_to_cell
415
+ map_attribute "FirstBaselineOffset", to: :first_baseline_offset
416
+ map_attribute "VerticalJustification", to: :vertical_justification
417
+ map_attribute "ParagraphSpacingLimit", to: :paragraph_spacing_limit
418
+ map_attribute "MinimumFirstBaselineOffset",
419
+ to: :minimum_first_baseline_offset
420
+ map_attribute "RotationAngle", to: :rotation_angle
421
+ map_attribute "WritingDirection", to: :writing_direction
422
+ map_attribute "MinimumHeight", to: :minimum_height
423
+ map_attribute "MaximumHeight", to: :maximum_height
424
+ map_attribute "KeepWithNextRow", to: :keep_with_next_row
425
+ map_attribute "StartRow", to: :start_row
426
+ map_attribute "AutoGrow", to: :auto_grow
427
+ map_attribute "NumHeaderColumns", to: :num_header_columns
428
+ map_attribute "HeaderColumnsPosition", to: :header_columns_position
429
+ map_attribute "CaptionParagraphCount", to: :caption_paragraph_count
430
+ map_attribute "CaptionPosition", to: :caption_position
431
+ map_attribute "GraphicLeftInset", to: :graphic_left_inset
432
+ map_attribute "GraphicTopInset", to: :graphic_top_inset
433
+ map_attribute "GraphicRightInset", to: :graphic_right_inset
434
+ map_attribute "GraphicBottomInset", to: :graphic_bottom_inset
435
+ map_attribute "ClipContentToGraphicCell",
436
+ to: :clip_content_to_graphic_cell
437
+ map_attribute "TextTopInset", to: :text_top_inset
438
+ map_attribute "TextLeftInset", to: :text_left_inset
439
+ map_attribute "TextBottomInset", to: :text_bottom_inset
440
+ map_attribute "TextRightInset", to: :text_right_inset
441
+ map_attribute "ClipContentToTextCell", to: :clip_content_to_text_cell
442
+ map_attribute "SingleRowHeight", to: :single_row_height
443
+ map_attribute "AppliedTableStyle", to: :applied_table_style
444
+ map_attribute "DisplayCollapsed", to: :display_collapsed
445
+ map_attribute "DisplayOrder", to: :display_order
78
446
  map_element "TableRow", to: :table_row
79
447
  map_element "Cell", to: :cell
80
448
  map_element "Row", to: :row
data/lib/idml/elements.rb CHANGED
@@ -43,6 +43,8 @@ module Idml
43
43
  autoload :DocumentPreference, "idml/elements/pref_document_preference"
44
44
  autoload :DottedStrokeStyle, "idml/elements/dotted_stroke_style"
45
45
  autoload :DropShadowSetting, "idml/elements/drop_shadow_setting"
46
+ autoload :Endnote, "idml/elements/endnote"
47
+ autoload :EndnoteRange, "idml/elements/endnote_range"
46
48
  autoload :EPubExportPreference, "idml/elements/pref_e_pub_export_preference"
47
49
  autoload :EPubFixedLayoutExportPreference,
48
50
  "idml/elements/pref_e_pub_fixed_layout_export_preference"
@@ -128,10 +128,11 @@ module Idml
128
128
  size: size)
129
129
  lines = TextEngine::LineBreaker.break(glyphs: glyphs,
130
130
  frame_width: wrap_width)
131
- lines.each do |line|
131
+ lines.each_with_index do |line, index|
132
132
  TextEngine::Justifier.justify(
133
133
  line: line, frame_width: wrap_width,
134
- alignment: paragraph.alignment || :left
134
+ alignment: paragraph.alignment || :left,
135
+ last_line: last_line?(paragraph, run, index, lines)
135
136
  )
136
137
  end
137
138
  leading = TextEngine::VerticalLayout.leading_for(
@@ -150,6 +151,13 @@ module Idml
150
151
  end
151
152
  private_class_method :layout_paragraph
152
153
 
154
+ # True for the final line of the footnote paragraph's final
155
+ # run — kept ragged under full justification.
156
+ def self.last_line?(paragraph, run, index, lines)
157
+ run.equal?(paragraph.runs.last) && index == lines.length - 1
158
+ end
159
+ private_class_method :last_line?
160
+
153
161
  # Height to reserve at the frame bottom for the entries:
154
162
  # separator gap + the measured paragraph stack.
155
163
  def self.reserved_height(entries, font, frame, option = nil)
@@ -511,7 +511,8 @@ module Idml
511
511
  canvas, run, paragraph, context, layout_frame, font,
512
512
  run_wrap, cursor_y, space_before,
513
513
  para_attrs[:first_line_indent], para_attrs[:left_indent],
514
- char_cursor, bottom_limit
514
+ char_cursor, bottom_limit,
515
+ paragraph_last: run.equal?(runs.last)
515
516
  )
516
517
  char_cursor += positioned.length
517
518
  cursor_y = next_y
@@ -712,7 +713,7 @@ module Idml
712
713
  def self.layout_run(canvas, run, paragraph, context, layout_frame,
713
714
  font, wrap_width, cursor_y, space_before,
714
715
  first_line_indent, left_indent,
715
- char_cursor, bottom_limit)
716
+ char_cursor, bottom_limit, paragraph_last: false)
716
717
  size = run.point_size || DEFAULT_SIZE
717
718
  glyphs = TextEngine::Shaper.shape(
718
719
  text: run.text, font: font, size: size,
@@ -720,12 +721,7 @@ module Idml
720
721
  lines = TextEngine::LineBreaker.break(
721
722
  glyphs: glyphs, frame_width: wrap_width,
722
723
  )
723
- lines.each do |line|
724
- TextEngine::Justifier.justify(
725
- line: line, frame_width: wrap_width,
726
- alignment: paragraph.alignment || :left
727
- )
728
- end
724
+ justify_lines(lines, paragraph, wrap_width, paragraph_last)
729
725
  leading = leading_for(paragraph, size)
730
726
 
731
727
  positioned, next_y = TextEngine::VerticalLayout.layout_block(
@@ -745,6 +741,21 @@ module Idml
745
741
  end
746
742
  private_class_method :layout_run
747
743
 
744
+ # Justifies the run's lines; only the final line of the
745
+ # paragraph's final run stays ragged under full
746
+ # justification.
747
+ def self.justify_lines(lines, paragraph, wrap_width,
748
+ paragraph_last)
749
+ lines.each_with_index do |line, index|
750
+ TextEngine::Justifier.justify(
751
+ line: line, frame_width: wrap_width,
752
+ alignment: paragraph.alignment || :left,
753
+ last_line: paragraph_last && index == lines.length - 1
754
+ )
755
+ end
756
+ end
757
+ private_class_method :justify_lines
758
+
748
759
  # Emits the run's positioned lines (clipped at the bottom
749
760
  # limit), recording positions and annotating the first line
750
761
  # with the run's ruby when present.
@@ -4,19 +4,22 @@ module Idml
4
4
  module TextEngine
5
5
  # Distributes slack space within a line per the paragraph's
6
6
  # alignment. Adjusts x_offset and optionally scales inter-word
7
- # spaces for justified text.
7
+ # spaces for justified text. `last_line:` (the paragraph's final
8
+ # line) keeps ragged right under :justified, as InDesign does.
8
9
  class Justifier
9
- def self.justify(line:, frame_width:, alignment: :left)
10
- new(frame_width, alignment).justify(line)
10
+ def self.justify(line:, frame_width:, alignment: :left,
11
+ last_line: false)
12
+ new(frame_width, alignment, last_line).justify(line)
11
13
  end
12
14
 
13
- def initialize(frame_width, alignment)
15
+ def initialize(frame_width, alignment, last_line)
14
16
  @frame_width = frame_width
15
17
  @alignment = alignment
18
+ @last_line = last_line
16
19
  end
17
20
 
18
21
  def justify(line)
19
- case @alignment
22
+ case effective_alignment
20
23
  when :left, :start then line.x_offset = 0
21
24
  when :center, :middle
22
25
  line.x_offset = (@frame_width - line.width) / 2
@@ -29,6 +32,14 @@ module Idml
29
32
 
30
33
  private
31
34
 
35
+ # The paragraph's last line stays ragged under full
36
+ # justification.
37
+ def effective_alignment
38
+ return :left if @alignment == :justified && @last_line
39
+
40
+ @alignment
41
+ end
42
+
32
43
  def justify_line(line)
33
44
  spaces = line.glyphs.count(&:is_space)
34
45
  slack = @frame_width - line.width
data/lib/idml/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Idml
4
- VERSION = "0.9.1"
4
+ VERSION = "0.9.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: idml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
@@ -173,6 +173,8 @@ files:
173
173
  - TODO.pdf/114-text-wrap-around-shapes.md
174
174
  - TODO.pdf/115-bullet-numbered-lists.md
175
175
  - TODO.pdf/116-applied-style-resolution.md
176
+ - TODO.pdf/116-justification-last-line.md
177
+ - TODO.pdf/117-endnote-support.md
176
178
  - TODO.pdf/12-idml-to-pdf-pipeline.md
177
179
  - TODO.pdf/13-cjk-text-layout.md
178
180
  - TODO.pdf/14-page-item-element-models.md
@@ -291,6 +293,8 @@ files:
291
293
  - lib/idml/elements/document_object.rb
292
294
  - lib/idml/elements/dotted_stroke_style.rb
293
295
  - lib/idml/elements/drop_shadow_setting.rb
296
+ - lib/idml/elements/endnote.rb
297
+ - lib/idml/elements/endnote_range.rb
294
298
  - lib/idml/elements/feather_setting.rb
295
299
  - lib/idml/elements/fill_transparency_setting.rb
296
300
  - lib/idml/elements/flex_layout_attribute_option.rb