ea 0.6.61 → 0.6.63

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: cb774d8053e789ef6200fc5c77c811166ce44308cbfe52c31255ab6c7f404c1d
4
- data.tar.gz: 15e26d6ecded00bea2bcedf20a03ac6ce94f3fdfd63dbba6f5357e85aae09969
3
+ metadata.gz: e6f6d084b7fd0042b8f31d006ed91d5fbc00c18d82937cd1ee5f5b6a6a8e2340
4
+ data.tar.gz: 6a93141b935afeac3c9409e933795100d5207a4ce532c3634906a174b7ce8c6e
5
5
  SHA512:
6
- metadata.gz: d33ce1e55c5904c77871d2cb2805e21f0326457b77ef567f73952dab004d92fd10692b547e61bf9c63fff7d35e619ce68dfc5646c22cf5e5a732fc76c7bfc00c
7
- data.tar.gz: 5ccac30a04cbeb1e4792473e6a674865d5bb1d1ffa56a271f9709c35d0bdd9488dd1dff5540ed6fc65bda57e175f42618d5dd3cf6521068f05fad5479a7520b0
6
+ metadata.gz: f4ff485fff168ca3d18ee168d1fa8f3c2acc168d8eb748cedd17c356b98ff8b9abea4b03432c5d3643c956025f358e25a7783cd24806e4e20f494df914992851
7
+ data.tar.gz: 9351c617930b3c3c54e74b98dc7da68ec8fe12d2031daf28cf0e0a99d0ca7c35f20fc49e85ca726634f9d7c86003b201f3dd808d00d5bc3ed1e7a0e8bc31a96d
@@ -53,16 +53,43 @@ module Ea
53
53
 
54
54
  # Width of `text` in EA's exported SVG units for the given pt
55
55
  # size, or nil when the family is not metric-compatible.
56
+ #
57
+ # EA's GDI driver quantizes each glyph advance to an integer
58
+ # pixel count at the logical font height H = round(pt * 10/7)
59
+ # (Carlito: 7pt -> H10, 9pt -> H13) and the published
60
+ # textLength is the SUM of those per-glyph integers - corpus
61
+ # fitted to 97-100% exact on 10k Carlito texts (bold 7pt
62
+ # 1666/1671). The legacy sum-then-round model matched only 27%.
56
63
  def text_length(text, size_pt, family: nil, weight: nil, style: nil)
57
64
  return nil unless supported_family?(family)
58
65
  return nil if text.nil? || text.empty?
59
66
 
60
- latin, cjk_count = split_advance(text, family: family,
61
- weight: weight, style: style)
62
- (latin * size_pt.to_f * factor_for(family, size_pt, weight, style) +
67
+ resolved = resolve_family(family)
68
+ if GDI_HEIGHT_FAMILIES.include?(resolved)
69
+ height = (size_pt.to_f * 10 / 7).round
70
+ table = table_for(family, weight, style)
71
+ latin = 0
72
+ cjk_count = 0
73
+ text.each_char do |ch|
74
+ if cjk?(ch.ord)
75
+ cjk_count += 1
76
+ else
77
+ latin += ((table[cp_key(ch)] || DEFAULT_ADVANCE) * height).round
78
+ end
79
+ end
80
+ return latin + cjk_count * CJK_ADVANCE * size_pt.to_f
81
+ end
82
+
83
+ _latin, cjk_count = split_advance(text, family: family,
84
+ weight: weight, style: style)
85
+ (_latin * size_pt.to_f * factor_for(family, size_pt, weight, style) +
63
86
  cjk_count * CJK_ADVANCE * size_pt.to_f).round(3)
64
87
  end
65
88
 
89
+ # Families whose EA driver quantizes per-glyph advances
90
+ # (fitted from published textLengths).
91
+ GDI_HEIGHT_FAMILIES = %w[Carlito].freeze
92
+
66
93
  def supported_family?(family)
67
94
  !resolve_family(family).nil?
68
95
  end
@@ -128,6 +128,29 @@ module Ea
128
128
  off_canvas_parent_name: parent_name,
129
129
  foreign_package_name: foreign_package_name_for(classifier),
130
130
  suppress_stereotypes: suppress_stereotypes?) : []
131
+ # Regenerated contexts (SuppressFOC=0) re-size EVERY box to
132
+ # fit ALL content (7F10BFBD: Set enum box stored 70x59 ->
133
+ # EA 165x223 with all six literals unwrapped): width =
134
+ # max(stored, title + pad_t, widest row + 8), height likewise
135
+ # grows via the standard content growth. Frozen contexts
136
+ # (SuppressFOC=1) keep stored sizes and wrap.
137
+ if regenerated_context? && classifier.is_a?(Ea::Model::Classifier) &&
138
+ !classifier.is_a?(Ea::Model::Package)
139
+ preview_lines = []
140
+ if show_attributes? && attributes_visible?(element) &&
141
+ !classifier.is_a?(Ea::Model::Interface)
142
+ preview_lines += Element::AttributeRenderer.lines_for(
143
+ classifier, lookup: attribute_lookup,
144
+ exclude_association_ids: drawn_association_ids
145
+ )
146
+ end
147
+ if show_operations? && operations_visible?(element)
148
+ preview_lines += Element::OperationRenderer.lines_for(classifier)
149
+ end
150
+ bounds = context_resized_bounds(bounds, classifier, size, family,
151
+ preview_lines)
152
+ end
153
+
131
154
  is_classifier = classifier.is_a?(Ea::Model::Classifier)
