mirror of
https://github.com/lexborisov/Modest
synced 2024-11-22 05:41:32 +03:00
275 lines
9.0 KiB
C
275 lines
9.0 KiB
C
/*
|
|
Copyright (C) 2016-2017 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"
|
|
|
|
mystatus_t myfont_load_table_glyf(myfont_font_t* mf, uint8_t* font_data, size_t data_size)
|
|
{
|
|
memset(&mf->table_glyf, 0, sizeof(myfont_table_glyf_t));
|
|
|
|
if(mf->cache.tables_offset[MyFONT_TKEY_glyf] == 0)
|
|
return MyFONT_STATUS_OK;
|
|
|
|
if(mf->table_maxp.numGlyphs == 0)
|
|
return MyFONT_STATUS_OK;
|
|
|
|
myfont_table_glyph_t *glyphs = (myfont_table_glyph_t*)myfont_calloc(mf, mf->table_maxp.numGlyphs, sizeof(myfont_table_glyph_t));
|
|
|
|
if(glyphs == NULL)
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
|
|
|
for(uint16_t i = 0; i < mf->table_maxp.numGlyphs; i++)
|
|
{
|
|
uint32_t offset = mf->cache.tables_offset[MyFONT_TKEY_glyf] + mf->table_loca.offsets[i];
|
|
mystatus_t status = myfont_glyf_load_data(mf, &glyphs[i], font_data, data_size, offset);
|
|
|
|
if(status)
|
|
return status;
|
|
}
|
|
|
|
mf->table_glyf.cache = glyphs;
|
|
|
|
return MyFONT_STATUS_OK;
|
|
}
|
|
|
|
mystatus_t myfont_glyf_load(myfont_font_t *mf, myfont_table_glyph_t *glyph, uint8_t* font_data, size_t data_size, uint16_t glyph_index)
|
|
{
|
|
memset(glyph, 0, sizeof(myfont_table_glyph_t));
|
|
|
|
if(mf->table_maxp.numGlyphs == 0)
|
|
return MyFONT_STATUS_OK;
|
|
|
|
uint16_t offset = myfont_loca_get_offset(mf, glyph_index);
|
|
offset += mf->cache.tables_offset[MyFONT_TKEY_glyf];
|
|
|
|
return myfont_glyf_load_data(mf, glyph, font_data, data_size, offset);
|
|
}
|
|
|
|
mystatus_t myfont_glyf_load_data(myfont_font_t *mf, myfont_table_glyph_t *glyph, uint8_t* font_data, size_t data_size, uint32_t offset)
|
|
{
|
|
memset(&glyph->head, 0, sizeof(myfont_table_glyf_head_t));
|
|
|
|
/* get current data */
|
|
uint8_t *data = &font_data[offset];
|
|
|
|
// load head
|
|
offset += 10;
|
|
if(offset > data_size)
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
|
|
glyph->head.numberOfContours = myfont_read_16(&data);
|
|
glyph->head.xMin = myfont_read_16(&data);
|
|
glyph->head.yMin = myfont_read_16(&data);
|
|
glyph->head.xMax = myfont_read_16(&data);
|
|
glyph->head.yMax = myfont_read_16(&data);
|
|
|
|
if(glyph->head.numberOfContours > 0)
|
|
return myfont_glyf_load_simple(mf, glyph, data, data_size, offset);
|
|
|
|
return MyFONT_STATUS_OK;
|
|
}
|
|
|
|
mystatus_t myfont_glyf_load_simple(myfont_font_t *mf, myfont_table_glyph_t *glyph, uint8_t *data, size_t data_size, uint32_t offset)
|
|
{
|
|
uint16_t *endPtsOfContours = (uint16_t *)myfont_calloc(mf, glyph->head.numberOfContours, sizeof(uint16_t));
|
|
|
|
if(endPtsOfContours == NULL)
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
|
|
|
offset = offset + (glyph->head.numberOfContours * 2) + 2;
|
|
|
|
if(offset > data_size)
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
|
|
for(uint16_t i = 0; i < glyph->head.numberOfContours; i++) {
|
|
endPtsOfContours[i] = myfont_read_u16(&data);
|
|
}
|
|
|
|
glyph->simple.endPtsOfContours = endPtsOfContours;
|
|
glyph->simple.instructionLength = myfont_read_u16(&data);
|
|
glyph->pointCount = endPtsOfContours[(glyph->head.numberOfContours - 1)] + 1;
|
|
|
|
/* instruction */
|
|
offset += glyph->simple.instructionLength;
|
|
if(offset > data_size)
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
|
|
if(glyph->simple.instructionLength) {
|
|
glyph->simple.instructions = (uint8_t *)myfont_calloc(mf, glyph->simple.instructionLength, sizeof(uint8_t));
|
|
|
|
if(glyph->simple.instructions == NULL)
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
|
|
|
memcpy(glyph->simple.instructions, data, glyph->simple.instructionLength);
|
|
data += glyph->simple.instructionLength;
|
|
}
|
|
|
|
return myfont_glyf_load_simple_flags(mf, glyph, data, data_size, offset);
|
|
}
|
|
|
|
mystatus_t myfont_glyf_load_simple_flags(myfont_font_t *mf, myfont_table_glyph_t *glyph, uint8_t *data, size_t data_size, uint32_t offset)
|
|
{
|
|
uint8_t *flags = (uint8_t *)myfont_calloc(mf, glyph->pointCount, sizeof(uint8_t));
|
|
|
|
if(flags == NULL)
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
|
|
|
uint16_t i = 0;
|
|
while(i < glyph->pointCount)
|
|
{
|
|
if(offset >= data_size) {
|
|
myfont_free(mf, flags);
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
}
|
|
|
|
flags[i] = myfont_read_u8(&data); offset++;
|
|
|
|
if(flags[i] & MyFONT_GLYF_SML_FLAGS_repeat)
|
|
{
|
|
if(offset >= data_size) {
|
|
myfont_free(mf, flags);
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
}
|
|
|
|
uint8_t repeat = myfont_read_u8(&data); offset++;
|
|
uint8_t curr = flags[i];
|
|
|
|
if(repeat > (glyph->pointCount - i)) {
|
|
myfont_free(mf, flags);
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
}
|
|
|
|
while(repeat--) {
|
|
i++;
|
|
|
|
flags[i] = curr;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
glyph->simple.flags = flags;
|
|
|
|
return myfont_glyf_load_simple_coordinates(mf, glyph, data, data_size, offset);
|
|
}
|
|
|
|
mystatus_t myfont_glyf_load_simple_coordinates(myfont_font_t *mf, myfont_table_glyph_t *glyph, uint8_t *data, size_t data_size, uint32_t offset)
|
|
{
|
|
/* alloc resources */
|
|
int16_t *xCoordinates = (int16_t *)myfont_calloc(mf, glyph->pointCount, sizeof(int16_t));
|
|
if(xCoordinates == NULL)
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
|
|
|
int16_t *yCoordinates = (int16_t *)myfont_calloc(mf, glyph->pointCount, sizeof(int16_t));
|
|
if(yCoordinates == NULL) {
|
|
myfont_free(mf, xCoordinates);
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
|
}
|
|
|
|
uint8_t *flags = glyph->simple.flags;
|
|
|
|
int32_t in_before = 0;
|
|
|
|
for(uint16_t i = 0; i < glyph->pointCount; i++)
|
|
{
|
|
if(flags[i] & MyFONT_GLYF_SML_FLAGS_x_ShortVector)
|
|
{
|
|
if(offset >= data_size) {
|
|
myfont_free(mf, xCoordinates);
|
|
myfont_free(mf, yCoordinates);
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
}
|
|
|
|
if(flags[i] & MyFONT_GLYF_SML_FLAGS_p_x_ShortVector) {
|
|
xCoordinates[i] = in_before + myfont_read_u8(&data); offset++;
|
|
}
|
|
else {
|
|
xCoordinates[i] = in_before - myfont_read_u8(&data); offset++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
offset++;
|
|
|
|
if(offset >= data_size) {
|
|
myfont_free(mf, xCoordinates);
|
|
myfont_free(mf, yCoordinates);
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
}
|
|
|
|
if(flags[i] & MyFONT_GLYF_SML_FLAGS_p_x_ShortVector) {
|
|
xCoordinates[i] = in_before;
|
|
}
|
|
else {
|
|
xCoordinates[i] = in_before + myfont_read_16(&data); offset++;
|
|
}
|
|
}
|
|
|
|
in_before = xCoordinates[i];
|
|
}
|
|
|
|
in_before = 0;
|
|
|
|
for(uint16_t i = 0; i < glyph->pointCount; i++)
|
|
{
|
|
if(flags[i] & MyFONT_GLYF_SML_FLAGS_y_ShortVector)
|
|
{
|
|
if(offset >= data_size) {
|
|
myfont_free(mf, xCoordinates);
|
|
myfont_free(mf, yCoordinates);
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
}
|
|
|
|
if(flags[i] & MyFONT_GLYF_SML_FLAGS_p_y_ShortVector) {
|
|
yCoordinates[i] = in_before + myfont_read_u8(&data); offset++;
|
|
}
|
|
else {
|
|
yCoordinates[i] = in_before - myfont_read_u8(&data); offset++;
|
|
}
|
|
}
|
|
else {
|
|
offset++;
|
|
|
|
if(offset >= data_size) {
|
|
myfont_free(mf, xCoordinates);
|
|
myfont_free(mf, yCoordinates);
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
}
|
|
|
|
if(flags[i] & MyFONT_GLYF_SML_FLAGS_p_y_ShortVector) {
|
|
yCoordinates[i] = in_before;
|
|
}
|
|
else {
|
|
yCoordinates[i] = in_before + myfont_read_16(&data); offset += 2;
|
|
}
|
|
}
|
|
|
|
in_before = yCoordinates[i];
|
|
}
|
|
|
|
glyph->simple.xCoordinates = xCoordinates;
|
|
glyph->simple.yCoordinates = yCoordinates;
|
|
|
|
return MyFONT_STATUS_OK;
|
|
}
|
|
|
|
|