/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */

#include <fonts/GeneratedFont.hpp>
#include <math.h>

namespace touchgfx
{
GeneratedFont::GeneratedFont(const GlyphNode* glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, uint8_t bitsPerPixel, uint8_t byteAlignRow, uint8_t maxLeft, uint8_t maxRight, const uint8_t* const* glyphDataInternalFlash, const KerningNode* kerningList, const Unicode::UnicodeChar fallbackChar, const Unicode::UnicodeChar ellipsisChar, const uint16_t* const gsubData, const FontContextualFormsTable* formsTable)
    : ConstFont(glyphs, numGlyphs, height, baseline, pixAboveTop, pixBelowBottom, bitsPerPixel, byteAlignRow, maxLeft, maxRight, fallbackChar, ellipsisChar),
      glyphData(glyphDataInternalFlash),
      kerningData(kerningList),
      gsubTable(gsubData),
      arabicTable(formsTable)
{
}

const uint8_t* GeneratedFont::getPixelData(const GlyphNode* glyph) const
{
    const uint8_t* const* table = (const uint8_t* const*)glyphData;
    return &(table[glyph->unicode / 2048][glyph->dataOffset]);
}

int8_t GeneratedFont::getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const
{
    if (!glyph || glyph->kerningTableSize == 0)
    {
        return 0;
    }

    const KerningNode* kerndata = kerningData + glyph->kerningTablePos();
    for (uint16_t i = glyph->kerningTableSize; i > 0; i--, kerndata++)
    {
        if (prevChar == kerndata->unicodePrevChar)
        {
            return kerndata->distance;
        }
        if (prevChar < kerndata->unicodePrevChar)
        {
            break;
        }
    }
    return 0;
}

const GlyphNode* FusedFont::getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const
{
    if (unicode < 0xAC00 || unicode > 0xD7A3)
    {
        return GeneratedFont::getGlyph(unicode, pixelData, bitsPerPixel);
    }
    else
    {
        fusedNode.unicode = unicode;
        bitsPerPixel = 1;
        pixelData = 0;
        return const_cast<const GlyphNode*>(&fusedNode);
    }
}

GlyphNode GeneratedVectorFont::glyphNode; // Static member

GeneratedVectorFont::GeneratedVectorFont(uint16_t baseline, float scale, const VectorFontNode* vectorGlyphs, const VectorFontData& fontData,
                                         const uint16_t* const* glyphData, const VectorKerningNode* kerning,
                                         const uint16_t* const gsubData, const FontContextualFormsTable* formsTable)
 : Font((int)ceilf((fontData.maxBelowBottom + fontData.baselineHeight) * scale), baseline,
        (uint8_t)ceilf(fontData.maxAboveTop * scale),
        (uint8_t)ceilf(fontData.maxBelowBottom * scale), 0 /*bitsPerPixel*/, 0 /*byteAlignRow*/,
        (uint8_t)ceilf(fontData.maxLeft * scale),
        (uint8_t)ceilf(fontData.maxRight * scale),
        fontData.fallbackChar,
        fontData.ellipsisChar),
   scaleFactor(scale), vectorNodes(vectorGlyphs), vectorTable(glyphData), kerningTable(kerning),
   arabicTable(formsTable), numberOfGlyphs(fontData.numberOfGlyphs)
{
    if (gsubData[0] != 0)
    {
        gsubTable = gsubData;
    }
    else
    {
        gsubTable = 0;
    }
}

const GlyphNode* GeneratedVectorFont::getGlyph(Unicode::UnicodeChar unicode) const
{
    const VectorFontNode* const node = find(unicode);
    if (node == 0)
    {
        return 0;
    }
    else
    {
        return getGlyphNode(node);
    }
}

const GlyphNode* GeneratedVectorFont::getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const
{
    const VectorFontNode* const node = find(unicode);
    if (node == 0)
    {
        return 0;
    }
    else
    {
        const uint16_t* contourData = &(vectorTable[unicode / 2048][node->dataOffset]);
        pixelData = (const uint8_t*)contourData;
        bitsPerPixel = 0xFF;
        return getGlyphNode(node);
    }
}

const GlyphNode* GeneratedVectorFont::getGlyphNode(const VectorFontNode* node) const
{
    glyphNode.dataOffset = 0;
    uint8_t flags = 0;

    //Convert data from VectorFontNode to glyphNode using scaleFactor
    glyphNode.unicode = node->unicode;

    const int width = (node->width == 0) ? 0 : ((int)ceilf(node->width * scaleFactor) + 1);
    glyphNode._width = width; // Save low 8 bit
    // Set flags bits for values above 8 bit
    if (width > 255)
    {
        flags |= GLYPH_DATA_WIDTH_BIT8;
    }

    const int height = (int)ceilf(node->height * scaleFactor);
    glyphNode._height = height;
    if (height > 255)
    {
        flags |= GLYPH_DATA_HEIGHT_BIT8;
    }

    const int top = (int)ceilf(node->top * scaleFactor);
    glyphNode._top = top;
    if (top > 255)
    {
        flags |= ((top & 0x300) >> 3); // GLYPH_DATA_TOP_BIT8 + 9
    }

    const int left = (int)(node->left * scaleFactor);
    glyphNode.left = left;

    const int advance = (int)(node->advance * scaleFactor + 0.5f);
    glyphNode._advance = advance;
    if (advance > 255)
    {
        flags |= GLYPH_DATA_ADVANCE_BIT8;
    }

    glyphNode._kerningTablePos = (uint8_t)node->kerningTablePos;
    if (node->kerningTablePos > 255)
    {
        flags |= (node->kerningTablePos >> 8) & GLYPH_DATA_KERNINGTABLEPOS_BIT8_10;
    }

    glyphNode.kerningTableSize = node->kerningTableSize;

    glyphNode.flags = flags;

    return &glyphNode;
}

int8_t GeneratedVectorFont::getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const
{
    if (!glyph || glyph->kerningTableSize == 0)
    {
        return 0;
    }

    const VectorKerningNode* kerndata = kerningTable + glyph->kerningTablePos();
    for (uint16_t i = glyph->kerningTableSize; i > 0; i--, kerndata++)
    {
        if (prevChar == kerndata->unicodePrevChar)
        {
            const float scaledDistance = kerndata->distance * scaleFactor;
            return (int)(scaledDistance >= 0.0f ? (scaledDistance + 0.5f) : (scaledDistance - 0.5f));
        }
        if (prevChar < kerndata->unicodePrevChar)
        {
            break;
        }
    }
    return 0;
}

const VectorFontNode* GeneratedVectorFont::find(Unicode::UnicodeChar unicode) const
{
    // Some fonts does not have a glyphList. Cannot be searched...
    if (vectorNodes == 0)
    {
        return 0;
    }

    int32_t min = 0;
    int32_t max = numberOfGlyphs - 1;

    int32_t mid = min + (unicode - vectorNodes[min].unicode); // Linear up from [min].unicode
    if (mid < min)
    {
        // Unicode < [min].unicode => not found
        return (VectorFontNode*)0;
    }
    if (mid > max)
    {
        // Linear up ends too high
        mid = max - (vectorNodes[max].unicode - unicode); // Linear down from [max].unicode
        if (mid > max)
        {
            // Unicode > [max].unicode => not found
            return (VectorFontNode*)0;
        }
        if (mid < min)
        {
            // Linear down ends too low, take the middle element
            mid = (min + max) / 2;
        }
    }
    while (min <= max)
    {
        const Unicode::UnicodeChar midUnicode = vectorNodes[mid].unicode;
        if (unicode == midUnicode)
        {
            // Found at [mid]
            return vectorNodes + mid;
        }
        if (unicode < midUnicode)
        {
            // Unicode is in lower half
            max = mid - 1;
            if (max < min)
            {
                // Range is empty => not found
                break;
            }
            // We adjusted max, try linear down from [max].unicode
            mid = max - (vectorNodes[max].unicode - unicode);
            if (mid > max)
            {
                // Unicode > [max].unicode => not found
                break;
            }
            if (mid < min)
            {
                // Linear down ends too low, take the middle element
                mid = (min + max) / 2;
            }
        }
        else
        {
            // Unicode is in upper half
            min = mid + 1;
            if (min > max)
            {
                // Range is empty => not found
                break;
            }
            // We adjusted min, try linear up from [min].unicode
            mid = min + (unicode - vectorNodes[min].unicode);
            if (mid < min)
            {
                // Unicode < [min].unicode => not found
                break;
            }
            if (mid > max)
            {
                // Linear up ends too high, take the middle element
                mid = (min + max) / 2;
            }
        }
    }
    return (VectorFontNode*)0;
}

} // namespace touchgfx
