#pragma author Shimogawa (aka Rebuild) #pragma description TrueType/OpenType font #pragma endian big #pragma MIME font/ttf #pragma MIME font/otf #pragma pattern_limit 1000000 import std.mem; import std.string; import std.time; import std.io; struct TableDirectory { char tag[4]; u32 checkSum; u32 offset; u32 length; }; fn format_fixed32(auto fp32) { return fp32.integer + fp32.fraction / 65536.0; }; fn format_f2dot14(auto f) { return f.integer + f.fraction / 16384.0; }; using FWord = s16; using UFWord = u16; struct FixedPoint32 { u16 integer; u16 fraction; } [[format("format_fixed32")]]; bitfield F2Dot14 { integer : 2; fraction : 14; } [[format("format_f2dot14")]]; fn format_longdatetime(auto t) { return std::time::format(std::time::to_utc(u32(t.time - 2082844800))); }; struct LongDatetime { s64 time; } [[format("format_longdatetime")]]; using HeadTable; u64 currentOffset; u64 currentLength; u64 glyfStart; bool hasPostScriptOutlines = false; u16 numHMetrics; u16 gNumGlyphs; HeadTable headTable; // begin avar struct AxisValueMap { F2Dot14 fromCoord; F2Dot14 toCoord; }; struct ShortFracSegment { u16 positionMapCount; AxisValueMap axisValueMaps[positionMapCount]; }; struct AvarTable { FixedPoint32 version; s32 axisCount; ShortFracSegment segments[axisCount]; }; // end avar // begin cmap u64 startOfCmapTable = 0; struct BaseCmapSubtable { u64 start = $; u16 format; }; struct CmapSubtable0 : BaseCmapSubtable { u16 length; u16 language; u8 glyphIndexArr[256]; }; struct CmapSubtable2 : BaseCmapSubtable { u16 length; u16 language; u16 subHeaderKeys[256]; u8 data[length - 516]; }; struct CmapSubtable4 : BaseCmapSubtable { u16 length; u64 end = start + length; u16 language; u16 segCountX2; u16 segCount = segCountX2 / 2; u16 searchRange; u16 entrySelector; u16 rangeShift; u16 endCode[segCount]; u16 reserved; u16 startCode[segCount]; s16 idDelta[segCount]; u16 idRangeOffset[segCount]; u16 glyphIdArr[(end - $) / sizeof(u16)]; }; struct CmapSubtable6 : BaseCmapSubtable { u16 length; u16 language; u16 firstCode; u16 entryCount; u16 glyphIdArr[entryCount]; }; struct SequentialMapGroup { u32 startCharCode; u32 endCharCode; u32 startGlyphId; }; struct CmapSubtable8 : BaseCmapSubtable { u16 reserved; u32 length; u32 language; u8 is32[8192]; u32 numGroups; SequentialMapGroup groups[numGroups]; }; struct CmapSubtable10 : BaseCmapSubtable { u16 reserved; u32 length; u64 end = start + length; u32 language; u32 startCharCode; u32 numChars; u16 glyphIdArr[(end - $) / sizeof(u16)]; }; struct CmapSubtable12 : BaseCmapSubtable { u16 reserved; u32 length; u32 language; u32 numGroups; SequentialMapGroup groups[numGroups]; }; struct CmapSubtable { u16 format = std::mem::read_unsigned($, 2, std::mem::Endian::Big); match (format) { (0): CmapSubtable0 table [[inline]]; (2): CmapSubtable2 table [[inline]]; (4): CmapSubtable4 table [[inline]]; (6): CmapSubtable6 table [[inline]]; (8): CmapSubtable8 table [[inline]]; (10): CmapSubtable10 table [[inline]]; (12): CmapSubtable12 table [[inline]]; (_): BaseCmapSubtable table [[inline]]; } } [[name(std::format("Subtable Format {}", format))]]; enum CmapPlatform : u16 { Unicode = 0, Macintosh = 1, ISO = 2, Microsoft = 3, Custom = 4, }; struct EncodingRecord { CmapPlatform platformId; u16 encodingId; u32 offset; u64 endEncodingRecord = $; $ = startOfCmapTable + offset; CmapSubtable subtable; $ = endEncodingRecord; }; struct CmapTable { startOfCmapTable = $; u16 version; u16 numSubtables; EncodingRecord encodingRecords[numSubtables]; }; // end cmap // begin cvt struct CvtTable { u64 size = currentLength / sizeof(FWord); FWord controlValues[size]; }; // end cvt // begin gasp bitfield RangeGaspBehavior { padding : 12; symmetricSmoothing : 1; symmetricGridfit : 1; doGray : 1; gridFit : 1; }; struct GaspRange { u16 rangeMaxPPEM; RangeGaspBehavior rangeGaspBehavior; }; struct GaspTable { u16 version; u16 numRanges; GaspRange gaspRanges[numRanges]; }; // end gasp // begin glyf struct GlyphTableHeader { u64 startOffset = $; s16 numContours; FWord xMin; FWord yMin; FWord xMax; FWord yMax; }; bitfield OutlineFlag { padding : 2; ySameOrPositive : 1; xSameOrPositive : 1; repeat : 1; yShort : 1; xShort : 1; onCurve : 1; }; u32 pIdx = 0; u32 curGlyfSize; struct SimpleGlyphFlag { pIdx += 1; OutlineFlag flag; if (flag.repeat) { pIdx += 1; u8 repeatTimes; } }; struct SimpleGlyphTable : GlyphTableHeader { u16 endPtsOfContours[numContours]; u32 numPoints = numContours == 0 ? 0 : endPtsOfContours[numContours - 1]; u16 instructionLength; u8 instructions[instructionLength]; pIdx = 0; SimpleGlyphFlag flags[while(pIdx < numPoints)] [[single_color]]; u8 data[startOffset + curGlyfSize - $]; }; bitfield CompositeGlyphFlag { padding : 3; unscaledComponentOffset : 1; scaledComponentOffset : 1; overlapCompound : 1; useMyMetrics : 1; weHaveInstructions : 1; weHaveA2x2 : 1; weHaveAnXAndYScale : 1; moreComponents : 1; padding : 1; weHaveAScale : 1; roundXYToGrid : 1; argsAreXYValues : 1; arg1And2AreWords : 1; }; bool componentGlyphHasMoreComponents; bool componentGlyphHasInstruction; struct ComponentGlyphRecord { CompositeGlyphFlag flags; u16 glyphIndex; if (flags.arg1And2AreWords) { FWord arg1; FWord arg2; } else { u8 arg1; u8 arg2; } if (flags.weHaveAScale) { F2Dot14 scale; } else if (flags.weHaveAnXAndYScale) { F2Dot14 xScale; F2Dot14 yScale; } else if (flags.weHaveA2x2) { F2Dot14 xScale; F2Dot14 scale01; F2Dot14 scale10; F2Dot14 yScale; } componentGlyphHasMoreComponents = flags.moreComponents; componentGlyphHasInstruction = flags.weHaveInstructions; }; struct CompositeGlyphTable : GlyphTableHeader { componentGlyphHasMoreComponents = true; componentGlyphHasInstruction = false; ComponentGlyphRecord records[while (componentGlyphHasMoreComponents)]; if (componentGlyphHasInstruction) { u16 instructionLength; u8 instructions[instructionLength]; } }; struct GlyfTable { s16 type = std::mem::read_signed($, 2, std::mem::Endian::Big); if (type >= 0) { SimpleGlyphTable table [[inline]]; } else { CompositeGlyphTable table [[inline]]; } } [[name(std::format("glyf ({})", table.numContours < 0 ? "Composite" : "Simple"))]]; // end glyf // begin hdmx struct DeviceRecord { u8 pixelSize; u8 maxWidth; u8 widths[gNumGlyphs]; }; struct HdmxTable { u16 version; u16 numRecords; u32 sizeDeviceRecord; DeviceRecord records[numRecords]; }; // end hdmx // begin head bitfield HeadFlag { padding : 1; lastResort : 1; clearTypeOptimized : 1; converted : 1; lossless : 1; indicStyleRearr : 1; RTLGlyph : 1; AATFont : 1; linguisticRender : 1; padding : 1; verticalLayout : 1; instrMayAlterAW : 1; integerScaling : 1; differentPointSize : 1; xLBlackBitIsLSB : 1; yZeroIsBaseline : 1; }; bitfield MacStyle { padding : 9; extended : 1; condensed : 1; shadow : 1; outline : 1; underline : 1; italic : 1; bold : 1; }; struct HeadTable { FixedPoint32 version; FixedPoint32 fontRevision; u32 checksumAdjustment; u32 magic; HeadFlag flags; u16 unitsPerEm; LongDatetime created; LongDatetime modified; FWord xMin; FWord yMin; FWord xMax; FWord yMax; MacStyle macStyle; u16 lowestRecPPEM; s16 fontDirectionHint; s16 indexToLocFormat; s16 glyphDataFormat; }; // end head // begin hhea struct HheaTable { FixedPoint32 version; FWord ascent; FWord descent; FWord lineGap; UFWord advanceWidthMax; FWord minLeftSideBearing; FWord minRightSideBearing; FWord xMaxExtent; s16 caretSlopeRise; s16 caretSlopeRun; s16 caretOffset; s16 reserved[4]; s16 metricDataFormat; u16 numberOfHMetrics; numHMetrics = numberOfHMetrics; }; // end hhea // begin hmtx struct LongHorMetric { UFWord advanceWidth; FWord lsb; }; struct HmtxTable { LongHorMetric hMetrics[numHMetrics]; FWord leftSideBearings[gNumGlyphs - numHMetrics]; }; // end hmtx // begin loca // loca contains offsets for glyf tables, so // we put glyf arrays here also. struct GlyfWithOffset { if (longOffset) { u32 offset; u32 realOffset = offset; u32 nextOff = std::mem::read_unsigned($, 4, std::mem::Endian::Big); } else { u16 offset; u32 realOffset = u32(offset) * 2; u32 nextOff = u32(std::mem::read_unsigned($, 2, std::mem::Endian::Big)) * 2; } curGlyfSize = nextOff - realOffset; u64 prev = $; $ = glyfStart + realOffset; if (curGlyfSize != 0) { GlyfTable glyf; } $ = prev; }; struct LocaTable { if (headTable.indexToLocFormat == 1) { //u32 offsets[gNumGlyphs + 1]; GlyfWithOffset glyfs[gNumGlyphs]; } else { // u16 offsets[gNumGlyphs + 1]; GlyfWithOffset glyfs[gNumGlyphs]; } }; // end loca // begin maxp struct MaxpTable { FixedPoint32 version; u16 numGlyphs; gNumGlyphs = numGlyphs; if (!hasPostScriptOutlines) { u16 maxPoints; u16 maxContours; u16 maxComponentPoints; u16 maxComponentContours; u16 maxZones; u16 maxTwilightPoints; u16 maxStorage; u16 maxFunctionDefs; u16 maxInstructionDefs; u16 maxStackElements; u16 maxSizeOfElements; u16 maxComponentDepth; } }; // end maxp // begin name u64 curStorageOffset; struct NameRecord { u16 platformId; u16 encodingId; u16 languageId; u16 nameId; u16 length; u16 stringOffset; u64 cur = $; $ = curStorageOffset + stringOffset; char16 string[length / 2]; $ = cur; }; struct LangTagRecord { u16 length; u16 langTagOffset; u64 cur = $; $ = curStorageOffset + langTagOffset; char16 langTag[length / 2]; $ = cur; }; struct NameTableV0 { u64 startOfNameTable = $; u16 version; u16 count; u16 storageOffset; curStorageOffset = startOfNameTable + storageOffset; NameRecord nameRecords[count]; }; struct NameTableV1 : NameTableV0 { u16 langTagCount; LangTagRecord langTagRecords[langTagCount]; }; struct NameTable { u16 version = std::mem::read_unsigned($, 2, std::mem::Endian::Big); match (version) { (0): NameTableV0 table [[inline]]; (_): NameTableV1 table [[inline]]; } }; // end name // begin OS/2 struct OS2TableV0 { u16 version; FWord xAvgCharWidth; u16 usWeightClass; u16 usWidthClass; u16 fsType; FWord ySubscriptXSize; FWord ySubscriptYSize; FWord SubscriptXOffset; FWord SubscriptYOffset; FWord ySuperscriptXSize; FWord ySuperscriptYSize; FWord SuperscriptXOffset; FWord SuperscriptYOffset; FWord yStrikeoutSize; FWord yStrikeoutPosition; s16 sFamilyClass; u8 panose[10]; u32 ulUnicodeRange[4]; u8 achVendID[4]; u16 fsSelection; u16 usFirstCharIndex; u16 usLastCharIndex; FWord sTypoAscender; FWord sTypoDescender; FWord sTypoLineGap; UFWord usWinAscent; UFWord usWinDescent; }; struct OS2TableV1 : OS2TableV0 { u32 ulCodePageRange[2]; }; struct OS2TableV4 : OS2TableV1 { FWord sxHeight; FWord sCapHeight; u16 usDefaultChar; u16 usBreakChar; u16 usMaxContent; }; struct OS2TableV5 : OS2TableV4 { u16 usLowerOpticalPointSize; u16 usUpperOpticalPointSize; }; struct OS2Table { u16 version = std::mem::read_unsigned($, 2, std::mem::Endian::Big); match (version) { (0): OS2TableV0 table [[inline]]; (1): OS2TableV1 table [[inline]]; (2 | 3 | 4): OS2TableV4 table [[inline]]; (_): OS2TableV5 table [[inline]]; } }; // end OS/2 // begin post struct PostTableV1 { u64 startOfTable = $; FixedPoint32 version; FixedPoint32 italicAngle; FWord underlinePosition; FWord underlineThickness; u32 isFixedPitch; u32 minMemType42; u32 maxMemType42; u32 minMemType1; u32 maxMemType1; }; struct PostTableV2 : PostTableV1 { u16 numGlyphs; u16 glyphNameIndex[numGlyphs]; std::string::SizedString stringData[while ($ < startOfTable + currentLength)]; }; struct PostTable { u16 major = std::mem::read_unsigned($, 2, std::mem::Endian::Big); u16 minor = std::mem::read_unsigned($ + 2, 2, std::mem::Endian::Big); match (major, minor) { (2, 0): PostTableV2 table [[inline]]; (_, _): PostTableV1 table [[inline]]; } }; // end post struct HiddenForPreprocessing { u64 defStart = $; TableDirectory td; $ = td.offset; currentOffset = td.offset; currentLength = td.length; match (td.tag) { ("CFF "): { hasPostScriptOutlines = true; } ("maxp"): MaxpTable table; ("head"): { HeadTable table; headTable = table; } ("glyf"): { glyfStart = $; } } $ = defStart + sizeof(TableDirectory); } [[hidden]]; struct Table { u64 defStart = $; TableDirectory td [[inline]]; $ = td.offset; currentOffset = td.offset; currentLength = td.length; match (td.tag) { ("avar"): AvarTable table; ("bhed"): HeadTable table; ("cmap"): CmapTable table; ("cvt "): CvtTable table; ("gasp"): GaspTable table; // ("glyf"): GlyfTable table; // glyf will be contained in loca. ("glyf"): {} ("hdmx"): HdmxTable table; ("head"): HeadTable table; ("hhea"): HheaTable table; ("hmtx"): HmtxTable table; ("loca"): LocaTable table; ("maxp"): MaxpTable table; ("name"): NameTable table; ("OS/2"): OS2Table table; ("post"): PostTable table; (_): u8 data[td.length]; } $ = defStart + sizeof(TableDirectory); } [[name(std::format("Table({})", td.tag))]]; struct TTF { u32 scalarType; u16 numTables; u16 searchRange; u16 entrySelector; u16 rangeShift; u64 start = $; HiddenForPreprocessing hidden[numTables] [[hidden]]; $ = start; Table tables[numTables]; }; TTF ttf @ 0x0;