steering-wheel/Middlewares/ST/touchgfx/framework/tools/textconvert/Templates/FontCache.cpp.temp

426 lines
12 KiB
Plaintext
Raw Normal View History

2023-03-06 21:21:00 +01:00
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <cstring>
#include <touchgfx/TextProvider.hpp>
#include <touchgfx/Utils.hpp>
#include <fonts/CachedFont.hpp>
#include <fonts/FontCache.hpp>
#include <texts/TypedTextDatabase.hpp>
namespace touchgfx
{
FontCache::FontCache()
: memorySize(0), memory(0), top(0), gsubStart(0), reader(0)
{
}
void FontCache::clear(bool keepGsubOrContextTable /* = false */)
{
memset(fontTable, 0, sizeof(fontTable));
// Top is beginning of memory, no glyphs are cached yet
top = memory;
if (!keepGsubOrContextTable)
{
// gsubStart points to end of memory (nothing loaded yet)
gsubStart = memory + memorySize;
// Round down to 32bit address
gsubStart = (uint8_t*)((uintptr_t)gsubStart & ~(uintptr_t)0x3);
}
}
void FontCache::setMemory(uint8_t* _memory, uint32_t size)
{
memory = _memory;
memorySize = size;
clear();
}
void FontCache::setReader(FontDataReader* _reader)
{
reader = _reader;
}
const GlyphNode* FontCache::getGlyph(Unicode::UnicodeChar unicode, FontId font) const
{
GlyphNode* g = (GlyphNode*)fontTable[font].first;
while (g)
{
if (g->unicode == unicode)
{
return g;
}
GlyphNode** next = (GlyphNode**)((uint8_t*)g + SizeGlyphNode);
g = *next;
}
return 0;
}
void FontCache::open()
{
if (reader)
{
reader->open();
}
}
void FontCache::close()
{
if (reader)
{
reader->close();
}
}
void FontCache::initializeCachedFont(TypedText t, CachedFont* font, bool loadGsubOrContextTable /*= false*/)
{
// Get font index from typed text
FontId fontId = t.getFontId();
// Reset to start of file
open();
setPosition(0);
assert(sizeof(touchgfx::BinaryFontData) < MAX_BUFFER_SIZE);
readData(buffer, sizeof(touchgfx::BinaryFontData));
const struct touchgfx::BinaryFontData* binaryFontData = reinterpret_cast<const struct touchgfx::BinaryFontData*>(buffer);
const Font** flashFonts = TypedTextDatabase::getFonts();
const GeneratedFont* flashFont = static_cast<const GeneratedFont*>(flashFonts[fontId]);
*font = CachedFont(reinterpret_cast<const struct touchgfx::BinaryFontData*>(buffer), fontId, this, flashFont);
if (loadGsubOrContextTable && (binaryFontData->offsetToGSUB != 0))
{
setPosition(binaryFontData->offsetToGSUB);
const uint32_t sizeOfGSUB = (binaryFontData->offsetToArabicTable != 0 ? binaryFontData->offsetToArabicTable : binaryFontData->sizeOfFontData) - binaryFontData->offsetToGSUB;
if (top + sizeOfGSUB < gsubStart) // Room for this GSUB table
{
uint8_t* const gsubPosition = gsubStart - sizeOfGSUB;
readData(gsubPosition, sizeOfGSUB);
font->setGSUBTable(reinterpret_cast<uint16_t*>(gsubPosition));
gsubStart -= sizeOfGSUB;
// Round down to 32bit address
gsubStart = (uint8_t*)((uintptr_t)gsubStart & ~(uintptr_t)0x3);
}
else
{
font->setGSUBTable(0);
}
}
if (loadGsubOrContextTable && (binaryFontData->offsetToArabicTable != 0))
{
setPosition(binaryFontData->offsetToArabicTable);
const uint32_t sizeTableData = binaryFontData->sizeOfFontData - binaryFontData->offsetToArabicTable;
if (top + sizeTableData + sizeof(FontContextualFormsTable) < gsubStart) // Room for the ContextualFormsTables
{
// Allocate FontContextualFormsTable first
gsubStart -= sizeof(FontContextualFormsTable);
// Round down to 32bit address
gsubStart = (uint8_t*)((uintptr_t)gsubStart & ~(uintptr_t)0x3);
FontContextualFormsTable* table = (FontContextualFormsTable*)gsubStart;
font->setContextualFormsTable(table);
gsubStart -= sizeTableData;
readData(gsubStart, sizeTableData);
// Set pointers in table
const uint16_t* const base = (const uint16_t*)gsubStart;
// First elements in binary font are offsets to arrays in 16bit words
table->contextualForms4Long = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[0]);
table->contextualForms3Long = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[1]);
table->contextualForms2Long = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[2]);
table->contextualForms0621_063a = (FontContextualFormsTable::arrayOf4UnicodesPtr)(base + base[3]);
table->contextualForms0641_064a = (FontContextualFormsTable::arrayOf4UnicodesPtr)(base + base[4]);
table->contextualForms06XX = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[5]);
table->contextualForms4LongSize = base[6];
table->contextualForms3LongSize = base[7];
table->contextualForms2LongSize = base[8];
table->contextualForms06XXSize = base[9];
}
else
{
font->setContextualFormsTable(0);
}
}
close();
}
bool FontCache::cacheString(TypedText t, const Unicode::UnicodeChar* string)
{
open();
if (!createSortedString(string))
{
close();
return false;
}
const bool result = cacheSortedString(t);
close();
return result;
}
bool FontCache::cacheLigatures(CachedFont* font, TypedText t, const Unicode::UnicodeChar* string)
{
open();
if (!createSortedLigatures(font, t, string, 0, 0))
{
close();
return false;
}
const bool result = cacheSortedString(t);
close();
return result;
}
bool FontCache::cacheSortedString(TypedText t)
{
setPosition(8); // Skip font index and size
uint32_t glyphNodeOffset;
uint32_t dummy;
readData(&glyphNodeOffset, sizeof(uint32_t)); // offsetToTable
readData(&dummy, sizeof(uint32_t)); // offsetToKerning
readData(&glyphDataOffset, sizeof(uint32_t)); // offsetToGlyphs
readData(&dummy, sizeof(uint32_t)); // offsetToGlyphs
readData(&dummy, sizeof(uint32_t)); // offsetToArabicTable
readData(&numGlyphs, sizeof(uint16_t)); // numberOfGlyphs
FontId fontId = t.getFontId(); // Get font index from typed text
uint32_t bpp = t.getFont()->getBitsPerPixel(); // Get BPP from standard font
setPosition(glyphNodeOffset); // Go to glyph nodes for font
currentFileGlyphNumber = 0;
currentFileGlyphNode.unicode = 0; // Force reading of first glyph
const Unicode::UnicodeChar* string = sortedString;
Unicode::UnicodeChar last = 0;
GlyphNode* firstNewGlyph = 0;
bool outOfMemory = false;
while (*string)
{
Unicode::UnicodeChar ch = *string;
if (ch != last)
{
if (!contains(ch, fontId))
{
insert(ch, fontId, bpp, outOfMemory);
if (outOfMemory)
{
break;
}
if (firstNewGlyph == 0)
{
firstNewGlyph = (GlyphNode*)fontTable[fontId].last;
}
}
}
last = ch;
string++;
}
cacheData(bpp, firstNewGlyph);
return !outOfMemory;
}
bool FontCache::contains(Unicode::UnicodeChar unicode, FontId font) const
{
GlyphNode* g = (GlyphNode*)fontTable[font].first;
while (g)
{
if (g->unicode == unicode)
{
return true;
}
GlyphNode** next = (GlyphNode**)((uint8_t*)g + SizeGlyphNode);
g = *next;
}
return false;
}
void FontCache::insert(Unicode::UnicodeChar unicode, FontId font, uint32_t bpp, bool& outOfMemory)
{
// Insert new glyphnode and glyph after last for font.
uint8_t* oldTop = top;
top = copyGlyph(top, unicode, font, bpp, outOfMemory);
if (top == oldTop)
{
return;
}
if (fontTable[font].last == 0)
{
// First glyph
fontTable[font].first = oldTop;
fontTable[font].last = oldTop;
}
else
{
// Set next pointer of old last glyph
uint8_t** old_next = (uint8_t**)(fontTable[font].last + SizeGlyphNode);
*old_next = oldTop;
// Save new glyph as last glyph
fontTable[font].last = oldTop;
}
}
uint8_t* FontCache::copyGlyph(uint8_t* top, Unicode::UnicodeChar unicode, FontId font, uint32_t bpp, bool& outOfMemory)
{
while (currentFileGlyphNumber < numGlyphs && currentFileGlyphNode.unicode < unicode)
{
readData(&currentFileGlyphNode, sizeof(GlyphNode));
currentFileGlyphNumber++;
}
if (currentFileGlyphNode.unicode != unicode)
{
// GlyphNode not found
return top;
}
// GlyphNode found
uint32_t glyphSize = ((currentFileGlyphNode.width() + 1) & ~1) * currentFileGlyphNode.height() * bpp / 8;
glyphSize = (glyphSize + 3) & ~0x03;
uint32_t requiredMem = SizeGlyphNode + 4 + glyphSize; // GlyphNode + next ptr + glyph
// Is space available before sortedString
if (top + requiredMem > (uint8_t*)sortedString)
{
outOfMemory = true;
return top;
}
*(GlyphNode*)top = currentFileGlyphNode;
// Clear next pointer
uint8_t** next = (uint8_t**)(top + SizeGlyphNode);
*next = 0;
top += requiredMem;
return top;
}
void FontCache::cacheData(uint32_t bpp, GlyphNode* first)
{
GlyphNode* gn = first;
while (gn)
{
uint8_t* p = (uint8_t*)gn;
if (gn->dataOffset != 0xFFFFFFFF)
{
p += SizeGlyphNode;
// Next pointer
p += 4;
// Seek and copy
setPosition(glyphDataOffset + gn->dataOffset);
uint32_t glyphSize = ((gn->width() + 1) & ~1) * gn->height() * bpp / 8;
readData(p, glyphSize);
// Mark glyphNode as cached
gn->dataOffset = 0xFFFFFFFF;
}
GlyphNode** next = (GlyphNode**)((uint8_t*)gn + SizeGlyphNode);
gn = *next;
}
}
bool FontCache::createSortedString(const Unicode::UnicodeChar* string)
{
int length = Unicode::strlen(string);
// Sorted string is allocated at end of buffer
sortedString = (Unicode::UnicodeChar*)(gsubStart - (length + 1) * 2);
if ((uint8_t*)sortedString < top)
{
// Unable to allocate string buffer in end of memory
return false;
}
int n = 0;
Unicode::UnicodeChar* uc = sortedString;
while (*string)
{
*uc++ = *string++;
n++;
}
*uc = 0;
return sortSortedString(n);
}
bool FontCache::createSortedLigatures(CachedFont* font, TypedText t, const Unicode::UnicodeChar* string, ...)
{
va_list pArg;
va_start(pArg, string);
TextProvider tp;
tp.initialize(string, pArg, font->getGSUBTable(), font->getContextualFormsTable());
va_end(pArg);
Unicode::UnicodeChar ligature;
sortedString = (Unicode::UnicodeChar*)(gsubStart);
if ((uint8_t*)(sortedString - 1) < top)
{
return false;
}
*--sortedString = 0;
int n = 0;
while ((ligature = tp.getNextLigature(t.getTextDirection())) != 0)
{
if ((uint8_t*)(sortedString - 1) < top)
{
return false;
}
*--sortedString = ligature;
n++;
}
return sortSortedString(n);
}
bool FontCache::sortSortedString(int n)
{
Unicode::UnicodeChar* uc = sortedString;
for (int i = 0; i < n - 1; i++)
{
bool swapped = false;
for (int j = 0; j < n - i - 1; j++)
{
if (uc[j] > uc[j + 1])
{
Unicode::UnicodeChar temp = uc[j];
uc[j] = uc[j + 1];
uc[j + 1] = temp;
swapped = true;
}
}
// If no two elements were swapped by inner loop, then break
if (!swapped)
{
break;
}
}
return true;
}
void FontCache::setPosition(uint32_t position)
{
if (reader)
{
reader->setPosition(position);
}
}
void FontCache::readData(void* out, uint32_t numberOfBytes)
{
if (reader)
{
reader->readData(out, numberOfBytes);
}
}
} // namespace touchgfx