132
155
  # Interfaces DO render attribute compartments when they own
133
156
  # attribute rows (936AA434/Surface lists its nine 19107
@@ -143,6 +166,7 @@ module Ea
143
166
  []
144
167
  end
145
168
  op_lines = if is_classifier && show_operations? && operations_visible?(element)
169
+ $stderr.puts "DBG ops: show=#{show_operations?} vis=#{operations_visible?(element)} cls=#{classifier.class} nops=#{classifier.operations.to_a.size}"
146
170
  Element::OperationRenderer.lines_for(classifier)
147
171
  else
148
172
  []
@@ -177,8 +201,24 @@ module Ea
177
201
  enum_literals_count: enum_row_count_for(classifier))
178
202
  end
179
203
  # EA suppresses the operations compartment when its rows
180
- # overflow the stored box height (same rule as attributes).
181
- if op_lines.any? && geometry.op_first_y &&
204
+ # overflow the stored box height (same rule as attributes)
205
+ # - EXCEPT on regenerated contexts, where EA GROWS the box
206
+ # to fit every row instead (7F10BFBD: Set stored 70x59 ->
207
+ # drawn 165x223 with all twelve operations).
208
+ if regenerated_context? && op_lines.any? && geometry.op_first_y &&
209
+ geometry.op_bottom_y.to_i > bounds.y + bounds.height
210
+ bounds = Ea::Model::Bounds.new(
211
+ x: bounds.x, y: bounds.y,
212
+ width: bounds.width,
213
+ height: geometry.op_bottom_y.to_i + 8 - bounds.y
214
+ )
215
+ geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
216
+ tagged_values_for(classifier).size,
217
+ header_lines, classifier: classifier,
218
+ constraints_count: constraints_for(classifier).size,
219
+ marker_count: marker_lines_for(classifier).size,
220
+ enum_literals_count: enum_row_count_for(classifier))
221
+ elsif op_lines.any? && geometry.op_first_y &&
182
222
  geometry.op_bottom_y.to_i > bounds.y + bounds.height
183
223
  op_lines = []
184
224
  geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
@@ -198,7 +238,12 @@ module Ea
198
238
  # position even with zero operations), so it must stay out
199
239
  # of the max.
200
240
  grown_bottom = geometry.content_bottom_y.to_i
201
- if attr_lines.any? && grown_bottom.positive? &&
241
+ # Enum literals grow the box too (7F10BFBD 'Context Diagram:
242
+ # Bag': Set enum box stored h59 -> EA 223 fitting six
243
+ # literals); op-only boxes keep the no-growth behavior
244
+ # (op_bottom_y is a divider sentinel, not content).
245
+ if (attr_lines.any? || enum_literals_for(classifier).any?) &&
246
+ grown_bottom.positive? &&
202
247
  grown_bottom + 8 > bounds.y + bounds.height
203
248
  bounds = Ea::Model::Bounds.new(
204
249
  x: bounds.x, y: bounds.y,
@@ -419,6 +464,34 @@ module Ea
419
464
  # classifier lives in a different package than the diagram
420
465
  # (descendant packages included). Corpus-verified (450
421
466
  # diagrams): ShowForeign=0 renders plain everywhere.
467
+ def regenerated_context?
468
+ diagram.name.to_s.downcase.start_with?("context diagram") &&
469
+ diagram.style_ex.to_s !~ /SuppressFOC=1/
470
+ end
471
+
472
+ TITLE_PAD = 18
473
+
474
+ def context_resized_bounds(bounds, classifier, size, family, rows)
475
+ label = classifier.name.to_s
476
+ pkg = foreign_package_name_for(classifier)
477
+ label = "#{pkg}::#{label}" if pkg
478
+ title_w = TextRenderer.estimate_width(
479
+ label, size, nil, family: family, weight: "700"
480
+ ).round
481
+ pad = title_w.odd? ? TITLE_PAD : 16
482
+ row_w = rows.map do |line|
483
+ line = line.sub(/\A«[^»]*»\z/, "")
484
+ TextRenderer.estimate_width(
485
+ line, size, nil, family: family, weight: "400"
486
+ ).round + 8
487
+ end.max.to_i
488
+ needed = [bounds.width, title_w + pad, row_w].max
489
+ return bounds if needed <= bounds.width
490
+
491
+ Ea::Model::Bounds.new(x: bounds.x, y: bounds.y,
492
+ width: needed, height: bounds.height)
493
+ end
494
+
422
495
  def foreign_package_name_for(classifier)
423
496
  return nil unless diagram.show_foreign
424
497
  return nil unless classifier.is_a?(Ea::Model::Classifier)
data/lib/ea/version.rb CHANGED
@@ -4,5 +4,5 @@ module Ea
4
4
  # Gem release version. Extracted to its own file so the
5
5
  # `gem-release` tool's `gem bump` can find and update it via the
6
6
  # standard `lib/<gem>/version.rb` convention.
7
- VERSION = "0.6.61"
7
+ VERSION = "0.6.63"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.61
4
+ version: 0.6.63
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-07 00:00:00.000000000 Z
11
+ date: 2026-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model