Initial commit

This commit is contained in:
2023-11-26 20:13:49 +01:00
commit dc2dc5c58b
820 changed files with 258269 additions and 0 deletions

View File

@ -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 %>
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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(&currentFileGlyphNode, sizeof(GlyphNode));
currentFileGlyphNumber++;
}
if (currentFileGlyphNode.unicode != unicode)
{
//glyphnode not found
return top;
}
//glyphnode found
uint32_t glyphSize = ((currentFileGlyphNode.width() + 1) & ~1) * currentFileGlyphNode.height() * bpp / 8;
glyphSize = (glyphSize + 3) & ~0x03;
uint32_t requiredMem = SizeGlyphNode + 4 + glyphSize; // GlyphNode + next ptr + glyph
//is space available before sortedString
if (top + requiredMem > (uint8_t*)sortedString)
{
outOfMemory = true;
return top;
}
*(GlyphNode*)top = currentFileGlyphNode;
//clear next pointer
uint8_t** next = (uint8_t**)(top + SizeGlyphNode);
*next = 0;
top += requiredMem;
return top;
}
void FontCache::cacheData(uint32_t bpp, GlyphNode* first)
{
GlyphNode* gn = first;
while (gn)
{
uint8_t* p = (uint8_t*)gn;
if (gn->dataOffset != 0xFFFFFFFF)
{
p += SizeGlyphNode;
//next pointer
p += 4;
//seek and copy
setPosition(glyphDataOffset + gn->dataOffset);
uint32_t glyphSize = ((gn->width() + 1) & ~1) * gn->height() * bpp / 8;
readData(p, glyphSize);
//mark glyphNode as cached
gn->dataOffset = 0xFFFFFFFF;
}
GlyphNode** next = (GlyphNode**)((uint8_t*)gn + SizeGlyphNode);
gn = *next;
}
}
bool FontCache::createSortedString(const Unicode::UnicodeChar* string)
{
int length = Unicode::strlen(string);
//sorted string is allocated at end of buffer
sortedString = (Unicode::UnicodeChar*)(gsubStart - (length + 1) * 2);
if ((uint8_t*)sortedString < top)
{
//unable to allocate string buffer in end of memory
return false;
}
int n = 0;
Unicode::UnicodeChar* uc = sortedString;
while (*string)
{
*uc++ = *string++;
n++;
}
*uc = 0;
return sortSortedString(n);
}
bool FontCache::createSortedLigatures(CachedFont* font, TypedText t, const Unicode::UnicodeChar* string, ...)
{
va_list pArg;
va_start(pArg, string);
TextProvider tp;
tp.initialize(string, pArg, font->getGSUBTable());
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 %>

View File

@ -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

View File

@ -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 &currentLanguagePtr[currentLanguageIndices[id]];
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,76 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,93 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,122 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,282 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,179 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,34 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,62 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,115 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,139 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,542 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,30 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,96 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,32 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,35 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,90 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,189 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,59 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,270 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,129 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,18 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,73 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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

View File

@ -0,0 +1,220 @@
##############################################################################
# This file is part of the TouchGFX 4.16.1 distribution.
#
# <h2><center>&copy; 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