From f6faf9ad6440c61f0d5ac517f9044320292d2101 Mon Sep 17 00:00:00 2001 From: lexborisov Date: Tue, 30 Aug 2016 13:07:41 +0400 Subject: [PATCH] Added MyFONT --- include/modest/myosi.h | 3 +- include/mycss/api.h | 10 +- include/mycss/myosi.h | 11 +- include/myhtml/api.h | 10 +- include/myhtml/myosi.h | 10 +- source/modest/myosi.h | 3 +- source/mycss/api.h | 10 +- source/mycss/myosi.h | 11 +- source/myfont/cmap.c | 184 ++++++++++++++++++ source/myfont/cmap.h | 209 ++++++++++++++++++++ source/myfont/glyf.c | 154 +++++++++++++++ source/myfont/glyf.h | 108 +++++++++++ source/myfont/head.c | 42 ++++ source/myfont/head.h | 56 ++++++ source/myfont/hhea.c | 26 +++ source/myfont/hhea.h | 55 ++++++ source/myfont/hmtx.c | 35 ++++ source/myfont/hmtx.h | 46 +++++ source/myfont/loca.c | 77 ++++++++ source/myfont/loca.h | 42 ++++ source/myfont/maxp.c | 54 ++++++ source/myfont/maxp.h | 52 +++++ source/myfont/myfont.c | 377 ++++++++++++++++++++++++++++++++++++ source/myfont/myfont.h | 113 +++++++++++ source/myfont/myosi.h | 140 +++++++++++++ source/myfont/name.c | 51 +++++ source/myfont/name.h | 61 ++++++ source/myfont/os_2.c | 81 ++++++++ source/myfont/os_2.h | 92 +++++++++ source/myfont/pclt.c | 46 +++++ source/myfont/pclt.h | 53 +++++ source/myfont/vhea.c | 50 +++++ source/myfont/vhea.h | 55 ++++++ source/myfont/vmtx.c | 56 ++++++ source/myfont/vmtx.h | 46 +++++ source/myhtml/api.h | 10 +- source/myhtml/myosi.h | 10 +- third_party/font/Arkhip.otf | Bin 0 -> 34012 bytes third_party/font/Arkhip.ttf | Bin 0 -> 78232 bytes third_party/font/readme.txt | 2 + 40 files changed, 2375 insertions(+), 76 deletions(-) create mode 100644 source/myfont/cmap.c create mode 100644 source/myfont/cmap.h create mode 100644 source/myfont/glyf.c create mode 100644 source/myfont/glyf.h create mode 100644 source/myfont/head.c create mode 100644 source/myfont/head.h create mode 100644 source/myfont/hhea.c create mode 100644 source/myfont/hhea.h create mode 100644 source/myfont/hmtx.c create mode 100644 source/myfont/hmtx.h create mode 100644 source/myfont/loca.c create mode 100644 source/myfont/loca.h create mode 100644 source/myfont/maxp.c create mode 100644 source/myfont/maxp.h create mode 100644 source/myfont/myfont.c create mode 100644 source/myfont/myfont.h create mode 100644 source/myfont/myosi.h create mode 100644 source/myfont/name.c create mode 100644 source/myfont/name.h create mode 100644 source/myfont/os_2.c create mode 100644 source/myfont/os_2.h create mode 100644 source/myfont/pclt.c create mode 100644 source/myfont/pclt.h create mode 100644 source/myfont/vhea.c create mode 100644 source/myfont/vhea.h create mode 100644 source/myfont/vmtx.c create mode 100644 source/myfont/vmtx.h create mode 100755 third_party/font/Arkhip.otf create mode 100755 third_party/font/Arkhip.ttf create mode 100644 third_party/font/readme.txt diff --git a/include/modest/myosi.h b/include/modest/myosi.h index 1e99aa4..8ba7049 100644 --- a/include/modest/myosi.h +++ b/include/modest/myosi.h @@ -37,7 +37,8 @@ extern "C" { for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + for myfont 070000..07ffff; MyFONT_STATUS_OK == 0x000000 + not occupied 080000.. */ enum modest_status { MODEST_STATUS_OK = 0x000000, diff --git a/include/mycss/api.h b/include/mycss/api.h index 09df493..02a8594 100644 --- a/include/mycss/api.h +++ b/include/mycss/api.h @@ -52,15 +52,7 @@ extern "C" { // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_tv */ enum mycss_status { MyCSS_STATUS_OK = 0x000000, diff --git a/include/mycss/myosi.h b/include/mycss/myosi.h index a1a306d..630fa4b 100644 --- a/include/mycss/myosi.h +++ b/include/mycss/myosi.h @@ -28,19 +28,10 @@ extern "C" { #include - // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_t */ enum mycss_status { MyCSS_STATUS_OK = 0x000000, diff --git a/include/myhtml/api.h b/include/myhtml/api.h index 9bbe049..fed7a73 100644 --- a/include/myhtml/api.h +++ b/include/myhtml/api.h @@ -370,15 +370,7 @@ enum myhtml_tags { // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_t */ enum myhtml_status { MyHTML_STATUS_OK = 0x0000, diff --git a/include/myhtml/myosi.h b/include/myhtml/myosi.h index 9b2da8a..1a09327 100644 --- a/include/myhtml/myosi.h +++ b/include/myhtml/myosi.h @@ -375,15 +375,7 @@ enum myhtml_insertion_mode { // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_t */ enum myhtml_status { MyHTML_STATUS_OK = 0x0000, diff --git a/source/modest/myosi.h b/source/modest/myosi.h index 1e99aa4..8ba7049 100644 --- a/source/modest/myosi.h +++ b/source/modest/myosi.h @@ -37,7 +37,8 @@ extern "C" { for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + for myfont 070000..07ffff; MyFONT_STATUS_OK == 0x000000 + not occupied 080000.. */ enum modest_status { MODEST_STATUS_OK = 0x000000, diff --git a/source/mycss/api.h b/source/mycss/api.h index 17ae8ac..9111bf5 100644 --- a/source/mycss/api.h +++ b/source/mycss/api.h @@ -52,15 +52,7 @@ extern "C" { // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_tv */ enum mycss_status { MyCSS_STATUS_OK = 0x000000, diff --git a/source/mycss/myosi.h b/source/mycss/myosi.h index 1a01cdd..124918f 100644 --- a/source/mycss/myosi.h +++ b/source/mycss/myosi.h @@ -28,19 +28,10 @@ extern "C" { #include "myhtml/myosi.h" - // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_t */ enum mycss_status { MyCSS_STATUS_OK = 0x000000, diff --git a/source/myfont/cmap.c b/source/myfont/cmap.c new file mode 100644 index 0000000..0b04175 --- /dev/null +++ b/source/myfont/cmap.c @@ -0,0 +1,184 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/cmap.h" + +void myfont_table_cmap_format_0(myfont_font_t *mf, myfont_tcmap_entry_t *entry) +{ + myfont_tcmap_format_0_t *f0 = (myfont_tcmap_format_0_t *)malloc(sizeof(myfont_tcmap_format_0_t)); + + uint16_t glyphCount = 256; + + fread(f0, (sizeof(uint16_t) * 2), 1, mf->file_h); + fread(f0->glyphIdArray, sizeof(uint8_t), glyphCount, mf->file_h); + + entry->header = (void *)f0; +} + +void myfont_table_cmap_format_4(myfont_font_t *mf, myfont_tcmap_entry_t *entry) +{ + myfont_tcmap_format_4_t *f4 = (myfont_tcmap_format_4_t *)malloc(sizeof(myfont_tcmap_format_4_t)); + + fread(f4, MyFONT_TCMAP_FORMAT_4_FIRST_LENGTH, 1, mf->file_h); + + uint16_t segCount = ntohs(f4->segCountX2) / 2; + uint16_t glyphCount = ((ntohs(f4->length) - (16L + 8L * segCount )) & 0xffff) / 2; + + f4->numGlyphId = glyphCount; + f4->endCount = (uint16_t *)malloc(sizeof(uint16_t) * segCount); + f4->startCount = (uint16_t *)malloc(sizeof(uint16_t) * segCount); + f4->idDelta = (int16_t *)malloc(sizeof(int16_t) * segCount); + f4->idRangeOffset = (uint16_t *)malloc(sizeof(uint16_t) * segCount); + f4->glyphIdArray = (uint16_t *)malloc(sizeof(uint16_t) * glyphCount); + + fread(f4->endCount , sizeof(uint16_t) , segCount, mf->file_h); + fread(&f4->reservedPad , sizeof(uint16_t) , 1, mf->file_h); + fread(f4->startCount , sizeof(uint16_t) , segCount, mf->file_h); + fread(f4->idDelta , sizeof(int16_t) , segCount, mf->file_h); + fread(f4->idRangeOffset, sizeof(int16_t) , segCount, mf->file_h); + fread(f4->glyphIdArray , sizeof(uint16_t) , glyphCount, mf->file_h); + + entry->header = (void *)f4; +} + +uint16_t myfont_glyph_index_by_code_format_0(myfont_tcmap_format_0_t *f0, unsigned long char_code) +{ + if(char_code < 256) + return (uint16_t)f0->glyphIdArray[char_code]; + + return 0; +} + +uint16_t myfont_glyph_index_by_code_format_4(myfont_tcmap_format_4_t *f4, unsigned long char_code) +{ + uint16_t segCount = ntohs(f4->segCountX2) / 2; + + uint16_t i; + + for(i = 0; i < segCount; i++) + if(char_code <= ntohs(f4->endCount[i])) + break; + + if(i >= segCount || char_code < ntohs(f4->startCount[i])) + return 0; + + if(f4->idRangeOffset[i] == 0) + { + return (char_code + ntohs((uint16_t)f4->idDelta[i])) & 0xFFFF; + } + else + { + uint16_t index = ntohs(f4->idRangeOffset[i]) / 2 + (char_code - ntohs(f4->startCount[i])) - (segCount - i); + + if(index < f4->numGlyphId) + { + if(f4->glyphIdArray[index] != 0) + return (ntohs(f4->glyphIdArray[index]) + ntohs((uint16_t)f4->idDelta[i])) & 0xFFFF; + } + } + + return 0; +} + +uint16_t myfont_glyph_index_by_code(myfont_font_t *mf, unsigned long char_code) +{ + uint16_t i, index = 0, tcout = ntohs(mf->table_cmap.header.numTables); + + for(i = 0; i < tcout; i++) + { + myfont_tcmap_entry_t *entry = &mf->table_cmap.entries[i]; + + switch (ntohs(entry->format)) { + case 0: + index = myfont_glyph_index_by_code_format_0((myfont_tcmap_format_0_t *)(entry->header), char_code); + break; + + case 4: + index = myfont_glyph_index_by_code_format_4((myfont_tcmap_format_4_t *)(entry->header), char_code); + break; + + default: + break; + }; + + if(index) + break; + } + + return index; +} + +uint16_t myfont_glyph_index_by_code_on_entry(myfont_tcmap_entry_t *entry, unsigned long char_code) +{ + switch (ntohs(entry->format)) { + case 0: + return myfont_glyph_index_by_code_format_0((myfont_tcmap_format_0_t *)(entry->header), char_code); + + case 4: + return myfont_glyph_index_by_code_format_4((myfont_tcmap_format_4_t *)(entry->header), char_code); + + default: + break; + }; + + return 0; +} + +void myfont_load_table_cmap(myfont_font_t *mf) +{ + myfont_table_cmap_t *tcmap = &mf->table_cmap; + myfont_load_table(mf, &tcmap->header, sizeof(myfont_tcmap_header_t), MyFONT_TKEY_cmap); + + uint16_t tcout = ntohs(tcmap->header.numTables); + + if(tcout == 0) + return; + + tcmap->records = (myfont_tcmap_record_t *)malloc(sizeof(myfont_tcmap_record_t) * tcout); + tcmap->entries = (myfont_tcmap_entry_t *)malloc(sizeof(myfont_tcmap_entry_t) * tcout); + + fread(tcmap->records, sizeof(myfont_tcmap_record_t), tcout, mf->file_h); + + uint16_t i; + for(i = 0; i < tcout; i++) + { + uint32_t offset = ntohl(tcmap->records[i].offset) + mf->cache.tables_offset[MyFONT_TKEY_cmap]; + fseek(mf->file_h, offset, SEEK_SET); + + fread(&tcmap->entries[i].format, sizeof(uint16_t), 1, mf->file_h); + + uint16_t hformat = ntohs(tcmap->entries[i].format); + + switch (hformat) { + case 0: + myfont_table_cmap_format_0(mf, &tcmap->entries[i]); + break; + + case 4: + myfont_table_cmap_format_4(mf, &tcmap->entries[i]); + break; + + default: + break; + } + } +} + + diff --git a/source/myfont/cmap.h b/source/myfont/cmap.h new file mode 100644 index 0000000..fe2ca2a --- /dev/null +++ b/source/myfont/cmap.h @@ -0,0 +1,209 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_CMAP_H +#define MyFONT_CMAP_H +#pragma once + +#include "myfont/myosi.h" + +// table cmap +// + formats +// for Format 8 and 12 +struct myfont_tcmap_group { + uint32_t startCharCode; + uint32_t endCharCode; + uint32_t startGlyphID; +} +typedef myfont_tcmap_group_t; + +// ++ Format 0: Byte encoding table +struct myfont_tcmap_format_0 { + uint16_t length; + uint16_t language; + uint8_t glyphIdArray[256]; +} +typedef myfont_tcmap_format_0_t; + +// ++ Format 2: High-byte mapping through table +struct myfont_tcmap_format_2_subHeader { + uint16_t firstCode; + uint16_t entryCount; + int16_t idDelta; + uint16_t idRangeOffset; +} +typedef myfont_tcmap_f2_sub_header_t; + +struct myfont_tcmap_format_2 { + uint16_t length; + uint16_t language; + uint16_t subHeaderKeys[256]; + + myfont_tcmap_f2_sub_header_t *subHeaders; + uint16_t *glyphIndexArray; +} +typedef myfont_tcmap_format_2_t; + +// ++ Format 4: Segment mapping to delta values +// from length to rangeShift +#define MyFONT_TCMAP_FORMAT_4_FIRST_LENGTH sizeof(uint16_t) * 6 + +struct myfont_tcmap_format_4 { + uint16_t length; + uint16_t language; + uint16_t segCountX2; + uint16_t searchRange; + uint16_t entrySelector; + uint16_t rangeShift; + uint16_t *endCount; // [segCountX2 / 2] + uint16_t reservedPad; + uint16_t *startCount; // [segCountX2 / 2] + int16_t *idDelta; // [segCountX2 / 2] + uint16_t *idRangeOffset; // [segCountX2 / 2] + uint16_t numGlyphId; + uint16_t *glyphIdArray; +} +typedef myfont_tcmap_format_4_t; + +// ++ Format 6: Trimmed table mapping +struct myfont_tcmap_format_6 { + uint16_t length; + uint16_t language; + uint16_t firstCode; + uint16_t entryCount; + uint16_t *glyphIdArray; // [entryCount] +} +typedef myfont_tcmap_format_6_t; + +// +++ Format 8: mixed 16-bit and 32-bit coverage +struct myfont_tcmap_format_8 { + uint16_t reserved; + uint32_t length; + uint32_t language; + uint8_t is32[8192]; + uint32_t nGroups; // follow myfont_tcmap_group_t +} +typedef myfont_tcmap_format_8_t; + +// +++ Format 10: Trimmed array +struct myfont_tcmap_format_10 { + uint16_t reserved; + uint32_t length; + uint32_t language; + uint32_t startCharCode; + uint32_t numChars; + uint16_t *glyphs; +} +typedef myfont_tcmap_format_10_t; + +// +++ Format 12: Segmented coverage +struct myfont_tcmap_format_12 { + uint16_t reserved; + uint32_t length; + uint32_t language; + uint32_t nGroups; // follow myfont_tcmap_group_t +} +typedef myfont_tcmap_format_12_t; + +// +++ Format 13: Many-to-one range mappings. +struct myfont_tcmap_format_13 { + uint16_t reserved; + uint32_t length; + uint32_t language; + // Glyph index to be used for all the characters in the group's range. + uint32_t nGroups; // follow myfont_tcmap_group_t +} +typedef myfont_tcmap_format_13_t; + +// +++ Format 14: Unicode Variation Sequences +struct myfont_tcmap_format_14 { + uint8_t varSelector[3]; // uint24_t + uint32_t length; + uint32_t numVarSelectorRecords; +} +typedef myfont_tcmap_format_14_t; + +struct myfont_tcmap_f14_records { + uint32_t defaultUVSOffset; + uint32_t nonDefaultUVSOffset; +} +typedef myfont_tcmap_f14_records_t; + +// Default UVS Table +struct myfont_tcmap_f14_val_range { + uint8_t startUnicodeValue[3]; // uint24_t + uint8_t additionalCount; +} +typedef myfont_tcmap_f14_val_range_t; + +struct myfont_tcmap_f14_def_uvs { + uint32_t numUnicodeValueRanges; + myfont_tcmap_f14_val_range_t *value_ranges; +} +typedef myfont_tcmap_f14_def_uvs_t; + +// Non-Default UVS Table +struct myfont_tcmap_f14_mapp { + uint8_t startUnicodeValue[3]; // uint24_t + uint8_t additionalCount; +} +typedef myfont_tcmap_f14_mapp_t; + +struct myfont_tcmap_f14_non_def_uvs { + uint32_t numUVSMappings; + myfont_tcmap_f14_mapp_t *mappings; +} +typedef myfont_tcmap_f14_non_def_uvs_t; + +// cmap headers +struct myfont_tcmap_header { + uint16_t version; + uint16_t numTables; +} +typedef myfont_tcmap_header_t; + +struct myfont_tcmap_record { + uint16_t platformID; + uint16_t encodingID; + uint32_t offset; +} +typedef myfont_tcmap_record_t; + +struct myfont_tcmap_entry { + uint16_t format; + void *header; +} +typedef myfont_tcmap_entry_t; + +struct myfont_table_cmap { + myfont_tcmap_header_t header; + myfont_tcmap_record_t *records; + myfont_tcmap_entry_t *entries; +} +typedef myfont_table_cmap_t; + +#include "myfont/myfont.h" + +void myfont_load_table_cmap(myfont_font_t *mf); + +uint16_t myfont_glyph_index_by_code(myfont_font_t *mf, unsigned long char_code); +uint16_t myfont_glyph_index_by_code_on_entry(myfont_tcmap_entry_t *entry, unsigned long char_code); + +#endif /* MyFONT_CMAP_H */ diff --git a/source/myfont/glyf.c b/source/myfont/glyf.c new file mode 100644 index 0000000..07898d8 --- /dev/null +++ b/source/myfont/glyf.c @@ -0,0 +1,154 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/glyf.h" + +void myfont_load_table_glyf(struct myfont_font *mf) +{ + +} + +void myfont_glyf_load(myfont_font_t *mf, myfont_table_glyph_t *glyph, uint16_t glyph_index) +{ + uint16_t offset = myfont_loca_get_offset(mf, glyph_index); + offset += mf->cache.tables_offset[MyFONT_TKEY_glyf]; + + myfont_glyf_load_data(mf, glyph, offset); +} + +void myfont_glyf_load_data(myfont_font_t *mf, myfont_table_glyph_t *glyph, uint16_t offset) +{ + if(offset > 0) + { + // load head + fseek(mf->file_h, offset, SEEK_SET); + fread(&glyph->head, sizeof(myfont_table_glyf_head_t), 1, mf->file_h); + + uint16_t instructionLength; + uint16_t numberOfContours = ntohs(glyph->head.numberOfContours); + uint16_t *endPtsOfContours = (uint16_t *)malloc(sizeof(uint16_t) * numberOfContours); + + fread(endPtsOfContours, sizeof(uint16_t), numberOfContours, mf->file_h); + fread(&instructionLength, sizeof(uint16_t), 1, mf->file_h); + + uint16_t pointCount = ntohs(endPtsOfContours[numberOfContours - 1]) + 1; + + uint8_t *instructions = (uint8_t *)malloc(sizeof(uint8_t) * instructionLength); + fread(instructions, sizeof(uint8_t), instructionLength, mf->file_h); + + glyph->simple.endPtsOfContours = endPtsOfContours; + glyph->simple.instructionLength = instructionLength; + glyph->simple.instructions = instructions; + + glyph->pointCount = pointCount; + + myfont_glyf_load_flags(mf, glyph); + myfont_glyf_load_coordinates(mf, glyph); + } +} + +void myfont_glyf_load_flags(myfont_font_t *mf, myfont_table_glyph_t *glyph) +{ + uint8_t *flags = (uint8_t *)malloc(sizeof(uint8_t) * myfont_glyf_pointCount(glyph)); + + uint16_t i, j; uint8_t repeat; + for(i = 0; i < myfont_glyf_pointCount(glyph); i++) + { + flags[i] = fread(flags, sizeof(uint8_t), 1, mf->file_h); + + if(flags[i] & MyFONT_GLYF_SML_FLAGS_repeat) + { + repeat = fread(flags, sizeof(uint8_t), 1, mf->file_h); + + for(j = 0; j < repeat; j++, i++) + flags[i+1] = flags[i]; + } + } + + glyph->simple.flags = flags; +} + +void myfont_glyf_load_coordinates(myfont_font_t *mf, myfont_table_glyph_t *glyph) +{ + int16_t *xCoordinates = (int16_t *)malloc(sizeof(int16_t) * myfont_glyf_pointCount(glyph)); + int16_t *yCoordinates = (int16_t *)malloc(sizeof(int16_t) * myfont_glyf_pointCount(glyph)); + + uint16_t i; + int16_t in_before = 0, in_now; + + for(i = 0; i < myfont_glyf_pointCount(glyph); i++) + { + in_now = 0; + + if( myfont_glyf_flags(glyph, i) & 0x02 && myfont_glyf_flags(glyph, i) & 0x10 ) + { + fread(&in_now, sizeof(uint8_t), 1, mf->file_h); + xCoordinates[i] = in_before + in_now; + } + else if (myfont_glyf_flags(glyph, i) & 0x02 && !(myfont_glyf_flags(glyph, i) & 0x10) ) + { + fread(&in_now, sizeof(uint8_t), 1, mf->file_h); + xCoordinates[i] = in_before - in_now; + } + else if (!(myfont_glyf_flags(glyph, i) & 0x02) && myfont_glyf_flags(glyph, i) & 0x10 ) + { + xCoordinates[i] = in_before; + } + else + { + fread(&in_now, sizeof(int16_t), 1, mf->file_h); + xCoordinates[i] = in_before + in_now; + } + + in_before = xCoordinates[i]; + } + + in_before = 0; + for(i = 0; i < myfont_glyf_pointCount(glyph); i++) + { + in_now = 0; + + if(myfont_glyf_flags(glyph, i) & 0x04 && myfont_glyf_flags(glyph, i) & 0x20) + { + fread(&in_now, sizeof(uint8_t), 1, mf->file_h); + yCoordinates[i] = in_before+in_now; + } + else if (myfont_glyf_flags(glyph, i) & 0x04 && !(myfont_glyf_flags(glyph, i) & 0x20)) + { + fread(&in_now, sizeof(uint8_t), 1, mf->file_h); + yCoordinates[i] = in_before-in_now; + } + else if (!(myfont_glyf_flags(glyph, i) & 0x04) && myfont_glyf_flags(glyph, i) & 0x20) + { + yCoordinates[i] = in_before; + } + else + { + fread(&in_now, sizeof(int16_t), 1, mf->file_h); + yCoordinates[i] = in_before+in_now; + } + + in_before = yCoordinates[i]; + } + + glyph->simple.xCoordinates = xCoordinates; + glyph->simple.yCoordinates = yCoordinates; +} + diff --git a/source/myfont/glyf.h b/source/myfont/glyf.h new file mode 100644 index 0000000..4d980c5 --- /dev/null +++ b/source/myfont/glyf.h @@ -0,0 +1,108 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_GLYF_H +#define MyFONT_GLYF_H +#pragma once + +#include "myfont/myosi.h" + +enum myfont_table_glyf_composite_flags { + MyFONT_GLYF_ARG_1_AND_2_ARE_WORDS = 0x0001, + MyFONT_GLYF_ARGS_ARE_XY_VALUES = 0x0002, + MyFONT_GLYF_ROUND_XY_TO_GRID = 0x0004, + MyFONT_GLYF_WE_HAVE_A_SCALE = 0x0008, + MyFONT_GLYF_RESERVED = 0x0010, + MyFONT_GLYF_MORE_COMPONENTS = 0x0020, + MyFONT_GLYF_WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, + MyFONT_GLYF_WE_HAVE_A_TWO_BY_TWO = 0x0080, + MyFONT_GLYF_WE_HAVE_INSTRUCTIONS = 0x0100, + MyFONT_GLYF_USE_MY_METRICS = 0x0200, + MyFONT_GLYF_OVERLAP_COMPOUND = 0x0400, + MyFONT_GLYF_SCALED_COMPONENT_OFFSET = 0x0800, + MyFONT_GLYF_UNSCALED_COMPONENT_OFFSET = 0x1000 +}; + +struct myfont_table_composite_glyph { + uint16_t flags; + uint16_t glyphIndex; + int16_t argument1; + int16_t argument2; +} +typedef myfont_table_composite_glyph_t; + +enum myfont_table_glyf_simple_flags { + MyFONT_GLYF_SML_FLAGS_onCurve = 0x001, + MyFONT_GLYF_SML_FLAGS_x_ShortVector = 0x002, + MyFONT_GLYF_SML_FLAGS_y_ShortVector = 0x004, + MyFONT_GLYF_SML_FLAGS_repeat = 0x008, + MyFONT_GLYF_SML_FLAGS_p_x_ShortVector = 0x010, + MyFONT_GLYF_SML_FLAGS_p_y_ShortVector = 0x020, + MyFONT_GLYF_SML_FLAGS_reserved_1 = 0x040, + MyFONT_GLYF_SML_FLAGS_reserved_2 = 0x080, + MyFONT_GLYF_SML_FLAGS_last = 0x100 +}; + +struct myfont_table_simple_glyph { + uint16_t *endPtsOfContours; + uint16_t instructionLength; + uint8_t *instructions; + uint8_t *flags; + int16_t *xCoordinates; + int16_t *yCoordinates; +} +typedef myfont_table_simple_glyph_t; + +struct myfont_table_glyf_head { + int16_t numberOfContours; + int16_t xMin; + int16_t yMin; + int16_t xMax; + int16_t yMax; +} +typedef myfont_table_glyf_head_t; + +struct myfont_table_glyph { + myfont_table_glyf_head_t head; + myfont_table_simple_glyph_t simple; + uint16_t pointCount; +} +typedef myfont_table_glyph_t; + +struct myfont_table_glyf { + myfont_table_glyph_t *cache; +} +typedef myfont_table_glyf_t; + +#include "myfont/myfont.h" + +#define myfont_glyf_pointCount(__glyph__) __glyph__->pointCount +#define myfont_glyf_flags(__glyph__, __i__) __glyph__->simple.flags[__i__] + +struct myfont_font; + +void myfont_load_table_glyf(struct myfont_font *mf); + +void myfont_glyf_load(struct myfont_font *mf, myfont_table_glyph_t *glyph, uint16_t glyph_index); +void myfont_glyf_load_data(struct myfont_font *mf, myfont_table_glyph_t *glyph, uint16_t offset); +void myfont_glyf_load_flags(struct myfont_font *mf, myfont_table_glyph_t *glyph); +void myfont_glyf_load_coordinates(struct myfont_font *mf, myfont_table_glyph_t *glyph); + +#endif /* MyFONT_GLYF_H */ diff --git a/source/myfont/head.c b/source/myfont/head.c new file mode 100644 index 0000000..9b327b8 --- /dev/null +++ b/source/myfont/head.c @@ -0,0 +1,42 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/head.h" + +void myfont_load_table_head(struct myfont_font *mf) +{ + fseek(mf->file_h, mf->cache.tables_offset[MyFONT_TKEY_head], SEEK_SET); + + fread(&mf->table_head , sizeof(uint32_t), 4, mf->file_h); + fread(&mf->table_head.flags , sizeof(uint16_t), 2, mf->file_h); + fread(mf->table_head.created , sizeof(uint32_t), 2, mf->file_h); + fread(mf->table_head.modified, sizeof(uint32_t), 2, mf->file_h); + fread(&mf->table_head.xMin , sizeof(int16_t) , 9, mf->file_h); +} + +float myfont_head_yMax_pixel(struct myfont_font *mf, float font_size) +{ + int16_t yMax = ntohs(mf->table_head.yMax); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)yMax * font_size / ((float)reso); + + return fsize; +} \ No newline at end of file diff --git a/source/myfont/head.h b/source/myfont/head.h new file mode 100644 index 0000000..bb7b8da --- /dev/null +++ b/source/myfont/head.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_HEAD_H +#define MyFONT_HEAD_H +#pragma once + +#include "myfont/myosi.h" + +struct myfont_table_head { + uint32_t version; + uint32_t fontRevision; + uint32_t checkSumAdjustment; + uint32_t magicNumber; + uint16_t flags; + uint16_t unitsPerEm; + uint32_t created[2]; // 64bit + uint32_t modified[2]; // 64bit + int16_t xMin; + int16_t yMin; + int16_t xMax; + int16_t yMax; + uint16_t macStyle; + uint16_t lowestRecPPEM; + int16_t fontDirectionHint; + int16_t indexToLocFormat; + int16_t glyphDataFormat; +} +typedef myfont_table_head_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_head(struct myfont_font *mf); + +float myfont_head_yMax_pixel(struct myfont_font *mf, float font_size); + +#endif /* MyFONT_HEAD_H */ diff --git a/source/myfont/hhea.c b/source/myfont/hhea.c new file mode 100644 index 0000000..a096810 --- /dev/null +++ b/source/myfont/hhea.c @@ -0,0 +1,26 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/hhea.h" + +void myfont_load_table_hhea(myfont_font_t *mf) +{ + myfont_load_table(mf, &mf->table_hhea, sizeof(myfont_table_hhea_t), MyFONT_TKEY_hhea); +} \ No newline at end of file diff --git a/source/myfont/hhea.h b/source/myfont/hhea.h new file mode 100644 index 0000000..c75e16a --- /dev/null +++ b/source/myfont/hhea.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_HHEA_H +#define MyFONT_HHEA_H +#pragma once + +#include "myfont/myosi.h" + +// table hhea +struct myfont_table_hhea { + int32_t version; + int16_t Ascender; + int16_t Descender; + int16_t LineGap; + uint16_t advanceWidthMax; + int16_t minLeftSideBearing; + int16_t minRightSideBearing; + int16_t xMaxExtent; + int16_t caretSlopeRise; + int16_t caretSlopeRun; + int16_t caretOffset; + int16_t reserved1; + int16_t reserved2; + int16_t reserved3; + int16_t reserved4; + int16_t metricDataFormat; + uint16_t numberOfHMetrics; +} +typedef myfont_table_hhea_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_hhea(struct myfont_font *mf); + +#endif /* MyFONT_HHEA_H */ diff --git a/source/myfont/hmtx.c b/source/myfont/hmtx.c new file mode 100644 index 0000000..93f08fd --- /dev/null +++ b/source/myfont/hmtx.c @@ -0,0 +1,35 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/hmtx.h" + +void myfont_load_table_hmtx(struct myfont_font *mf) +{ + uint16_t num_metrics = htons(mf->table_hhea.numberOfHMetrics); + + myfont_long_hor_metric_t *lhor_metric = (myfont_long_hor_metric_t *)malloc(sizeof(myfont_long_hor_metric_t) * num_metrics); + + fseek(mf->file_h, mf->cache.tables_offset[MyFONT_TKEY_hmtx], SEEK_SET); + fread(lhor_metric, sizeof(myfont_long_hor_metric_t), num_metrics, mf->file_h); + + mf->table_hmtx.hMetrics = lhor_metric; + mf->table_hmtx.leftSideBearing = NULL; +} + diff --git a/source/myfont/hmtx.h b/source/myfont/hmtx.h new file mode 100644 index 0000000..d8f1ac6 --- /dev/null +++ b/source/myfont/hmtx.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_HMTX_H +#define MyFONT_HMTX_H +#pragma once + +#include "myfont/myosi.h" + +struct myfont_long_hor_metric { + uint16_t advanceWidth; + int16_t lsb; +} +typedef myfont_long_hor_metric_t; + +// table hhea +struct myfont_table_hmtx { + myfont_long_hor_metric_t *hMetrics; + int16_t *leftSideBearing; +} +typedef myfont_table_hmtx_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_hmtx(struct myfont_font *mf); + +#endif /* MyFONT_HMTX_H */ diff --git a/source/myfont/loca.c b/source/myfont/loca.c new file mode 100644 index 0000000..5f00e93 --- /dev/null +++ b/source/myfont/loca.c @@ -0,0 +1,77 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/loca.h" + +void myfont_load_table_loca(struct myfont_font *mf) +{ + if(mf->cache.tables_offset[MyFONT_TKEY_loca]) + { + uint16_t numGlyph = ntohs(mf->table_maxp.numGlyphs); + + if(numGlyph) + { + numGlyph++; + + if(mf->table_head.indexToLocFormat) + { + mf->table_loca.long_offsets = (uint32_t *)malloc(sizeof(uint32_t) * numGlyph); + + fseek(mf->file_h, mf->cache.tables_offset[MyFONT_TKEY_loca], SEEK_SET); + fread(mf->table_loca.long_offsets, sizeof(uint32_t), numGlyph, mf->file_h); + + mf->table_loca.short_offsets = NULL; + } + else + { + mf->table_loca.short_offsets = (uint16_t *)malloc(sizeof(uint16_t) * numGlyph); + + fseek(mf->file_h, mf->cache.tables_offset[MyFONT_TKEY_loca], SEEK_SET); + fread(mf->table_loca.short_offsets, sizeof(uint16_t) , numGlyph, mf->file_h); + + mf->table_loca.long_offsets = NULL; + } + } + else + { + mf->table_loca.short_offsets = NULL; + mf->table_loca.long_offsets = NULL; + + } + } +} + +uint32_t myfont_loca_get_offset(struct myfont_font *mf, uint16_t glyph_index) +{ + //uint16_t numGlyph = ntohs(mf->table_maxp.numGlyphs); + + if(mf->table_head.indexToLocFormat) + { + return ntohl(mf->table_loca.long_offsets[glyph_index]); + } + else + { + return ntohs(mf->table_loca.short_offsets[glyph_index]); + } + + return 0; +} + + diff --git a/source/myfont/loca.h b/source/myfont/loca.h new file mode 100644 index 0000000..db592bd --- /dev/null +++ b/source/myfont/loca.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_LOCA_H +#define MyFONT_LOCA_H +#pragma once + +#include "myfont/myosi.h" + +// table pclt +struct myfont_table_loca { + uint16_t *short_offsets; + uint32_t *long_offsets; +} +typedef myfont_table_loca_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_loca(struct myfont_font *mf); + +uint32_t myfont_loca_get_offset(struct myfont_font *mf, uint16_t glyph_index); + +#endif /* MyFONT_LOCA_H */ diff --git a/source/myfont/maxp.c b/source/myfont/maxp.c new file mode 100644 index 0000000..3f3044e --- /dev/null +++ b/source/myfont/maxp.c @@ -0,0 +1,54 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/maxp.h" + +void myfont_load_table_maxp(myfont_font_t *mf) +{ + uint32_t version; + + fseek(mf->file_h, mf->cache.tables_offset[MyFONT_TKEY_maxp], SEEK_SET); + fread(&version, sizeof(uint32_t), 1, mf->file_h); + + if(myfont_table_version_major(version) == 1) + { + myfont_load_table(mf, &mf->table_maxp, sizeof(myfont_table_maxp_t), MyFONT_TKEY_maxp); + } + else + { + fread(&(mf->table_maxp.numGlyphs), sizeof(uint16_t), 1, mf->file_h); + + mf->table_maxp.version = version; + mf->table_maxp.maxPoints = 0; + mf->table_maxp.maxContours = 0; + mf->table_maxp.maxCompositePoints = 0; + mf->table_maxp.maxCompositeContours = 0; + mf->table_maxp.maxZones = 0; + mf->table_maxp.maxTwilightPoints = 0; + mf->table_maxp.maxStorage = 0; + mf->table_maxp.maxFunctionDefs = 0; + mf->table_maxp.maxInstructionDefs = 0; + mf->table_maxp.maxStackElements = 0; + mf->table_maxp.maxSizeOfInstructions = 0; + mf->table_maxp.maxComponentElements = 0; + mf->table_maxp.maxComponentDepth = 0; + } +} + diff --git a/source/myfont/maxp.h b/source/myfont/maxp.h new file mode 100644 index 0000000..e96b1cb --- /dev/null +++ b/source/myfont/maxp.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_MAXP_H +#define MyFONT_MAXP_H +#pragma once + +#include "myfont/myosi.h" + +struct myfont_table_maxp { + uint32_t version; + uint16_t numGlyphs; + uint16_t maxPoints; + uint16_t maxContours; + uint16_t maxCompositePoints; + uint16_t maxCompositeContours; + uint16_t maxZones; + uint16_t maxTwilightPoints; + uint16_t maxStorage; + uint16_t maxFunctionDefs; + uint16_t maxInstructionDefs; + uint16_t maxStackElements; + uint16_t maxSizeOfInstructions; + uint16_t maxComponentElements; + uint16_t maxComponentDepth; +} +typedef myfont_table_maxp_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_maxp(struct myfont_font *mf); + +#endif /* MyFONT_MAXP_H */ diff --git a/source/myfont/myfont.c b/source/myfont/myfont.c new file mode 100644 index 0000000..b9f2a54 --- /dev/null +++ b/source/myfont/myfont.c @@ -0,0 +1,377 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/myfont.h" + +const char myfont_table_name[][5] = { + "cmap", "head", "hhea", "hmtx", "maxp", "name", + "OS/2", "post", "cvt ", "fpgm", "glyf", "loca", + "prep", "CFF ", "VORG", "EBDT", "EBLC", "EBSC", + "BASE", "GDEF", "GPOS", "GSUB", "JSTF", "DSIG", + "gasp", "hdmx", "kern", "LTSH", "PCLT", "VDMX", + "vhea", "vmtx" +}; + +myfont_font_t * myfont_create(void) +{ + myfont_font_t *mf = (myfont_font_t *)malloc(sizeof(myfont_font_t)); + + memset(mf->cache.tables_offset, 0, sizeof(uint32_t) * MyFONT_TKEY_LAST_KEY); + memset(&mf->header, 0, sizeof(myfont_header_t)); + + mf->file_path = NULL; + mf->file_h = NULL; + + return mf; +} + +void myfont_clean(myfont_font_t *mf) +{ + memset(mf->cache.tables_offset, 0, sizeof(uint32_t) * MyFONT_TKEY_LAST_KEY); + memset(&mf->header, 0, sizeof(myfont_header_t)); + + if(mf->file_h) + fclose(mf->file_h); + + mf->file_path = NULL; + mf->file_h = NULL; +} + +myfont_font_t * myfont_destroy(myfont_font_t *mf) +{ + if(mf->file_h) + fclose(mf->file_h); + + if(mf) + free(mf); + + return NULL; +} + +void myfont_load(myfont_font_t *mf, const char *filepath) +{ + FILE *fh = fopen(filepath, "rb"); + + fseek(fh, 0L, SEEK_END); + long file_size = ftell(fh); + fseek(fh, 0L, SEEK_SET); + + if(file_size > 0) + mf->file_size = (size_t)file_size; + + fread(&mf->header, sizeof(myfont_header_t), 1, fh); + + myfont_table_t table = {0}; + uint16_t i; + + for(i = 0; i < htons(mf->header.numTables); i++) + { + fread(&table, sizeof(myfont_table_t), 1, fh); + + switch(table.tag) { + case MyFONT_TABLE_TYPE_cmap: mf->cache.tables_offset[ MyFONT_TKEY_cmap ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_head: mf->cache.tables_offset[ MyFONT_TKEY_head ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_hhea: mf->cache.tables_offset[ MyFONT_TKEY_hhea ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_hmtx: mf->cache.tables_offset[ MyFONT_TKEY_hmtx ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_maxp: mf->cache.tables_offset[ MyFONT_TKEY_maxp ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_name: mf->cache.tables_offset[ MyFONT_TKEY_name ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_OS_2: mf->cache.tables_offset[ MyFONT_TKEY_OS_2 ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_post: mf->cache.tables_offset[ MyFONT_TKEY_post ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_cvt: mf->cache.tables_offset[ MyFONT_TKEY_cvt ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_fpgm: mf->cache.tables_offset[ MyFONT_TKEY_fpgm ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_glyf: mf->cache.tables_offset[ MyFONT_TKEY_glyf ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_loca: mf->cache.tables_offset[ MyFONT_TKEY_loca ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_prep: mf->cache.tables_offset[ MyFONT_TKEY_prep ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_gasp: mf->cache.tables_offset[ MyFONT_TKEY_gasp ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_CFF: mf->cache.tables_offset[ MyFONT_TKEY_CFF ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_VORG: mf->cache.tables_offset[ MyFONT_TKEY_VORG ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_SVG: mf->cache.tables_offset[ MyFONT_TKEY_SVG ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_EBDT: mf->cache.tables_offset[ MyFONT_TKEY_EBDT ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_EBLC: mf->cache.tables_offset[ MyFONT_TKEY_EBLC ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_EBSC: mf->cache.tables_offset[ MyFONT_TKEY_EBSC ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_CBDT: mf->cache.tables_offset[ MyFONT_TKEY_CBDT ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_CBLC: mf->cache.tables_offset[ MyFONT_TKEY_CBLC ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_BASE: mf->cache.tables_offset[ MyFONT_TKEY_BASE ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_GDEF: mf->cache.tables_offset[ MyFONT_TKEY_GDEF ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_GPOS: mf->cache.tables_offset[ MyFONT_TKEY_GPOS ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_GSUB: mf->cache.tables_offset[ MyFONT_TKEY_GSUB ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_JSTF: mf->cache.tables_offset[ MyFONT_TKEY_JSTF ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_MATH: mf->cache.tables_offset[ MyFONT_TKEY_MATH ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_DSIG: mf->cache.tables_offset[ MyFONT_TKEY_DSIG ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_hdmx: mf->cache.tables_offset[ MyFONT_TKEY_hdmx ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_kern: mf->cache.tables_offset[ MyFONT_TKEY_kern ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_LTSH: mf->cache.tables_offset[ MyFONT_TKEY_LTSH ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_PCLT: mf->cache.tables_offset[ MyFONT_TKEY_PCLT ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_VDMX: mf->cache.tables_offset[ MyFONT_TKEY_VDMX ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_vhea: mf->cache.tables_offset[ MyFONT_TKEY_vhea ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_vmtx: mf->cache.tables_offset[ MyFONT_TKEY_vmtx ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_COLR: mf->cache.tables_offset[ MyFONT_TKEY_COLR ] = ntohl(table.offset); break; + case MyFONT_TABLE_TYPE_CPAL: mf->cache.tables_offset[ MyFONT_TKEY_CPAL ] = ntohl(table.offset); break; + default: + break; + }; + } + + mf->file_h = fh; + mf->file_path = filepath; + + myfont_load_table_cmap(mf); + myfont_load_table_head(mf); + myfont_load_table_name(mf); + myfont_load_table_os_2(mf); + myfont_load_table_maxp(mf); + myfont_load_table_hhea(mf); + myfont_load_table_hmtx(mf); + myfont_load_table_glyf(mf); + myfont_load_table_vhea(mf); + myfont_load_table_vmtx(mf); + myfont_load_table_pclt(mf); + myfont_load_table_loca(mf); +} + +myfont_status_t myfont_load_table(myfont_font_t *mf, void *table, size_t size, enum myfont_table_key tkey) +{ + if(mf->cache.tables_offset[tkey] == 0) + return MyFONT_STATUS_NOT_FOUND; + + fseek(mf->file_h, mf->cache.tables_offset[tkey], SEEK_SET); + fread(table, size, 1, mf->file_h); + + return MyFONT_STATUS_OK; +} + +void myfont_font_print_exists_table(myfont_font_t *mf, FILE *file) +{ + size_t i; + for(i = 0; i < MyFONT_TKEY_LAST_KEY; i++) + { + if(!mf->cache.tables_offset[i]) + continue; + + fprintf(file, "%s = %u\n", myfont_table_name[i], mf->cache.tables_offset[i]); + } +} + +// metrics +float myfont_metrics_baseline(myfont_font_t *mf, float font_size) +{ + uint16_t baseline = ntohs(mf->table_os_2.usWinAscent); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)baseline * font_size / ((float)reso); + + return fsize; +} + +float myfont_metrics_ascent(myfont_font_t *mf, float font_size) +{ + return 0.0f; +} + +float myfont_metrics_descent(myfont_font_t *mf, float font_size) +{ + float baseline = myfont_metrics_baseline(mf, font_size); + uint16_t descent = ntohs(mf->table_os_2.usWinDescent); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)descent * font_size / ((float)reso); + + return (baseline + fsize); +} + +float myfont_metrics_ascender(myfont_font_t *mf, float font_size) +{ + float baseline = myfont_metrics_baseline(mf, font_size); + int16_t ascender = ntohs(mf->table_os_2.sTypoAscender); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)ascender * font_size / ((float)reso); + + return (baseline - fsize); +} + +float myfont_metrics_descender(myfont_font_t *mf, float font_size) +{ + float baseline = myfont_metrics_baseline(mf, font_size); + int16_t descender = ntohs(mf->table_os_2.sTypoDescender); + + if(descender < 0.0f) + descender = -descender; + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)descender * font_size / ((float)reso); + + return (baseline + fsize); +} + +float myfont_metrics_x_height(myfont_font_t *mf, float font_size) +{ + float baseline = myfont_metrics_baseline(mf, font_size); + + int16_t xheight = 0; + + if(myfont_table_version_major(mf->table_os_2.version) > 1) + { + if(mf->table_os_2.sxHeight) + xheight = mf->table_os_2.sxHeight; + } + + if(xheight == 0 && mf->table_pclt.xHeight) + xheight = (int16_t)mf->table_pclt.xHeight; + + if(xheight == 0) + { + uint16_t glyph_index = myfont_glyph_index_by_code(mf, (unsigned long)('x')); + + if(glyph_index) + { + myfont_table_glyph_t glyph; + myfont_glyf_load(mf, &glyph, glyph_index); + + xheight = glyph.head.yMax; + } + } + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)(ntohs(xheight)) * font_size / (float)(reso); + + return (baseline - fsize); +} + +float myfont_metrics_cap_height(myfont_font_t *mf, float font_size) +{ + float baseline = myfont_metrics_baseline(mf, font_size); + + int16_t cap_height = 0; + + if(myfont_table_version_major(mf->table_os_2.version) > 1) + { + if(mf->table_os_2.sCapHeight) + cap_height = mf->table_os_2.sCapHeight; + } + + if(cap_height == 0 && mf->table_pclt.capHeight) + cap_height = (int16_t)mf->table_pclt.capHeight; + + if(cap_height == 0) + { + uint16_t glyph_index = myfont_glyph_index_by_code(mf, (unsigned long)('H')); + + if(glyph_index) + { + myfont_table_glyph_t glyph; + myfont_glyf_load(mf, &glyph, glyph_index); + + cap_height = glyph.head.yMax; + } + } + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)(ntohs(cap_height)) * font_size / (float)(reso); + + return (baseline - fsize); +} + +// width, height and ... +float myfont_char_width(myfont_font_t *mf, unsigned long char_code, float font_size) +{ + uint16_t glyph_index = myfont_glyph_index_by_code(mf, char_code); + uint16_t num_metrics = ntohs(mf->table_hhea.numberOfHMetrics); + + if(num_metrics == 0) + return 0.0f; + + if(glyph_index > num_metrics) + glyph_index = num_metrics - 1; + + uint16_t width = ntohs(mf->table_hmtx.hMetrics[glyph_index].advanceWidth); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)width * font_size / ((float)reso); + + return fsize; +} + +float myfont_char_height(myfont_font_t *mf, unsigned long char_code, float font_size) +{ + uint16_t glyph_index = myfont_glyph_index_by_code(mf, char_code); + uint16_t num_metrics = ntohs(mf->table_vhea.numOfLongVerMetrics); + + if(num_metrics == 0) + { + return myfont_font_height(mf, font_size); + } + + if(glyph_index > num_metrics) + glyph_index = num_metrics - 1; + + uint16_t height = ntohs(mf->table_vmtx.vMetrics[glyph_index].advanceHeight); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)height * font_size / ((float)reso); + + return fsize; +} + +float myfont_font_height(myfont_font_t *mf, float font_size) +{ + int16_t height = ntohs(mf->table_os_2.usWinAscent) + ntohs(mf->table_os_2.usWinDescent); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)height * font_size / ((float)reso); + + return fsize; +} + +float myfont_font_ascent(myfont_font_t *mf, float font_size) +{ + int16_t ascent = ntohs(mf->table_os_2.usWinAscent); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)ascent * font_size / ((float)reso); + + return fsize; +} + +float myfont_font_descent(myfont_font_t *mf, float font_size) +{ + int16_t descent = ntohs(mf->table_os_2.usWinDescent); + + uint16_t reso = ntohs(mf->table_head.unitsPerEm); + float fsize = (float)descent * font_size / ((float)reso); + + return fsize; +} + +int16_t myfont_table_version_major(uint32_t version) +{ + version = htonl(version); + version >>= 16; + return (int16_t)version; +} + +int16_t myfont_table_version_minor(uint32_t version) +{ + version = htonl(version); + version <<= 16; + version >>= 16; + return (int16_t)version; +} + diff --git a/source/myfont/myfont.h b/source/myfont/myfont.h new file mode 100644 index 0000000..ba3b2e1 --- /dev/null +++ b/source/myfont/myfont.h @@ -0,0 +1,113 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_MyFONT_H +#define MyFONT_MyFONT_H +#pragma once + +#include "myfont/myosi.h" +#include "myfont/cmap.h" +#include "myfont/head.h" +#include "myfont/name.h" +#include "myfont/os_2.h" +#include "myfont/maxp.h" +#include "myfont/hhea.h" +#include "myfont/hmtx.h" +#include "myfont/glyf.h" +#include "myfont/vhea.h" +#include "myfont/vmtx.h" +#include "myfont/pclt.h" +#include "myfont/loca.h" + +// base +#pragma pack(push, 1) +struct myfont_header { + int32_t version; + uint16_t numTables; + uint16_t searchRange; + uint16_t entrySelector; + uint16_t rangeShift; +} +typedef myfont_header_t; + +struct myfont_table { + uint32_t tag; + uint32_t checkSum; + uint32_t offset; + uint32_t length; +} +typedef myfont_table_t; +#pragma pack(pop) + +struct myfont_cache { + uint32_t tables_offset[MyFONT_TKEY_LAST_KEY]; +} +typedef myfont_cache_t; + +struct myfont_font { + myfont_header_t header; + myfont_cache_t cache; + + myfont_table_cmap_t table_cmap; + myfont_table_head_t table_head; + myfont_table_name_t table_name; + myfont_table_os_2_t table_os_2; + myfont_table_maxp_t table_maxp; + myfont_table_hhea_t table_hhea; + myfont_table_hmtx_t table_hmtx; + myfont_table_glyf_t table_glyf; + myfont_table_vmtx_t table_vmtx; + myfont_table_vhea_t table_vhea; + myfont_table_pclt_t table_pclt; + myfont_table_loca_t table_loca; + + const char *file_path; + FILE *file_h; + size_t file_size; +}; + +myfont_font_t * myfont_create(void); +void myfont_clean(myfont_font_t *mf); +myfont_font_t * myfont_destroy(myfont_font_t *mf); + +void myfont_load(myfont_font_t *mf, const char *filepath); + +void myfont_font_print_exists_table(myfont_font_t *mf, FILE *file); + +float myfont_metrics_baseline(myfont_font_t *mf, float font_size); +float myfont_metrics_ascent(myfont_font_t *mf, float font_size); +float myfont_metrics_descent(myfont_font_t *mf, float font_size); +float myfont_metrics_ascender(myfont_font_t *mf, float font_size); +float myfont_metrics_descender(myfont_font_t *mf, float font_size); +float myfont_metrics_x_height(myfont_font_t *mf, float font_size); +float myfont_metrics_cap_height(myfont_font_t *mf, float font_size); + +float myfont_char_width(myfont_font_t *mf, unsigned long char_code, float font_size); +float myfont_char_height(myfont_font_t *mf, unsigned long char_code, float font_size); +float myfont_font_height(myfont_font_t *mf, float font_size); +float myfont_font_ascent(myfont_font_t *mf, float font_size); +float myfont_font_descent(myfont_font_t *mf, float font_size); + +myfont_status_t myfont_load_table(myfont_font_t *mf, void *table, size_t size, enum myfont_table_key tkey); + +int16_t myfont_table_version_major(uint32_t version); +int16_t myfont_table_version_minor(uint32_t version); + +#endif /* MyFONT_MyFONT_H */ diff --git a/source/myfont/myosi.h b/source/myfont/myosi.h new file mode 100644 index 0000000..b2f3fd5 --- /dev/null +++ b/source/myfont/myosi.h @@ -0,0 +1,140 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) + + By specification https://www.microsoft.com/typography/otspec/otff.htm +*/ + +#ifndef MyFONT_BASE_H +#define MyFONT_BASE_H +#pragma once + +#include "myhtml/myosi.h" + +// Required Tables +#define MyFONT_TABLE_TYPE_cmap 1885433187 +#define MyFONT_TABLE_TYPE_head 1684104552 +#define MyFONT_TABLE_TYPE_hhea 1634035816 +#define MyFONT_TABLE_TYPE_hmtx 2020896104 +#define MyFONT_TABLE_TYPE_maxp 1886937453 +#define MyFONT_TABLE_TYPE_name 1701667182 +#define MyFONT_TABLE_TYPE_OS_2 841962319 // OS/2 +#define MyFONT_TABLE_TYPE_post 1953722224 + +// Tables Related to TrueType Outlines +#define MyFONT_TABLE_TYPE_cvt 1953915648 +#define MyFONT_TABLE_TYPE_fpgm 1835495526 +#define MyFONT_TABLE_TYPE_glyf 1719233639 +#define MyFONT_TABLE_TYPE_loca 1633906540 +#define MyFONT_TABLE_TYPE_prep 1885696624 +#define MyFONT_TABLE_TYPE_gasp 1886609767 + +// Tables Related to PostScript Outlines +#define MyFONT_TABLE_TYPE_CFF 1179009792 +#define MyFONT_TABLE_TYPE_VORG 1196576598 + +// Tables Related to SVG +#define MyFONT_TABLE_TYPE_SVG 1196839680 + +// Tables Related to Bitmap Glyphs +#define MyFONT_TABLE_TYPE_EBDT 1413759557 +#define MyFONT_TABLE_TYPE_EBLC 1129071173 +#define MyFONT_TABLE_TYPE_EBSC 1129529925 +#define MyFONT_TABLE_TYPE_CBDT 1413759555 +#define MyFONT_TABLE_TYPE_CBLC 1129071171 + +// Advanced Typographic Tables +#define MyFONT_TABLE_TYPE_BASE 1163084098 +#define MyFONT_TABLE_TYPE_GDEF 1178944583 +#define MyFONT_TABLE_TYPE_GPOS 1397706823 +#define MyFONT_TABLE_TYPE_GSUB 1112888135 +#define MyFONT_TABLE_TYPE_JSTF 1179931466 +#define MyFONT_TABLE_TYPE_MATH 1213481293 + +// Other OpenType Tables +#define MyFONT_TABLE_TYPE_DSIG 1195987780 +#define MyFONT_TABLE_TYPE_hdmx 2020435048 +#define MyFONT_TABLE_TYPE_kern 1852990827 +#define MyFONT_TABLE_TYPE_LTSH 1213420620 +#define MyFONT_TABLE_TYPE_PCLT 1414284112 +#define MyFONT_TABLE_TYPE_VDMX 1481458774 +#define MyFONT_TABLE_TYPE_vhea 1634035830 +#define MyFONT_TABLE_TYPE_vmtx 2020896118 +#define MyFONT_TABLE_TYPE_COLR 1380732739 +#define MyFONT_TABLE_TYPE_CPAL 1279348803 + +// base +/* + Very important!!! + see modest/myosi.h:modest_status_t +*/ +enum myfont_status { + MyFONT_STATUS_OK = 0x000000, + MyFONT_STATUS_ERROR_MEMORY_ALLOCATION = 0x070000, + MyFONT_STATUS_NOT_FOUND = 0x070001, +} +typedef myfont_status_t; + +enum myfont_table_key { + MyFONT_TKEY_cmap = 0x00, + MyFONT_TKEY_head = 0x01, + MyFONT_TKEY_hhea = 0x02, + MyFONT_TKEY_hmtx = 0x03, + MyFONT_TKEY_maxp = 0x04, + MyFONT_TKEY_name = 0x05, + MyFONT_TKEY_OS_2 = 0x06, + MyFONT_TKEY_post = 0x07, + MyFONT_TKEY_cvt = 0x08, + MyFONT_TKEY_fpgm = 0x09, + MyFONT_TKEY_glyf = 0x0A, + MyFONT_TKEY_loca = 0x0B, + MyFONT_TKEY_prep = 0x0C, + MyFONT_TKEY_gasp = 0x0D, + MyFONT_TKEY_CFF = 0x0E, + MyFONT_TKEY_VORG = 0x0F, + MyFONT_TKEY_SVG = 0x10, + MyFONT_TKEY_EBDT = 0x11, + MyFONT_TKEY_EBLC = 0x12, + MyFONT_TKEY_EBSC = 0x13, + MyFONT_TKEY_CBDT = 0x14, + MyFONT_TKEY_CBLC = 0x15, + MyFONT_TKEY_BASE = 0x16, + MyFONT_TKEY_GDEF = 0x17, + MyFONT_TKEY_GPOS = 0x18, + MyFONT_TKEY_GSUB = 0x19, + MyFONT_TKEY_JSTF = 0x1A, + MyFONT_TKEY_MATH = 0x1B, + MyFONT_TKEY_DSIG = 0x1C, + MyFONT_TKEY_hdmx = 0x1D, + MyFONT_TKEY_kern = 0x1E, + MyFONT_TKEY_LTSH = 0x1F, + MyFONT_TKEY_PCLT = 0x20, + MyFONT_TKEY_VDMX = 0x21, + MyFONT_TKEY_vhea = 0x22, + MyFONT_TKEY_vmtx = 0x23, + MyFONT_TKEY_COLR = 0x24, + MyFONT_TKEY_CPAL = 0x25, + MyFONT_TKEY_LAST_KEY = 0x26 +} +typedef myfont_table_key_t; + +/* base struct typedef */ +typedef struct myfont_font myfont_font_t; + + +#endif /* MyFONT_BASE_H */ diff --git a/source/myfont/name.c b/source/myfont/name.c new file mode 100644 index 0000000..bd37dc8 --- /dev/null +++ b/source/myfont/name.c @@ -0,0 +1,51 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/name.h" + +void myfont_load_table_name(myfont_font_t *mf) +{ + myfont_table_name_t *table_name = &mf->table_name; + + fseek(mf->file_h, mf->cache.tables_offset[MyFONT_TKEY_name], SEEK_SET); + fread(table_name, sizeof(uint16_t) * 3, 1, mf->file_h); + + size_t record_size = sizeof(myfont_record_t) * ntohs(table_name->count); + myfont_record_t *record = (myfont_record_t *)malloc(record_size); + + fread(record, record_size, 1, mf->file_h); + + table_name->nameRecord = record; + + if(ntohs(table_name->format) == 1) + { + fread(&table_name->langTagCount, sizeof(uint16_t), 1, mf->file_h); + + size_t lang_record_size = sizeof(myfont_ltag_record_t) * ntohs(table_name->langTagCount); + myfont_ltag_record_t *lang_record = (myfont_ltag_record_t *)malloc(lang_record_size); + + fread(lang_record, lang_record_size, 1, mf->file_h); + + table_name->langTagRecord = lang_record; + } + + myfont_load_table(mf, table_name, sizeof(myfont_table_hhea_t), MyFONT_TKEY_hhea); +} + diff --git a/source/myfont/name.h b/source/myfont/name.h new file mode 100644 index 0000000..5d57601 --- /dev/null +++ b/source/myfont/name.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_NAME_H +#define MyFONT_NAME_H +#pragma once + +#include "myfont/myosi.h" + +// table name +struct myfont_table_name_record { + uint16_t platformID; + uint16_t encodingID; + uint16_t languageID; + uint16_t nameID; + uint16_t length; + uint16_t offset; +} +typedef myfont_record_t; + +struct myfont_lang_tag_record { + uint16_t length; + uint16_t offset; +} +typedef myfont_ltag_record_t; + +struct myfont_table_name { + uint16_t format; + uint16_t count; + uint16_t stringOffset; + myfont_record_t *nameRecord; + uint16_t langTagCount; + myfont_ltag_record_t *langTagRecord; + char *str_data; +} +typedef myfont_table_name_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_name(struct myfont_font *mf); + +#endif /* MyFONT_NAME_H */ diff --git a/source/myfont/os_2.c b/source/myfont/os_2.c new file mode 100644 index 0000000..bbb291c --- /dev/null +++ b/source/myfont/os_2.c @@ -0,0 +1,81 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/os_2.h" + +void myfont_load_table_os_2(myfont_font_t *mf) +{ + if(mf->cache.tables_offset[MyFONT_TKEY_OS_2]) + { + myfont_load_table(mf, &mf->table_os_2, sizeof(int16_t) * 16, MyFONT_TKEY_OS_2); + + fread(mf->table_os_2.panose , sizeof(uint8_t) , 10, mf->file_h); + fread(&mf->table_os_2.ulUnicodeRange1 , sizeof(uint32_t), 4, mf->file_h); + fread(mf->table_os_2.achVendID , sizeof(int8_t) , 4, mf->file_h); + fread(&mf->table_os_2.fsSelection , sizeof(int16_t) , 8, mf->file_h); + + uint16_t version = myfont_table_version_major(mf->table_os_2.version); + + memset(&mf->table_os_2.ulCodePageRange1, 0, sizeof(uint32_t) * 2); + memset(&mf->table_os_2.sxHeight, 0, sizeof(int16_t) * 7); + + switch (version) + { + case 1: + fread(&mf->table_os_2.ulCodePageRange1, sizeof(uint32_t), 2, mf->file_h); + break; + case 2: + fread(&mf->table_os_2.ulCodePageRange1, sizeof(uint32_t), 2, mf->file_h); + fread(&mf->table_os_2.sxHeight, sizeof(int16_t), 5, mf->file_h); + break; + case 3: + fread(&mf->table_os_2.ulCodePageRange1, sizeof(uint32_t), 2, mf->file_h); + fread(&mf->table_os_2.sxHeight, sizeof(int16_t), 5, mf->file_h); + break; + case 4: + fread(&mf->table_os_2.ulCodePageRange1, sizeof(uint32_t), 2, mf->file_h); + fread(&mf->table_os_2.sxHeight, sizeof(int16_t), 5, mf->file_h); + break; + case 5: + fread(&mf->table_os_2.ulCodePageRange1, sizeof(uint32_t), 2, mf->file_h); + fread(&mf->table_os_2.sxHeight, sizeof(int16_t), 7, mf->file_h); + break; + default: + break; + } + } + else + { + memset(&mf->table_os_2.version , 0, sizeof(int16_t) * 16); + memset(&mf->table_os_2.panose , 0, sizeof(int8_t) * 10); + memset(&mf->table_os_2.ulUnicodeRange1 , 0, sizeof(uint32_t) * 4); + memset(&mf->table_os_2.achVendID , 0, sizeof(int8_t) * 4); + memset(&mf->table_os_2.achVendID , 0, sizeof(int16_t) * 8); + memset(&mf->table_os_2.ulCodePageRange1, 0, sizeof(uint32_t) * 2); + memset(&mf->table_os_2.sxHeight , 0, sizeof(int16_t) * 7); + } +} + +int8_t myfont_os_2_panose(myfont_font_t *mf, enum myfont_table_os_2_panose id) +{ + return mf->table_os_2.panose[id]; +} + + diff --git a/source/myfont/os_2.h b/source/myfont/os_2.h new file mode 100644 index 0000000..0abc4df --- /dev/null +++ b/source/myfont/os_2.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_OS_2_H +#define MyFONT_OS_2_H +#pragma once + +#include "myfont/myosi.h" + +enum myfont_table_os_2_panose { + MyFONT_PANOSE_panose_bFamilyType = 0, + MyFONT_PANOSE_bSerifStyle = 1, + MyFONT_PANOSE_bWeight = 2, + MyFONT_PANOSE_bProportion = 3, + MyFONT_PANOSE_bContrast = 4, + MyFONT_PANOSE_bStrokeVariation = 5, + MyFONT_PANOSE_bArmStyle = 6, + MyFONT_PANOSE_bLetterform = 7, + MyFONT_PANOSE_bMidline = 8, + MyFONT_PANOSE_bXHeight = 9, + MyFONT_PANOSE_last = 10 +}; + +struct myfont_table_os_2 { + uint16_t version; + int16_t xAvgCharWidth; + uint16_t usWeightClass; + uint16_t usWidthClass; + int16_t fsType; + int16_t ySubscriptXSize; + int16_t ySubscriptYSize; + int16_t ySubscriptXOffset; + int16_t ySubscriptYOffset; + int16_t ySuperscriptXSize; + int16_t ySuperscriptYSize; + int16_t ySuperscriptXOffset; + int16_t ySuperscriptYOffset; + int16_t yStrikeoutSize; + int16_t yStrikeoutPosition; + int16_t sFamilyClass; + uint8_t panose[10]; + uint32_t ulUnicodeRange1; + uint32_t ulUnicodeRange2; + uint32_t ulUnicodeRange3; + uint32_t ulUnicodeRange4; + int8_t achVendID[4]; + uint16_t fsSelection; + uint16_t usFirstCharIndex; + uint16_t usLastCharIndex; + int16_t sTypoAscender; + int16_t sTypoDescender; + int16_t sTypoLineGap; + uint16_t usWinAscent; + uint16_t usWinDescent; + uint32_t ulCodePageRange1; + uint32_t ulCodePageRange2; + int16_t sxHeight; + int16_t sCapHeight; + uint16_t usDefaultChar; + uint16_t usBreakChar; + uint16_t usMaxContext; + uint16_t usLowerOpticalPointSize; + uint16_t usUpperOpticalPointSize; +} +typedef myfont_table_os_2_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_os_2(struct myfont_font *mf); + +int8_t myfont_os_2_panose(struct myfont_font *mf, enum myfont_table_os_2_panose id); + +#endif /* MyFONT_OS_2_H */ diff --git a/source/myfont/pclt.c b/source/myfont/pclt.c new file mode 100644 index 0000000..9feca69 --- /dev/null +++ b/source/myfont/pclt.c @@ -0,0 +1,46 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/pclt.h" + +void myfont_load_table_pclt(struct myfont_font *mf) +{ + if(mf->cache.tables_offset[MyFONT_TKEY_PCLT]) + { + myfont_load_table(mf, &mf->table_pclt, sizeof(int32_t) * 2, MyFONT_TKEY_PCLT); + + fread(&mf->table_pclt.pitch , sizeof(uint32_t) , 6, mf->file_h); + fread(&mf->table_pclt.typeface , sizeof(char) , 16, mf->file_h); + fread(mf->table_pclt.characterComplement , sizeof(char) , 8, mf->file_h); + fread(&mf->table_pclt.fileName , sizeof(char) , 6, mf->file_h); + fread(&mf->table_pclt.strokeWeight , sizeof(char) , 2, mf->file_h); + fread(&mf->table_pclt.serifStyle , sizeof(uint8_t) , 2, mf->file_h); + } + else + { + memset(&mf->table_pclt.pitch , 0, sizeof(uint32_t) * 6); + memset(&mf->table_pclt.typeface , 0, sizeof(char) * 16); + memset(&mf->table_pclt.characterComplement , 0, sizeof(char) * 8); + memset(&mf->table_pclt.fileName , 0, sizeof(char) * 6); + memset(&mf->table_pclt.strokeWeight , 0, sizeof(char) * 2); + memset(&mf->table_pclt.serifStyle , 0, sizeof(uint32_t) * 2); + } +} + diff --git a/source/myfont/pclt.h b/source/myfont/pclt.h new file mode 100644 index 0000000..c90628a --- /dev/null +++ b/source/myfont/pclt.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_PCLT_H +#define MyFONT_PCLT_H +#pragma once + +#include "myfont/myosi.h" + +// table pclt +struct myfont_table_pclt { + int32_t version; + uint32_t fontNumber; + uint16_t pitch; + uint16_t xHeight; + uint16_t style; + uint16_t typeFamily; + uint16_t capHeight; + uint16_t symbolSet; + char typeface[16]; + char characterComplement[8]; + char fileName[6]; + char strokeWeight; + char widthType; + uint8_t serifStyle; + uint8_t reserved; +} +typedef myfont_table_pclt_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_pclt(struct myfont_font *mf); + +#endif /* MyFONT_PCLT_H */ diff --git a/source/myfont/vhea.c b/source/myfont/vhea.c new file mode 100644 index 0000000..b14a810 --- /dev/null +++ b/source/myfont/vhea.c @@ -0,0 +1,50 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/vhea.h" + +void myfont_load_table_vhea(myfont_font_t *mf) +{ + if(mf->cache.tables_offset[MyFONT_TKEY_vhea]) + { + myfont_load_table(mf, &mf->table_vhea, sizeof(myfont_table_vhea_t), MyFONT_TKEY_vhea); + } + else + { + mf->table_vhea.version = 0; + mf->table_vhea.Ascender = 0; + mf->table_vhea.Descender = 0; + mf->table_vhea.LineGap = 0; + mf->table_vhea.advanceHeightMax = 0; + mf->table_vhea.minTopSideBearing = 0; + mf->table_vhea.minBottomSideBearing = 0; + mf->table_vhea.yMaxExtent = 0; + mf->table_vhea.caretSlopeRise = 0; + mf->table_vhea.caretSlopeRun = 0; + mf->table_vhea.caretOffset = 0; + mf->table_vhea.reserved1 = 0; + mf->table_vhea.reserved2 = 0; + mf->table_vhea.reserved3 = 0; + mf->table_vhea.reserved4 = 0; + mf->table_vhea.metricDataFormat = 0; + mf->table_vhea.numOfLongVerMetrics = 0; + } +} + diff --git a/source/myfont/vhea.h b/source/myfont/vhea.h new file mode 100644 index 0000000..b6b91c6 --- /dev/null +++ b/source/myfont/vhea.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_VHEA_H +#define MyFONT_VHEA_H +#pragma once + +#include "myfont/myosi.h" + +// table vhea +struct myfont_table_vhea { + uint32_t version; + int16_t Ascender; + int16_t Descender; + int16_t LineGap; + int16_t advanceHeightMax; + int16_t minTopSideBearing; + int16_t minBottomSideBearing; + int16_t yMaxExtent; + int16_t caretSlopeRise; + int16_t caretSlopeRun; + int16_t caretOffset; + int16_t reserved1; + int16_t reserved2; + int16_t reserved3; + int16_t reserved4; + int16_t metricDataFormat; + uint16_t numOfLongVerMetrics; +} +typedef myfont_table_vhea_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_vhea(struct myfont_font *mf); + +#endif /* MyFONT_VHEA_H */ diff --git a/source/myfont/vmtx.c b/source/myfont/vmtx.c new file mode 100644 index 0000000..14e0364 --- /dev/null +++ b/source/myfont/vmtx.c @@ -0,0 +1,56 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include "myfont/vmtx.h" + +void myfont_load_table_vmtx(myfont_font_t *mf) +{ + uint16_t num_metrics = htons(mf->table_vhea.numOfLongVerMetrics); + + if(num_metrics) + { + myfont_long_ver_metric_t *lver_metric = (myfont_long_ver_metric_t *)malloc(sizeof(myfont_long_ver_metric_t) * num_metrics); + + fseek(mf->file_h, mf->cache.tables_offset[MyFONT_TKEY_vmtx], SEEK_SET); + fread(lver_metric, sizeof(myfont_long_ver_metric_t), num_metrics, mf->file_h); + + mf->table_vmtx.vMetrics = lver_metric; + + uint16_t numOfTSB = htons(mf->table_maxp.numGlyphs - mf->table_vhea.numOfLongVerMetrics); + + if(numOfTSB) + { + int16_t *topSideBearing = (int16_t *)malloc(sizeof(int16_t) * numOfTSB); + fread(topSideBearing, sizeof(int16_t), numOfTSB, mf->file_h); + + mf->table_vmtx.topSideBearing = topSideBearing; + } + else { + mf->table_vmtx.topSideBearing = NULL; + } + } + else + { + mf->table_vmtx.vMetrics = NULL; + mf->table_vmtx.topSideBearing = NULL; + } +} + + diff --git a/source/myfont/vmtx.h b/source/myfont/vmtx.h new file mode 100644 index 0000000..aa3a722 --- /dev/null +++ b/source/myfont/vmtx.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#ifndef MyFONT_VMTX_H +#define MyFONT_VMTX_H +#pragma once + +#include "myfont/myosi.h" + +struct myfont_long_ver_metric { + uint16_t advanceHeight; + int16_t topSideBearing; +} +typedef myfont_long_ver_metric_t; + +// table vmtx +struct myfont_table_vmtx { + myfont_long_ver_metric_t *vMetrics; + int16_t *topSideBearing; +} +typedef myfont_table_vmtx_t; + +#include "myfont/myfont.h" + +struct myfont_font; + +void myfont_load_table_vmtx(struct myfont_font *mf); + +#endif /* MyFONT_VMTX_H */ diff --git a/source/myhtml/api.h b/source/myhtml/api.h index 9bbe049..fed7a73 100644 --- a/source/myhtml/api.h +++ b/source/myhtml/api.h @@ -370,15 +370,7 @@ enum myhtml_tags { // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_t */ enum myhtml_status { MyHTML_STATUS_OK = 0x0000, diff --git a/source/myhtml/myosi.h b/source/myhtml/myosi.h index 9b2da8a..1a09327 100644 --- a/source/myhtml/myosi.h +++ b/source/myhtml/myosi.h @@ -375,15 +375,7 @@ enum myhtml_insertion_mode { // base /* Very important!!! - - for myhtml 0..00ffff; MyHTML_STATUS_OK == 0x000000 - for mycss and modules 010000..01ffff; MyCSS_STATUS_OK == 0x000000 - for modest 020000..02ffff; MODEST_STATUS_OK == 0x000000 - for myrender 030000..03ffff; MyRENDER_STATUS_OK == 0x000000 - for mydom 040000..04ffff; MyDOM_STATUS_OK == 0x000000 - for mynetwork 050000..05ffff; MyNETWORK_STATUS_OK == 0x000000 - for myecma 060000..06ffff; MyECMA_STATUS_OK == 0x000000 - not occupied 070000.. + see modest/myosi.h:modest_status_t */ enum myhtml_status { MyHTML_STATUS_OK = 0x0000, diff --git a/third_party/font/Arkhip.otf b/third_party/font/Arkhip.otf new file mode 100755 index 0000000000000000000000000000000000000000..f9db38fd666828a69f1d4ea449955f37991502a6 GIT binary patch literal 34012 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 literal 0 HcmV?d00001 diff --git a/third_party/font/Arkhip.ttf b/third_party/font/Arkhip.ttf new file mode 100755 index 0000000000000000000000000000000000000000..837bc86fb46e74110144d49b45c26d23ba772a9e GIT binary patch literal 78232 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 literal 0 HcmV?d00001 diff --git a/third_party/font/readme.txt b/third_party/font/readme.txt new file mode 100644 index 0000000..233b319 --- /dev/null +++ b/third_party/font/readme.txt @@ -0,0 +1,2 @@ +Free Font +From: http://arkhipfont.ru/