426 lines
12 KiB
Plaintext
426 lines
12 KiB
Plaintext
/* 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(¤tFileGlyphNode, 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
|