Class: Fontisan::Woff2::EncoderRules
- Inherits:
-
Object
- Object
- Fontisan::Woff2::EncoderRules
- Defined in:
- lib/fontisan/woff2/encoder_rules.rb
Overview
Applies WOFF2 spec "encoder MUST" rules to a table collection before the table directory is built and brotli compression is applied.
Each spec-mandated transform lives here so the encoder stays a thin orchestrator and new rules are MECE/discoverable instead of sprinkled as inline conditionals across Woff2Encoder.
Reference: W3C WOFF2 spec, section 5 ("Recommended table directory").
Constant Summary collapse
- EXCLUDED_TABLES =
Tables that MUST NOT appear in WOFF2 output.
Per spec section 5: "The compliant WOFF2 encoder MUST remove the DSIG table from an input font data, prior to applying transformations and entropy coding steps." Chrome's OpenType Sanitizer (OTS) rejects WOFF2 files that still contain DSIG.
%w[DSIG].freeze
- TRANSFORMED_TABLES =
Tables that MUST be transformed (when present) per WOFF2 spec section 5.3: glyf and loca are paired — both are either transformed (version 0) or null-transformed (version 3) together. Browsers (Chrome OTS) only accept the transformed form.
%w[glyf loca].freeze
Class Method Summary collapse
-
.apply!(table_data) ⇒ Hash{String => String}
Apply all WOFF2 encoder rules to
table_datain place. -
.exclude_tables!(table_data) ⇒ Object
Drop spec-excluded tables from the collection.
-
.excluded?(tag) ⇒ Boolean
Whether
tagis dropped by WOFF2 spec rules. -
.mark_lossless_modifying!(table_data) ⇒ Object
Set head.flags bit 11 to indicate the font was losslessly modified.
-
.set_head_index_to_loc_format!(table_data, format_code) ⇒ Object
Set head.indexToLocFormat to match the chosen output loca format.
-
.touch_head_modified!(table_data) ⇒ Object
Bump head.modified past head.created.
Class Method Details
.apply!(table_data) ⇒ Hash{String => String}
Apply all WOFF2 encoder rules to table_data in place.
33 34 35 36 37 38 |
# File 'lib/fontisan/woff2/encoder_rules.rb', line 33 def self.apply!(table_data) exclude_tables!(table_data) (table_data) touch_head_modified!(table_data) table_data end |
.exclude_tables!(table_data) ⇒ Object
Drop spec-excluded tables from the collection.
46 47 48 |
# File 'lib/fontisan/woff2/encoder_rules.rb', line 46 def self.exclude_tables!(table_data) EXCLUDED_TABLES.each { |tag| table_data.delete(tag) } end |
.excluded?(tag) ⇒ Boolean
Whether tag is dropped by WOFF2 spec rules.
41 42 43 |
# File 'lib/fontisan/woff2/encoder_rules.rb', line 41 def self.excluded?(tag) EXCLUDED_TABLES.include?(tag) end |
.mark_lossless_modifying!(table_data) ⇒ Object
Set head.flags bit 11 to indicate the font was losslessly modified.
Per spec section 5: "The WOFF 2.0 encoders MUST also set bit 11 of the 'flags' field of the head table ... to indicate that a recreated font file was subjected to lossless modifying transform."
Uses the model-driven Head BinData record so the bits are set via a named attribute on a typed object, not via raw byte slicing.
58 59 60 61 62 63 64 |
# File 'lib/fontisan/woff2/encoder_rules.rb', line 58 def self.(table_data) return unless table_data.key?("head") head = Tables::Head.read(table_data["head"]) head.flags |= Tables::Head::FLAG_LOSSLESS_MODIFYING table_data["head"] = head.to_binary_s end |
.set_head_index_to_loc_format!(table_data, format_code) ⇒ Object
Set head.indexToLocFormat to match the chosen output loca format.
fontTools' WOFF2 encoder re-picks the loca format (preferring short when glyf fits). The reconstructed SFNT must carry the matching indexToLocFormat in head, or Chrome's OTS rejects the file with "Failed to convert WOFF 2.0 font to SFNT".
75 76 77 78 79 80 81 |
# File 'lib/fontisan/woff2/encoder_rules.rb', line 75 def self.set_head_index_to_loc_format!(table_data, format_code) return unless table_data.key?("head") head = Tables::Head.read(table_data["head"]) head.index_to_loc_format = format_code table_data["head"] = head.to_binary_s end |
.touch_head_modified!(table_data) ⇒ Object
Bump head.modified past head.created.
Chrome's OTS rejects fonts whose modified timestamp is not strictly greater than created (source fonts often have modified == created, which fails this check). Setting modified = created + 1 is the minimal change that satisfies the constraint.
Must be called BEFORE checksum recompute so the modified bytes are included in the checksum.
94 95 96 97 98 99 100 101 102 |
# File 'lib/fontisan/woff2/encoder_rules.rb', line 94 def self.touch_head_modified!(table_data) return unless table_data.key?("head") head = Tables::Head.read(table_data["head"]) return if head.modified_raw.to_i > head.created_raw.to_i head.modified_raw = head.created_raw + 1 table_data["head"] = head.to_binary_s end |