/* DO NOT EDIT THIS FILE */ /* This file is autogenerated by the text-database code generator */ #include #include #include #include #include #include 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(buffer); const Font** flashFonts = TypedTextDatabase::getFonts(); const GeneratedFont* flashFont = static_cast(flashFonts[fontId]); *font = CachedFont(reinterpret_cast(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(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