add screen library
This commit is contained in:
		| @@ -0,0 +1,28 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #include <fonts/ApplicationFontProvider.hpp> | ||||
| #include <fonts/GeneratedFont.hpp> | ||||
| #include <texts/TypedTextDatabase.hpp> | ||||
| <% if save_flashreader %> | ||||
|  | ||||
| touchgfx::FlashDataReader* ApplicationFontProvider::fontFlashReader = 0; | ||||
| <% end %> | ||||
|  | ||||
| touchgfx::Font* ApplicationFontProvider::getFont(touchgfx::FontId typography) | ||||
| { | ||||
| <% if typographies.empty? %> | ||||
|     return 0; | ||||
| <% else %> | ||||
|     switch (typography) | ||||
|     { | ||||
| <% typographies.each_with_index do |typography, index| %> | ||||
|     case Typography::<%= typography.name.upcase %>: | ||||
|         // <%= typography.cpp_name %>_<%= typography.font_size %>_<%= typography.bpp %>bpp | ||||
|         return const_cast<touchgfx::Font*>(TypedTextDatabase::getFonts()[<%= font_index(index) %>]); | ||||
| <% end %> | ||||
|     default: | ||||
|         return 0; | ||||
|     } | ||||
| <% end %> | ||||
| } | ||||
| @@ -0,0 +1,45 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #ifndef APPLICATIONFONTPROVIDER_HPP | ||||
| #define APPLICATIONFONTPROVIDER_HPP | ||||
|  | ||||
| #include <touchgfx/FontManager.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
|     class FlashDataReader; | ||||
| } | ||||
|  | ||||
| struct Typography | ||||
| { | ||||
| <% typographies.each_with_index do |typography, index| %> | ||||
|     static const touchgfx::FontId <%= typography.name.upcase %> = <%= index %>; | ||||
| <% end %> | ||||
| }; | ||||
|  | ||||
| struct TypographyFontIndex | ||||
| { | ||||
| <% typographies.each_with_index do |typography, index| %> | ||||
|     static const touchgfx::FontId <%= typography.name.upcase %> = <%= font_index(index) %>; <%= font_comment(index) %> | ||||
| <% end %> | ||||
|     static const uint16_t NUMBER_OF_FONTS = <%= max_font_index %>; | ||||
| }; | ||||
|  | ||||
| class ApplicationFontProvider : public touchgfx::FontProvider | ||||
| { | ||||
| public: | ||||
|     virtual touchgfx::Font* getFont(touchgfx::FontId typography); | ||||
|  | ||||
| <% if save_flashreader %> | ||||
|     static void setFlashReader(touchgfx::FlashDataReader* flashReader) { fontFlashReader = flashReader; } | ||||
|     static touchgfx::FlashDataReader* getFlashReader() { return fontFlashReader; } | ||||
| private: | ||||
|     static touchgfx::FlashDataReader* fontFlashReader; | ||||
| <% else %> | ||||
|     static void setFlashReader(touchgfx::FlashDataReader* /* flashReader */) { } | ||||
|     static touchgfx::FlashDataReader* getFlashReader() { return 0; } | ||||
| <% end %> | ||||
| }; | ||||
|  | ||||
| #endif // APPLICATIONFONTPROVIDER_HPP | ||||
| @@ -0,0 +1,58 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #include <fonts/CachedFont.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
| const uint8_t* CachedFont::getPixelData(const GlyphNode* glyph) const | ||||
| { | ||||
|     //if glyph is cached, then data is present just after the GlyphNode | ||||
|     if (FontCache::isCached(glyph)) | ||||
|     { | ||||
|         const uint8_t* data = FontCache::getPixelData(glyph); | ||||
|         return data; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return flashFont->getPixelData(glyph); | ||||
|     } | ||||
| } | ||||
|  | ||||
| const GlyphNode* CachedFont::getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const | ||||
| { | ||||
|     //look first in internal flash font | ||||
|     const GlyphNode* n = flashFont->find(unicode); | ||||
|  | ||||
|     if ((n == 0) && (cache != 0)) | ||||
|     { | ||||
|         //now look in FontCache table | ||||
|         n = cache->getGlyph(unicode, fontId); | ||||
|     } | ||||
|  | ||||
|     //revert to normal behaviour if still not found | ||||
|     if (n == 0 && unicode != 0 && unicode != '\n') | ||||
|     { | ||||
|         Unicode::UnicodeChar fallbackChar = flashFont->getFallbackChar(); | ||||
|         n = flashFont->find(fallbackChar); | ||||
|         if (n == 0) | ||||
|         { | ||||
|             n = cache->getGlyph(fallbackChar, fontId); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (n != 0) | ||||
|     { | ||||
|         pixelData = getPixelData(n); | ||||
|         bitsPerPixel = getBitsPerPixel(); | ||||
|         return n; | ||||
|     } | ||||
|     return (const GlyphNode*)0; | ||||
| } | ||||
|  | ||||
| int8_t CachedFont::getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const | ||||
| { | ||||
|     //Kerning is not supported by Font Caching | ||||
|     return 0; | ||||
| } | ||||
| } | ||||
| @@ -0,0 +1,71 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #ifndef CACHEDFONT_HPP | ||||
| #define CACHEDFONT_HPP | ||||
|  | ||||
| #include <fonts/GeneratedFont.hpp> | ||||
| #include <fonts/FontCache.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
| class CachedFont : public GeneratedFont | ||||
| { | ||||
| public: | ||||
|     CachedFont(const struct touchgfx::BinaryFontData* data, FontId id, FontCache* _cache, const GeneratedFont* _flashFont) | ||||
|         : GeneratedFont(0, //GlyphNode* | ||||
|                         data->numberOfGlyphs, | ||||
|                         data->height, | ||||
|                         data->pixBelowBase, | ||||
|                         data->bitsPerPixel, | ||||
|                         data->byteAlignRow, | ||||
|                         data->maxLeft, | ||||
|                         data->maxRight, | ||||
|                         0, //glyphDataPointer | ||||
|                         0, //Kerning table not used for cached font | ||||
|                         data->fallbackChar, | ||||
|                         data->ellipsisChar, | ||||
|                         0), //gsubTablePointer | ||||
|           fontId(id), | ||||
|           cache(_cache), | ||||
|           flashFont(_flashFont) | ||||
|     {} | ||||
|  | ||||
|     CachedFont() : GeneratedFont() {} | ||||
|  | ||||
|     using GeneratedFont::getGlyph; | ||||
|  | ||||
|     virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const; | ||||
|  | ||||
|     virtual const uint8_t* getPixelData(const GlyphNode* glyph) const; | ||||
|  | ||||
|     virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const; | ||||
|  | ||||
|     void setFontCache(FontCache& cache); | ||||
|     FontId getFontId() const | ||||
|     { | ||||
|         return fontId; | ||||
|     } | ||||
|  | ||||
|     virtual const uint16_t* getGSUBTable() const | ||||
|     { | ||||
|         if (gsubTable != 0) | ||||
|         { | ||||
|             return gsubTable; | ||||
|         } | ||||
|         return flashFont->getGSUBTable(); | ||||
|     } | ||||
|  | ||||
|     virtual void setGSUBTable(const uint16_t* table) | ||||
|     { | ||||
|         gsubTable = table; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     FontId fontId; | ||||
|     FontCache* cache; | ||||
|     const GeneratedFont* flashFont; | ||||
| }; | ||||
| } // namespace touchgfx | ||||
|  | ||||
| #endif // CACHEDFONT_HPP | ||||
| @@ -0,0 +1,378 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #include <fonts/FontCache.hpp> | ||||
| #include <fonts/CachedFont.hpp> | ||||
| #include <texts/TypedTextDatabase.hpp> | ||||
| #include <touchgfx/TextProvider.hpp> | ||||
| #include <touchgfx/Utils.hpp> | ||||
| #include <cstring> | ||||
|  | ||||
| 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<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 (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<uint16_t*>(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 | ||||
| @@ -0,0 +1,94 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #ifndef FONTCACHE_HPP | ||||
| #define FONTCACHE_HPP | ||||
|  | ||||
| #include <fonts/ApplicationFontProvider.hpp> | ||||
| #include <touchgfx/Font.hpp> | ||||
| #include <touchgfx/TypedText.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
| class CachedFont; | ||||
|  | ||||
| class FontDataReader | ||||
| { | ||||
| public: | ||||
|     virtual ~FontDataReader() { } | ||||
|     virtual void open() = 0; | ||||
|     virtual void close() = 0; | ||||
|     virtual void setPosition(uint32_t position) = 0; | ||||
|     virtual void readData(void* out, uint32_t numberOfBytes) = 0; | ||||
| }; | ||||
|  | ||||
| class FontCache | ||||
| { | ||||
| public: | ||||
|     FontCache(); | ||||
|     void setReader(FontDataReader* reader); | ||||
|     void clear(bool keepGsubTable = false); | ||||
|     void setMemory(uint8_t* memory, uint32_t size); | ||||
|     void initializeCachedFont(TypedText t, CachedFont* font, bool loadGsubTable = false); | ||||
|     bool cacheString(TypedText t, const Unicode::UnicodeChar* string); | ||||
|     bool cacheLigatures(CachedFont* font, TypedText t, const Unicode::UnicodeChar* string); | ||||
|  | ||||
|     const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, FontId font) const; | ||||
|     uint32_t getMemoryUsage() | ||||
|     { | ||||
|         return memorySize - (gsubStart - top); | ||||
|     } | ||||
|  | ||||
|     void open(); | ||||
|     void close(); | ||||
|  | ||||
|     static inline const uint8_t* getPixelData(const GlyphNode* glyph) | ||||
|     { | ||||
|         return ((const uint8_t*)glyph) + SizeGlyphNode + 4; | ||||
|     } | ||||
|     static inline bool isCached(const GlyphNode* g) | ||||
|     { | ||||
|         return g->dataOffset == 0xFFFFFFFF; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     static const uint32_t SizeGlyphNode = 16; | ||||
|  | ||||
|     bool contains(Unicode::UnicodeChar unicode, FontId font) const; | ||||
|     void insert(Unicode::UnicodeChar unicode, FontId font, uint32_t bpp, bool& outOfMemory); | ||||
|     uint8_t* copyGlyph(uint8_t* top, Unicode::UnicodeChar unicode, FontId font, uint32_t bpp, bool& outOfMemory); | ||||
|  | ||||
|     void cacheData(uint32_t bpp, GlyphNode* first); | ||||
|     bool cacheSortedString(TypedText t); | ||||
|     bool createSortedString(const Unicode::UnicodeChar* string); | ||||
|     bool createSortedLigatures(CachedFont* font, TypedText t, const Unicode::UnicodeChar* string, ...); | ||||
|     bool sortSortedString(int n); | ||||
|  | ||||
|     void setPosition(uint32_t position); | ||||
|     void readData(void* out, uint32_t numberOfBytes); | ||||
|  | ||||
|     struct | ||||
|     { | ||||
|         uint8_t* first; //first glyphnode, glyph in cache; | ||||
|         uint8_t* last; //first glyphnode, glyph in cache; | ||||
|     } fontTable[MAX(TypographyFontIndex::NUMBER_OF_FONTS, 1)]; | ||||
|  | ||||
|     uint32_t memorySize; | ||||
|     uint8_t* memory;    //start of memory | ||||
|     uint8_t* top;       //first unused byte | ||||
|     uint8_t* gsubStart; //first address of GSUB tables, allocated in the end of the cache | ||||
|  | ||||
|     FontDataReader* reader; | ||||
|  | ||||
|     Unicode::UnicodeChar* sortedString; | ||||
|     //Must be bigger than BinaryFontData | ||||
|     static const uint32_t MAX_BUFFER_SIZE = 64; | ||||
|     char buffer[MAX_BUFFER_SIZE]; | ||||
|     uint32_t glyphDataOffset; | ||||
|     uint16_t numGlyphs; | ||||
|     uint16_t currentFileGlyphNumber; | ||||
|     GlyphNode currentFileGlyphNode; | ||||
| }; | ||||
| } // namespace touchgfx | ||||
|  | ||||
| #endif // FONTCACHE_HPP | ||||
| @@ -0,0 +1,43 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #include <fonts/GeneratedFont.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
| GeneratedFont::GeneratedFont(const GlyphNode* list, uint16_t size, uint16_t height, uint8_t pixBelowBase, 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) : | ||||
|     ConstFont(list, size, height, pixBelowBase, bitsPerPixel, byteAlignRow, maxLeft, maxRight, fallbackChar, ellipsisChar), | ||||
|     glyphData(glyphDataInternalFlash), | ||||
|     kerningData(kerningList), | ||||
|     gsubTable(gsubData) | ||||
| { | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
| } // namespace touchgfx | ||||
| @@ -0,0 +1,133 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #ifndef GENERATEDFONT_HPP | ||||
| #define GENERATEDFONT_HPP | ||||
|  | ||||
| #include <touchgfx/ConstFont.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
| /** | ||||
|  * An GeneratedFont has both glyph table and glyph data placed in a flash which | ||||
|  * supports random access read (i.e. not a NAND flash) | ||||
|  * | ||||
|  * @see ConstFont | ||||
|  */ | ||||
| class GeneratedFont : public ConstFont | ||||
| { | ||||
| public: | ||||
|     /** | ||||
|      * Construct the GeneratedFont. | ||||
|      * | ||||
|      * @param list                   The array of glyphs known to this font. | ||||
|      * @param size                   The number of glyphs in list. | ||||
|      * @param height                 The height in pixels of the highest character in this font. | ||||
|      * @param pixBelowBase           The maximum number of pixels that can be drawn below the | ||||
|      *                               baseline in this font. | ||||
|      * @param bitsPerPixel           The number of bits per pixel in this font. | ||||
|      * @param byteAlignRow           Are glyphs encoded using A4 format | ||||
|      * @param maxLeft                The maximum a character extends to the left. | ||||
|      * @param maxRight               The maximum a character extends to the right. | ||||
|      * @param glyphDataInternalFlash Pointer to the glyph data for the font, placed in internal | ||||
|      *                               flash. | ||||
|      * @param kerningList            pointer to the kerning data for the font, placed in internal | ||||
|      *                               flash. | ||||
|      * @param fallbackChar           The fallback character for the typography in case no glyph is | ||||
|      *                               available. | ||||
|      * @param ellipsisChar           The ellipsis character used for truncating long texts. | ||||
|      * @param gsubTable              Pointer to GSUB table. | ||||
|      */ | ||||
|     GeneratedFont(const GlyphNode* list, uint16_t size, uint16_t height, uint8_t pixBelowBase, 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); | ||||
|  | ||||
|     using ConstFont::getGlyph; | ||||
|  | ||||
|     /** | ||||
|      * Obtains a RAM-based pointer to the pixel data for the specified glyph. | ||||
|      * | ||||
|      * @param glyph The glyph to get the pixels data of. | ||||
|      * | ||||
|      * @return The pixel data of the glyph. | ||||
|      */ | ||||
|     virtual const uint8_t* getPixelData(const GlyphNode* glyph) const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the kerning distance between two characters. | ||||
|      * | ||||
|      * @param prevChar The unicode value of the previous character. | ||||
|      * @param glyph    the glyph object for the current character. | ||||
|      * | ||||
|      * @return The kerning distance between prevChar and glyph char. | ||||
|      */ | ||||
|     virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const; | ||||
|  | ||||
|     /** | ||||
|      * Gets GSUB table. | ||||
|      * | ||||
|      * @return The GSUB table or null if font has GSUB no table | ||||
|      */ | ||||
|     virtual const uint16_t* getGSUBTable() const | ||||
|     { | ||||
|         return gsubTable; | ||||
|     } | ||||
|  | ||||
| protected: | ||||
|     GeneratedFont() : ConstFont(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), glyphData(0), kerningData(0), gsubTable(0) { } | ||||
|     const void* glyphData;          ///< Information describing the glyphs | ||||
|     const KerningNode* kerningData; ///< Information describing the kerning | ||||
|     const uint16_t* gsubTable;      ///< Information describing the GSUB tables | ||||
| }; | ||||
|  | ||||
| struct BinaryFontData | ||||
| { | ||||
|     uint32_t fontIndex;                // The font index (as used by TypedTextDatabase) | ||||
|     uint32_t sizeOfFontData;           // Size of the complete BinaryFont | ||||
|     uint32_t offsetToTable;            // GlyphNode[] | ||||
|     uint32_t offsetToKerning;          // KerningNode[] | ||||
|     uint32_t offsetToGlyphs;           // uint8_t[] | ||||
|     uint32_t offsetToGSUB;             // uint16_t[] | ||||
|     uint16_t numberOfGlyphs;           // Number of glyphs in Table and Glyphs | ||||
|     uint16_t height;                   // Font height from base | ||||
|     uint8_t  pixBelowBase;             // Max pixels below base | ||||
|     uint8_t  bitsPerPixel: 7;          // Bpp | ||||
|     uint8_t  byteAlignRow: 1;          // A4/A2/A1 | ||||
|     uint8_t  maxLeft;                  // The maximum a character extends to the left | ||||
|     uint8_t  maxRight;                 // The maximum a character extends to the right | ||||
|     Unicode::UnicodeChar fallbackChar; // Fallback Character for the font | ||||
|     Unicode::UnicodeChar ellipsisChar; // Ellipsis Character for the font | ||||
| }; | ||||
|  | ||||
| class BinaryFont : public GeneratedFont | ||||
| { | ||||
| public: | ||||
|     BinaryFont(const struct touchgfx::BinaryFontData* data) | ||||
|         : GeneratedFont((const GlyphNode*)((const uint8_t*)data + data->offsetToTable), | ||||
|                         data->numberOfGlyphs, | ||||
|                         data->height, | ||||
|                         data->pixBelowBase, | ||||
|                         data->bitsPerPixel, | ||||
|                         data->byteAlignRow, | ||||
|                         data->maxLeft, | ||||
|                         data->maxRight, | ||||
|                         0, | ||||
|                         (const KerningNode*)((const uint8_t*)data + data->offsetToKerning), | ||||
|                         data->fallbackChar, | ||||
|                         data->ellipsisChar, | ||||
|                         (data->offsetToGSUB == 0) ? 0 : (const uint16_t*)((const uint8_t*)data + data->offsetToGSUB)), | ||||
|           glyphData((const uint8_t*)data + data->offsetToGlyphs) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     BinaryFont() : GeneratedFont() {} | ||||
|  | ||||
|     virtual const uint8_t* getPixelData(const GlyphNode* glyph) const | ||||
|     { | ||||
|         const uint8_t* data = (const uint8_t*)glyphData; | ||||
|         return &(data[glyph->dataOffset]); | ||||
|     } | ||||
| protected: | ||||
|     const uint8_t* glyphData; | ||||
| }; | ||||
| } // namespace touchgfx | ||||
|  | ||||
| #endif // GENERATEDFONT_HPP | ||||
| @@ -0,0 +1,42 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| <% if generate_binary_files? %> | ||||
| // Empty Language file | ||||
| <% else %> | ||||
| #include <stdint.h> | ||||
| #include <touchgfx/Unicode.hpp> | ||||
|  | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const uint32_t indices<%= language %>[] TEXT_LOCATION_FLASH_ATTRIBUTE; | ||||
| <% if not remap_strings? %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const touchgfx::Unicode::UnicodeChar texts<%= language %>[]  TEXT_LOCATION_FLASH_ATTRIBUTE; | ||||
| <% end %> | ||||
|  | ||||
| <% if remap_strings? %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const uint32_t indices<%= language %>[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% entries.each_with_index do |entry, index| %> | ||||
|     <%= string_index(entry) << ((index==entries.length-1) ? ' ': ',') %> // <%= entry.text_id %> | ||||
| <% end %> | ||||
| }; | ||||
| <% else %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const touchgfx::Unicode::UnicodeChar texts<%= language %>[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% entries.each_with_index do |entry, index| %> | ||||
|     <%= (entry.int_array*',').to_s << ',0' << ((index==entries.length-1) ? ' ': ',') %> // <%= entry.text_id %> | ||||
| <% end %> | ||||
| }; | ||||
|  | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const uint32_t indices<%= language %>[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% index_acc = 0 %><% entries.each_with_index do |entry, index| %> | ||||
|     <%= index_acc.to_s << ((index==entries.length-1) ? ' ': ',') %> // <%= entry.text_id %><% index_acc += entry.int_array.length+1 %> | ||||
| <% end %> | ||||
| }; | ||||
| <% end %> | ||||
| <% end %> | ||||
| @@ -0,0 +1,29 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #ifndef TEXTKEYSANDLANGUAGES_HPP | ||||
| #define TEXTKEYSANDLANGUAGES_HPP | ||||
|  | ||||
| <% | ||||
| #ENUM OF LANGUAGES | ||||
| %> | ||||
| typedef enum | ||||
| { | ||||
| <% if !(countries.empty?) %> | ||||
|     <%= countries %>, | ||||
| <% end %> | ||||
|     NUMBER_OF_LANGUAGES | ||||
| } LANGUAGES; | ||||
|  | ||||
| <% | ||||
| #ENUM DEF OF TEXT_TYPES | ||||
| %> | ||||
| typedef enum | ||||
| { | ||||
| <% texts.each do |text| %> | ||||
|     <%= text.upcase %>, | ||||
| <% end %> | ||||
|     NUMBER_OF_TEXT_KEYS | ||||
| } TEXTS; | ||||
|  | ||||
| #endif // TEXTKEYSANDLANGUAGES_HPP | ||||
| @@ -0,0 +1,182 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #include <stdarg.h> | ||||
| #include <texts/TypedTextDatabase.hpp> | ||||
| #include <touchgfx/TextProvider.hpp> | ||||
| #include <touchgfx/Texts.hpp> | ||||
| #include <touchgfx/TypedText.hpp> | ||||
| #include <touchgfx/Unicode.hpp> | ||||
| #include <touchgfx/hal/HAL.hpp> | ||||
| #include <touchgfx/lcd/LCD.hpp> | ||||
|  | ||||
| uint16_t touchgfx::Font::getStringWidth(const touchgfx::Unicode::UnicodeChar* text, ...) const | ||||
| { | ||||
|     va_list pArg; | ||||
|     va_start(pArg, text); | ||||
|     uint16_t width = getStringWidth<%= is_rtl ? 'RTL' : 'LTR' %>(TEXT_DIRECTION_LTR, text, pArg); | ||||
|     va_end(pArg); | ||||
|     return width; | ||||
| } | ||||
|  | ||||
| uint16_t touchgfx::Font::getStringWidth(touchgfx::TextDirection textDirection, const touchgfx::Unicode::UnicodeChar* text, ...) const | ||||
| { | ||||
|     va_list pArg; | ||||
|     va_start(pArg, text); | ||||
|     uint16_t width = getStringWidth<%= is_rtl ? 'RTL' : 'LTR' %>(textDirection, text, pArg); | ||||
|     va_end(pArg); | ||||
|     return width; | ||||
| } | ||||
|  | ||||
| touchgfx::Unicode::UnicodeChar touchgfx::TextProvider::getNextLigature(TextDirection direction) | ||||
| {<% if is_rtl %> | ||||
|     nextCharacters.replaceAt0(unicodeConverter(direction));<% end %> | ||||
|     if (fontGsubTable && nextCharacters.peekChar()) | ||||
|     { | ||||
|         substituteGlyphs(); | ||||
|         if (nextCharacters.peekChar(1) == 0x093F) //Hindi I-matra | ||||
|         { | ||||
|             nextCharacters.replaceAt1(nextCharacters.peekChar()); | ||||
|             nextCharacters.replaceAt0(0x093F); | ||||
|         } | ||||
|     } | ||||
|     return getNextChar(); | ||||
| } | ||||
|  | ||||
| void touchgfx::TextProvider::initializeInternal() | ||||
| { | ||||
|     fillInputBuffer();<% if is_rtl %> | ||||
|     unicodeConverterInit();<% end %> | ||||
| } | ||||
|  | ||||
| void touchgfx::LCD::drawString(touchgfx::Rect widgetArea, const touchgfx::Rect& invalidatedArea, const touchgfx::LCD::StringVisuals& stringVisuals, const touchgfx::Unicode::UnicodeChar* format, ...) | ||||
| { | ||||
|     va_list pArg; | ||||
|     va_start(pArg, format); | ||||
|     drawString<%= is_rtl ? 'RTL' : 'LTR' %>(widgetArea, invalidatedArea, stringVisuals, format, pArg); | ||||
|     va_end(pArg); | ||||
| } | ||||
|  | ||||
| //Default typed text database | ||||
| extern const touchgfx::TypedText::TypedTextData* const typedTextDatabaseArray[]; | ||||
|  | ||||
| <% if generate_binary_files? %> | ||||
| extern const touchgfx::Unicode::UnicodeChar EmptyLanguageTexts[]; | ||||
| extern uint32_t const EmptyLanguageIndices[]; | ||||
| <% else %> | ||||
| <% if remap_strings? %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const touchgfx::Unicode::UnicodeChar texts_all_languages[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
|     <%= all_unicodes %> | ||||
| }; | ||||
| <% end %> | ||||
| <% countries.each do |lang| %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern uint32_t const indices<%= lang %>[] TEXT_LOCATION_FLASH_ATTRIBUTE; | ||||
| <% if not remap_strings? %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const touchgfx::Unicode::UnicodeChar texts<%= lang %>[] TEXT_LOCATION_FLASH_ATTRIBUTE; | ||||
| <% end %> | ||||
| <% end %> | ||||
| <% end %> | ||||
|  | ||||
| //array holding dynamically installed languages | ||||
| struct TranslationHeader | ||||
| { | ||||
|     uint32_t offset_to_texts; | ||||
|     uint32_t offset_to_indices; | ||||
|     uint32_t offset_to_typedtext; | ||||
| }; | ||||
| static const TranslationHeader* languagesArray[<%= countries.length > 0 ? countries.length : 1 %>] = { 0 }; | ||||
|  | ||||
| //Compiled and linked in languages | ||||
| static const uint32_t* const staticLanguageIndices[] = | ||||
| { | ||||
| <% if generate_binary_files? %> | ||||
|     EmptyLanguageIndices | ||||
| <% else %> | ||||
| <% if countries.empty? %> | ||||
|     0 | ||||
| <% end %> | ||||
| <% countries.each_with_index do |lang, index| %> | ||||
|     indices<%= lang %><%= (index==countries.length-1) ? '': ',' %> | ||||
| <% end %> | ||||
| <% end %> | ||||
| }; | ||||
| <% if generate_binary_files? %> | ||||
| static const touchgfx::Unicode::UnicodeChar* const staticLanguageTexts[] = { | ||||
|     EmptyLanguageTexts | ||||
| }; | ||||
| <% else %> | ||||
| <% if not remap_strings? %> | ||||
| static const touchgfx::Unicode::UnicodeChar* const staticLanguageTexts[] = { | ||||
| <% if countries.empty? %> | ||||
|     0 | ||||
| <% end %> | ||||
| <% countries.each_with_index do |lang, index| %> | ||||
|     texts<%= lang %><%= (index==countries.length-1) ? '': ',' %> | ||||
| <% end %> | ||||
| }; | ||||
| <% end %> | ||||
| <% end %> | ||||
|  | ||||
| touchgfx::LanguageId touchgfx::Texts::currentLanguage = static_cast<touchgfx::LanguageId>(0); | ||||
| static const touchgfx::Unicode::UnicodeChar* currentLanguagePtr = 0; | ||||
| static const uint32_t* currentLanguageIndices = 0; | ||||
|  | ||||
| void touchgfx::Texts::setLanguage(touchgfx::LanguageId id) | ||||
| { | ||||
|     const touchgfx::TypedText::TypedTextData* currentLanguageTypedText = 0; | ||||
|     if (id < <%= countries.length > 0 ? countries.length : 1 %>) | ||||
|     { | ||||
|         if (languagesArray[id] != 0) | ||||
|         { | ||||
|             //dynamic translation is added | ||||
|             const TranslationHeader* translation = languagesArray[id]; | ||||
|             currentLanguagePtr = (const touchgfx::Unicode::UnicodeChar*)(((const uint8_t*)translation) + translation->offset_to_texts); | ||||
|             currentLanguageIndices = (const uint32_t*)(((const uint8_t*)translation) + translation->offset_to_indices); | ||||
|             currentLanguageTypedText = (const touchgfx::TypedText::TypedTextData*)(((const uint8_t*)translation) + translation->offset_to_typedtext); | ||||
|         } | ||||
| <% if generate_binary_files? %> | ||||
|         else | ||||
|         { | ||||
|             //compiled and linked empty texts and indices in typedTextData | ||||
|             currentLanguagePtr = staticLanguageTexts[0]; | ||||
|             currentLanguageIndices = staticLanguageIndices[0]; | ||||
|             currentLanguageTypedText = typedTextDatabaseArray[0]; | ||||
|         } | ||||
| <% else %> | ||||
|         else | ||||
|         { | ||||
|             //compiled and linked in languages | ||||
| <% if remap_strings? %> | ||||
|             currentLanguagePtr = texts_all_languages; | ||||
|             currentLanguageIndices = staticLanguageIndices[id]; | ||||
| <% else %> | ||||
|             currentLanguagePtr = staticLanguageTexts[id]; | ||||
|             currentLanguageIndices = staticLanguageIndices[id]; | ||||
| <% end %> | ||||
|             currentLanguageTypedText = typedTextDatabaseArray[id]; | ||||
|         } | ||||
| <% end %> | ||||
|     } | ||||
|  | ||||
|     if (currentLanguageTypedText) | ||||
|     { | ||||
|         currentLanguage = id; | ||||
|         touchgfx::TypedText::registerTypedTextDatabase(currentLanguageTypedText, | ||||
|                                                        TypedTextDatabase::getFonts(), TypedTextDatabase::getInstanceSize()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void touchgfx::Texts::setTranslation(touchgfx::LanguageId id, const void* translation) | ||||
| { | ||||
|     languagesArray[id] = (const TranslationHeader*)translation; | ||||
| } | ||||
|  | ||||
| const touchgfx::Unicode::UnicodeChar* touchgfx::Texts::getText(TypedTextId id) const | ||||
| { | ||||
|     return ¤tLanguagePtr[currentLanguageIndices[id]]; | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,145 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #include <touchgfx/TypedText.hpp> | ||||
| #include <fonts/<%= font_class_name%>.hpp> | ||||
| #include <texts/TypedTextDatabase.hpp> | ||||
|  | ||||
| <% fonts.each do |font| %> | ||||
| extern touchgfx::<%= font_class_name%>& <%= font%>(); | ||||
| <% end %> | ||||
|  | ||||
| const touchgfx::Font* touchgfx_fonts[] = | ||||
| { | ||||
| <% if fonts.empty? %> | ||||
|     0 | ||||
| <% end %> | ||||
| <%= fonts.map { |font| "    &(#{font}())" } * ",\n" | ||||
| %> | ||||
| }; | ||||
|  | ||||
| <% if generate_binary_files? %> | ||||
| extern const touchgfx::TypedText::TypedTextData typedText_database_EMPTY[]; | ||||
| <% else %> | ||||
| extern const touchgfx::TypedText::TypedTextData typedText_database_DEFAULT[]; | ||||
| <% end %> | ||||
| extern const touchgfx::TypedText::TypedTextData* const typedTextDatabaseArray[]; | ||||
|  | ||||
| <% if generate_binary_files? %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const touchgfx::Unicode::UnicodeChar EmptyLanguageTexts[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% layouts.each do |layout| %> | ||||
| <% typed_texts(layout).each_with_index do |entry, index| %> | ||||
|     <%= '0' << ((index==typed_texts(layout).length-1) ? ' ': ',') %> | ||||
| <% end %> | ||||
| <% break %> | ||||
| <% end %> | ||||
| }; | ||||
|  | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| KEEP extern const uint32_t EmptyLanguageIndices[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% layouts.each do |layout| %> | ||||
| <% index_acc = 0 %><% typed_texts(layout).each_with_index do |entry, index| %> | ||||
|     <%= index_acc.to_s << ((index==typed_texts(layout).length-1) ? ' ': ',') %><% index_acc += 1 %> | ||||
| <% end %> | ||||
| <% break %> | ||||
| <% end %> | ||||
| }; | ||||
|  | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| const touchgfx::TypedText::TypedTextData typedText_database_EMPTY[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% layouts.each do |layout| %> | ||||
| <% typed_texts(layout).each_with_index do |entry, index| %> | ||||
|     <%= ('{ 0, touchgfx::LEFT, touchgfx::TEXT_DIRECTION_LTR }').to_s << ((index==typed_texts(layout).length-1) ? ' ': ',') %> | ||||
| <% end %> | ||||
| <% break %> | ||||
| <% end %> | ||||
| }; | ||||
| <% else %> | ||||
| <% layouts.each do |layout| %> | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| const touchgfx::TypedText::TypedTextData typedText_database_<%= layout %>[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% if typed_texts(layout).empty?%> | ||||
|     { 0, touchgfx::LEFT, touchgfx::TEXT_DIRECTION_LTR } | ||||
| <% end %> | ||||
| <%= typed_texts(layout).map { |typed_text| | ||||
|      fontIdx = fontmap["getFont_#{typed_text.typography.cpp_name}_#{typed_text.typography.font_size}_#{typed_text.typography.bpp}bpp"] | ||||
|      alignment = "touchgfx::#{typed_text.alignment.upcase}" | ||||
|      direction = "touchgfx::TEXT_DIRECTION_#{typed_text.direction.upcase}" | ||||
|      "    { #{fontIdx}, #{alignment}, #{direction} }" | ||||
|    } * ",\n" | ||||
| %> | ||||
| }; | ||||
| <% end %> | ||||
| <% end %> | ||||
|  | ||||
| TEXT_LOCATION_FLASH_PRAGMA | ||||
| const touchgfx::TypedText::TypedTextData* const typedTextDatabaseArray[] TEXT_LOCATION_FLASH_ATTRIBUTE = | ||||
| { | ||||
| <% if generate_binary_files? %> | ||||
| <% text_entries.languages.each_with_index do |entry,index| %> | ||||
| <% if (index==text_entries.languages.length-1) %> | ||||
|     typedText_database_EMPTY | ||||
| <% else %> | ||||
|     typedText_database_EMPTY, | ||||
| <% end %> | ||||
| <% end %> | ||||
| <% else %> | ||||
| <% if text_entries.languages.empty? %> | ||||
|     typedText_database_DEFAULT | ||||
| <% end %> | ||||
| <%= text_entries.languages.map { |language| | ||||
|       "    typedText_database_#{layouts.find { |l| l == language } || 'DEFAULT'}" | ||||
|     } * ",\n" | ||||
| %> | ||||
| <% end %> | ||||
| }; | ||||
|  | ||||
| namespace TypedTextDatabase | ||||
| { | ||||
| const touchgfx::TypedText::TypedTextData* getInstance(touchgfx::LanguageId id) | ||||
| { | ||||
|     return typedTextDatabaseArray[id]; | ||||
| } | ||||
|  | ||||
| uint16_t getInstanceSize() | ||||
| { | ||||
| <% if generate_binary_files? %> | ||||
|     return sizeof(typedText_database_EMPTY) / sizeof(touchgfx::TypedText::TypedTextData); | ||||
| <% else %> | ||||
|     return sizeof(typedText_database_DEFAULT) / sizeof(touchgfx::TypedText::TypedTextData); | ||||
| <% end %> | ||||
| } | ||||
|  | ||||
| const touchgfx::Font** getFonts() | ||||
| { | ||||
|     return touchgfx_fonts; | ||||
| } | ||||
|  | ||||
| const touchgfx::Font* setFont(touchgfx::FontId fontId, const touchgfx::Font* font) | ||||
| { | ||||
|     const touchgfx::Font* old = touchgfx_fonts[fontId]; | ||||
|     touchgfx_fonts[fontId] = font; | ||||
|     return old; | ||||
| } | ||||
|  | ||||
| void resetFont(touchgfx::FontId fontId) | ||||
| { | ||||
| <% if fonts.empty? %> | ||||
|     return; | ||||
| <% else %> | ||||
|     switch (fontId) | ||||
|     { | ||||
| <% fonts.each_with_index do |font, index| %> | ||||
|     case <%= index %>: | ||||
|         touchgfx_fonts[<%= index %>] = &(<%= font %>()); | ||||
|         break; | ||||
| <% end %> | ||||
|     } | ||||
| <% end %> | ||||
| } | ||||
| }  // namespace TypedTextDatabase | ||||
| @@ -0,0 +1,21 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #ifndef TYPEDTEXTDATABASE_HPP | ||||
| #define TYPEDTEXTDATABASE_HPP | ||||
|  | ||||
| #include <touchgfx/hal/Types.hpp> | ||||
| #include <touchgfx/TypedText.hpp> | ||||
|  | ||||
| namespace TypedTextDatabase | ||||
| { | ||||
| class TypedTextData; | ||||
| const touchgfx::TypedText::TypedTextData* getInstance(touchgfx::LanguageId id); | ||||
| const touchgfx::TypedText::TypedTextData* getInstance(); | ||||
| const touchgfx::Font** getFonts(); | ||||
| const touchgfx::Font* setFont(touchgfx::FontId fontId, const touchgfx::Font*); | ||||
| void resetFont(touchgfx::FontId fontId); | ||||
| uint16_t getInstanceSize(); | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -0,0 +1,148 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #include <fonts/UnmappedDataFont.hpp> | ||||
| #include <fonts/ApplicationFontProvider.hpp> | ||||
| #include <touchgfx/hal/FlashDataReader.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
| GlyphNode UnmappedDataFont::glyphNodeBuffer; | ||||
|  | ||||
| UnmappedDataFont::UnmappedDataFont(const GlyphNode* list, const uint16_t* unicodeList, uint16_t size, uint16_t height, uint8_t pixBelowBase, uint8_t bitsPerPixel, uint8_t byteAlignRow, uint8_t maxLeft, uint8_t maxRight, const uint8_t* const* glyphDataList, const KerningNode* kerningList, const Unicode::UnicodeChar fallbackChar, const Unicode::UnicodeChar ellipsisChar, const uint16_t* const gsubData) : | ||||
|     Font(height, pixBelowBase, bitsPerPixel, byteAlignRow, maxLeft, maxRight, fallbackChar, ellipsisChar), | ||||
|     glyphList(list), | ||||
|     listSize(size), | ||||
|     unicodes(unicodeList), | ||||
|     glyphDataList(glyphDataList), | ||||
|     kerningData(kerningList), | ||||
|     gsubTable(gsubData) | ||||
| { | ||||
| } | ||||
|  | ||||
| const GlyphNode* UnmappedDataFont::getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const | ||||
| { | ||||
|     int index = lookupUnicode(unicode); | ||||
|  | ||||
|     if (index != -1) | ||||
|     { | ||||
|         //Read glyphNode from unmapped flash | ||||
|         touchgfx::FlashDataReader* const flashReader = ApplicationFontProvider::getFlashReader(); | ||||
|         flashReader->copyData(glyphList + index, &glyphNodeBuffer, sizeof(GlyphNode)); | ||||
|  | ||||
|         pixelData = getPixelData(const_cast<const GlyphNode*>(&glyphNodeBuffer)); | ||||
|         bitsPerPixel = getBitsPerPixel(); | ||||
|         return &glyphNodeBuffer; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| const uint8_t* UnmappedDataFont::getPixelData(const GlyphNode* glyph) const | ||||
| { | ||||
|     const uint8_t* const* table = (const uint8_t* const*)glyphDataList; | ||||
|     return &(table[glyph->unicode / 2048][glyph->dataOffset]); | ||||
| } | ||||
|  | ||||
| int8_t UnmappedDataFont::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; | ||||
| } | ||||
|  | ||||
| int UnmappedDataFont::lookupUnicode(uint16_t unicode) const | ||||
| { | ||||
|     int32_t min = 0; | ||||
|     int32_t max = listSize - 1; | ||||
|  | ||||
|     int32_t mid = min + (unicode - unicodes[min]); // Linear up from [min].unicode | ||||
|     if (mid < min) | ||||
|     { | ||||
|         // Unicode < unicodes[min] => not found | ||||
|         return -1; | ||||
|     } | ||||
|     if (mid > max) | ||||
|     { | ||||
|         // Linear up ends too high | ||||
|         mid = max - (unicodes[max] - unicode); // Linear down from [max].unicode | ||||
|         if (mid > max) | ||||
|         { | ||||
|             // Unicode > unicodes[max] => not found | ||||
|             return -1; | ||||
|         } | ||||
|         if (mid < min) | ||||
|         { | ||||
|             // Linear down ends too low, take the middle element | ||||
|             mid = (min + max) / 2; | ||||
|         } | ||||
|     } | ||||
|     while (min <= max) | ||||
|     { | ||||
|         if (unicode == unicodes[mid]) | ||||
|         { | ||||
|             // Found at [mid] | ||||
|             return mid; | ||||
|         } | ||||
|         if (unicode < unicodes[mid]) | ||||
|         { | ||||
|             // 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 - (unicodes[max] - 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 - unicodes[min]); | ||||
|             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 -1; | ||||
| } | ||||
| } // namespace touchgfx | ||||
| @@ -0,0 +1,109 @@ | ||||
| /* DO NOT EDIT THIS FILE */ | ||||
| /* This file is autogenerated by the text-database code generator */ | ||||
|  | ||||
| #ifndef UNMAPPEDDATAFONT_HPP | ||||
| #define UNMAPPEDDATAFONT_HPP | ||||
|  | ||||
| #include <touchgfx/Font.hpp> | ||||
|  | ||||
| namespace touchgfx | ||||
| { | ||||
| /** | ||||
|  * An UnmappedDataFont has both glyph table and glyph data placed in a | ||||
|  * flash which does not support random access read (indirect | ||||
|  * access). A unicode table is located in a flash with random read | ||||
|  * access (direct access). | ||||
|  * | ||||
|  * @see Font, ConstFont | ||||
|  */ | ||||
| class UnmappedDataFont : public Font | ||||
| { | ||||
| public: | ||||
|     /** | ||||
|      * Construct the UnmappedDataFont. | ||||
|      * | ||||
|      * @param list                   The array of glyphs known to this font (indirect). | ||||
|      * @param unicodes               The array of unicodes known to this font (direct). | ||||
|      * @param size                   The number of glyphs in list. | ||||
|      * @param height                 The height in pixels of the highest character in this font. | ||||
|      * @param pixBelowBase           The maximum number of pixels that can be drawn below the | ||||
|      *                               baseline in this font. | ||||
|      * @param bitsPerPixel           The number of bits per pixel in this font. | ||||
|      * @param byteAlignRow           Are glyphs encoded using A4 format | ||||
|      * @param maxLeft                The maximum a character extends to the left. | ||||
|      * @param maxRight               The maximum a character extends to the right. | ||||
|      * @param glyphDataList          Pointer to pointers the glyph data for the font (indirect). | ||||
|      * @param kerningList            pointer to the kerning data for the font (direct). | ||||
|      * @param fallbackChar           The fallback character for the typography in case no glyph is | ||||
|      *                               available. | ||||
|      * @param ellipsisChar           The ellipsis character used for truncating long texts. | ||||
|      * @param gsubTable              Pointer to GSUB table (direct). | ||||
|      */ | ||||
|     UnmappedDataFont(const GlyphNode* list, const uint16_t* unicodes, uint16_t size, uint16_t height, uint8_t pixBelowBase, uint8_t bitsPerPixel, uint8_t byteAlignRow, uint8_t maxLeft, uint8_t maxRight, const uint8_t* const* glyphDataList, const KerningNode* kerningList, const Unicode::UnicodeChar fallbackChar, const Unicode::UnicodeChar ellipsisChar, const uint16_t* const gsubData); | ||||
|  | ||||
|     using Font::getGlyph; | ||||
|  | ||||
|     /** | ||||
|      * Gets the glyph data associated with the specified Unicode. The | ||||
|        GlyphNode is allocated in the buffer passed to the constructor. | ||||
|      * | ||||
|      * Please note that in case of Thai letters and Arabic letters | ||||
|      * where diacritics can be placed relative to the previous | ||||
|      * character(s), please use TextProvider::getNextLigature() | ||||
|      * instead as it will create a temporary GlyphNode that will be | ||||
|      * adjusted with respect to X/Y position. | ||||
|      * | ||||
|      * @param       unicode      The character to look up. | ||||
|      * @param       pixelData    Pointer to the pixel data for the glyph if the glyph is | ||||
|      *                           found. This is set by this method. | ||||
|      * @param [out] bitsPerPixel Reference where to place the number of bits per pixel. | ||||
|      * | ||||
|      * @return A pointer to the glyph node or null if the glyph was not found. | ||||
|      */ | ||||
|     virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const; | ||||
|  | ||||
|     /** | ||||
|      * Obtains the address to the pixel data for the specified glyph. | ||||
|      * | ||||
|      * @param glyph The glyph to get the pixels data of. | ||||
|      * | ||||
|      * @return The address of the pixel data of the glyph. | ||||
|      */ | ||||
|     virtual const uint8_t* getPixelData(const GlyphNode* glyph) const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the kerning distance between two characters. | ||||
|      * | ||||
|      * @param prevChar The unicode value of the previous character. | ||||
|      * @param glyph    the glyph object for the current character. | ||||
|      * | ||||
|      * @return The kerning distance between prevChar and glyph char. | ||||
|      */ | ||||
|     virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const; | ||||
|  | ||||
|     /** | ||||
|      * Gets GSUB table. | ||||
|      * | ||||
|      * @return The GSUB table or null if font has GSUB no table | ||||
|      */ | ||||
|     virtual const uint16_t* getGSUBTable() const | ||||
|     { | ||||
|         return gsubTable; | ||||
|     } | ||||
|  | ||||
| protected: | ||||
|     UnmappedDataFont() : Font(0, 0, 0, 0, 0, 0, 0, 0), glyphList(0), unicodes(0), glyphDataList(0), kerningData(0), gsubTable(0) { } | ||||
|     int lookupUnicode(uint16_t unicode) const; | ||||
|  | ||||
|     const GlyphNode* glyphList;     ///< The list of glyphs | ||||
|     uint16_t listSize;              ///< The size of the list of glyphs | ||||
|     const uint16_t* unicodes;       ///< LookupTable with all unicodes in this font | ||||
|     const void* glyphDataList;      ///< Information describing the glyphs (list of pointers) | ||||
|     const KerningNode* kerningData; ///< Information describing the kerning | ||||
|     const uint16_t* gsubTable;      ///< Information describing the GSUB tables | ||||
|  | ||||
|     static GlyphNode glyphNodeBuffer; ///< Buffer for GlyphNodes read from unmapped flash | ||||
| }; | ||||
| } // namespace touchgfx | ||||
|  | ||||
| #endif // UNMAPPEDDATAFONT_HPP | ||||
| @@ -0,0 +1,76 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'json' | ||||
|  | ||||
| class ApplicationFontProviderCpp < Template | ||||
|   def initialize(text_entries, typographies, output_directory, generate_font_format) | ||||
|     super(text_entries, typographies, output_directory) | ||||
|     @generate_font_format = generate_font_format | ||||
|     @cache = {} | ||||
|   end | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','ApplicationFontProvider.cpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     'src/ApplicationFontProvider.cpp' | ||||
|   end | ||||
|   def cache_file | ||||
|     File.join(@output_directory, 'cache/ApplicationFontProvider.cache') | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     @cache["typographies"] = typographies.collect{|t| [t.name, t.font_file, t.font_size, t.bpp] } | ||||
|     @cache["generate_font_format"] = @generate_font_format | ||||
|     new_cache_file = false | ||||
|     if not File::exists?(cache_file) | ||||
|       new_cache_file = true | ||||
|     else | ||||
|         #cache file exists, compare data with cache file | ||||
|         old_cache = JSON.parse(File.read(cache_file)) | ||||
|         new_cache_file = (old_cache != @cache) | ||||
|     end | ||||
|  | ||||
|     if new_cache_file | ||||
|       #write new cache file | ||||
|       FileIO.write_file_silent(cache_file, @cache.to_json) | ||||
|     end | ||||
|  | ||||
|     if (!File::exists?(output_filename)) || new_cache_file | ||||
|       #generate ApplicationFontProvider.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
|   def font_index(index) | ||||
|     #map typographies to index of first using same font = font index | ||||
|     @font_index ||= | ||||
|       begin | ||||
|         list = {} | ||||
|         typographies.each_with_index do |typography, index| | ||||
|           name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp" | ||||
|           if not list[name] | ||||
|             list[name] = list.size | ||||
|           end | ||||
|         end | ||||
|         list | ||||
|       end | ||||
|     typography = typographies[index] | ||||
|     name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp" | ||||
|     @font_index[name] | ||||
|   end | ||||
|   def save_flashreader | ||||
|     @generate_font_format == "1" | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,93 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class ApplicationFontProviderHpp < Template | ||||
|   def initialize(text_entries, typographies, output_directory, generate_font_format) | ||||
|     super(text_entries, typographies, output_directory) | ||||
|     @generate_font_format = generate_font_format | ||||
|     @cache = {} | ||||
|   end | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','ApplicationFontProvider.hpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/include/fonts/ApplicationFontProvider.hpp' | ||||
|   end | ||||
|   def cache_file | ||||
|     File.join(@output_directory, 'cache/ApplicationFontProviderHpp.cache') | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     @cache["typographies"] = typographies.collect{|t| [t.name, t.font_file, t.font_size, t.bpp] } | ||||
|     @cache["generate_font_format"] = @generate_font_format | ||||
|     @max_length = 0 | ||||
|     typographies.each do |t| | ||||
|       if t.name.length > @max_length | ||||
|         @max_length = t.name.length | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     new_cache_file = false | ||||
|     if not File::exists?(cache_file) | ||||
|       new_cache_file = true | ||||
|     else | ||||
|         #cache file exists, compare data with cache file | ||||
|         old_cache = JSON.parse(File.read(cache_file)) | ||||
|         new_cache_file = (old_cache != @cache) | ||||
|     end | ||||
|  | ||||
|     if new_cache_file | ||||
|       #write new cache file | ||||
|       FileIO.write_file_silent(cache_file, @cache.to_json) | ||||
|     end | ||||
|  | ||||
|     if (!File::exists?(output_filename)) || new_cache_file | ||||
|       #generate ApplicationFontProvider.hpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
|   def font_index(index) | ||||
|     #map typographies to index of first using same font = font index | ||||
|     @font_index ||= | ||||
|       begin | ||||
|         list = {} | ||||
|         typographies.each_with_index do |typography, index| | ||||
|           name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp" | ||||
|           if not list[name] | ||||
|             list[name] = list.size | ||||
|           end | ||||
|         end | ||||
|         list | ||||
|       end | ||||
|     typography = typographies[index] | ||||
|     name = "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp" | ||||
|     @font_index[name] | ||||
|   end | ||||
|   def max_font_index | ||||
|     if @font_index | ||||
|       @font_index.size | ||||
|     else | ||||
|       0 | ||||
|     end | ||||
|   end | ||||
|   def font_comment(index) | ||||
|     typography = typographies[index] | ||||
|     spaces = @max_length - typography.name.length | ||||
|     "#{' '*spaces}// #{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp" | ||||
|   end | ||||
|   def save_flashreader | ||||
|     @generate_font_format == "1" | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class CachedFontCpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','CachedFont.cpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/src/CachedFont.cpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate CachedFont.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class CachedFontHpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','CachedFont.hpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/include/fonts/CachedFont.hpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate CachedFont.hpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class FontCacheCpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','FontCache.cpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/src/FontCache.cpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate FontCache.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class FontCacheHpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','FontCache.hpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/include/fonts/FontCache.hpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate FontCache.hpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,122 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class FontsCpp | ||||
|   def self.font_convert=(font_convert) | ||||
|     @@font_convert = font_convert | ||||
|   end | ||||
|  | ||||
|   def initialize(text_entries, typographies, output_directory, font_asset_path, data_format, generate_binary_fonts, generate_font_format) | ||||
|     @typographies = typographies | ||||
|     @output_directory = output_directory | ||||
|     @font_asset_path = font_asset_path | ||||
|     @data_format = data_format | ||||
|     @generate_binary_fonts = generate_binary_fonts | ||||
|     @generate_font_format = generate_font_format | ||||
|   end | ||||
|   def run | ||||
|     unique_typographies = @typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp, t.fallback_character, t.ellipsis_character) }.uniq | ||||
|  | ||||
|     #remove old Table, Kerning, Font files | ||||
|     #1. Create a list of font names | ||||
|     font_names = unique_typographies.collect do |typography| | ||||
|       "#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp" | ||||
|     end | ||||
|     local_path = "#{@output_directory}/src".gsub('\\','/') | ||||
|  | ||||
|     #2, scan for Kerning files, delete files not using a font in font_names | ||||
|     Dir["#{local_path}/Kerning_*.cpp"].each do |kerning_file| | ||||
|       if font_names.none? {|font_name| kerning_file == "#{local_path}/Kerning_#{font_name}.cpp" } | ||||
|         FileUtils.rm(kerning_file) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     #3, scan for Table files | ||||
|     Dir["#{local_path}/Table_*.cpp"].each do |table_file| | ||||
|       if font_names.none? {|font_name| table_file == "#{local_path}/Table_#{font_name}.cpp" } | ||||
|         FileUtils.rm(table_file) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     #4, scan for Font files, remove unused | ||||
|     Dir["#{local_path}/Font_*.cpp"].each do |font_file| | ||||
|       if font_names.none? {|font_name| font_file.match /#{local_path}\/Font_#{font_name}_\d+.cpp/ } | ||||
|         FileUtils.rm(font_file) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     #5, scan for cache files | ||||
|     local_path = "#{@output_directory}/cache".gsub('\\','/') | ||||
|     Dir["#{local_path}/Font_*Cpp.cache"].each do |cache_file| | ||||
|       if font_names.none? {|font_name| cache_file == "#{local_path}/Font_#{font_name}Cpp.cache" } | ||||
|         FileUtils.rm(cache_file) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     unique_typographies.sort_by { |t| sprintf("%s %04d %d",t.font_file,t.font_size,t.bpp) }.each do |typography| | ||||
|       fonts_directory = File.expand_path(@output_directory) | ||||
|       font_file = File.expand_path("#{@font_asset_path}/#{typography.font_file}") | ||||
|       font_index = fontmap["getFont_#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}bpp"] | ||||
|       fallback_char = typography[:fallback_character] | ||||
|       fallback_char ||= 0 | ||||
|       ellipsis_char = typography[:ellipsis_character] | ||||
|       ellipsis_char ||= 0 | ||||
|       byte_align = @data_format.match("A#{typography.bpp}") ? "-ba" : "" | ||||
|       cmd = "\"#{@@font_convert}\" \ | ||||
| -f \"#{font_file}\" \ | ||||
| -i #{font_index} \ | ||||
| -w #{typography.font_size} \ | ||||
| -r #{typography.font_size} \ | ||||
| -o \"#{fonts_directory}\" \ | ||||
| -c \"#{@output_directory}/UnicodeList#{typography.cpp_name}_#{typography.font_size}_#{typography.bpp}.txt\" \ | ||||
| -n \"#{typography.cpp_name}\" \ | ||||
| -b #{typography.bpp} \ | ||||
| -d #{fallback_char} \ | ||||
| -e #{ellipsis_char} \ | ||||
| -bf #{@generate_binary_fonts} \ | ||||
| -ff #{@generate_font_format} \ | ||||
| #{byte_align}" | ||||
|       #puts "Command: #{cmd}" | ||||
|       output = `#{cmd}` | ||||
|       #puts "FontConverter: #{output}\n" | ||||
|       if !$?.success? | ||||
|         puts cmd | ||||
|         puts output | ||||
|         raise "Error generating font from #{font_file}" | ||||
|       elsif output.match(/WARNING/i) | ||||
|         puts output | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def fonts | ||||
|     @fonts ||= | ||||
|       begin | ||||
|         @typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.collect do |f| | ||||
|           "getFont_#{f.cpp_name}_#{f.font_size}_#{f.bpp}bpp" | ||||
|         end | ||||
|       end | ||||
|   end | ||||
|  | ||||
|   def fontmap | ||||
|     @fontmap ||= | ||||
|       begin | ||||
|         @fontmap = Hash.new | ||||
|         fonts.each_with_index do |f, i| | ||||
|           fontmap[f] = i | ||||
|         end | ||||
|         fontmap | ||||
|       end | ||||
|   end | ||||
|  | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class GeneratedFontCpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','GeneratedFont.cpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/src/GeneratedFont.cpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate GeneratedFont.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class GeneratedFontHpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','GeneratedFont.hpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/include/fonts/GeneratedFont.hpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate GeneratedFont.hpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,282 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'json' | ||||
|  | ||||
| class LanguagesBin | ||||
|   def initialize(text_entries, typographies, output_directory) | ||||
|     @text_entries = text_entries | ||||
|     @typographies = typographies | ||||
|     @output_directory = output_directory | ||||
|   end | ||||
|   def run | ||||
|     #remove_old_binary_files | ||||
|  | ||||
|     @text_entries.languages.each do |language| | ||||
|       LanguageXxBin.new(@text_entries, @typographies, @output_directory, language).run | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def remove_old_binary_files | ||||
|     # Remove any old bin file | ||||
|     local_path = @output_directory.gsub('\\','/') | ||||
|     Dir["#{local_path}/binary/Language*.bin"].each do |language_bin_file| | ||||
|       puts "Deleting #{language_bin_file}" | ||||
|       FileUtils.rm(language_bin_file) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class LanguageXxBin < Template | ||||
|   Presenter = Struct.new(:text_id, :unicodes) | ||||
|   LanguageHeader = Struct.new(:offset_to_texts, :offset_to_indices, :offset_to_typedtext) | ||||
|   TypedTextPresenter = Struct.new(:alignment, :direction, :typography) | ||||
|  | ||||
|   ALIGNMENT = { "LEFT" => 0, "CENTER" => 1, "RIGHT" => 2 } | ||||
|   TEXT_DIRECTION = { "LTR" => 0, "RTL" => 1 } | ||||
|  | ||||
|   def initialize(text_entries, typographies, output_directory, language) | ||||
|     @language = language | ||||
|     @typographies = typographies | ||||
|     @text_entries = text_entries | ||||
|     @output_directory = output_directory | ||||
|     @cache = {} | ||||
|   end | ||||
|  | ||||
|   def cache_file | ||||
|     File.join(@output_directory, "cache/LanguageBin_#{@language}.cache") | ||||
|   end | ||||
|  | ||||
|   def alignment_to_value(alignment) | ||||
|     ALIGNMENT[alignment.to_s] | ||||
|   end | ||||
|  | ||||
|   def text_direction_to_value(direction) | ||||
|     TEXT_DIRECTION[direction.to_s] | ||||
|   end | ||||
|  | ||||
|   def language | ||||
|     @language | ||||
|   end | ||||
|  | ||||
|   def entries | ||||
|     #only generate entries once | ||||
|     @cached_entries ||= | ||||
|       begin | ||||
|         entries = text_entries | ||||
|         entries = handle_no_entries(entries, "DO_NOT_USE") | ||||
|         present(entries) | ||||
|       end | ||||
|   end | ||||
|  | ||||
|   def entries_texts_const_initialization | ||||
|     entries.map { |entry| "    #{entry.text_id}_#{language}" }.join(",\n") | ||||
|   end | ||||
|  | ||||
|   def input_path | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|  | ||||
|   def output_path | ||||
|     "binary/Language#{language}.bin" | ||||
|   end | ||||
|  | ||||
|   def typed_texts(language) | ||||
|     text_entries.collect do |entry| | ||||
|         typography_name = entry.typographies[language] || entry.typography | ||||
|         typography = typographies.find { |t| t.name == typography_name } | ||||
|         alignment = entry.alignments[language] || entry.alignment | ||||
|         direction = entry.directions[language] || entry.direction | ||||
|         TypedTextPresenter.new(alignment, direction, typography); | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def typed_texts_(language) | ||||
|     typed_text_str = typed_texts(language) | ||||
|     puts "typed_text_str = #{typed_text_str}" | ||||
|   end | ||||
|  | ||||
|   def fonts | ||||
|    typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.collect do |f| | ||||
|       "getFont_#{f.cpp_name}_#{f.font_size}_#{f.bpp}bpp" | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def fontmap | ||||
|     fontmap = Hash.new | ||||
|     fonts.each_with_index do |f, i| | ||||
|       fontmap[f] = i | ||||
|     end | ||||
|     fontmap | ||||
|   end | ||||
|  | ||||
|   def header(entries) | ||||
|     nb_entries = 0 | ||||
|     header_struct_size = 12 | ||||
|     header_unicodes_size = 0; | ||||
|     offset_to_texts = 0 | ||||
|     offset_to_indices = 0 | ||||
|     offset_to_typedtext = 0 | ||||
|     entries.each do |entry| | ||||
|       nb_entries += 1 | ||||
|       entry.unicodes.split(', ').each { |c| | ||||
|           header_unicodes_size += 2 | ||||
|       } | ||||
|     end | ||||
|     offset_to_texts = header_struct_size | ||||
|     offset_to_indices = ((offset_to_texts + header_unicodes_size + 3) &~ 0x3) | ||||
|     offset_to_typedtext = ((offset_to_indices + (4 * nb_entries) + 3) &~ 0x3) | ||||
|     # puts "Number of Entries     = #{nb_entries}" | ||||
|     # puts "Header size           = #{header_struct_size}" | ||||
|     # puts "Unicodes size         = #{header_unicodes_size}" | ||||
|     # puts "Text Offset           = #{offset_to_texts}" | ||||
|     # puts "Indices Offset        = #{offset_to_indices}" | ||||
|     # puts "TypedText Offset      = #{offset_to_typedtext}" | ||||
|     LanguageHeader.new('0x' + offset_to_texts.to_s(16), '0x' + offset_to_indices.to_s(16), '0x' + offset_to_typedtext.to_s(16)) | ||||
|   end | ||||
|  | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|  | ||||
|   def run | ||||
|    #build cache dictionary | ||||
|     @cache["typographies"] = typographies.collect{|t| [t.name, t.font_file, t.font_size, t.bpp] } | ||||
|     @cache["language"] = @language | ||||
|     @cache["language_index"] = @text_entries.languages.index(@language) | ||||
|     list = [] #list of index,textid | ||||
|     entries.each_with_index do |entry, index| | ||||
|       list[index] = [entry.unicodes, entry.text_id] | ||||
|     end | ||||
|     @cache["indices"] = list | ||||
|  | ||||
|     new_cache_file = false | ||||
|     if not File::exists?(cache_file) | ||||
|       new_cache_file = true | ||||
|     else | ||||
|         #cache file exists, compare data with cache file | ||||
|         old_cache = JSON.parse(File.read(cache_file)) | ||||
|         new_cache_file = (old_cache != @cache) | ||||
|     end | ||||
|  | ||||
|     if new_cache_file | ||||
|       #write new cache file | ||||
|       FileIO.write_file_silent(cache_file, @cache.to_json) | ||||
|     end | ||||
|  | ||||
|     if (!File::exists?(output_filename)) || new_cache_file | ||||
|       #generate LanguageXX.bin | ||||
|       FileUtils.mkdir_p(File.dirname(input_path)) | ||||
|       callingPath = Pathname.new($calling_path) | ||||
|       filePath = Pathname.new(input_path) | ||||
|       puts "Generating #{filePath.relative_path_from(callingPath)}" | ||||
|       File.open(input_path,'wb') do |f| | ||||
|         # create indices array | ||||
|         indices_arr = [] | ||||
|  | ||||
|         # Writing Language Header | ||||
|         lang_header = header(entries) | ||||
|         lang_header.each { |c| | ||||
|             f.write [c.to_i(16)].pack("L") | ||||
|         } | ||||
|  | ||||
|         # Writing Texts data | ||||
|         indices_arr.clear | ||||
|         indices_arr << 0 # first element is @ offset zero | ||||
|         nb_data_in_entry = 0 | ||||
|         entries.each do |entry| | ||||
|           #puts "All Unicodes #{entry.unicodes}" | ||||
|           entry.unicodes.split(', ').each { |c| | ||||
|               f.write [c.to_i(16)].pack("S") | ||||
|               nb_data_in_entry += 1 | ||||
|           } | ||||
|           indices_arr << nb_data_in_entry #populate the indices array | ||||
|         end | ||||
|  | ||||
|         # Add padding to align on word size  for next indeces data writing | ||||
|         loop do | ||||
|           if Integer(f.pos) == Integer(lang_header.offset_to_indices) | ||||
|             break | ||||
|           end | ||||
|           f.write ["0x00".to_i(16)].pack("S") | ||||
|         end | ||||
|  | ||||
|         # Remove last indice | ||||
|         indices_arr.pop | ||||
|  | ||||
|         # Writing Indices | ||||
|         indices_arr.each { |idx| f.write [idx].pack("L") } | ||||
|  | ||||
|         # Add padding to align on word size for next typed_text data writing | ||||
|         loop do | ||||
|           if Integer(f.pos) == Integer(lang_header.offset_to_typedtext) | ||||
|             break | ||||
|           end | ||||
|           f.write ["0x00".to_i(16)].pack("S") | ||||
|         end | ||||
|  | ||||
|         # Create and Fill TypedTextsData Array | ||||
|         typed_text_arr = [] | ||||
|         if typed_texts(language).empty? | ||||
|           # puts "    { #{0}, #{alignment_to_value("LEFT")}, #{text_direction_to_value("LTR")} }" | ||||
|           typed_text_arr << 0 << alignment_to_value("LEFT") << text_direction_to_value("LTR") | ||||
|         else | ||||
|           typed_texts(language).map do |typed_text| | ||||
|             fontIdx = fontmap["getFont_#{typed_text.typography.cpp_name}_#{typed_text.typography.font_size}_#{typed_text.typography.bpp}bpp"] | ||||
|             alignment = alignment_to_value(typed_text.alignment.upcase) | ||||
|             direction = text_direction_to_value(typed_text.direction.upcase) | ||||
|             # puts "Font Index     --> #{fontIdx}" | ||||
|             # puts "Alignment      --> #{typed_text.alignment.upcase}" | ||||
|             # puts "Text Direction --> #{typed_text.direction.upcase}" | ||||
|             # puts "    { #{fontIdx}, #{alignment_to_value(typed_text.alignment.upcase)}, #{text_direction_to_value(typed_text.direction.upcase)} }" | ||||
|             combined = direction.to_s(2).to_i(2) * 4 + alignment.to_s(2).to_i(2) | ||||
|             typed_text_arr << fontIdx << combined | ||||
|           end | ||||
|         end | ||||
|  | ||||
|         # Writing TypedTextsData | ||||
|         typed_text_arr.each do |idx| | ||||
|             f.write [idx].pack("C") | ||||
|         end | ||||
|  | ||||
|         # # Add padding to align the binary file size on word size | ||||
|         loop do | ||||
|           if ((f.pos & 0x3) == 0) | ||||
|             break | ||||
|           end | ||||
|           f.write ["0x00".to_i(16)].pack("C") | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def handle_no_entries(entries, text) | ||||
|     if entries.empty? | ||||
|        empty_entry = TextEntry.new(text, "typography") | ||||
|        empty_entry.add_translation(language, "") | ||||
|        [empty_entry] | ||||
|     else | ||||
|       entries | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def present(entries) | ||||
|     entries.map do |entry| | ||||
|       Presenter.new(entry.cpp_text_id, ( entry.translation_in(language).unicodes.map { |u| '0x' + u.to_s(16) } << '0x0' ) .join(', ') ) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,179 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'json' | ||||
|  | ||||
| class LanguagesCpp | ||||
|   def initialize(string_indices, text_entries, output_directory, remap_identical_texts, generate_binary_translations) | ||||
|     @string_indices = string_indices #dictionary of all string indices into the characters array | ||||
|     @text_entries = text_entries | ||||
|     @output_directory = output_directory | ||||
|     @remap_identical_texts = remap_identical_texts | ||||
|     @generate_binary_translations = generate_binary_translations | ||||
|   end | ||||
|   def run | ||||
|     @text_entries.languages.each do |language| | ||||
|       LanguageXxCpp.new(@string_indices, @text_entries, @output_directory, @remap_identical_texts, @generate_binary_translations, language).run | ||||
|     end | ||||
|  | ||||
|     #remove any unused LanguageXX.cpp files | ||||
|     Dir.glob("#{@output_directory}/src/Language*.cpp").each do |file| | ||||
|       m = /Language(.*).cpp/.match(file) | ||||
|       if !@text_entries.languages.include?(m[1]) | ||||
|         File.delete(file) if File.exist?(file) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|   end | ||||
| end | ||||
|  | ||||
| class LanguageXxCpp < Template | ||||
|   Presenter = Struct.new(:text_id, :int_array) | ||||
|  | ||||
|   def initialize(string_indices, text_entries, output_directory, remap_identical_texts, generate_binary_translations, language) | ||||
|     @string_indices = string_indices #dictionary of all string indices into the characters array | ||||
|     @remap_identical_texts = remap_identical_texts | ||||
|     @generate_binary_translations = generate_binary_translations | ||||
|     @language = language | ||||
|     super(text_entries, [], output_directory) | ||||
|     @cache = {} | ||||
|   end | ||||
|  | ||||
|   def cache_file | ||||
|     File.join(@output_directory, "cache/LanguageCpp_#{@language}.cache") | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def texts | ||||
|     @text_entries.entries.map(&:cpp_text_id) | ||||
|   end | ||||
|   def run | ||||
|     #build cache dictionary | ||||
|     @cache["remap"] = @remap_identical_texts | ||||
|     @cache["language"] = @language | ||||
|     @cache["language_index"] = @text_entries.languages.index(@language) | ||||
|     if remap_strings? | ||||
|       #save text ids and index | ||||
|       list = [] #list of index,textid | ||||
|       entries.each_with_index do |entry, index| | ||||
|         list[index] = [string_index(entry), entry.text_id] | ||||
|       end | ||||
|       @cache["indices"] = list | ||||
|     else | ||||
|       #save texts | ||||
|       texts = [] | ||||
|       entries.each_with_index do |entry, index| | ||||
|         texts << [entry.text_id, entry.int_array] | ||||
|       end | ||||
|       @cache["texts"] = texts | ||||
|     end | ||||
|  | ||||
|     new_cache_file = false | ||||
|     if not File::exists?(cache_file) | ||||
|       new_cache_file = true | ||||
|     else | ||||
|         #cache file exists, compare data with cache file | ||||
|         old_cache = JSON.parse(File.read(cache_file)) | ||||
|         new_cache_file = (old_cache != @cache) | ||||
|     end | ||||
|  | ||||
|     if new_cache_file | ||||
|       #write new cache file | ||||
|       FileIO.write_file_silent(cache_file, @cache.to_json) | ||||
|     end | ||||
|  | ||||
|     if (!File::exists?(output_filename)) || new_cache_file | ||||
|       #generate LanguageXX.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def remap_strings? | ||||
|     @remap_identical_texts=="yes" | ||||
|   end | ||||
|  | ||||
|   def generate_binary_files? | ||||
|     @generate_binary_translations=="yes" | ||||
|   end | ||||
|  | ||||
|   def language | ||||
|     @language | ||||
|   end | ||||
|  | ||||
|   def entries | ||||
|     #only generate entries once | ||||
|     @cached_entries ||= | ||||
|       begin | ||||
|         entries = text_entries | ||||
|         entries = handle_no_entries(entries, "DO_NOT_USE") | ||||
|         present(entries) | ||||
|       end | ||||
|   end | ||||
|  | ||||
|   def entries_texts_const_initialization | ||||
|     entries.map { |entry| "    #{entry.text_id}_#{language}" }.join(",\n") | ||||
|   end | ||||
|  | ||||
|   def string_index(entry) | ||||
|     index = @string_indices[entry.int_array] | ||||
|     index.to_s | ||||
|   end | ||||
|  | ||||
| #  def entries_s | ||||
| #    entries = text_entries.entries_with_1_substitution | ||||
| #    entries = handle_no_entries(entries, "DO_NOT_USE_S") | ||||
| #    present(entries) | ||||
| #  end | ||||
|  | ||||
| # def entries_s_texts_const_initialization | ||||
| #   entries_s.map { |entry| "#{entry.text_id}_#{language}" }.join(",\n") | ||||
| # end | ||||
|  | ||||
| # def entries_ss | ||||
| #   entries = text_entries.entries_with_2_substitutions | ||||
| #   entries = handle_no_entries(entries, "DO_NOT_USE_SS") | ||||
| #   present(entries) | ||||
| # end | ||||
|  | ||||
| # def entries_ss_texts_const_initialization | ||||
| #   entries_ss.map { |entry| "#{entry.text_id}_#{language}" }.join(",\n") | ||||
| # end | ||||
|  | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','LanguageXX.cpp.temp') | ||||
|   end | ||||
|  | ||||
|   def output_path | ||||
|     "src/Language#{language}.cpp" | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def handle_no_entries(entries, text) | ||||
|     if entries.empty? | ||||
|        empty_entry = TextEntry.new(text, "typography") | ||||
|        empty_entry.add_translation(language, "") | ||||
|        [empty_entry] | ||||
|     else | ||||
|       entries | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def present(entries) | ||||
|     entries.map do |entry| | ||||
|       Presenter.new(entry.cpp_text_id, entry.translation_in(language).unicodes)  | ||||
|     end | ||||
|   end | ||||
|  | ||||
| end | ||||
| @@ -0,0 +1,34 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'erb' | ||||
| require 'lib/file_io' | ||||
|  | ||||
| class Template | ||||
|   attr_accessor :text_entries | ||||
|   attr_accessor :typographies | ||||
|  | ||||
|   def initialize(text_entries, typographies, output_directory) | ||||
|     @text_entries = text_entries | ||||
|     @typographies = typographies | ||||
|     @output_directory = output_directory | ||||
|   end | ||||
|   def run | ||||
|     result = ERB.new(File.read(input_path). | ||||
|         gsub(WINDOWS_LINE_ENDINGS, UNIX_LINE_ENDINGS),0,"<>").result( binding ). | ||||
|         gsub(WINDOWS_LINE_ENDINGS, UNIX_LINE_ENDINGS). | ||||
|         gsub(UNIX_LINE_ENDINGS, LINE_ENDINGS) | ||||
|     FileIO.write_file(File.join(@output_directory, output_path), result) | ||||
|   end | ||||
| end | ||||
|  | ||||
| @@ -0,0 +1,62 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'json' | ||||
|  | ||||
| class TextKeysAndLanguages < Template | ||||
|   def initialize(text_entries, typographies, output_directory) | ||||
|     super | ||||
|     @cache = {} | ||||
|   end | ||||
|   def countries | ||||
|     text_entries.languages.map { |language| language.upcase }.join(",\n    ") | ||||
|   end | ||||
|   def texts | ||||
|     text_entries.entries.map(&:cpp_text_id) | ||||
|   end | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','TextKeysAndLanguages.hpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     'include/texts/TextKeysAndLanguages.hpp' | ||||
|   end | ||||
|   def cache_file | ||||
|     File.join(@output_directory, 'cache/TextKeysAndLanguages.cache') | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     @cache["languages"] = text_entries.languages | ||||
|     @cache["textids"] = texts; | ||||
|  | ||||
|     new_cache_file = false | ||||
|     if not File::exists?(cache_file) | ||||
|       new_cache_file = true | ||||
|     else | ||||
|         #cache file exists, compare data with cache file | ||||
|         old_cache = JSON.parse(File.read(cache_file)) | ||||
|         new_cache_file = (old_cache != @cache) | ||||
|     end | ||||
|  | ||||
|     if new_cache_file | ||||
|       #write new cache file | ||||
|       FileIO.write_file_silent(cache_file, @cache.to_json) | ||||
|     end | ||||
|  | ||||
|     if (!File::exists?(output_filename)) || new_cache_file || $Force_Generate_TextKeysAndLanguages | ||||
|       #generate TextKeysAndLanguages.hpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,115 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class TextsCpp < Template | ||||
|   def initialize(characters, text_entries, typographies, output_directory, remap_identical_texts, generate_binary_translations) | ||||
|     @characters = characters         #one array of the needed strings in optimal order | ||||
|     @remap_identical_texts = remap_identical_texts | ||||
|     @generate_binary_translations = generate_binary_translations | ||||
|     super(text_entries, typographies, output_directory) | ||||
|     @cache = {} | ||||
|   end | ||||
|  | ||||
|   def run | ||||
|     #build @cache and compare with file if exists | ||||
|     @cache["remap"] = @remap_identical_texts | ||||
|  | ||||
|     if remap_strings? | ||||
|       #record language list and strings | ||||
|       @cache["languages"] = countries | ||||
|       @cache["characters"] = @characters | ||||
|     else | ||||
|       #record list of languages only | ||||
|       @cache["languages"] = countries | ||||
|     end | ||||
|      | ||||
|     new_cache_file = false | ||||
|     if not File::exists?(cache_file) | ||||
|       new_cache_file = true | ||||
|     else | ||||
|         #cache file exists, compare data with cache file | ||||
|         old_cache = JSON.parse(File.read(cache_file)) | ||||
|         new_cache_file = (old_cache != @cache) | ||||
|     end | ||||
|  | ||||
|     if new_cache_file | ||||
|       #write new cache file | ||||
|       FileIO.write_file_silent(cache_file, @cache.to_json) | ||||
|     end | ||||
|  | ||||
|     if (!File::exists?(output_filename)) || new_cache_file | ||||
|       #generate TypedTextDatabase.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def remap_strings? | ||||
|     @remap_identical_texts=="yes" | ||||
|   end | ||||
|   def generate_binary_files? | ||||
|     @generate_binary_translations=="yes" | ||||
|   end | ||||
|   def countries | ||||
|     text_entries.languages.map { |language| language.capitalize } | ||||
|   end | ||||
|   def countries_texts | ||||
|     if countries.empty? | ||||
|         "0" | ||||
|     else | ||||
|         countries.map{ |country| "texts#{country}" }.join(",\n    ") | ||||
|     end | ||||
|   end | ||||
|   def is_rtl | ||||
|     text_entries.is_rtl | ||||
|   end | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','Texts.cpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     'src/Texts.cpp' | ||||
|   end | ||||
|   def cache_file | ||||
|     File.join(@output_directory, 'cache/TextsCpp.cache') | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def all_unicodes | ||||
|     if @characters.length==0 | ||||
|       return "0 // No characters in application" | ||||
|     end | ||||
|     text = "" | ||||
|     offset = 0 | ||||
|     initial_offset = 0 | ||||
|     @characters.inject("") do |txt, i| | ||||
|       last = (offset == @characters.length-1) | ||||
|       txt << "0x#{i.to_s(16)}#{last ? '' : ','} " | ||||
|       offset+=1 | ||||
|       if i==0 #end of current word, change line | ||||
|         txt << "// @#{initial_offset} \"#{text}\"" | ||||
|         txt << "\n    " unless last | ||||
|         text = "" | ||||
|         initial_offset = offset | ||||
|       else | ||||
|         if i==2 | ||||
|           text << "<>" | ||||
|         elsif i>=32 && i <127 | ||||
|           text << i.chr | ||||
|         else | ||||
|           text << '?' | ||||
|         end | ||||
|       end | ||||
|       txt | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,139 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class TypedTextDatabaseCpp < Template | ||||
|   TypedTextPresenter = Struct.new(:alignment, :direction, :typography) | ||||
|  | ||||
|   def initialize(text_entries, typographies, output_directory, generate_binary_translations, generate_font_format) | ||||
|     super(text_entries, typographies, output_directory) | ||||
|     @generate_binary_translations = generate_binary_translations | ||||
|     @generate_font_format = generate_font_format | ||||
|     @cache = {} | ||||
|   end | ||||
|  | ||||
|   def run | ||||
|     #compute the typed text table once | ||||
|     compute_typed_texts | ||||
|  | ||||
|     #calculate the cache map | ||||
|     #first the layout databases | ||||
|     databases = {} | ||||
|     layouts.each do |l| | ||||
|       tts = typed_texts(l) | ||||
|       tt_db = [] | ||||
|       tts.inject(tt_db) do |a, tt| | ||||
|         #each text has a font index, alignment and direction | ||||
|         fontIdx = fontmap["getFont_#{tt.typography.cpp_name}_#{tt.typography.font_size}_#{tt.typography.bpp}bpp"] | ||||
|         a << [fontIdx, tt.alignment.upcase, tt.direction.upcase] | ||||
|       end | ||||
|       databases[l] = tt_db | ||||
|     end | ||||
|     #now the list of typed text databases | ||||
|     language_db_list = [] | ||||
|     text_entries.languages.inject(language_db_list) do |list, lang| | ||||
|       list << (layouts.find{|l|l==lang}||'DEFAULT');list | ||||
|     end | ||||
|     @cache["databases"] = databases | ||||
|     @cache["database_list"]=language_db_list | ||||
|     @cache["fonts"] = fontmap | ||||
|     @cache["generate_font_format"] = @generate_font_format | ||||
|  | ||||
|     new_cache_file = false | ||||
|     if not File::exists?(cache_file) | ||||
|       new_cache_file = true | ||||
|     else | ||||
|         #cache file exists, compare data with cache file | ||||
|         old_cache = JSON.parse(File.read(cache_file)) | ||||
|         new_cache_file = (old_cache != @cache) | ||||
|     end | ||||
|  | ||||
|     if new_cache_file | ||||
|       #write new cache file | ||||
|       FileIO.write_file_silent(cache_file, @cache.to_json) | ||||
|     end | ||||
|  | ||||
|     if (!File::exists?(output_filename)) || new_cache_file | ||||
|       #generate TypedTextDatabase.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def typed_texts(layout) | ||||
|     @typed_texts[layout] | ||||
|   end | ||||
|  | ||||
|   def compute_typed_texts | ||||
|     @typed_texts = {} | ||||
|     layouts.each do |layout| | ||||
|       @typed_texts[layout] = text_entries.collect do |entry| | ||||
|         typography_name = entry.typographies[layout] || entry.typography | ||||
|         typography = typographies.find { |t| t.name == typography_name } | ||||
|         alignment = entry.alignments[layout] || entry.alignment | ||||
|         direction = entry.directions[layout] || entry.direction | ||||
|         TypedTextPresenter.new(alignment, direction, typography); | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def generate_binary_files? | ||||
|     @generate_binary_translations=="yes" | ||||
|   end | ||||
|  | ||||
|   def layouts | ||||
|     @layouts ||= | ||||
|       begin | ||||
|         if text_entries.empty? | ||||
|           ["DEFAULT"] | ||||
|         else | ||||
|           (text_entries.first.typographies.keys + text_entries.first.alignments.keys + text_entries.first.directions.keys << "DEFAULT").uniq | ||||
|         end | ||||
|       end | ||||
|   end | ||||
|  | ||||
|   def fonts | ||||
|     @fonts ||= | ||||
|       begin | ||||
|         typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.collect do |f| | ||||
|           "getFont_#{f.cpp_name}_#{f.font_size}_#{f.bpp}bpp" | ||||
|         end | ||||
|       end | ||||
|   end | ||||
|  | ||||
|   def fontmap | ||||
|     @fontmap ||= | ||||
|       begin | ||||
|         @fontmap = Hash.new | ||||
|         fonts.each_with_index do |f, i| | ||||
|           fontmap[f] = i | ||||
|         end | ||||
|         fontmap | ||||
|       end | ||||
|   end | ||||
|  | ||||
|   def font_class_name | ||||
|     @generate_font_format == "1" ? "UnmappedDataFont" : "GeneratedFont" | ||||
|   end | ||||
|  | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','TypedTextDatabase.cpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     'src/TypedTextDatabase.cpp' | ||||
|   end | ||||
|   def cache_file | ||||
|     File.join(@output_directory, 'cache/TypedTextDatabaseCpp.cache') | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class TypedTextDatabaseHpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','TypedTextDatabase.hpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     'include/texts/TypedTextDatabase.hpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate TypedTextDatabase.hpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,542 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class UnicodesTxt | ||||
|   def initialize(text_entries, typographies, output_directory) | ||||
|     @text_entries = text_entries | ||||
|     @typographies = typographies | ||||
|     @output_directory = output_directory | ||||
|   end | ||||
|   def run | ||||
|     unique_typographies = @typographies.map{ |t| Typography.new("", t.font_file, t.font_size, t.bpp) }.uniq.sort_by { |t| sprintf("%s %04d %d",t.font_file,t.font_size,t.bpp) } | ||||
|     unique_typographies.each do |unique_typography| | ||||
|       UnicodeForTypographyTxt.new(@text_entries, @output_directory, @typographies, unique_typography).run | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class UnicodeForTypographyTxt | ||||
|   def initialize(text_entries, output_directory, typographies, unique_typography) | ||||
|     @text_entries = text_entries | ||||
|     @output_directory = output_directory | ||||
|     @typographies = typographies | ||||
|     @unique_typography = unique_typography | ||||
|   end | ||||
|  | ||||
|   def convert_to_contextual_forms(unicodes) | ||||
|     unicodes.sort! | ||||
|     [ | ||||
|       [[0x0621],[0xFE80]], # ARABIC LETTER HAMZA | ||||
|       [[0x0622],[0xFE81,0xFE82]], # ARABIC LETTER ALEF WITH MADDA ABOVE | ||||
|       [[0x0622,0x0644],[0xFEF5,0xFEF6]], # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE | ||||
|       [[0x0623],[0xFE83,0xFE84]], # ARABIC LETTER ALEF WITH HAMZA ABOVE | ||||
|       [[0x0623,0x0644],[0xFEF7,0xFEF8]], # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE | ||||
|       [[0x0624],[0xFE85,0xFE86]], # ARABIC LETTER WAW WITH HAMZA ABOVE | ||||
|       [[0x0625],[0xFE87,0xFE88]], # ARABIC LETTER ALEF WITH HAMZA BELOW | ||||
|       [[0x0625,0x0644],[0xFEF9,0xFEFA]], # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW | ||||
|       [[0x0626],[0xFE89,0xFE8A,0xFE8B,0xFE8C]], # ARABIC LETTER YEH WITH HAMZA ABOVE | ||||
|       [[0x0626,0x0627],[0xFBEA,0xFBEB]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF | ||||
|       [[0x0626,0x062C],[0xFC00,0xFC97]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM | ||||
|       [[0x0626,0x062D],[0xFC01,0xFC98]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH | ||||
|       [[0x0626,0x062E],[0xFC99]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH | ||||
|       [[0x0626,0x0631],[0xFC64]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH | ||||
|       [[0x0626,0x0632],[0xFC65]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN | ||||
|       [[0x0626,0x0645],[0xFC02,0xFC66,0xFC9A,0xFCDF]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM | ||||
|       [[0x0626,0x0646],[0xFC67]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON | ||||
|       [[0x0626,0x0647],[0xFC9B,0xFCE0]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH | ||||
|       [[0x0626,0x0648],[0xFBEE,0xFBEF]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW | ||||
|       [[0x0626,0x0649],[0xFBF9,0xFBFA,0xFBFB,0xFC03,0xFC68]], # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA / ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA | ||||
|       [[0x0626,0x064A],[0xFC04,0xFC69]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH | ||||
|       [[0x0626,0x06C6],[0xFBF2,0xFBF3]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE | ||||
|       [[0x0626,0x06C7],[0xFBF0,0xFBF1]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U | ||||
|       [[0x0626,0x06C8],[0xFBF4,0xFBF5]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU | ||||
|       [[0x0626,0x06D0],[0xFBF6,0xFBF7,0xFBF8]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E | ||||
|       [[0x0626,0x06D5],[0xFBEC,0xFBED]], # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE | ||||
|       [[0x0627],[0xFE8D,0xFE8E]], # ARABIC LETTER ALEF | ||||
|       [[0x0627,0x0628,0x0631,0x0643],[0xFDF3]], # ARABIC LIGATURE AKBAR | ||||
|       [[0x0627,0x0631,0x0644,0x06CC],[0xFDFC]], # RIAL SIGN | ||||
|       [[0x0627,0x0643],[0xFC37,0xFC80]], # ARABIC LIGATURE KAF WITH ALEF | ||||
|       [[0x0627,0x0644],[0xFEFB,0xFEFC]], # ARABIC LIGATURE LAM WITH ALEF | ||||
|       [[0x0627,0x0644,0x0647],[0xFDF2]], # ARABIC LIGATURE ALLAH | ||||
|       [[0x0627,0x0645],[0xFC88]], # ARABIC LIGATURE MEEM WITH ALEF | ||||
|       [[0x0627,0x064B],[0xFD3C,0xFD3D]], # ARABIC LIGATURE ALEF WITH FATHATAN | ||||
|       [[0x0628],[0xFE8F,0xFE90,0xFE91,0xFE92]], # ARABIC LETTER BEH | ||||
|       [[0x0628,0x062C],[0xFC05,0xFC9C]], # ARABIC LIGATURE BEH WITH JEEM | ||||
|       [[0x0628,0x062D],[0xFC06,0xFC9D]], # ARABIC LIGATURE BEH WITH HAH | ||||
|       [[0x0628,0x062D,0x064A],[0xFDC2]], # ARABIC LIGATURE BEH WITH HAH WITH YEH | ||||
|       [[0x0628,0x062E],[0xFC07,0xFC9E]], # ARABIC LIGATURE BEH WITH KHAH | ||||
|       [[0x0628,0x062E,0x064A],[0xFD9E]], # ARABIC LIGATURE BEH WITH KHAH WITH YEH | ||||
|       [[0x0628,0x0631],[0xFC6A]], # ARABIC LIGATURE BEH WITH REH | ||||
|       [[0x0628,0x0632],[0xFC6B]], # ARABIC LIGATURE BEH WITH ZAIN | ||||
|       [[0x0628,0x0645],[0xFC08,0xFC6C,0xFC9F,0xFCE1]], # ARABIC LIGATURE BEH WITH MEEM | ||||
|       [[0x0628,0x0646],[0xFC6D]], # ARABIC LIGATURE BEH WITH NOON | ||||
|       [[0x0628,0x0647],[0xFCA0,0xFCE2]], # ARABIC LIGATURE BEH WITH HEH | ||||
|       [[0x0628,0x0649],[0xFC09,0xFC6E]], # ARABIC LIGATURE BEH WITH ALEF MAKSURA | ||||
|       [[0x0628,0x064A],[0xFC0A,0xFC6F]], # ARABIC LIGATURE BEH WITH YEH | ||||
|       [[0x0629],[0xFE93,0xFE94]], # ARABIC LETTER TEH MARBUTA | ||||
|       [[0x062A],[0xFE95,0xFE96,0xFE97,0xFE98]], # ARABIC LETTER TEH | ||||
|       [[0x062A,0x062C],[0xFC0B,0xFCA1]], # ARABIC LIGATURE TEH WITH JEEM | ||||
|       [[0x062A,0x062C,0x062D],[0xFD51,0xFD52]], # ARABIC LIGATURE TEH WITH HAH WITH JEEM | ||||
|       [[0x062A,0x062C,0x0645],[0xFD50,0xFD55]], # ARABIC LIGATURE TEH WITH JEEM WITH MEEM / ARABIC LIGATURE TEH WITH MEEM WITH JEEM | ||||
|       [[0x062A,0x062C,0x0649],[0xFDA0]], # ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA | ||||
|       [[0x062A,0x062C,0x064A],[0xFD9F]], # ARABIC LIGATURE TEH WITH JEEM WITH YEH | ||||
|       [[0x062A,0x062D],[0xFC0C,0xFCA2]], # ARABIC LIGATURE TEH WITH HAH | ||||
|       [[0x062A,0x062D,0x0645],[0xFD53,0xFD56]], # ARABIC LIGATURE TEH WITH HAH WITH MEEM / ARABIC LIGATURE TEH WITH MEEM WITH HAH | ||||
|       [[0x062A,0x062E],[0xFC0D,0xFCA3]], # ARABIC LIGATURE TEH WITH KHAH | ||||
|       [[0x062A,0x062E,0x0645],[0xFD54,0xFD57]], # ARABIC LIGATURE TEH WITH KHAH WITH MEEM / ARABIC LIGATURE TEH WITH MEEM WITH KHAH | ||||
|       [[0x062A,0x062E,0x0649],[0xFDA2]], # ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA | ||||
|       [[0x062A,0x062E,0x064A],[0xFDA1]], # ARABIC LIGATURE TEH WITH KHAH WITH YEH | ||||
|       [[0x062A,0x0631],[0xFC70]], # ARABIC LIGATURE TEH WITH REH | ||||
|       [[0x062A,0x0632],[0xFC71]], # ARABIC LIGATURE TEH WITH ZAIN | ||||
|       [[0x062A,0x0645],[0xFC0E,0xFC72,0xFCA4,0xFCE3]], # ARABIC LIGATURE TEH WITH MEEM | ||||
|       [[0x062A,0x0645,0x0649],[0xFDA4]], # ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA | ||||
|       [[0x062A,0x0645,0x064A],[0xFDA3]], # ARABIC LIGATURE TEH WITH MEEM WITH YEH | ||||
|       [[0x062A,0x0646],[0xFC73]], # ARABIC LIGATURE TEH WITH NOON | ||||
|       [[0x062A,0x0647],[0xFCA5,0xFCE4]], # ARABIC LIGATURE TEH WITH HEH | ||||
|       [[0x062A,0x0649],[0xFC0F,0xFC74]], # ARABIC LIGATURE TEH WITH ALEF MAKSURA | ||||
|       [[0x062A,0x064A],[0xFC10,0xFC75]], # ARABIC LIGATURE TEH WITH YEH | ||||
|       [[0x062B],[0xFE99,0xFE9A,0xFE9B,0xFE9C]], # ARABIC LETTER THEH | ||||
|       [[0x062B,0x062C],[0xFC11]], # ARABIC LIGATURE THEH WITH JEEM | ||||
|       [[0x062B,0x0631],[0xFC76]], # ARABIC LIGATURE THEH WITH REH | ||||
|       [[0x062B,0x0632],[0xFC77]], # ARABIC LIGATURE THEH WITH ZAIN | ||||
|       [[0x062B,0x0645],[0xFC12,0xFC78,0xFCA6,0xFCE5]], # ARABIC LIGATURE THEH WITH MEEM | ||||
|       [[0x062B,0x0646],[0xFC79]], # ARABIC LIGATURE THEH WITH NOON | ||||
|       [[0x062B,0x0647],[0xFCE6]], # ARABIC LIGATURE THEH WITH HEH | ||||
|       [[0x062B,0x0649],[0xFC13,0xFC7A]], # ARABIC LIGATURE THEH WITH ALEF MAKSURA | ||||
|       [[0x062B,0x064A],[0xFC14,0xFC7B]], # ARABIC LIGATURE THEH WITH YEH | ||||
|       [[0x062C],[0xFE9D,0xFE9E,0xFE9F,0xFEA0]], # ARABIC LETTER JEEM | ||||
|       [[0x062C,0x062D],[0xFC15,0xFC17,0xFCA7,0xFCA9]], # ARABIC LIGATURE JEEM WITH HAH / ARABIC LIGATURE HAH WITH JEEM | ||||
|       [[0x062C,0x062D,0x0633],[0xFD5C,0xFD5D]], # ARABIC LIGATURE SEEN WITH HAH WITH JEEM / ARABIC LIGATURE SEEN WITH JEEM WITH HAH | ||||
|       [[0x062C,0x062D,0x0645],[0xFD58,0xFD59,0xFD89,0xFD8C]], # ARABIC LIGATURE JEEM WITH MEEM WITH HAH / ARABIC LIGATURE MEEM WITH HAH WITH JEEM / ARABIC LIGATURE MEEM WITH JEEM WITH HAH | ||||
|       [[0x062C,0x062D,0x0646],[0xFDB8,0xFDBD]], # ARABIC LIGATURE NOON WITH JEEM WITH HAH | ||||
|       [[0x062C,0x062D,0x0649],[0xFDA6]], # ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA | ||||
|       [[0x062C,0x062D,0x064A],[0xFDBE,0xFDBF]], # ARABIC LIGATURE JEEM WITH HAH WITH YEH / ARABIC LIGATURE HAH WITH JEEM WITH YEH | ||||
|       [[0x062C,0x062E],[0xFC19,0xFCAB]], # ARABIC LIGATURE KHAH WITH JEEM | ||||
|       [[0x062C,0x062E,0x0645],[0xFD8E,0xFD92]], # ARABIC LIGATURE MEEM WITH KHAH WITH JEEM / ARABIC LIGATURE MEEM WITH JEEM WITH KHAH | ||||
|       [[0x062C,0x0633],[0xFC1C,0xFCAD,0xFD34]], # ARABIC LIGATURE SEEN WITH JEEM | ||||
|       [[0x062C,0x0633,0x0645],[0xFD61]], # ARABIC LIGATURE SEEN WITH MEEM WITH JEEM | ||||
|       [[0x062C,0x0633,0x0649],[0xFD5E]], # ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA | ||||
|       [[0x062C,0x0634],[0xFD09,0xFD25,0xFD2D,0xFD37]], # ARABIC LIGATURE SHEEN WITH JEEM | ||||
|       [[0x062C,0x0634,0x064A],[0xFD69]], # ARABIC LIGATURE SHEEN WITH JEEM WITH YEH | ||||
|       [[0x062C,0x0636],[0xFC22,0xFCB4]], # ARABIC LIGATURE DAD WITH JEEM | ||||
|       [[0x062C,0x0639],[0xFC29,0xFCBA]], # ARABIC LIGATURE AIN WITH JEEM | ||||
|       [[0x062C,0x0639,0x0645],[0xFD75,0xFDC4]], # ARABIC LIGATURE AIN WITH JEEM WITH MEEM | ||||
|       [[0x062C,0x063A],[0xFC2B,0xFCBC]], # ARABIC LIGATURE GHAIN WITH JEEM | ||||
|       [[0x062C,0x0641],[0xFC2D,0xFCBE]], # ARABIC LIGATURE FEH WITH JEEM | ||||
|       [[0x062C,0x0643],[0xFC38,0xFCC4]], # ARABIC LIGATURE KAF WITH JEEM | ||||
|       [[0x062C,0x0644],[0xFC3F,0xFCC9,0xFD83,0xFD84]], # ARABIC LIGATURE LAM WITH JEEM / ARABIC LIGATURE LAM WITH JEEM WITH JEEM | ||||
|       [[0x062C,0x0644,0x0645],[0xFDBA,0xFDBC]], # ARABIC LIGATURE LAM WITH JEEM WITH MEEM | ||||
|       [[0x062C,0x0644,0x064A],[0xFDAC]], # ARABIC LIGATURE LAM WITH JEEM WITH YEH | ||||
|       [[0x062C,0x0645],[0xFC16,0xFC45,0xFCA8,0xFCCE,0xFD8D]], # ARABIC LIGATURE JEEM WITH MEEM / ARABIC LIGATURE MEEM WITH JEEM / ARABIC LIGATURE MEEM WITH JEEM WITH MEEM | ||||
|       [[0x062C,0x0645,0x0646],[0xFD97,0xFD98]], # ARABIC LIGATURE NOON WITH JEEM WITH MEEM | ||||
|       [[0x062C,0x0645,0x0647],[0xFD93]], # ARABIC LIGATURE HEH WITH MEEM WITH JEEM | ||||
|       [[0x062C,0x0645,0x0649],[0xFDA7]], # ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA | ||||
|       [[0x062C,0x0645,0x064A],[0xFDA5,0xFDC0]], # ARABIC LIGATURE JEEM WITH MEEM WITH YEH / ARABIC LIGATURE MEEM WITH JEEM WITH YEH | ||||
|       [[0x062C,0x0646],[0xFC4B,0xFCD2]], # ARABIC LIGATURE NOON WITH JEEM | ||||
|       [[0x062C,0x0646,0x0649],[0xFD99]], # ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA | ||||
|       [[0x062C,0x0646,0x064A],[0xFDC7]], # ARABIC LIGATURE NOON WITH JEEM WITH YEH | ||||
|       [[0x062C,0x0647],[0xFC51,0xFCD7]], # ARABIC LIGATURE HEH WITH JEEM | ||||
|       [[0x062C,0x0649],[0xFD01,0xFD1D]], # ARABIC LIGATURE JEEM WITH ALEF MAKSURA | ||||
|       [[0x062C,0x064A],[0xFC55,0xFCDA,0xFD02,0xFD1E,0xFDAF]], # ARABIC LIGATURE YEH WITH JEEM / ARABIC LIGATURE JEEM WITH YEH / ARABIC LIGATURE YEH WITH JEEM WITH YEH | ||||
|       [[0x062D],[0xFEA1,0xFEA2,0xFEA3,0xFEA4]], # ARABIC LETTER HAH | ||||
|       [[0x062D,0x062E],[0xFC1A]], # ARABIC LIGATURE KHAH WITH HAH | ||||
|       [[0x062D,0x062F,0x0645],[0xFDF4]], # ARABIC LIGATURE MOHAMMAD | ||||
|       [[0x062D,0x0633],[0xFC1D,0xFCAE,0xFD35]], # ARABIC LIGATURE SEEN WITH HAH | ||||
|       [[0x062D,0x0633,0x0645],[0xFD5F,0xFD60]], # ARABIC LIGATURE SEEN WITH MEEM WITH HAH | ||||
|       [[0x062D,0x0634],[0xFD0A,0xFD26,0xFD2E,0xFD38]], # ARABIC LIGATURE SHEEN WITH HAH | ||||
|       [[0x062D,0x0634,0x0645],[0xFD67,0xFD68]], # ARABIC LIGATURE SHEEN WITH HAH WITH MEEM | ||||
|       [[0x062D,0x0634,0x064A],[0xFDAA]], # ARABIC LIGATURE SHEEN WITH HAH WITH YEH | ||||
|       [[0x062D,0x0635],[0xFC20,0xFCB1,0xFD64,0xFD65]], # ARABIC LIGATURE SAD WITH HAH / ARABIC LIGATURE SAD WITH HAH WITH HAH | ||||
|       [[0x062D,0x0635,0x064A],[0xFDA9]], # ARABIC LIGATURE SAD WITH HAH WITH YEH | ||||
|       [[0x062D,0x0636],[0xFC23,0xFCB5]], # ARABIC LIGATURE DAD WITH HAH | ||||
|       [[0x062D,0x0636,0x0649],[0xFD6E]], # ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA | ||||
|       [[0x062D,0x0636,0x064A],[0xFDAB]], # ARABIC LIGATURE DAD WITH HAH WITH YEH | ||||
|       [[0x062D,0x0637],[0xFC26,0xFCB8]], # ARABIC LIGATURE TAH WITH HAH | ||||
|       [[0x062D,0x0637,0x0645],[0xFD71,0xFD72]], # ARABIC LIGATURE TAH WITH MEEM WITH HAH | ||||
|       [[0x062D,0x0641],[0xFC2E,0xFCBF]], # ARABIC LIGATURE FEH WITH HAH | ||||
|       [[0x062D,0x0642],[0xFC33,0xFCC2]], # ARABIC LIGATURE QAF WITH HAH | ||||
|       [[0x062D,0x0642,0x0645],[0xFD7E,0xFDB4]], # ARABIC LIGATURE QAF WITH MEEM WITH HAH | ||||
|       [[0x062D,0x0643],[0xFC39,0xFCC5]], # ARABIC LIGATURE KAF WITH HAH | ||||
|       [[0x062D,0x0644],[0xFC40,0xFCCA]], # ARABIC LIGATURE LAM WITH HAH | ||||
|       [[0x062D,0x0644,0x0645],[0xFD80,0xFD87,0xFD88,0xFDB5]], # ARABIC LIGATURE LAM WITH HAH WITH MEEM / ARABIC LIGATURE LAM WITH MEEM WITH HAH | ||||
|       [[0x062D,0x0644,0x0649],[0xFD82]], # ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA | ||||
|       [[0x062D,0x0644,0x064A],[0xFD81]], # ARABIC LIGATURE LAM WITH HAH WITH YEH | ||||
|       [[0x062D,0x0645],[0xFC18,0xFC46,0xFCAA,0xFCCF,0xFD8A]], # ARABIC LIGATURE HAH WITH MEEM / ARABIC LIGATURE MEEM WITH HAH / ARABIC LIGATURE MEEM WITH HAH WITH MEEM | ||||
|       [[0x062D,0x0645,0x0646],[0xFD95]], # ARABIC LIGATURE NOON WITH HAH WITH MEEM | ||||
|       [[0x062D,0x0645,0x0649],[0xFD5B]], # ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA | ||||
|       [[0x062D,0x0645,0x064A],[0xFD5A,0xFD8B]], # ARABIC LIGATURE HAH WITH MEEM WITH YEH / ARABIC LIGATURE MEEM WITH HAH WITH YEH | ||||
|       [[0x062D,0x0646],[0xFC4C,0xFCD3]], # ARABIC LIGATURE NOON WITH HAH | ||||
|       [[0x062D,0x0646,0x0649],[0xFD96]], # ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA | ||||
|       [[0x062D,0x0646,0x064A],[0xFDB3]], # ARABIC LIGATURE NOON WITH HAH WITH YEH | ||||
|       [[0x062D,0x0649],[0xFCFF,0xFD1B]], # ARABIC LIGATURE HAH WITH ALEF MAKSURA | ||||
|       [[0x062D,0x064A],[0xFC56,0xFCDB,0xFD00,0xFD1C,0xFDAE]], # ARABIC LIGATURE YEH WITH HAH / ARABIC LIGATURE HAH WITH YEH / ARABIC LIGATURE YEH WITH HAH WITH YEH | ||||
|       [[0x062E],[0xFEA5,0xFEA6,0xFEA7,0xFEA8]], # ARABIC LETTER KHAH | ||||
|       [[0x062E,0x0633],[0xFC1E,0xFCAF,0xFD36]], # ARABIC LIGATURE SEEN WITH KHAH | ||||
|       [[0x062E,0x0633,0x0649],[0xFDA8]], # ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA | ||||
|       [[0x062E,0x0633,0x064A],[0xFDC6]], # ARABIC LIGATURE SEEN WITH KHAH WITH YEH | ||||
|       [[0x062E,0x0634],[0xFD0B,0xFD27,0xFD2F,0xFD39]], # ARABIC LIGATURE SHEEN WITH KHAH | ||||
|       [[0x062E,0x0634,0x0645],[0xFD6A,0xFD6B]], # ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH | ||||
|       [[0x062E,0x0635],[0xFCB2]], # ARABIC LIGATURE SAD WITH KHAH | ||||
|       [[0x062E,0x0636],[0xFC24,0xFCB6]], # ARABIC LIGATURE DAD WITH KHAH | ||||
|       [[0x062E,0x0636,0x0645],[0xFD6F,0xFD70]], # ARABIC LIGATURE DAD WITH KHAH WITH MEEM | ||||
|       [[0x062E,0x0641],[0xFC2F,0xFCC0]], # ARABIC LIGATURE FEH WITH KHAH | ||||
|       [[0x062E,0x0641,0x0645],[0xFD7C,0xFD7D]], # ARABIC LIGATURE FEH WITH KHAH WITH MEEM | ||||
|       [[0x062E,0x0643],[0xFC3A,0xFCC6]], # ARABIC LIGATURE KAF WITH KHAH | ||||
|       [[0x062E,0x0644],[0xFC41,0xFCCB]], # ARABIC LIGATURE LAM WITH KHAH | ||||
|       [[0x062E,0x0644,0x0645],[0xFD85,0xFD86]], # ARABIC LIGATURE LAM WITH KHAH WITH MEEM | ||||
|       [[0x062E,0x0645],[0xFC1B,0xFC47,0xFCAC,0xFCD0,0xFD8F]], # ARABIC LIGATURE KHAH WITH MEEM / ARABIC LIGATURE MEEM WITH KHAH / ARABIC LIGATURE MEEM WITH KHAH WITH MEEM | ||||
|       [[0x062E,0x0645,0x064A],[0xFDB9]], # ARABIC LIGATURE MEEM WITH KHAH WITH YEH | ||||
|       [[0x062E,0x0646],[0xFC4D,0xFCD4]], # ARABIC LIGATURE NOON WITH KHAH | ||||
|       [[0x062E,0x0649],[0xFD03,0xFD1F]], # ARABIC LIGATURE KHAH WITH ALEF MAKSURA | ||||
|       [[0x062E,0x064A],[0xFC57,0xFCDC,0xFD04,0xFD20]], # ARABIC LIGATURE YEH WITH KHAH / ARABIC LIGATURE KHAH WITH YEH | ||||
|       [[0x062F],[0xFEA9,0xFEAA]], # ARABIC LETTER DAL | ||||
|       [[0x0630],[0xFEAB,0xFEAC]], # ARABIC LETTER THAL | ||||
|       [[0x0630,0x0670],[0xFC5B]], # ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF | ||||
|       [[0x0631],[0xFEAD,0xFEAE]], # ARABIC LETTER REH | ||||
|       [[0x0631,0x0633],[0xFD0E,0xFD2A]], # ARABIC LIGATURE SEEN WITH REH | ||||
|       [[0x0631,0x0633,0x0644,0x0648],[0xFDF6]], # ARABIC LIGATURE RASOUL | ||||
|       [[0x0631,0x0634],[0xFD0D,0xFD29]], # ARABIC LIGATURE SHEEN WITH REH | ||||
|       [[0x0631,0x0635],[0xFD0F,0xFD2B]], # ARABIC LIGATURE SAD WITH REH | ||||
|       [[0x0631,0x0636],[0xFD10,0xFD2C]], # ARABIC LIGATURE DAD WITH REH | ||||
|       [[0x0631,0x0646],[0xFC8A]], # ARABIC LIGATURE NOON WITH REH | ||||
|       [[0x0631,0x064A],[0xFC91]], # ARABIC LIGATURE YEH WITH REH | ||||
|       [[0x0631,0x0670],[0xFC5C]], # ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF | ||||
|       [[0x0632],[0xFEAF,0xFEB0]], # ARABIC LETTER ZAIN | ||||
|       [[0x0632,0x0646],[0xFC8B]], # ARABIC LIGATURE NOON WITH ZAIN | ||||
|       [[0x0632,0x064A],[0xFC92]], # ARABIC LIGATURE YEH WITH ZAIN | ||||
|       [[0x0633],[0xFEB1,0xFEB2,0xFEB3,0xFEB4]], # ARABIC LETTER SEEN | ||||
|       [[0x0633,0x0644,0x0645,0x0648],[0xFDF8]], # ARABIC LIGATURE WASALLAM | ||||
|       [[0x0633,0x0645],[0xFC1F,0xFCB0,0xFCE7,0xFD62,0xFD63]], # ARABIC LIGATURE SEEN WITH MEEM / ARABIC LIGATURE SEEN WITH MEEM WITH MEEM | ||||
|       [[0x0633,0x0647],[0xFCE8,0xFD31]], # ARABIC LIGATURE SEEN WITH HEH | ||||
|       [[0x0633,0x0649],[0xFCFB,0xFD17]], # ARABIC LIGATURE SEEN WITH ALEF MAKSURA | ||||
|       [[0x0633,0x064A],[0xFCFC,0xFD18]], # ARABIC LIGATURE SEEN WITH YEH | ||||
|       [[0x0634],[0xFEB5,0xFEB6,0xFEB7,0xFEB8]], # ARABIC LETTER SHEEN | ||||
|       [[0x0634,0x0645],[0xFCE9,0xFD0C,0xFD28,0xFD30,0xFD6C,0xFD6D]], # ARABIC LIGATURE SHEEN WITH MEEM / ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM | ||||
|       [[0x0634,0x0647],[0xFCEA,0xFD32]], # ARABIC LIGATURE SHEEN WITH HEH | ||||
|       [[0x0634,0x0649],[0xFCFD,0xFD19]], # ARABIC LIGATURE SHEEN WITH ALEF MAKSURA | ||||
|       [[0x0634,0x064A],[0xFCFE,0xFD1A]], # ARABIC LIGATURE SHEEN WITH YEH | ||||
|       [[0x0635],[0xFEB9,0xFEBA,0xFEBB,0xFEBC]], # ARABIC LETTER SAD | ||||
|       [[0x0635,0x0639,0x0644,0x0645],[0xFDF5]], # ARABIC LIGATURE SALAM | ||||
|       [[0x0635,0x0644,0x0649],[0xFDF9]], # ARABIC LIGATURE SALLA | ||||
|       [[0x0635,0x0644,0x06D2],[0xFDF0]], # ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN | ||||
|       [[0x0635,0x0645],[0xFC21,0xFCB3,0xFD66,0xFDC5]], # ARABIC LIGATURE SAD WITH MEEM / ARABIC LIGATURE SAD WITH MEEM WITH MEEM | ||||
|       [[0x0635,0x0649],[0xFD05,0xFD21]], # ARABIC LIGATURE SAD WITH ALEF MAKSURA | ||||
|       [[0x0635,0x064A],[0xFD06,0xFD22]], # ARABIC LIGATURE SAD WITH YEH | ||||
|       [[0x0636],[0xFEBD,0xFEBE,0xFEBF,0xFEC0]], # ARABIC LETTER DAD | ||||
|       [[0x0636,0x0645],[0xFC25,0xFCB7]], # ARABIC LIGATURE DAD WITH MEEM | ||||
|       [[0x0636,0x0649],[0xFD07,0xFD23]], # ARABIC LIGATURE DAD WITH ALEF MAKSURA | ||||
|       [[0x0636,0x064A],[0xFD08,0xFD24]], # ARABIC LIGATURE DAD WITH YEH | ||||
|       [[0x0637],[0xFEC1,0xFEC2,0xFEC3,0xFEC4]], # ARABIC LETTER TAH | ||||
|       [[0x0637,0x0645],[0xFC27,0xFD33,0xFD3A,0xFD73]], # ARABIC LIGATURE TAH WITH MEEM / ARABIC LIGATURE TAH WITH MEEM WITH MEEM | ||||
|       [[0x0637,0x0645,0x064A],[0xFD74]], # ARABIC LIGATURE TAH WITH MEEM WITH YEH | ||||
|       [[0x0637,0x0649],[0xFCF5,0xFD11]], # ARABIC LIGATURE TAH WITH ALEF MAKSURA | ||||
|       [[0x0637,0x064A],[0xFCF6,0xFD12]], # ARABIC LIGATURE TAH WITH YEH | ||||
|       [[0x0638],[0xFEC5,0xFEC6,0xFEC7,0xFEC8]], # ARABIC LETTER ZAH | ||||
|       [[0x0638,0x0645],[0xFC28,0xFCB9,0xFD3B]], # ARABIC LIGATURE ZAH WITH MEEM | ||||
|       [[0x0639],[0xFEC9,0xFECA,0xFECB,0xFECC]], # ARABIC LETTER AIN | ||||
|       [[0x0639,0x0644,0x0647,0x064A],[0xFDF7]], # ARABIC LIGATURE ALAYHE | ||||
|       [[0x0639,0x0645],[0xFC2A,0xFCBB,0xFD76,0xFD77]], # ARABIC LIGATURE AIN WITH MEEM / ARABIC LIGATURE AIN WITH MEEM WITH MEEM | ||||
|       [[0x0639,0x0645,0x0649],[0xFD78]], # ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA | ||||
|       [[0x0639,0x0645,0x064A],[0xFDB6]], # ARABIC LIGATURE AIN WITH MEEM WITH YEH | ||||
|       [[0x0639,0x0649],[0xFCF7,0xFD13]], # ARABIC LIGATURE AIN WITH ALEF MAKSURA | ||||
|       [[0x0639,0x064A],[0xFCF8,0xFD14]], # ARABIC LIGATURE AIN WITH YEH | ||||
|       [[0x063A],[0xFECD,0xFECE,0xFECF,0xFED0]], # ARABIC LETTER GHAIN | ||||
|       [[0x063A,0x0645],[0xFC2C,0xFCBD,0xFD79]], # ARABIC LIGATURE GHAIN WITH MEEM / ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM | ||||
|       [[0x063A,0x0645,0x0649],[0xFD7B]], # ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA | ||||
|       [[0x063A,0x0645,0x064A],[0xFD7A]], # ARABIC LIGATURE GHAIN WITH MEEM WITH YEH | ||||
|       [[0x063A,0x0649],[0xFCF9,0xFD15]], # ARABIC LIGATURE GHAIN WITH ALEF MAKSURA | ||||
|       [[0x063A,0x064A],[0xFCFA,0xFD16]], # ARABIC LIGATURE GHAIN WITH YEH | ||||
|       [[0x0640,0x064B],[0xFE71]], # ARABIC TATWEEL WITH FATHATAN ABOVE | ||||
|       [[0x0640,0x064E],[0xFE77]], # ARABIC FATHA | ||||
|       [[0x0640,0x064E,0x0651],[0xFCF2]], # ARABIC LIGATURE SHADDA WITH FATHA | ||||
|       [[0x0640,0x064F],[0xFE79]], # ARABIC DAMMA | ||||
|       [[0x0640,0x064F,0x0651],[0xFCF3]], # ARABIC LIGATURE SHADDA WITH DAMMA | ||||
|       [[0x0640,0x0650],[0xFE7B]], # ARABIC KASRA | ||||
|       [[0x0640,0x0650,0x0651],[0xFCF4]], # ARABIC LIGATURE SHADDA WITH KASRA | ||||
|       [[0x0640,0x0651],[0xFE7D]], # ARABIC SHADDA | ||||
|       [[0x0640,0x0652],[0xFE7F]], # ARABIC SUKUN | ||||
|       [[0x0641],[0xFED1,0xFED2,0xFED3,0xFED4]], # ARABIC LETTER FEH | ||||
|       [[0x0641,0x0645],[0xFC30,0xFCC1]], # ARABIC LIGATURE FEH WITH MEEM | ||||
|       [[0x0641,0x0645,0x064A],[0xFDC1]], # ARABIC LIGATURE FEH WITH MEEM WITH YEH | ||||
|       [[0x0641,0x0649],[0xFC31,0xFC7C]], # ARABIC LIGATURE FEH WITH ALEF MAKSURA | ||||
|       [[0x0641,0x064A],[0xFC32,0xFC7D]], # ARABIC LIGATURE FEH WITH YEH | ||||
|       [[0x0642],[0xFED5,0xFED6,0xFED7,0xFED8]], # ARABIC LETTER QAF | ||||
|       [[0x0642,0x0644,0x06D2],[0xFDF1]], # ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN | ||||
|       [[0x0642,0x0645],[0xFC34,0xFCC3,0xFD7F]], # ARABIC LIGATURE QAF WITH MEEM / ARABIC LIGATURE QAF WITH MEEM WITH MEEM | ||||
|       [[0x0642,0x0645,0x064A],[0xFDB2]], # ARABIC LIGATURE QAF WITH MEEM WITH YEH | ||||
|       [[0x0642,0x0649],[0xFC35,0xFC7E]], # ARABIC LIGATURE QAF WITH ALEF MAKSURA | ||||
|       [[0x0642,0x064A],[0xFC36,0xFC7F]], # ARABIC LIGATURE QAF WITH YEH | ||||
|       [[0x0643],[0xFED9,0xFEDA,0xFEDB,0xFEDC]], # ARABIC LETTER KAF | ||||
|       [[0x0643,0x0644],[0xFC3B,0xFC81,0xFCC7,0xFCEB]], # ARABIC LIGATURE KAF WITH LAM | ||||
|       [[0x0643,0x0645],[0xFC3C,0xFC82,0xFCC8,0xFCEC,0xFDBB,0xFDC3]], # ARABIC LIGATURE KAF WITH MEEM / ARABIC LIGATURE KAF WITH MEEM WITH MEEM | ||||
|       [[0x0643,0x0645,0x064A],[0xFDB7]], # ARABIC LIGATURE KAF WITH MEEM WITH YEH | ||||
|       [[0x0643,0x0649],[0xFC3D,0xFC83]], # ARABIC LIGATURE KAF WITH ALEF MAKSURA | ||||
|       [[0x0643,0x064A],[0xFC3E,0xFC84]], # ARABIC LIGATURE KAF WITH YEH | ||||
|       [[0x0644],[0xFEDD,0xFEDE,0xFEDF,0xFEE0]], # ARABIC LETTER LAM | ||||
|       [[0x0644,0x0645],[0xFC42,0xFC85,0xFCCC,0xFCED]], # ARABIC LIGATURE LAM WITH MEEM | ||||
|       [[0x0644,0x0645,0x064A],[0xFDAD]], # ARABIC LIGATURE LAM WITH MEEM WITH YEH | ||||
|       [[0x0644,0x0647],[0xFCCD]], # ARABIC LIGATURE LAM WITH HEH | ||||
|       [[0x0644,0x0649],[0xFC43,0xFC86]], # ARABIC LIGATURE LAM WITH ALEF MAKSURA | ||||
|       [[0x0644,0x064A],[0xFC44,0xFC87]], # ARABIC LIGATURE LAM WITH YEH | ||||
|       [[0x0645],[0xFC48,0xFC89,0xFCD1,0xFEE1,0xFEE2,0xFEE3,0xFEE4]], # ARABIC LIGATURE MEEM WITH MEEM / ARABIC LETTER MEEM | ||||
|       [[0x0645,0x0646],[0xFC4E,0xFC8C,0xFCD5,0xFCEE]], # ARABIC LIGATURE NOON WITH MEEM | ||||
|       [[0x0645,0x0646,0x0649],[0xFD9B]], # ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA | ||||
|       [[0x0645,0x0646,0x064A],[0xFD9A]], # ARABIC LIGATURE NOON WITH MEEM WITH YEH | ||||
|       [[0x0645,0x0647],[0xFC52,0xFCD8,0xFD94]], # ARABIC LIGATURE HEH WITH MEEM / ARABIC LIGATURE HEH WITH MEEM WITH MEEM | ||||
|       [[0x0645,0x0649],[0xFC49]], # ARABIC LIGATURE MEEM WITH ALEF MAKSURA | ||||
|       [[0x0645,0x064A],[0xFC4A,0xFC58,0xFC93,0xFCDD,0xFCF0,0xFD9C,0xFD9D,0xFDB0,0xFDB1]], # ARABIC LIGATURE MEEM WITH YEH / ARABIC LIGATURE YEH WITH MEEM / ARABIC LIGATURE YEH WITH MEEM WITH MEEM / ARABIC LIGATURE YEH WITH MEEM WITH YEH / ARABIC LIGATURE MEEM WITH MEEM WITH YEH | ||||
|       [[0x0646],[0xFC8D,0xFEE5,0xFEE6,0xFEE7,0xFEE8]], # ARABIC LIGATURE NOON WITH NOON / ARABIC LETTER NOON | ||||
|       [[0x0646,0x0647],[0xFCD6,0xFCEF]], # ARABIC LIGATURE NOON WITH HEH | ||||
|       [[0x0646,0x0649],[0xFC4F,0xFC8E]], # ARABIC LIGATURE NOON WITH ALEF MAKSURA | ||||
|       [[0x0646,0x064A],[0xFC50,0xFC8F,0xFC94]], # ARABIC LIGATURE NOON WITH YEH / ARABIC LIGATURE YEH WITH NOON | ||||
|       [[0x0647],[0xFEE9,0xFEEA,0xFEEB,0xFEEC]], # ARABIC LETTER HEH | ||||
|       [[0x0647,0x0649],[0xFC53]], # ARABIC LIGATURE HEH WITH ALEF MAKSURA | ||||
|       [[0x0647,0x064A],[0xFC54,0xFCDE,0xFCF1]], # ARABIC LIGATURE HEH WITH YEH / ARABIC LIGATURE YEH WITH HEH | ||||
|       [[0x0647,0x0670],[0xFCD9]], # ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF | ||||
|       [[0x0648],[0xFEED,0xFEEE]], # ARABIC LETTER WAW | ||||
|       [[0x0649],[0xFBE8,0xFBE9,0xFEEF,0xFEF0]], # ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA / ARABIC LETTER ALEF MAKSURA | ||||
|       [[0x0649,0x064A],[0xFC59,0xFC95]], # ARABIC LIGATURE YEH WITH ALEF MAKSURA | ||||
|       [[0x0649,0x0670],[0xFC5D,0xFC90]], # ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF | ||||
|       [[0x064A],[0xFC5A,0xFC96,0xFEF1,0xFEF2,0xFEF3,0xFEF4]], # ARABIC LIGATURE YEH WITH YEH / ARABIC LETTER YEH | ||||
|       [[0x064B],[0xFE70]], # ARABIC FATHATAN | ||||
|       [[0x064C],[0xFE72]], # ARABIC DAMMATAN | ||||
|       [[0x064C,0x0651],[0xFC5E]], # ARABIC LIGATURE SHADDA WITH DAMMATAN | ||||
|       [[0x064D],[0xFE74]], # ARABIC KASRATAN | ||||
|       [[0x064D,0x0651],[0xFC5F]], # ARABIC LIGATURE SHADDA WITH KASRATAN | ||||
|       [[0x064E],[0xFE76]], # ARABIC FATHA | ||||
|       [[0x064E,0x0651],[0xFC60]], # ARABIC LIGATURE SHADDA WITH FATHA | ||||
|       [[0x064F],[0xFE78]], # ARABIC DAMMA | ||||
|       [[0x064F,0x0651],[0xFC61]], # ARABIC LIGATURE SHADDA WITH DAMMA | ||||
|       [[0x0650],[0xFE7A]], # ARABIC KASRA | ||||
|       [[0x0650,0x0651],[0xFC62]], # ARABIC LIGATURE SHADDA WITH KASRA | ||||
|       [[0x0651],[0xFE7C]], # ARABIC SHADDA | ||||
|       [[0x0651,0x0670],[0xFC63]], # ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF | ||||
|       [[0x0652],[0xFE7E]], # ARABIC SUKUN | ||||
|       [[0x0671],[0xFB50,0xFB51]], # ARABIC LETTER ALEF WASLA | ||||
|       [[0x0677],[0xFBDD]], # ARABIC LETTER U WITH HAMZA ABOVE | ||||
|       [[0x0679],[0xFB66,0xFB67,0xFB68,0xFB69]], # ARABIC LETTER TTEH | ||||
|       [[0x067A],[0xFB5E,0xFB5F,0xFB60,0xFB61]], # ARABIC LETTER TTEHEH | ||||
|       [[0x067B],[0xFB52,0xFB53,0xFB54,0xFB55]], # ARABIC LETTER BEEH | ||||
|       [[0x067E],[0xFB56,0xFB57,0xFB58,0xFB59]], # ARABIC LETTER PEH | ||||
|       [[0x067F],[0xFB62,0xFB63,0xFB64,0xFB65]], # ARABIC LETTER TEHEH | ||||
|       [[0x0680],[0xFB5A,0xFB5B,0xFB5C,0xFB5D]], # ARABIC LETTER BEHEH | ||||
|       [[0x0683],[0xFB76,0xFB77,0xFB78,0xFB79]], # ARABIC LETTER NYEH | ||||
|       [[0x0684],[0xFB72,0xFB73,0xFB74,0xFB75]], # ARABIC LETTER DYEH | ||||
|       [[0x0686],[0xFB7A,0xFB7B,0xFB7C,0xFB7D]], # ARABIC LETTER TCHEH | ||||
|       [[0x0687],[0xFB7E,0xFB7F,0xFB80,0xFB81]], # ARABIC LETTER TCHEHEH | ||||
|       [[0x0688],[0xFB88,0xFB89]], # ARABIC LETTER DDAL | ||||
|       [[0x068C],[0xFB84,0xFB85]], # ARABIC LETTER DAHAL | ||||
|       [[0x068D],[0xFB82,0xFB83]], # ARABIC LETTER DDAHAL | ||||
|       [[0x068E],[0xFB86,0xFB87]], # ARABIC LETTER DUL | ||||
|       [[0x0691],[0xFB8C,0xFB8D]], # ARABIC LETTER RREH | ||||
|       [[0x0698],[0xFB8A,0xFB8B]], # ARABIC LETTER JEH | ||||
|       [[0x06A4],[0xFB6A,0xFB6B,0xFB6C,0xFB6D]], # ARABIC LETTER VEH | ||||
|       [[0x06A6],[0xFB6E,0xFB6F,0xFB70,0xFB71]], # ARABIC LETTER PEHEH | ||||
|       [[0x06A9],[0xFB8E,0xFB8F,0xFB90,0xFB91]], # ARABIC LETTER KEHEH | ||||
|       [[0x06AD],[0xFBD3,0xFBD4,0xFBD5,0xFBD6]], # ARABIC LETTER NG | ||||
|       [[0x06AF],[0xFB92,0xFB93,0xFB94,0xFB95]], # ARABIC LETTER GAF | ||||
|       [[0x06B1],[0xFB9A,0xFB9B,0xFB9C,0xFB9D]], # ARABIC LETTER NGOEH | ||||
|       [[0x06B3],[0xFB96,0xFB97,0xFB98,0xFB99]], # ARABIC LETTER GUEH | ||||
|       [[0x06BA],[0xFB9E,0xFB9F]], # ARABIC LETTER NOON GHUNNA | ||||
|       [[0x06BB],[0xFBA0,0xFBA1,0xFBA2,0xFBA3]], # ARABIC LETTER RNOON | ||||
|       [[0x06BE],[0xFBAA,0xFBAB,0xFBAC,0xFBAD]], # ARABIC LETTER HEH DOACHASHMEE | ||||
|       [[0x06C0],[0xFBA4,0xFBA5]], # ARABIC LETTER HEH WITH YEH ABOVE | ||||
|       [[0x06C1],[0xFBA6,0xFBA7,0xFBA8,0xFBA9]], # ARABIC LETTER HEH GOAL | ||||
|       [[0x06C5],[0xFBE0,0xFBE1]], # ARABIC LETTER KIRGHIZ OE | ||||
|       [[0x06C6],[0xFBD9,0xFBDA]], # ARABIC LETTER OE | ||||
|       [[0x06C7],[0xFBD7,0xFBD8]], # ARABIC LETTER U | ||||
|       [[0x06C8],[0xFBDB,0xFBDC]], # ARABIC LETTER YU | ||||
|       [[0x06C9],[0xFBE2,0xFBE3]], # ARABIC LETTER KIRGHIZ YU | ||||
|       [[0x06CB],[0xFBDE,0xFBDF]], # ARABIC LETTER VE | ||||
|       [[0x06CC],[0xFBFC,0xFBFD,0xFBFE,0xFBFF]], # ARABIC LETTER FARSI YEH | ||||
|       [[0x06D0],[0xFBE4,0xFBE5,0xFBE6,0xFBE7]], # ARABIC LETTER E | ||||
|       [[0x06D2],[0xFBAE,0xFBAF]], # ARABIC LETTER YEH BARREE | ||||
|       [[0x06D3],[0xFBB0,0xFBB1]], # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE | ||||
|       [[0],[0]] | ||||
|     ].each do |u,l| | ||||
|       if (unicodes & u) == u | ||||
|         unicodes += l | ||||
|       end | ||||
|     end | ||||
|     unicodes.uniq | ||||
|   end | ||||
|  | ||||
|   def mirror_brackes(unicodes) | ||||
|     [['<','>'],['(',')'],['[',']'],['{','}']].each do |l,r| | ||||
|       has_l = unicodes.include?(l.ord) | ||||
|       has_r = unicodes.include?(r.ord) | ||||
|       unicodes.push(r.ord) if has_l and !has_r | ||||
|       unicodes.push(l.ord) if has_r and !has_l | ||||
|     end | ||||
|     unicodes | ||||
|   end | ||||
|  | ||||
|   def add_thai(unicodes) | ||||
|     # Add Thai unicodes which are used to calculate diacritic positions when the Thai characters have special shapes. | ||||
|     [[0x0E09, 0x0E08],[0x0E13,0x0E0C],[0x0E19,0x0E18],[0x0E1B, 0x0E1A],[0x0E1D,0x0E1C],[0x0E1F,0x0E1E],[0x0E33,0x0E32],[0x0E33,0x0E4D]].each do |has,need| | ||||
|       has_unicode = unicodes.include?(has) | ||||
|       has_needed = unicodes.include?(need) | ||||
|       unicodes.push(need) if has_unicode and !has_needed | ||||
|     end | ||||
|     unicodes | ||||
|   end | ||||
|  | ||||
|   def check_for_rtl(unicodes) | ||||
|     return if @text_entries.is_rtl # No need to look for unicode if RTL already detected | ||||
|     # Look for hebrew (0x0590-0x05ff) or arabic (0x0600-0x06ff) + arabic ligatures (0xFE70-0xFEFF) | ||||
|     @text_entries.unicode_uses_rtl if unicodes.any?{|u| u.between?(0x0590, 0x05FF) || u.between?(0x0600, 0x06FF) || u.between?(0xFE70, 0xFEFE) } | ||||
|   end | ||||
|  | ||||
|   def decode_ranges(str) | ||||
|     result = [] | ||||
|     while str.length > 0 | ||||
|       char_range = str.match(/^(.)-(.)(.*)$/) | ||||
|       if char_range | ||||
|         first_char = char_range[1] | ||||
|         last_char = char_range[2] | ||||
|         result += (first_char.ord .. last_char.ord).to_a | ||||
|         str = char_range[3] | ||||
|       else | ||||
|         num_range = str.match(/^(0[xX][0-9a-fA-F]+|\d+)(?:\.0+)?-(0[xX][0-9a-fA-F]+|\d+)(?:\.0+)?(.*)$/) | ||||
|         if num_range | ||||
|           first_num = Integer(num_range[1]) | ||||
|           last_num = Integer(num_range[2]) | ||||
|           result += (first_num..last_num).to_a | ||||
|           str = num_range[3] | ||||
|         else | ||||
|           num = str.match(/^(0[xX][0-9a-fA-F]+|\d+)(?:\.0+)?(.*)/) | ||||
|           if num | ||||
|             # Check for typo such as 0,2-9 | ||||
|             if num[1].length == 1 | ||||
|               result += [ num[1].ord ] | ||||
|             else | ||||
|               result += [ Integer(num[1]) ] | ||||
|             end | ||||
|             str = num[2] | ||||
|           else | ||||
|             abort "Unexpected character at #{str}" | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|       if str.length > 0 | ||||
|         if str[0] == ',' | ||||
|           str = str[1..-1] | ||||
|         else | ||||
|           abort "Please separate wildcard ranges with ','" | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|     result | ||||
|   end | ||||
|  | ||||
|   def run | ||||
|     typographies_identical = @typographies.select{ |t| t.font_file == @unique_typography.font_file && | ||||
|                                                        t.font_size == @unique_typography.font_size && | ||||
|                                                        t.bpp == @unique_typography.bpp } | ||||
|     typography_names = typographies_identical.map{ |t| t.name }.uniq | ||||
|  | ||||
|     # Find a typography with a fallback character | ||||
|     typography_with_fallback_character = typographies_identical.find { |t| t.fallback_character } | ||||
|     if typography_with_fallback_character | ||||
|       # Now get the actual fallback character (or 'skip') | ||||
|       typography_fallback_character = typography_with_fallback_character.fallback_character | ||||
|       # Check to see if one of the other typographes has a different fallback character | ||||
|       index = typographies_identical.find_index{ |t| t.fallback_character && t.fallback_character != typography_fallback_character } | ||||
|       if index | ||||
|         abort "The fallback character differs for typography \"#{typography_with_fallback_character.name}\" and typography \"#{typographies_identical[index].name}\"" | ||||
|       end | ||||
|       # set all fallback characters to the same character | ||||
|       typographies_identical.each { |t| t.fallback_character = typography_fallback_character } | ||||
|     end | ||||
|  | ||||
|     # Find a typography with a ellipsis character | ||||
|     typography_with_ellipsis_character = typographies_identical.find { |t| t.ellipsis_character } | ||||
|     if typography_with_ellipsis_character | ||||
|       # Now get the actual ellipsis character (or 'skip') | ||||
|       typography_ellipsis_character = typography_with_ellipsis_character.ellipsis_character | ||||
|       # Check to see if one of the other typographes has a different ellipsis character | ||||
|       index = typographies_identical.find_index{ |t| t.ellipsis_character && t.ellipsis_character != typography_ellipsis_character } | ||||
|       if index | ||||
|         abort "The ellipsis character differs for typography \"#{typography_with_ellipsis_character.name}\" and typography \"#{typographies_identical[index].name}\"" | ||||
|       end | ||||
|       # set all ellipsis characters to the same character | ||||
|       typographies_identical.each { |t| t.ellipsis_character = typography_ellipsis_character } | ||||
|     end | ||||
|  | ||||
|     all_translations = typography_names.map{ |typography_name| @text_entries.collect{ |entry| entry.translations_with_typography(typography_name) }.flatten }.flatten | ||||
|  | ||||
|     unicodes = all_translations.map(&:unicodes).flatten.uniq.sort | ||||
|  | ||||
|     typographies_identical.each do |t| | ||||
|       fbc = t.fallback_character | ||||
|       fbcUnicode = 0 | ||||
|       if fbc | ||||
|         if fbc.downcase == 'skip' | ||||
|           fbcUnicode = 0xFEFF | ||||
|         elsif fbc.length == 1 | ||||
|           fbcUnicode = fbc[0].ord | ||||
|         else | ||||
|           begin | ||||
|             fbcUnicode = Integer(fbc.gsub(/\.0*$/,'')) | ||||
|           rescue | ||||
|             fail "Please only specify one character or ('skip') as Fallback Character, typography \"#{typography_with_fallback_character.name}\" has Fallback Character \"#{typography_with_fallback_character.fallback_character}\"" | ||||
|           end | ||||
|         end | ||||
|         unicodes += [ fbcUnicode ] | ||||
|       end | ||||
|       t.fallback_character = fbcUnicode | ||||
|  | ||||
|       tec = t.ellipsis_character | ||||
|       tecUnicode = 0 | ||||
|       if tec | ||||
|         if tec.length == 1 | ||||
|           tecUnicode = tec[0].ord | ||||
|         else | ||||
|           begin | ||||
|             tecUnicode = Integer(tec.gsub(/\.0*$/,'')) | ||||
|           rescue | ||||
|             fail "Please only specify one character as Ellipsis Character for typography \"#{typography_with_fallback_character.name}\"" | ||||
|           end | ||||
|         end | ||||
|         unicodes += [ tecUnicode ] | ||||
|       end | ||||
|       t.ellipsis_character = tecUnicode | ||||
|     end | ||||
|     typographies_identical.each{ |t| | ||||
|       if t.wildcard_characters | ||||
|         t.wildcard_characters.to_s.split('').each { |c| | ||||
|           unicodes += [ c[0].ord ] | ||||
|         } | ||||
|       end | ||||
|       if t.wildcard_ranges | ||||
|         unicodes += decode_ranges(t.wildcard_ranges) | ||||
|       end | ||||
|     } | ||||
|      | ||||
|     unicodes = convert_to_contextual_forms(unicodes) | ||||
|  | ||||
|     unicodes = mirror_brackes(unicodes) | ||||
|  | ||||
|     unicodes = add_thai(unicodes) | ||||
|  | ||||
|     unicodes.delete(0x0002) # TouchGFX wildcard character | ||||
|     unicodes.delete(0x200B) # ZERO WIDTH SPACE | ||||
|     unicodes.delete(0xFEFF) # ZERO WIDTH NO-BREAK SPACE | ||||
|  | ||||
|     unicodes = unicodes.uniq.sort | ||||
|  | ||||
|     check_for_rtl(unicodes) | ||||
|  | ||||
|     FileIO.write_file_silent(File.join(@output_directory, "UnicodeList#{@unique_typography.cpp_name}_#{@unique_typography.font_size}_#{@unique_typography.bpp}.txt"), unicodes.join(LINE_ENDINGS) ) | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class UnmappedDataFontCpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','UnmappedDataFont.cpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/src/UnmappedDataFont.cpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate UnmappedDataFont.cpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,30 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class UnmappedDataFontHpp < Template | ||||
|   def input_path | ||||
|     File.join(root_dir,'Templates','UnmappedDataFont.hpp.temp') | ||||
|   end | ||||
|   def output_path | ||||
|     '/include/fonts/UnmappedDataFont.hpp' | ||||
|   end | ||||
|   def output_filename | ||||
|     File.join(@output_directory, output_path) | ||||
|   end | ||||
|   def run | ||||
|     if (!File::exists?(output_filename)) | ||||
|       #generate GeneratedFont.hpp | ||||
|       super | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,96 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'roo' | ||||
| require 'lib/text_entries' | ||||
|  | ||||
| class ExcelRow | ||||
|  | ||||
|   def initialize(excel_file, header, row_number, first_column) | ||||
|     @excel_file = excel_file | ||||
|     @header = header | ||||
|     @row_number = row_number | ||||
|     @first_column = first_column | ||||
|   end | ||||
|  | ||||
|   def [](column_header) | ||||
|     value_at(@row_number, column_number(column_header.to_s)) | ||||
|   end | ||||
|  | ||||
|   def exists?(name) | ||||
|     !@header[name.to_s.downcase].nil? | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def column_number(name) | ||||
|     column_index = @header[name.downcase] | ||||
|     raise "#{name} column not found in excel file" if column_index.nil? | ||||
|     column_index + @first_column | ||||
|   end | ||||
|  | ||||
|   def value_at(row, col) | ||||
|     value = @excel_file.cell(row,col).to_s | ||||
|     if value.empty? | ||||
|       nil | ||||
|     else | ||||
|       check_encoding(value) | ||||
|       value | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def check_encoding(value) | ||||
|     puts value if value.force_encoding("UTF-8").valid_encoding? == false | ||||
|   end | ||||
|  | ||||
| end | ||||
|  | ||||
| class ExcelReader | ||||
|  | ||||
|   def initialize(file_name, sheet, header_row, first_column) | ||||
|     @excel_file = Roo::Excelx.new file_name | ||||
|     @sheet = sheet | ||||
|     @excel_file.default_sheet = sheet | ||||
|     @header_row = header_row | ||||
|     @first_column = first_column | ||||
|     @header = {} | ||||
|     header.each_with_index do |cell, ix| | ||||
|       @header[cell.downcase] = ix | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def read_header | ||||
|     yield header | ||||
|   end | ||||
|  | ||||
|   def read_rows | ||||
|     (@header_row + 1).upto(last_row_number) do |row_number| | ||||
|       yield row(row_number) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def last_row_number | ||||
|     @excel_file.last_row | ||||
|   end | ||||
|  | ||||
|   def header | ||||
|     @excel_file.row(@header_row).compact.map(&:strip) | ||||
|   end | ||||
|  | ||||
|   def row(row_number) | ||||
|     ExcelRow.new(@excel_file, @header, row_number, @first_column) | ||||
|   end | ||||
|  | ||||
| end | ||||
| @@ -0,0 +1,32 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'rubygems' | ||||
| require 'erb' | ||||
| require 'fileutils' | ||||
| require 'pathname' | ||||
|  | ||||
| class FileIO | ||||
|   def self.write_file(file_name, contents) | ||||
|     callingPath = Pathname.new($calling_path) | ||||
|     filePath = Pathname.new(file_name) | ||||
|     puts "Generating #{filePath.relative_path_from(callingPath)}" | ||||
|     write_file_silent(file_name, contents) | ||||
|   end | ||||
|   def self.write_file_silent(file_name, contents) | ||||
|     FileUtils.mkdir_p(File.dirname(file_name)) | ||||
|     unless File.exist?(file_name) && contents == File.open(file_name, 'r') { |f| f.read() } | ||||
|       File.open(file_name, 'w') { |f| f.write(contents) } | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,35 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'lib/text_entries_excel_reader' | ||||
| require 'lib/typographies_excel_reader' | ||||
| require 'lib/sanitizer' | ||||
| require 'lib/string_collector' | ||||
| require 'lib/outputter' | ||||
|  | ||||
| class Generator | ||||
|   def run(file_name, output_path, text_output_path, font_asset_path, data_format, remap_identical_texts, generate_binary_translations, generate_binary_fonts, framebuffer_bpp, generate_font_format) | ||||
|     #puts "Running TextEntriesExcelReader, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     text_entries = TextEntriesExcelReader.new(file_name).run | ||||
|     #puts "Running TypoEntriesExcelReader, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     typographies = TypographiesExcelReader.new(file_name).run | ||||
|     #puts "Running Sanitizer, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     Sanitizer.new(text_entries, typographies, framebuffer_bpp).run | ||||
|     #puts "Running StringCollector, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     if remap_identical_texts=='yes' | ||||
|       string_indices, characters = StringCollector.new(text_entries, typographies).run | ||||
|     end | ||||
|     #puts "Running Outputter, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     Outputter.new(string_indices, characters, text_entries, typographies, text_output_path, output_path, font_asset_path, data_format, remap_identical_texts, generate_binary_translations, generate_binary_fonts, generate_font_format).run | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,90 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'lib/file_io' | ||||
| require 'lib/emitters/template' | ||||
| require 'lib/emitters/text_keys_and_languages_hpp' | ||||
| require 'lib/emitters/texts_cpp' | ||||
| require 'lib/emitters/languages_cpp' | ||||
| require 'lib/emitters/languages_bin' | ||||
| require 'lib/emitters/unicodes_txt' | ||||
| require 'lib/emitters/fonts_cpp' | ||||
| require 'lib/emitters/generated_font_cpp' | ||||
| require 'lib/emitters/generated_font_hpp' | ||||
| require 'lib/emitters/unmapped_data_font_cpp' | ||||
| require 'lib/emitters/unmapped_data_font_hpp' | ||||
| require 'lib/emitters/cached_font_cpp' | ||||
| require 'lib/emitters/cached_font_hpp' | ||||
| require 'lib/emitters/font_cache_cpp' | ||||
| require 'lib/emitters/font_cache_hpp' | ||||
| require 'lib/emitters/application_font_provider_hpp' | ||||
| require 'lib/emitters/application_font_provider_cpp' | ||||
| require 'lib/emitters/typed_text_database_hpp' | ||||
| require 'lib/emitters/typed_text_database_cpp' | ||||
|  | ||||
| class Outputter | ||||
|   def initialize(string_indices, characters, text_entries, typographies, localization_output_directory, fonts_output_directory, font_asset_path, data_format, remap_identical_texts, generate_binary_translations, generate_binary_fonts, generate_font_format) | ||||
|     @string_indices = string_indices #dictionary of all string indices into the characters array | ||||
|     @characters = characters         #one array of the needed strings in optimal order | ||||
|     @text_entries = text_entries | ||||
|     @typographies = typographies | ||||
|     @localization_output_directory = localization_output_directory | ||||
|     @fonts_output_directory = fonts_output_directory | ||||
|     @font_asset_path = font_asset_path | ||||
|     @data_format = data_format | ||||
|     @remap_identical_texts = remap_identical_texts | ||||
|     @generate_binary_translations = generate_binary_translations | ||||
|     @generate_binary_fonts = generate_binary_fonts | ||||
|     @generate_font_format = generate_font_format | ||||
|   end | ||||
|  | ||||
|   def run | ||||
|  | ||||
|     #puts "Running Outputter1, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     [ GeneratedFontHpp, | ||||
|       GeneratedFontCpp, | ||||
|       UnmappedDataFontHpp, | ||||
|       UnmappedDataFontCpp, | ||||
|       CachedFontHpp, | ||||
|       CachedFontCpp, | ||||
|       FontCacheHpp, | ||||
|       FontCacheCpp, | ||||
|       UnicodesTxt ].each { |template| template.new(@text_entries, @typographies, @fonts_output_directory).run } | ||||
|  | ||||
|     [ ApplicationFontProviderCpp, | ||||
|       ApplicationFontProviderHpp ].each { |template| template.new(@text_entries, @typographies, @fonts_output_directory, @generate_font_format).run } | ||||
|  | ||||
|     #puts "Running Outputter2, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     [ TextKeysAndLanguages, | ||||
|       TypedTextDatabaseHpp].each { |template| template.new(@text_entries, @typographies, @localization_output_directory).run } | ||||
|  | ||||
|     #puts "Running Outputter3, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     TypedTextDatabaseCpp.new(@text_entries, @typographies, @localization_output_directory, @generate_binary_translations, @generate_font_format).run | ||||
|  | ||||
|     #puts "Running Outputter4, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     TextsCpp.new(@characters, @text_entries, @typographies, @localization_output_directory, @remap_identical_texts, @generate_binary_translations).run | ||||
|  | ||||
|     #puts "Running Outputter5, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     LanguagesCpp.new(@string_indices, @text_entries, @localization_output_directory, @remap_identical_texts, @generate_binary_translations).run | ||||
|  | ||||
|     #puts "Running Outputter6, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     FontsCpp.new(@text_entries, @typographies, @fonts_output_directory, @font_asset_path, @data_format, @generate_binary_fonts, @generate_font_format).run | ||||
|  | ||||
|     if @generate_binary_translations.downcase == 'yes' | ||||
|       #puts "Running Outputter7, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|       [ LanguagesBin ].each { |template| template.new(@text_entries, @typographies, @localization_output_directory).run } | ||||
|     end | ||||
|     #puts "Done Outputter, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|   end | ||||
| end | ||||
|  | ||||
| @@ -0,0 +1,189 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| TextEntrySanitizer = Struct.new(:text_entries, :typographies, :framebuffer_bpp) | ||||
|  | ||||
| $warning_prefix = "\nWARNING (TextConverter): " | ||||
|  | ||||
| class Sanitizer < TextEntrySanitizer | ||||
|  | ||||
|   def run | ||||
|     [ RemoveDuplicateKeys, | ||||
|       RemoveIncompleteLanguages, | ||||
|       RemoveKeysWithMoreThanTwoSubstitutions, | ||||
|       RemoveKeysWithDifferentNumberOfSubstitutions, | ||||
|       RemoveTextEntriesWithInvalidTypography, | ||||
|       RemoveTextEntriesWithInvalidAlignment, | ||||
|       RemoveTextEntriesWithInvalidDirection, | ||||
|       CheckSizeAndBpp, | ||||
|       DowngradeFontsBitDepth | ||||
|     ].each do |sanitizer| | ||||
|       sanitizer.new(text_entries, typographies, framebuffer_bpp).run | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class RemoveDuplicateKeys < TextEntrySanitizer | ||||
|   def run | ||||
| #        puts "Removing duplicate text ids" | ||||
|     counts = Hash.new(0) | ||||
|     counts = text_entries.inject(Hash.new(0)) do |h, entry| | ||||
|       h[entry.cpp_text_id.upcase] = h[entry.cpp_text_id.upcase] + 1 | ||||
|       h | ||||
|     end | ||||
|  | ||||
|     text_entries.each do |text_entry| | ||||
|       if counts[text_entry.cpp_text_id.upcase] > 1 | ||||
|         raise "#{$warning_prefix} Duplicate key removed: #{text_entry.text_id}, yields cpp identifier #{text_entry.cpp_text_id.upcase}" | ||||
|         text_entries.remove(text_entry) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class RemoveIncompleteLanguages < TextEntrySanitizer | ||||
|   def run | ||||
| #       puts "Removing incomplete languages" | ||||
|     languages = text_entries.languages | ||||
|     languages.each do |language| | ||||
|       text_entries_with_missing_translations = text_entries.select do |text_entry| | ||||
|         text_entry.translation_in(language).empty? | ||||
|       end | ||||
|       text_entries_with_missing_translations.each do |text_entry| | ||||
|         raise "#{$warning_prefix} Language #{language} is missing translation for #{text_entry.text_id}" | ||||
|       end | ||||
|       if text_entries_with_missing_translations.any? | ||||
|         text_entries.remove_language(language) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class RemoveKeysWithMoreThanTwoSubstitutions < TextEntrySanitizer | ||||
|   def run | ||||
| #        puts "Removing text entries with more than two substitutions" | ||||
|     text_entries.languages.each do |language| | ||||
|       text_entries_with_more_than_two_substitutions = text_entries.select do |text_entry| | ||||
|         text_entry.number_of_substitutions_in(language) > 2 | ||||
|       end | ||||
|       text_entries_with_more_than_two_substitutions.each do |text_entry| | ||||
|         raise "#{$warning_prefix}  Text id #{text_entry.text_id} has #{text_entry.number_of_substitutions_in(language)} substitutions" | ||||
|         #text_entries.remove(text_entry) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class RemoveKeysWithDifferentNumberOfSubstitutions < TextEntrySanitizer | ||||
|   def run | ||||
| #        puts "Removing text entries with different number of substitutions" | ||||
|     text_entries.each do |text_entry| | ||||
|       translations = text_entry.translations | ||||
|       number_of_substitutions_per_translation = translations.collect { |translation| translation.number_of_substitutions } | ||||
|       if number_of_substitutions_per_translation.uniq.count > 1 | ||||
|         raise "#{$warning_prefix} Text id #{text_entry.text_id} has different number of substitutions for some languages" | ||||
|         #text_entries.remove(text_entry) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class RemoveTextEntriesWithInvalidTypography < TextEntrySanitizer | ||||
|   def run | ||||
| #        puts "Removing text entries referring to non existing typographies" | ||||
|     text_entries.each do |text_entry| | ||||
|       non_existing_typographies = (text_entry.get_all_typographies - typographies.map( &:name )).compact; | ||||
|  | ||||
|       if non_existing_typographies.any? | ||||
|         raise "#{$warning_prefix} Text id #{text_entry.text_id} uses unknown typographies #{non_existing_typographies}" | ||||
|         #text_entries.remove(text_entry) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class RemoveTextEntriesWithInvalidAlignment < TextEntrySanitizer | ||||
|   def run | ||||
|     #    puts "Removing text entries referring to invalid alignment" | ||||
|     text_entries.each do |text_entry| | ||||
|       alignments = text_entry.get_all_alignments_as_string | ||||
|       illegal_alignments = alignments.select { |a| !['LEFT', 'RIGHT', 'CENTER'].include?(a) } | ||||
|       if illegal_alignments.any? | ||||
|         raise "#{$warning_prefix} Text id #{text_entry.text_id} uses unknown alignments #{illegal_alignments}" | ||||
|         #text_entries.remove(text_entry) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class RemoveTextEntriesWithInvalidDirection < TextEntrySanitizer | ||||
|   def run | ||||
|     #    puts "Removing text entries referring to invalid direction" | ||||
|     text_entries.each do |text_entry| | ||||
|       directions = text_entry.get_all_directions_as_string | ||||
|       illegal_directions = directions.select { |d| !['LTR', 'RTL'].include?(d) } | ||||
|       if illegal_directions.any? | ||||
|         raise "#{$warning_prefix} Text id #{text_entry.text_id} uses unknown directions #{illegal_directions}" | ||||
|         #text_entries.remove(text_entry) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class CheckSizeAndBpp < TextEntrySanitizer | ||||
|   def run | ||||
| #        puts "Raise an error if typography size or bpp does have sane values" | ||||
|     typographies.each do |typography| | ||||
|       if (not [1, 2, 4, 8].include?(typography.bpp)) | ||||
|         raise "#{$warning_prefix} Typography named '#{typography.name}' has bpp value '#{typography.bpp}', which is not a valid value" | ||||
|       end | ||||
|  | ||||
|       if ( (not typography.font_size.integer?) or (typography.font_size < 1) ) | ||||
|         raise "#{$warning_prefix} Typography named '#{typography.name}' has font size value '#{typography.font_size}', which is not a valid value" | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| class DowngradeFontsBitDepth < TextEntrySanitizer | ||||
|   def run | ||||
|     if (not framebuffer_bpp.nil?) | ||||
|       m = framebuffer_bpp.match(/BPP(\d+)/) | ||||
|       bpp = m.nil? ? 24 : m[1].to_i | ||||
|       typographies.each do |typography| | ||||
|         case bpp | ||||
|         when 8 | ||||
|           if typography.bpp > 2 | ||||
|             puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 2bpp" | ||||
|             typography.bpp = 2 | ||||
|           end | ||||
|         when 4 | ||||
|           if typography.bpp > 4 | ||||
|             puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 4bpp" | ||||
|             typography.bpp = 4 | ||||
|           end | ||||
|         when 2 | ||||
|           if typography.bpp > 2 | ||||
|             puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 2bpp" | ||||
|             typography.bpp = 2 | ||||
|           end | ||||
|         when 1 | ||||
|           if typography.bpp > 1 | ||||
|             puts "Downgrading typography #{typography.name} from #{typography.bpp.to_s}bpp to 1bpp" | ||||
|             typography.bpp = 1 | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,59 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| CollectorStruct = Struct.new(:text_entries, :typographies) | ||||
|  | ||||
| $warning_prefix = "\nWARNING (TextConverter): " | ||||
|  | ||||
| class StringCollector < CollectorStruct | ||||
|   def run | ||||
|     string_indices = {} | ||||
|     characters = Array.new | ||||
|  | ||||
|     #collect all strings for sorting | ||||
|     all_strings = Array.new | ||||
|     text_entries.each do |text_entry| | ||||
|       text_entry.translations.each do |translation| | ||||
|         all_strings.push(translation) | ||||
|       end | ||||
|     end | ||||
|     #sort by length | ||||
|     all_strings.sort_by!(){|x| -x.length} | ||||
|  | ||||
|     #collect all string indeces, and add to characters array | ||||
|     all_strings.each do |translation| | ||||
|       #lookup translation in hash | ||||
|       #if not found, add to characters and insert index in hash for translation and all suffices | ||||
|       #if found, do nothing | ||||
|       unicodes = translation.unicodes | ||||
|       index = string_indices[unicodes] | ||||
|       if not index | ||||
|         new_index = characters.length | ||||
|         #puts "new string: #{translation.to_cpp} index: #{new_index}" | ||||
|         characters.concat(unicodes).push(0) | ||||
|         for start in 0 .. unicodes.length-1 | ||||
|           sub_string = unicodes[start..-1] | ||||
|           # if the substring is present, all shorter substrings are also present, so do not add again | ||||
|           break if string_indices[sub_string] | ||||
|           string_indices[sub_string] = (new_index + start) | ||||
|         end | ||||
|       else | ||||
|         #puts "existing string: #{translation.to_cpp} index: #{index}" | ||||
|       end | ||||
|     end | ||||
|     #puts characters.inject("") {|t,i| "#{t}#{i==0?'|' : i.chr}"} | ||||
|     #puts "Total: #{characters.length} chars" | ||||
|     #puts string_indices | ||||
|     [string_indices, characters] | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,270 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class TextEntries | ||||
|   include Enumerable | ||||
|  | ||||
|   def initialize | ||||
|     @entries = [] | ||||
|     @is_rtl = false | ||||
|     @unicode_is_rtl = false | ||||
|   end | ||||
|  | ||||
|   def each(&block) | ||||
|     @entries.each(&block) | ||||
|   end | ||||
|  | ||||
|   def remove(entry) | ||||
|     @entries.delete(entry) | ||||
|   end | ||||
|  | ||||
|   def add(entry) | ||||
|     @entries.push(entry) | ||||
|   end | ||||
|  | ||||
|   def empty? | ||||
|     @entries.empty? | ||||
|   end | ||||
|  | ||||
|   def different_typographies | ||||
|     [ar,default] | ||||
|   end | ||||
|  | ||||
|   def different_alignments | ||||
|     [ar,default] | ||||
|   end | ||||
|  | ||||
|   def languages | ||||
|     if @entries.empty? | ||||
|       [] | ||||
|     else | ||||
|       @entries.first.languages | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def remove_language(language) | ||||
|     @entries.each { |entry| entry.remove_translation_in(language) } | ||||
|   end | ||||
|  | ||||
|   def typographies | ||||
|     @entries.map { |entry| entry.typography }.uniq | ||||
|   end | ||||
|  | ||||
|   def entries | ||||
|     @entries | ||||
|   end | ||||
|  | ||||
|   def with_typography(typography) | ||||
|     @entries.select { |entry| entry.typography == typography } | ||||
|   end | ||||
|  | ||||
|   def include?(text_entry) | ||||
|     @entries.find { |entry| entry.text_id == text_entry.text_id || entry.cpp_text_id == text_entry.cpp_text_id } | ||||
|   end | ||||
|  | ||||
|   def unicode_uses_rtl | ||||
|     @unicode_is_rtl = true | ||||
|   end | ||||
|  | ||||
|   def is_rtl | ||||
|     @unicode_is_rtl || @entries.any? { |entry| entry.is_rtl } | ||||
|   end | ||||
|  | ||||
| end | ||||
|  | ||||
| class TextEntry | ||||
|   attr_reader :text_id | ||||
|   attr_reader :typography | ||||
|   attr_reader :typographies | ||||
|   attr_reader :alignments | ||||
|   attr_reader :directions | ||||
|  | ||||
|   def initialize(text_id, typography, alignment, direction) | ||||
|     @text_id = text_id | ||||
|     @typographies = {} | ||||
|     @alignments = {} | ||||
|     @directions = {} | ||||
|     @translations = {} | ||||
|  | ||||
|     # default typography | ||||
|     @typography = typography | ||||
|  | ||||
|     # default alignment | ||||
|     @alignment = alignment | ||||
|  | ||||
|     # default direction | ||||
|     @direction = get_direction_as_string(direction) | ||||
|     @right_to_left = false | ||||
|   end | ||||
|  | ||||
|   def add_typography(language, typography) | ||||
|     @typographies[language] = typography | ||||
|   end | ||||
|   def add_alignment(language, alignment) | ||||
|     @alignments[language] = alignment | ||||
|   end | ||||
|   def add_direction(language, direction) | ||||
|     @directions[language] = direction | ||||
|   end | ||||
|  | ||||
|   def add_translation(language, text) | ||||
|     translation = Translation.new(text) | ||||
|     @translations[language] = translation | ||||
|   end | ||||
|  | ||||
|   def remove_translation_in(language) | ||||
|     @translations.delete(language) | ||||
|   end | ||||
|  | ||||
|   def translations | ||||
|     @translations.values | ||||
|   end | ||||
|  | ||||
|   def translation_in(language) | ||||
|     @translations[language] | ||||
|   end | ||||
|  | ||||
|   def translations_with_typography(typography) | ||||
|     languages_with_typography = languages.select do |language| | ||||
|       if @typographies[language].nil? | ||||
|         @typography == typography | ||||
|       else | ||||
|         @typographies[language] == typography | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     languages_with_typography.collect{ |language| translation_in(language) } | ||||
|   end | ||||
|  | ||||
|   def languages | ||||
|     @translations.keys | ||||
|   end | ||||
|  | ||||
|   def number_of_substitutions_in(language) | ||||
|     @translations[language].number_of_substitutions | ||||
|   end | ||||
|  | ||||
|   def cpp_text_id | ||||
|     cppify(text_id) | ||||
|   end | ||||
|  | ||||
|   def alignment | ||||
|     get_alignment_as_string(@alignment) | ||||
|   end | ||||
|  | ||||
|   def direction | ||||
|     get_direction_as_string(@direction) | ||||
|   end | ||||
|  | ||||
|   # includes the default typography | ||||
|   def get_all_typographies | ||||
|     @typographies.values.compact.insert(0, @typography) | ||||
|   end | ||||
|  | ||||
|   # includes the default alignment | ||||
|   def get_all_alignments_as_string | ||||
|     @alignments.values.compact.collect{ |a| get_alignment_as_string(a) }.insert(0, alignment) | ||||
|   end | ||||
|  | ||||
|   # includes the default direction | ||||
|   def get_all_directions_as_string | ||||
|     @directions.values.compact.collect{ |a| get_direction_as_string(a) }.insert(0, direction) | ||||
|   end | ||||
|  | ||||
|   def is_rtl | ||||
|     @is_rtl | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def get_alignment_as_string(a) | ||||
|     case a.to_s.downcase | ||||
|     when 'right' | ||||
|       'RIGHT' | ||||
|     when 'center' | ||||
|       'CENTER' | ||||
|     when 'left', '' | ||||
|       'LEFT' | ||||
|     else | ||||
|       a.to_s | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def get_direction_as_string(d) | ||||
|     case d.to_s.downcase | ||||
|     when 'ltr', '' | ||||
|       'LTR' | ||||
|     when 'rtl' | ||||
|       @is_rtl = true | ||||
|       'RTL' | ||||
|     else | ||||
|       d.to_s | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def cppify(text) | ||||
|     t_type = "T_" + text | ||||
|  | ||||
|     # strip the keys for characters, that can not be used in C++ | ||||
|     t_type = t_type.to_ascii | ||||
|     t_type.gsub!(" ", "_") | ||||
|     t_type.gsub!(")", "") | ||||
|     t_type.gsub!("(", "") | ||||
|     t_type.gsub!("-", "") | ||||
|     t_type.gsub!("\"", "") | ||||
|     t_type.gsub!("/", "") | ||||
|     t_type.gsub!(".", "") | ||||
|     t_type | ||||
|   end | ||||
| end | ||||
|  | ||||
| class Translation | ||||
|   def initialize(text) | ||||
|     @text = text | ||||
|   end | ||||
|   def empty? | ||||
|     @text.nil? || @text.empty? | ||||
|   end | ||||
|   def length | ||||
|     @text.length | ||||
|   end | ||||
|   def number_of_substitutions | ||||
|     to_cpp.count("\2") | ||||
|   end | ||||
|   def unicodes | ||||
|     @unicodes ||= | ||||
|       begin | ||||
|         numbers.map { |number| number.to_s.gsub(/\[|\]/,'').to_i } | ||||
|       end | ||||
|   end | ||||
|   def to_cpp | ||||
|     cpp_text = @text.gsub("\2", '') # Remove all existing placeholders | ||||
|     regex = Regexp.new(/([^\\]|^)<(|.*?[^\\])>/) # Avoid matching \< and \> | ||||
|     while cpp_text.match(regex) | ||||
|       cpp_text.gsub!(regex, '\1'+"\2") | ||||
|     end | ||||
|     cpp_text.gsub('\\<', '<').gsub('\\>', '>') # Remove \ before < and > | ||||
|   end | ||||
|   private | ||||
|   def numbers | ||||
|     to_cpp.unpack('U*') | ||||
|   end | ||||
| end | ||||
|  | ||||
| class String | ||||
|   def to_ascii | ||||
|     # modernized version of http://craigjolicoeur.com/blog/ruby-iconv-to-the-rescue | ||||
|     self.encode("ASCII", "UTF-8", :undef => :replace, :invalid => :replace, :replace => ''). | ||||
|       unpack('U*').select { |cp| cp < 127 }.pack('U*') | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,129 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'lib/excel_reader' | ||||
|  | ||||
| class TextEntriesExcelReader | ||||
|   attr_reader :reader | ||||
|  | ||||
|   def initialize(file_name) | ||||
|     #puts "Running TextEntriesExcelReader:init, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     header_row_number = 3 | ||||
|     header_column_number = 2 | ||||
|     @reader = ExcelReader.new(file_name, "Translation", header_row_number, header_column_number) | ||||
|     @text_entries = TextEntries.new | ||||
|   end | ||||
|  | ||||
|   def run | ||||
|     #puts "Running TextEntriesExcelReader:run, #{Time.now.strftime("%H:%M:%S:%L")}" | ||||
|     reader.read_header do |header| | ||||
|       @alignments = header.select { |column| column.match(/^.*-ALIGNMENT$/i) }.map(&:capitalize) | ||||
|       @directions = header.select { |column| column.match(/^.*-DIRECTION$/i) }.map(&:capitalize) | ||||
|       @typographies = header.select { |column| column.match(/^.*-TYPOGRAPHY$/i) }.map(&:capitalize) | ||||
|       @languages = header.select { |column| column.match(/^(\w{1,3})$/i ) }.map(&:capitalize) | ||||
|     end | ||||
|  | ||||
|     # Check for undefined languages in language specific typographies | ||||
|     # Any undefined language specific typographies are removed | ||||
|     @typographies.select! do |typography| | ||||
|       language, _ = typography.split('-') | ||||
|  | ||||
|       if not @languages.include?(language) | ||||
|         raise "#{$warning_prefix} Unknown language in column #{language}-TYPOGRAPHY" | ||||
|       end | ||||
|  | ||||
|       @languages.include?(language) | ||||
|     end | ||||
|  | ||||
|     # Check for undefined languages in language specific alignments | ||||
|     # Any undefined language specific alignments are removed | ||||
|     @alignments.select! do |alignment| | ||||
|       language, _ = alignment.split('-') | ||||
|  | ||||
|       if not @languages.include?(language) | ||||
|         raise "#{$warning_prefix} Unknown language in column #{language}-ALIGNMENT" | ||||
|       end | ||||
|  | ||||
|       @languages.include?(language) | ||||
|     end | ||||
|  | ||||
|     # Check for undefined languages in language specific directions | ||||
|     # Any undefined language specific directions are removed | ||||
|     @directions.select! do |direction| | ||||
|       language, _ = direction.split('-') | ||||
|  | ||||
|       if not @languages.include?(language) | ||||
|         raise "#{$warning_prefix} Unknown language in column #{language}-DIRECTION" | ||||
|       end | ||||
|  | ||||
|       @languages.include?(language) | ||||
|     end | ||||
|  | ||||
|     reader.read_rows do |row| | ||||
|       text_id = row[:"Text ID"] | ||||
|       default_typography = row[:"Typography Name"] | ||||
|       default_alignment = row[:Alignment] | ||||
|       if row.exists?(:Direction) | ||||
|         default_direction = row[:Direction] | ||||
|       end | ||||
|  | ||||
|       text_id = text_id.strip if text_id | ||||
|       default_typography = default_typography.strip if default_typography | ||||
|       default_alignment = default_alignment.strip if default_alignment | ||||
|       default_direction = default_direction.strip if default_direction | ||||
|  | ||||
|       if text_id && default_typography | ||||
|         unless text_id.match(/^([0-9a-zA-Z_])*$/) | ||||
|           puts "Illegal characters found in Text ID '#{text_id}'" | ||||
|           fail | ||||
|         end | ||||
|          | ||||
|         text_entry = TextEntry.new(text_id, default_typography, default_alignment, default_direction) | ||||
|  | ||||
|         @typographies.each do |typography| | ||||
|           language, _ = typography.split('-') | ||||
|           #puts "adding typography #{typography}" | ||||
|           t = row[typography] | ||||
|           t = t.strip if t | ||||
|           text_entry.add_typography(language, t) | ||||
|         end | ||||
|  | ||||
|         @alignments.each do |alignment| | ||||
|           language, _ = alignment.split('-') | ||||
|           #puts "adding alignment #{alignment}" | ||||
|           a = row[alignment] | ||||
|           a = a.strip if a | ||||
|           text_entry.add_alignment(language, a) | ||||
|         end | ||||
|  | ||||
|         @directions.each do |direction| | ||||
|           language, _ = direction.split('-') | ||||
|           #puts "adding direction #{direction}" | ||||
|           d = row[direction] | ||||
|           d = d.strip if d | ||||
|           text_entry.add_direction(language, d) | ||||
|         end | ||||
|  | ||||
|         @languages.each do |language| | ||||
|           #puts "adding language #{language}" | ||||
|           # Do *not* strip leading/trailing whitespace from translations. | ||||
|           text_entry.add_translation(language, row[language]) | ||||
|         end | ||||
|  | ||||
|         @text_entries.add(text_entry) | ||||
|       end | ||||
|     end | ||||
|     @text_entries | ||||
|   end | ||||
|  | ||||
| end | ||||
| @@ -0,0 +1,18 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| class Typography < Struct.new(:name, :font_file, :font_size, :bpp, :fallback_character, :ellipsis_character, :wildcard_characters, :wildcard_ranges) | ||||
|   def cpp_name | ||||
|     font_file.gsub(/\.ttf$/,"").gsub(/[^0-9a-zA-Z]/, "_") | ||||
|   end | ||||
| end | ||||
| @@ -0,0 +1,73 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| require 'lib/excel_reader' | ||||
| require 'lib/typographies' | ||||
|  | ||||
| class TypographiesExcelReader | ||||
|   attr_reader :reader | ||||
|  | ||||
|   def initialize(file_name) | ||||
|     header_row_number = 3 | ||||
|     header_column_number = 2 | ||||
|     @reader = ExcelReader.new(file_name, 'Typography', header_row_number, header_column_number) | ||||
|     @typographies = [] | ||||
|   end | ||||
|  | ||||
|   def run | ||||
|     reader.read_rows do |row| | ||||
|       name = row[:'Typography Name'] | ||||
|       font = row[:font] | ||||
|       size = row[:size] | ||||
|       bpp = row[:bpp] | ||||
|       if row.exists?(:'Fallback Character') | ||||
|         fallback_character = row[:'Fallback Character'] | ||||
|       end | ||||
|       if row.exists?(:'Wildcard Characters') | ||||
|         wildcard_characters = row[:'Wildcard Characters'] | ||||
|       end | ||||
|       if row.exists?(:'Widget Wildcard Characters') | ||||
|         wildcard_characters ||= '' # Make sure wc_chars is defined | ||||
|         wildcard_characters += (row[:'Widget Wildcard Characters'] || '') | ||||
|       end | ||||
|       if row.exists?(:'Character Ranges') # New name | ||||
|         wildcard_ranges = row[:'Character Ranges'] | ||||
|       elsif row.exists?(:'Wildcard Ranges') # Old name | ||||
|         wildcard_ranges = row[:'Wildcard Ranges'] | ||||
|       end | ||||
|       if row.exists?(:'Ellipsis Character') | ||||
|         ellipsis_character = row[:'Ellipsis Character'] | ||||
|       end | ||||
|  | ||||
|       if name | ||||
|         name = name.strip | ||||
|         unless name.match(/^([0-9a-zA-Z_])*$/) | ||||
|           fail "Illegal characters found in Text ID '#{name}'" | ||||
|         end | ||||
|       end | ||||
|       font = font.strip if font | ||||
|       size = size.strip if size | ||||
|       bpp = bpp.strip if bpp | ||||
|       fallback_character = fallback_character.strip if fallback_character | ||||
|       wildcard_characters = wildcard_characters.strip if wildcard_characters | ||||
|       wildcard_ranges = wildcard_ranges.strip if wildcard_ranges | ||||
|       ellipsis_character = ellipsis_character.strip if ellipsis_character | ||||
|  | ||||
|       if name && font && size && bpp | ||||
|         @typographies.push Typography.new(name, font, size.to_i, bpp.to_i, fallback_character, ellipsis_character, wildcard_characters, wildcard_ranges) | ||||
|       end | ||||
|     end | ||||
|     @typographies | ||||
|   end | ||||
|  | ||||
| end | ||||
| @@ -0,0 +1,220 @@ | ||||
| ############################################################################## | ||||
| # This file is part of the TouchGFX 4.16.1 distribution. | ||||
| # | ||||
| # <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
| # All rights reserved.</center></h2> | ||||
| # | ||||
| # This software component is licensed by ST under Ultimate Liberty license | ||||
| # SLA0044, the "License"; You may not use this file except in compliance with | ||||
| # the License. You may obtain a copy of the License at: | ||||
| #                             www.st.com/SLA0044 | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| $:.unshift File.dirname(__FILE__) | ||||
|  | ||||
| WINDOWS_LINE_ENDINGS = "\r\n" | ||||
| UNIX_LINE_ENDINGS = "\n" | ||||
| #on windows/mingw file.write will it self translate \n to \r\n, on linux not | ||||
| LINE_ENDINGS = RUBY_PLATFORM.match(/linux/) ? WINDOWS_LINE_ENDINGS : UNIX_LINE_ENDINGS | ||||
|  | ||||
| def root_dir | ||||
|   # Get the dirname of this (main.rb) file: | ||||
|   @root_dir ||= File.dirname(__FILE__) | ||||
| end | ||||
|  | ||||
| class Main | ||||
|   def self.banner | ||||
|     <<-BANNER | ||||
| Create binary and cpp text files from excel translations | ||||
|  | ||||
| Usage: #{File.basename($0)} file.xlsx path/to/fontconvert.out path/to/fonts_output_dir path/to/localization_output_dir path/to/font/asset calling_path {remap|yes|no} {A1|A2|A4|A8} {binary_translations} {binary_fonts} {RGB565|RGB888|BW|GRAY2|GRAY4|ARGB2222|ABGR2222|RGBA2222|BGRA2222} | ||||
| Where 'remap'/'yes' will map identical texts to the same memory area to save space | ||||
|       'A1'/'A2'/'A4'/'A8' will generate fonts in the given format | ||||
|       'binary_translations' will generate binary translations instead of cpp files | ||||
|       'binary_fonts' will generate binary font files instead of cpp files | ||||
|       last argument is the framebuffer format (used to limit the bit depth of the generated fonts) | ||||
|       Configuration specified in the application.config file take precedence over the commandline arguments | ||||
| BANNER | ||||
|   end | ||||
|  | ||||
|   def self.missing_files | ||||
|     return !File.exists?("#{@fonts_output_path}/include/fonts/ApplicationFontProvider.hpp") || | ||||
|            !File.exists?("#{@localization_output_path}/include/texts/TextKeysAndLanguages.hpp") | ||||
|   end | ||||
|  | ||||
|   if __FILE__ == $0 | ||||
|  | ||||
|     if ARGV.count < 6 | ||||
|       abort self.banner | ||||
|     end | ||||
|  | ||||
|     file_name = ARGV.shift | ||||
|     font_convert_path = ARGV.shift | ||||
|     @fonts_output_path = ARGV.shift | ||||
|     @localization_output_path = ARGV.shift | ||||
|     font_asset_path = ARGV.shift | ||||
|     $calling_path = ARGV.shift | ||||
|  | ||||
|     #optional arguments | ||||
|     remap_identical_texts = ARGV.include?("yes") || ARGV.include?("remap") ? "yes" : "no" | ||||
|  | ||||
|     data_format_a1 = ARGV.include?("A1") ? "A1" : "" | ||||
|     data_format_a2 = ARGV.include?("A2") ? "A2" : "" | ||||
|     data_format_a4 = ARGV.include?("A4") ? "A4" : "" | ||||
|     data_format_a8 = ARGV.include?("A8") ? "A8" : "" | ||||
|  | ||||
|     generate_binary_translations = ARGV.include?("binary_translations") ? "yes" : "no" | ||||
|     generate_binary_fonts = ARGV.include?("binary_fonts") ? "yes" : "no" | ||||
|  | ||||
|     framebuffer_bpp = "" | ||||
|     ["BPP32", "BPP24", "BPP16", "BPP8", "BPP4", "BPP2", "BPP1"].each do |format| | ||||
|       if ARGV.include?(format) | ||||
|         framebuffer_bpp = format | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     require 'fileutils' | ||||
|     require 'json' | ||||
|     require 'lib/file_io' | ||||
|  | ||||
|     generate_font_format = "0" # 0 = normal font format, 1 = unmapped_flash_font_format | ||||
|  | ||||
|     application_config = File.join($calling_path, "application.config") | ||||
|     if File.file?(application_config) | ||||
|       text_conf = JSON.parse(File.read(application_config))["text_configuration"] || {} | ||||
|  | ||||
|       remap = text_conf["remap"] | ||||
|       if !remap.nil? | ||||
|         remap_identical_texts = remap == "yes" ? "yes" : "no" | ||||
|       end | ||||
|  | ||||
|       a1 = text_conf["a1"] | ||||
|       if !a1.nil? | ||||
|         data_format_a1 = a1 == "yes" ? "A1" : "" | ||||
|       end | ||||
|       a2 = text_conf["a2"] | ||||
|       if !a2.nil? | ||||
|         data_format_a2 = a2 == "yes" ? "A2" : "" | ||||
|       end | ||||
|       a4 = text_conf["a4"] | ||||
|       if !a4.nil? | ||||
|         data_format_a4 = a4 == "yes" ? "A4" : "" | ||||
|       end | ||||
|       a8 = text_conf["a8"] | ||||
|       if !a8.nil? | ||||
|         data_format_a8 = a8 == "yes" ? "A8" : "" | ||||
|       end | ||||
|  | ||||
|       binary_translations = text_conf["binary_translations"] | ||||
|       if !binary_translations.nil? | ||||
|         generate_binary_translations = binary_translations == "yes" ? "yes" : "no" | ||||
|       end | ||||
|  | ||||
|       binary_fonts = text_conf["binary_fonts"] | ||||
|       if !binary_fonts.nil? | ||||
|         generate_binary_fonts = binary_fonts== "yes" ? "yes" : "no" | ||||
|       end | ||||
|  | ||||
|       bpp = text_conf["framebuffer_bpp"] | ||||
|       if !bpp.nil? | ||||
|         framebuffer_bpp = "BPP" + bpp | ||||
|       end | ||||
|  | ||||
|       font_format = text_conf["font_format"] | ||||
|       if !font_format.nil? | ||||
|         values = ["0", "1"] | ||||
|         if values.include? font_format | ||||
|           generate_font_format = font_format | ||||
|         else | ||||
|           puts "Font format #{font_format} not correct, using default: \"0\"" | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     data_format = "#{data_format_a1}#{data_format_a2}#{data_format_a4}#{data_format_a8}" | ||||
|     if generate_binary_translations == "yes" && remap_identical_texts == "yes" | ||||
|       puts "Disabling remapping of identical texts, because binary language files are generated" | ||||
|       remap_identical_texts = "no" | ||||
|     end | ||||
|  | ||||
|     begin | ||||
|       # 1. if text_converter is newer than compile_time.cache, remove all files under generated/texts and generated/fonts | ||||
|       # 1b if generated/fonts/include/fonts/ApplicationFontProvider.hpp is missing, force generation of TextKeysAndLanguages.hpp | ||||
|       # 1c if generated/texts/cache/options.cache contents differ from supplies arguments, force run | ||||
|       # 2. if generated/texts/cache/compile_time.cache is newer than excel sheet and fonts/ApplicationFontProvider.hpp exists then stop now | ||||
|       # 3. remove UnicodeList*.txt and CharSizes*.csv | ||||
|       # 4. create #{@localization_output_path}/include/texts/ and #{@fonts_output_path}/include/fonts/ | ||||
|  | ||||
|       # 1: | ||||
|       text_converter_time = [File.mtime( __FILE__), File.ctime( __FILE__ )].max; | ||||
|  | ||||
|       if ((compile_time_exists = File.exists?("#{@localization_output_path}/cache/compile_time.cache")) && text_converter_time > File.mtime("#{@localization_output_path}/cache/compile_time.cache")) || !compile_time_exists | ||||
|         #remove all files, as text converter is newer (probably upgraded to new TouchGFX) | ||||
|         puts "Cleaning generated files from #{@localization_output_path} and #{@fonts_output_path}." | ||||
|         if @localization_output_path.match /generated\/texts$/ | ||||
|           local_path = @localization_output_path.gsub('\\','/') | ||||
|           FileUtils.rm_rf("#{local_path}") | ||||
|         end | ||||
|         if @fonts_output_path.match /generated\/fonts$/ | ||||
|           local_path = @fonts_output_path.gsub('\\','/') | ||||
|           FileUtils.rm_rf("#{local_path}") | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # 1b: | ||||
|       $Force_Generate_TextKeysAndLanguages = self.missing_files | ||||
|  | ||||
|       # 1c: | ||||
|       force_run = false | ||||
|       options_file = "#{@localization_output_path}/cache/options.cache" | ||||
|       options = File.exists?(options_file) && File.read(options_file) | ||||
|  | ||||
|       new_options = { :remap => remap_identical_texts, | ||||
|                       :data_format => data_format, | ||||
|                       :binary_translations => generate_binary_translations, | ||||
|                       :binary_fonts => generate_binary_fonts, | ||||
|                       :font_format => generate_font_format, | ||||
|                       :framebuffer_bpp => framebuffer_bpp }.to_json | ||||
|  | ||||
|       if (options != new_options) | ||||
|         force_run = true | ||||
|         FileIO.write_file_silent(options_file, new_options) | ||||
|       end | ||||
|  | ||||
|       # 2: | ||||
|       if File.exists?("#{@localization_output_path}/cache/compile_time.cache") && !self.missing_files && !force_run | ||||
|         excel_mod_time = [File.mtime(file_name), File.ctime(file_name)].max | ||||
|         if excel_mod_time < File.mtime("#{@localization_output_path}/cache/compile_time.cache") | ||||
|           exit | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # 3: | ||||
|       Dir["#{@fonts_output_path}/UnicodeList*.txt"].each do |text_file| | ||||
|         FileUtils.rm_f(text_file) | ||||
|       end | ||||
|       Dir["#{@fonts_output_path}/CharSizes*.csv"].each do |text_file| | ||||
|         FileUtils.rm_f(text_file) | ||||
|       end | ||||
|  | ||||
|       # 4: | ||||
|       FileUtils.mkdir_p("#{@localization_output_path}/include/texts/") | ||||
|       FileUtils.mkdir_p("#{@fonts_output_path}/include/fonts") | ||||
|  | ||||
|       require 'rubygems' | ||||
|       require 'lib/generator' | ||||
|       require 'lib/emitters/fonts_cpp' | ||||
|       FontsCpp.font_convert = font_convert_path | ||||
|       Generator.new.run(file_name, @fonts_output_path, @localization_output_path, font_asset_path, data_format, remap_identical_texts, generate_binary_translations, generate_binary_fonts, framebuffer_bpp, generate_font_format) | ||||
|       #touch the cache compile time that we rely on in the makefile | ||||
|       FileUtils.touch "#{@localization_output_path}/cache/compile_time.cache" | ||||
|  | ||||
|     rescue SystemExit => e | ||||
|  | ||||
|     rescue Exception => e | ||||
|       STDERR.puts e | ||||
|       abort "an error occurred in converting texts:\r\n#{e}" | ||||
|     end | ||||
|   end | ||||
| end | ||||
		Reference in New Issue
	
	Block a user