Skip to content

Release v0.11.1 - #3

Closed
libraz wants to merge 12 commits into
mainfrom
develop
Closed

Release v0.11.1#3
libraz wants to merge 12 commits into
mainfrom
develop

Conversation

@libraz

@libraz libraz commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Release v0.11.1

Added

  • A workbook's default font can be declared (fm_workbook_set_default_font / fm_styles_set_font, reaching WASM, the native Node addon and Python).
  • Phonetic guides can be authored span by span, not only as one reading for the whole cell (fm_workbook_set_cell_phonetic_runs and the matching readers).
  • getCellPhonetic / setCellPhonetic reach the native Node addon, which had neither.
  • How a phonetic guide renders can be authored (fm_workbook_set_cell_phonetic_properties / ..._get_...): the ruby font, the kana form and the distribution over the covered characters.
  • Phonetic guides survive the MS-XLSB container — BrtSSTItem's phonetic tail is decoded and emitted, and the shared-string interner keys on the guide as well as the text.

Fixed

  • A font's <scheme> theme link survives a load and save, through both containers, and reaches the record projections on every binding.
  • A phonetic guide's <phoneticPr> block survives a load and save. An absent element and a bare <phoneticPr/> resolve differently and are now read apart.

Verification

  • make oracle-verify: 4732/4732, zero failures.
  • make test (fast tier): 13727/13727.
  • make node-test, make python-test, make test-wasm, make format-check: all green.
  • tools/oracle/divergence_check.py --strict: clean (no stale stamps, no unclassified skips).
  • WASM: 2,752,821 B uncompressed (2.63 MiB), 738,999 B Brotli (722 KiB) — within both hard ceilings.

See CHANGELOG.md for the full entry.

libraz added 12 commits August 22, 2026 17:44
- decode the BrtSSTItem phonetic tail in src/io/xlsb/reader.cpp: the kana
  is stored once and each PhRun names where its slice starts, so a run's
  reading ends where the next run's begins and the last runs to the end
- treat an empty run array with a non-empty reading as the whole-string
  case Excel writes when it elides the runs, the same shape <rPh> takes
  when it spans the entire surface text
- emit that tail from src/io/xlsb/sst_writer.cpp behind the RichStr
  phonetic flag bit, writing the concatenated kana followed by a running
  ichFirst offset per run
- key SstBuilder::intern on the guide as well as the text, so two cells
  that read the same kanji differently no longer collapse onto a single
  SST entry
- pass cell.phonetic_runs into EmitLiteralCellRecord in cell_writer.cpp
  so a Text payload carries its guide into the table
- add tests/unit/io/xlsb_phonetic_test.cpp over the new xlsb_phonetic
  fixtures, plus sst_writer cases for the interner key and the tail
- add fm_workbook_set_cell_phonetic_runs plus
  fm_workbook_get_cell_phonetic_run_count and
  fm_workbook_get_cell_phonetic_run to src/c_api/formulon_c.h: each <rPh>
  block travels as an ordered partition of the surface text, spanned in
  UTF-16 code units
- the core has kept one run per <rPh> since 0.11.0 while the bindings
  carried a single string in each direction, so reading a partially
  annotated cell and writing it back collapsed every span into one
  whole-cell annotation
- surface the runs as setCellPhoneticRuns / getCellPhoneticRuns on WASM
  and the Node addon and as set_phonetic_runs / get_phonetic_runs in
  Python; the flattening getCellPhonetic is unchanged and still returns
  the readings concatenated
- give the native Node addon getCellPhonetic / setCellPhonetic, the last
  cell-level pair that existed on WASM and Python only, and shrink the
  WASM-only list in tools/dev/check_binding_drift.py and the npm-native
  README method counts to match
- add fm_styles_set_font, which overwrites an existing font slot in
  place, and fm_workbook_set_default_font, which declares font 0 -- the
  record every unstyled cell resolves to, seeded as Calibri 11 -- that
  fm_styles_add_font could never reach because it only appends
- surface those as setFont / setDefaultFont (WASM + Node addon) and
  set_font / set_default_font (Python); the current default reads back
  through the existing getFont(0)
- extend the C API, WASM, Node and Python test surfaces to cover the new
  entry points
… font

- record the Unreleased Added entries for
  fm_workbook_set_cell_phonetic_runs and the two run readers, the native
  Node addon gaining getCellPhonetic / setCellPhonetic, the BrtSSTItem
  phonetic tail surviving an xlsb round trip, and
  fm_workbook_set_default_font / fm_styles_set_font
- name the binding-level spelling of each entry point alongside the C ABI
  one, so a reader on any surface can find it
- add PhoneticProperties to src/phonetic.h -- ruby font id, kana form and
  alignment as ordinals -- hang it off Cell beside phonetic_runs, and give
  Sheet a set_cell_phonetic_props that is independent of the readings, so
  editing the kana does not reset how it renders
- only the <rPh> runs were carried before, so a guide set to hiragana or
  to a distributed layout came back as Excel's default halfwidth katakana
  on the next save
- read the element in the DOM, SAX and shared-string paths, and emit it
  beside every non-empty run list with all three attributes spelled out
  rather than left to be inferred, which is what Excel writes
- an absent <phoneticPr> resolves to halfwidthKatakana / noControl while a
  bare one falls back per attribute to fullwidthKatakana / left; the two
  states are different and are now read apart
