/* 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 keepGsubTable /* = false */) { memset(fontTable, 0, sizeof(fontTable)); //top is beginning of memory, no glyphs are cached yet top = memory; if (!keepGsubTable) { //gsubStart points to end of memory (nothing loaded yet) gsubStart = memory + memorySize; } } 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 loadGsubTable /*= 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 (loadGsubTable) { setPosition(binaryFontData->offsetToGSUB); const uint32_t sizeOfGSUB = 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; } else { font->setGSUBTable(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)); readData(&dummy, sizeof(uint32_t)); readData(&glyphDataOffset, sizeof(uint32_t)); readData(&dummy, sizeof(uint32_t)); readData(&numGlyphs, sizeof(uint16_t)); 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()); 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