diff options
author | Norbert Preining <norbert@preining.info> | 2023-01-12 03:01:29 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2023-01-12 03:01:29 +0000 |
commit | 6a7900c93acc16d1bbd2f1e26286c7dd7387e6c0 (patch) | |
tree | 76196287351cba68a51934c49468bf1a7846aa76 /dviware/dvisvgm/src/ttf/OS2Table.cpp | |
parent | c1c19023b4b1d43cb874f84df5102b485853e672 (diff) |
CTAN sync 202301120301
Diffstat (limited to 'dviware/dvisvgm/src/ttf/OS2Table.cpp')
-rw-r--r-- | dviware/dvisvgm/src/ttf/OS2Table.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/dviware/dvisvgm/src/ttf/OS2Table.cpp b/dviware/dvisvgm/src/ttf/OS2Table.cpp new file mode 100644 index 0000000000..4ce5ff613b --- /dev/null +++ b/dviware/dvisvgm/src/ttf/OS2Table.cpp @@ -0,0 +1,246 @@ +/************************************************************************* +** OS2Table.cpp ** +** ** +** This file is part of dvisvgm -- a fast DVI to SVG converter ** +** Copyright (C) 2005-2023 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** This program is free software; you can redistribute it and/or ** +** modify it under the terms of the GNU General Public License as ** +** published by the Free Software Foundation; either version 3 of ** +** the License, or (at your option) any later version. ** +** ** +** This program is distributed in the hope that it will be useful, but ** +** WITHOUT ANY WARRANTY; without even the implied warranty of ** +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. ** +** ** +** You should have received a copy of the GNU General Public License ** +** along with this program; if not, see <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <algorithm> +#include <array> +#include <cmath> +#include <vector> +#include "OS2Table.hpp" +#include "TTFWriter.hpp" +#include "../Font.hpp" + +using namespace std; +using namespace ttf; + + +/** Returns the average width of all non-zero width glyphs. + * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#acw */ +int16_t OS2Table::averageCharWidth () const { + const RangeMap &charmap = ttfWriter()->getUnicodeCharMap(); + if (charmap.empty()) + return 0; + int sum=ttfWriter()->hAdvance(0); // width of .notdef character + int count=1; + for (auto uc2charcode : charmap) { + int c = int(uc2charcode.second); + if (int w = ttfWriter()->hAdvance(c)) { + sum += w; + count++; + } + } + return int16_t(double(sum)/count); +} + +static vector<uint32_t> compute_unicode_range_bits (const RangeMap &charmap); + + +void OS2Table::write (ostream &os) const { + const PhysicalFont &font = ttfWriter()->getFont(); + int upem = ttfWriter()->targetUnitsPerEm(); + double scale = ttfWriter()->unitsPerEmFactor(); + const RangeMap &charmap = ttfWriter()->getUnicodeCharMap(); + + writeUInt16(os, 3); // table version + writeInt16(os, averageCharWidth()); // average char width + writeUInt16(os, 400); // usWeightClass, "normal" for now + writeUInt16(os, 5); // usWidthClass, "medium" for now + writeUInt16(os, 0); // fsType + writeInt16(os, round(0.65*upem)); // ySubscriptXSize + writeInt16(os, round(0.7*upem)); // ySubscriptYSize + writeInt16(os, round(-0.48*upem)); // ySubscriptXOffset + writeInt16(os, round(0.14*upem)); // ySubscriptYOffset + writeInt16(os, round(0.65*upem)); // ySuperscriptXSize + writeInt16(os, round(0.7*upem)); // ySuperscriptYSize + writeInt16(os, round(0.48*upem)); // ySuperscriptXOffset + writeInt16(os, round(0.48*upem)); // ySuperscriptYOffset + writeInt16(os, 102*upem/2048); // yStrikeoutSize + writeInt16(os, 530*upem/2048); // yStrikeoutPosition + writeInt16(os, 0); // sFamilyClass (no classification) + for (uint8_t p : {0, 0, 6, 0, 0, 0, 0, 0, 0, 0}) // Panose + writeUInt8(os, p); + for (uint32_t bits : compute_unicode_range_bits(charmap)) + writeUInt32(os, bits); + writeUInt32(os, name2id("dsvg")); + writeUInt16(os, 6); // fsSelection, "regular" for now + writeUInt16(os, min(charmap.minKey(), uint32_t(0xFFFF))); // usFirstCharIndex + writeUInt16(os, min(charmap.maxKey(), uint32_t(0xFFFF))); // usLastCharIndex + writeInt16(os, round(scale*font.ascent())); // sTypoAscender + writeInt16(os, round(-scale*font.descent())); // sTypoDescender + writeInt16(os, 0); // sTypoLineGap + writeUInt16(os, round(scale*font.ascent())); + writeUInt16(os, round(scale*font.descent())); + writeUInt32(os, 1); // ulCodePageRange1, "Latin 1" for now + writeUInt32(os, 0); // ulCodePageRange2 + writeInt16(os, 0); // sxHeight + writeInt16(os, charmap.valueExists(0x48) ? 0x48 : 0); // sCapHeight + writeUInt16(os, 0); // usDefaultChar + writeUInt16(os, charmap.valueExists(0x20) ? 0x20 : 0xffff); // usBreakChar (space or .notdef) + writeUInt16(os, 0); // usMaxContext +} + +#if 0 +void OS2Table::updateYMinMax (int16_t ymin, int16_t ymax) { + _usWinAscent = max(_usWinAscent, uint16_t(ymax)); + _usWinDescent = max(_usWinDescent, uint16_t(ymin < 0 ? -ymin : 0)); +} +#endif + + +/** Returns the bit number denoting the Unicode range for a codepoint according to + * the OS/2 table specification. If there's no matching range for the codepoint, + * the function returns -1. Currently, only the ranges specified by OS/2 table + * version 1 are considered. */ +static int unicode_range_bit (uint32_t codepoint) { + struct UCRange { + UCRange (uint32_t cp) : first(cp), last(cp), os2bit(0) {} + UCRange (uint32_t cp1, uint32_t cp2, int bit) : first(cp1), last(cp2), os2bit(bit) {} + uint32_t first, last; + int os2bit; + }; + // Unicode ranges according to http://unicode.org/Public/UNIDATA/Blocks.txt + static array<UCRange, 100> ucranges {{ + {0x00020, 0x0007E, 0}, // Basic Latin + {0x000A0, 0x000FF, 1}, // Latin-1 Supplement + {0x00100, 0x0017F, 2}, // Latin Extended-A + {0x00180, 0x0024F, 3}, // Latin Extended-B + {0x00250, 0x002AF, 4}, // IPA Extensions + {0x002B0, 0x002FF, 5}, // Spacing Modifier Letters + {0x00300, 0x0036F, 6}, // Combining Diacritical Marks + {0x00370, 0x003FF, 7}, // Greek and Coptic + {0x00400, 0x0052F, 9}, // Cyrillic / Cyrillic Supplement + {0x00530, 0x0058F, 10}, // Armenian + {0x00590, 0x005FF, 11}, // Hebrew + {0x00600, 0x006FF, 13}, // Arabic + {0x00700, 0x0074F, 71}, // Syriac + {0x00750, 0x0077F, 13}, // Arabic Supplement + {0x00780, 0x007BF, 72}, // Thaana + {0x007C0, 0x007FF, 14}, // N'Ko + {0x00800, 0x0083F, 12}, // Samaritan + {0x00900, 0x0097F, 15}, // Devanagari + {0x00980, 0x009FF, 16}, // Bengali + {0x00A00, 0x00A7F, 17}, // Gurmukhi + {0x00A80, 0x00AFF, 18}, // Gujarati + {0x00B00, 0x00B7F, 19}, // Oriya + {0x00B80, 0x00BFF, 20}, // Tamil + {0x00C00, 0x00C7F, 21}, // Telugu + {0x00C80, 0x00CFF, 22}, // Kannada + {0x00D00, 0x00D7F, 23}, // Malayalam + {0x00E00, 0x00E7F, 24}, // Thai + {0x00E80, 0x00EFF, 25}, // Lao + {0x010A0, 0x010FF, 26}, // Georgian + {0x01100, 0x011FF, 28}, // Hangul Jamo + {0x01B00, 0x01B7F, 27}, // Balinese + {0x01D00, 0x01DBF, 4}, // Phonetic Extensions & Supplement + {0x01D80, 0x01DFF, 6}, // Combining Diacritical Marks Supplement + {0x01E00, 0x01EFF, 29}, // Latin Extended Additional + {0x01F00, 0x01FFF, 30}, // Greek Extended + {0x02000, 0x0206F, 31}, // General Punctuation + {0x02070, 0x0209F, 32}, // Superscripts and Subscripts + {0x020A0, 0x020CF, 33}, // Currency Symbols + {0x020D0, 0x020FF, 34}, // Combining Marks for Symbols + {0x02100, 0x0214F, 35}, // Letterlike Symbols + {0x02150, 0x0218F, 36}, // Number Forms + {0x02190, 0x021FF, 37}, // Arrows + {0x02200, 0x022FF, 38}, // Mathematical Operators + {0x02300, 0x0237F, 39}, // Miscellaneous Technical + {0x02400, 0x0243F, 40}, // Control Pictures + {0x02440, 0x0245F, 41}, // Optical Character Recognition + {0x02460, 0x024FF, 42}, // Enclosed Alphanumerics + {0x02500, 0x0257F, 43}, // Box Drawing + {0x02580, 0x0259F, 44}, // Block Elements + {0x025A0, 0x025FF, 45}, // Geometric Shapes + {0x02600, 0x0267F, 46}, // Miscellaneous Symbols + {0x02700, 0x027BF, 47}, // Dingbats + {0x027C0, 0x027EF, 38}, // Miscellaneous Mathematical Symbols-A + {0x027F0, 0x027FF, 37}, // Supplementary Arrows-A + {0x02800, 0x028FF, 82}, // Braille Patterns + {0x02900, 0x0297F, 37}, // Supplementary Arrows-B + {0x02980, 0x02AFF, 38}, // Miscellaneous Mathematical Symbols-B + Supplemental Mathematical Operators + {0x02B00, 0x02BFF, 37}, // Miscellaneous Symbols and Arrows + {0x02C60, 0x02C7F, 29}, // Latin Extended-C + {0x02C80, 0x02CFF, 8}, // Coptic + {0x02D00, 0x02D25, 26}, // Georgian Supplement + {0x02DE0, 0x02DFF, 9}, // Cyrillic Extended-A + {0x02E00, 0x02E7F, 31}, // Supplemental Punctuation + {0x02E80, 0x02FFF, 59}, // CJK Radicals Supplement + Kangxi Radicals + Ideographic Description Characters + {0x03000, 0x0303F, 48}, // CJK Symbols and Punctuation + {0x03040, 0x0309F, 49}, // Hiragana + {0x030A0, 0x030FF, 50}, // Katakana + {0x03100, 0x0312F, 51}, // Bopomofo + {0x03130, 0x0318F, 52}, // Hangul Compatibility Jamo + {0x03190, 0x0319F, 59}, // Kanbun + {0x031A0, 0x031BF, 51}, // Bopomofo Extended + {0x031F0, 0x031FF, 50}, // Katakana Phonetic Extensions + {0x03200, 0x032FF, 54}, // Enclosed CJK Letters and Months + {0x03300, 0x033FF, 55}, // CJK compatability + {0x03400, 0x04DBF, 59}, // CJK Unified Ideographs Extension A + {0x04E00, 0x09FFF, 59}, // CJK Unified Ideographs + {0x0A500, 0x0A62B, 12}, // Vai + {0x0A640, 0x0A69F, 9}, // Cyrillic Extended-B + {0x0A700, 0x0A71F, 5}, // Modifier Tone Letters + {0x0A720, 0x0A7FF, 29}, // Latin Extended-D + {0x0A840, 0x0A87F, 53}, // Phags-pa + {0x0AC00, 0x0D7AF, 56}, // Hangul Syllables + {0x0D800, 0x0DFFF, 57}, // Non-Plane 0 + {0x0E000, 0x0F8FF, 60}, // Private Use Area + {0x0F900, 0x0FAFF, 61}, // CJK Compatibility Ideographs + {0x0FA2A, 0x0FAFF, 61}, // CJK Compatibility Ideographs + {0x0FB00, 0x0FB4F, 62}, // Alphabetic Presentation Forms + {0x0FB50, 0x0FDFF, 63}, // Arabic Presentation Forms-A + {0x0FE00, 0x0FE0F, 91}, // Variation Selectors + {0x0FE20, 0x0FE2F, 64}, // Combining Half Marks + {0x0FE30, 0x0FE4F, 65}, // CJK Compatibility Forms + {0x0FE50, 0x0FE6F, 66}, // Small Form Variants + {0x0FE70, 0x0FEEF, 67}, // Arabic Presentation Forms-B + {0x0FF00, 0x0FFEF, 68}, // Halfwidth and Fullwidth Forms + {0x0FFF0, 0x0FFFF, 69}, // Specials + {0x10900, 0x1091F, 58}, // Phoenician + {0x20000, 0x2A6DF, 59}, // CJK Unified Ideographs Extension B + {0x2A700, 0x2B73F, 59}, // CJK Unified Ideographs Extension C + {0x2B740, 0x2B81F, 59}, // CJK Unified Ideographs Extension D + {0x2F800, 0x2FA1F, 61}, // CJK Compatibility Ideographs Supplement + }}; + auto it = lower_bound(ucranges.begin(), ucranges.end(), UCRange(codepoint), [](const UCRange &r1, const UCRange &r2) { + return r1.last < r2.first; + }); + if (it != ucranges.end() && codepoint >= it->first && codepoint <= it->last) + return it->os2bit; + return -1; +} + + +/** Returns the Unicode ranges encompassed by the font. The ranges are encoded by four dwords, + * where each of the 128 bits represents a certain range. The returned vector contains the + * dwords in little-endian order, i.e. [bits 0-31, bits 32-63, bits 64-95, bits 96-127]. */ +static vector<uint32_t> compute_unicode_range_bits (const RangeMap &charmap) { + vector<uint32_t> rangeBits(4, 0); + for (auto uc2charcode : charmap) { + int bit = unicode_range_bit(uc2charcode.first); + if (bit >= 0) { + for (int i=0; i < 4; i++) { + if (bit < 32*(i+1)) { + rangeBits[i] |= (1 << (bit-32*i)); + break; + } + } + } + } + return rangeBits; +} |