- put the OOXML attribute vocabulary in the new src/io/phonetic_pr.h so the
  model header stays free of XML; XLSB packs the same ordinals into
  BrtSSTItem's trailing (ifnt, flags) pair, so the binary path shares the
  struct without a mapping table
- decode that pair in src/io/xlsb/reader.cpp leniently -- a record stopping
  short of it keeps the defaults rather than failing the load -- and emit
  the entry's own values from sst_writer.cpp in place of a fixed 0x0030
- key both shared-string interners on the properties as well as the text
  and the runs, so one reading rendered as hiragana and another as katakana
  stay separate string items
- compare the font record's theme scheme in the xlsb fidelity and
  cross-format symmetry checks
- read <scheme val="major|minor"> into the new FontRecord::scheme and write
  it back as the last child of <font>, after <family> and <charset>, which
  is the order Excel emits them in
- a ja-JP workbook's Normal font carries scheme="minor", which is what makes
  Excel show it as the body font and re-resolve it when the theme changes;
  the element was dropped on read, so re-saving rewrote the font as a
  literal name
- collapse an unrecognised value to 0, which emits no element at all:
  writing an uninterpretable link back would leave a theme reference Excel
  cannot resolve
- decode BrtFont's bFontScheme into the same field and emit it from the
  xlsb writer instead of a hardcoded 0; the ordinals match, so the binary
  path needs no mapping table and the field is no longer listed among the
  record's unmodelled ones
- cover minor, major, an unrecognised value and a font with no link on both
  the reader and the writer
- add scheme to fm_font_record and carry it through font_to_c and
  font_from_c, so a read-modify-write of a font over the C ABI no longer
  unlinks it from the workbook theme
- project it as scheme on WASM and the native Node addon and as
  FontRecord.scheme in Python, defaulting to 0 (no link) on each
- the struct grew by one field, so the Python layout expectations for
  FONT_RECORD and DXF_RECORD and the C ABI offset assertions move with it
- state on fm_styles_set_default_font that a workbook Formulon created
  carries no theme part, so leave scheme at 0 there; a package loaded with
  its own theme keeps that part, and preserving the link is what keeps
  Excel showing the font as the theme's body font
- exercise the read-modify-write path over the ABI, down to the <scheme>
  element in the saved styles part
- state in src/print/pagination.cpp that MDW is a property of the Normal
  font, so a workbook whose Normal style names a different one resolves a
  different number of points per character
- record the measured scope: at 11 pt the family does not move the width
  (Calibri, Yu Gothic and MS PGothic resolve a 30-unit column alike), while
  the point size does move it roughly in proportion and the family starts
  to matter away from 11 pt
- note that those observations are Mac Excel's, a different column-geometry
  regime from the Windows primary oracle the constants come from, so they
  establish the dependency without supplying the numbers to model it
- until a Windows capture over the same sweep exists, a workbook whose
  Normal font is not 11 pt paginates against the 11 pt geometry
- add an Unreleased Fixed entry for the <scheme> theme link surviving a
  load and save through both containers and reaching the record
  projections on WASM, the native Node addon and Python
- add the <phoneticPr> entry: the ruby font, kana form and distribution
  now round-trip, and an absent element is read apart from a bare one
- add fm_workbook_set_cell_phonetic_properties /
  fm_workbook_get_cell_phonetic_properties, carrying the OOXML <phoneticPr>
  triple: the font that draws the ruby, the kana form (FM_PHONETIC_TYPE_*)
  and how the kana is distributed over the characters it covers
  (FM_PHONETIC_ALIGNMENT_*); scalar arguments rather than a new struct,
  matching fm_workbook_set_iterative
- project it as setCellPhoneticProperties / getCellPhoneticProperties on
  WASM and the native Node addon, and as set_phonetic_properties /
  get_phonetic_properties with a PhoneticProperties dataclass on Python
- keep it independent of the run entry points in both directions: editing
  the readings does not reset the rendering, and setting the rendering does
  not touch the readings; a value-setting call still clears both
- reject an out-of-range type, alignment or font_id rather than truncate
  it, since each of the two enumerations occupies two bits of the XLSB
  record's trailing flags word and the font id sixteen
- report the defaults beside a failure status in the read result instead of
  dropping the payload keys the return type declares
- the core already round-tripped these properties, so this adds only the
  authoring surface
- add the non-oracle deferred-feature entry
  pagination_column_width_calibrated_to_one_normal_font
- Excel resolves a column's width in points from its stored character-unit
  width times the Normal font's maximum digit width, so the conversion is a
  property of that font and pagination carries one calibration for it
- measured against Mac Excel 365 16.112.1 by opening workbooks that differ
  only in font 0: at 11 pt the family is not observable, since Calibri and
  both Japanese body faces resolve the same width; the point size is, and
  the family becomes observable away from 11 pt
- closing it needs the same sweep captured on the Windows primary oracle,
  whose column geometry is a different regime from the Mac numbers
- record under Unreleased / Added that how a phonetic guide renders can now
  be authored, not only round-tripped, naming the C ABI pair and its WASM,
  Node addon and Python projections
- state that it stays separate from the run entry points in both directions
  and that a value write still clears both
- Bump the version to 0.11.1 across CMake, both npm packages, the Python
  project and the embedded version header
- Close the changelog's unreleased section as 0.11.1 and add its compare link
- Index v0.11.1 as the latest release
@libraz

libraz commented Aug 22, 2026

Copy link
Copy Markdown
Owner Author

Closed: this repo promotes develop to main by fast-forward, not by PR merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant