This commit is contained in:
thomas committed 2026-10-18 14:06:40 +02:00
commit 2c2202e60d
2491 files changed
+1295990

No files matched your search

@@ -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()[<%= get_font_index(index) %>]);
<% end %>
default:
return 0;
}
<% end %>
}
@@ -0,0 +1,59 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_APPLICATIONFONTPROVIDER_HPP
#define TOUCHGFX_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 %> = <%= get_font_index(index) %>; <%= get_font_comment_space(index) %>// <%= get_font_comment(index) %>
<% end %>
static const uint16_t NUMBER_OF_FONTS = <%= get_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 // TOUCHGFX_APPLICATIONFONTPROVIDER_HPP
@@ -0,0 +1,55 @@
/* 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;
}
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;
}
} // namespace touchgfx
@@ -0,0 +1,93 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_CACHEDFONT_HPP
#define TOUCHGFX_CACHEDFONT_HPP
#include <fonts/FontCache.hpp>
#include <fonts/GeneratedFont.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->fontHeight,
data->baseline,
data->pixAboveTop,
data->pixBelowBottom,
data->bitsPerPixel,
data->byteAlignRow,
data->maxLeft,
data->maxRight,
0, // glyphDataPointer
0, // Kerning table not used for cached font
data->fallbackChar,
data->ellipsisChar,
0, // lsubTablePointer
0), // contextualFormsPointer
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;
}
virtual const FontContextualFormsTable* getContextualFormsTable() const
{
if (arabicTable != 0)
{
return arabicTable;
}
return flashFont->getContextualFormsTable();
}
virtual void setContextualFormsTable(const FontContextualFormsTable* table)
{
arabicTable = table;
}
private:
FontId fontId;
FontCache* cache;
const GeneratedFont* flashFont;
};
} // namespace touchgfx
#endif // TOUCHGFX_CACHEDFONT_HPP
@@ -0,0 +1,183 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <fonts/CompressedFontCache.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/hal/Paint.hpp>
namespace touchgfx
{
LOCATION_PRAGMA_32("TouchGFX_CompressedFontCache")
uint32_t CompressedFontCache::bitmapFontCache[cacheWords] LOCATION_ATTRIBUTE_32("TouchGFX_CompressedFontCache");
uint8_t* CompressedFontCache::pixelsTop = (uint8_t*)CompressedFontCache::bitmapFontCache;
int CompressedFontCache::glyphsAllocated = 0;
int CompressedFontCache::cacheClearCounter = 0;
namespace
{
/* Read nibbles from a compressed data array */
struct NibReader
{
NibReader(const uint8_t* buffer)
: buffer(buffer), byteIndex(0), low(true)
{}
const uint8_t* buffer;
int byteIndex;
bool low;
uint8_t getNext()
{
if (low)
{
const uint8_t val = buffer[byteIndex] & 0xF;
low = false;
return val;
}
const uint8_t val = buffer[byteIndex] >> 4;
low = true;
byteIndex++;
return val;
}
};
struct NibWriter
{
NibWriter(uint8_t* buffer, int size)
: buffer(buffer), bufferEnd(buffer + size), low(true) {}
uint8_t* buffer;
uint8_t* bufferEnd;
int low;
void put(uint8_t v)
{
if (low)
{
*buffer = v;
low = false;
return;
}
*buffer |= (v << 4);
buffer++;
low = true;
}
bool eof() { return buffer >= bufferEnd; }
};
} // anonymous namespace
uint8_t* CompressedFontCache::decompressGlyph(uint8_t* pixelsTop, const GlyphNode* glyphNode, const uint8_t* compressedData)
{
const int byteSize = (glyphNode->width() + 1) / 2 * glyphNode->height();
NibWriter writer(pixelsTop, byteSize);
NibReader reader(compressedData);
uint8_t* const pixelsEnd = pixelsTop + byteSize;
const int algorithm = glyphNode->dataOffset >> 30;
if (algorithm == 1)
{
// RLE1
while (!writer.eof())
{
const uint8_t value = reader.getNext();
if (value == 0)
{
int zeroCount = reader.getNext();
while (zeroCount)
{
writer.put(0);
zeroCount--;
}
}
writer.put(value);
}
}
else if (algorithm == 2)
{
// RLE2
while (!writer.eof())
{
const uint8_t value = reader.getNext();
if (value == 0 || value == 0xF)
{
int count = reader.getNext();
while (count)
{
writer.put(value);
count--;
}
}
writer.put(value);
}
}
else
{
// Uncompressed
while (pixelsTop < pixelsEnd)
{
*pixelsTop++ = *compressedData++;
}
}
return pixelsEnd;
}
void CompressedFontCache::clearCache()
{
// Wait for DMA2D/GPU2D to finish drawing
HAL::getInstance()->lockUnlockFrameBuffer();
glyphsAllocated = 0;
cacheClearCounter++;
pixelsTop = (uint8_t*)bitmapFontCache;
}
void CompressedFontCache::unableToCache(const GlyphNode* glyphNode, int byteSize)
{
while(1);
}
const uint8_t* CompressedFontCache::hasCachedGlyph(const GlyphNode* glyphNode)
{
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
const BitmapFontCacheKey* first = end - glyphsAllocated;
while (first < end)
{
if (first->glyphNode == glyphNode)
{
return first->pixels;
}
first++;
}
return 0;
}
const uint8_t* CompressedFontCache::cacheGlyph(const GlyphNode* glyph, const uint8_t* compressedData)
{
const int byteSize = (glyph->width() + 1) / 2 * glyph->height();
if (byteSize + 8 > cacheSizeBytes)
{
unableToCache(glyph, byteSize);
return 0;
}
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
if (pixelsTop + byteSize + 8 > (const uint8_t*)&end[-glyphsAllocated])
{
// Unable to fit glyph in data, clear cache
clearCache();
}
const uint8_t* glyphData = pixelsTop;
pixelsTop = decompressGlyph(pixelsTop, glyph, compressedData);
// Flush the cache lines, must be 32byte aligned
uint8_t* rowStart = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(glyphData) & ~0x1F);
int alignmentOffset = glyphData - rowStart;
paint::flushLine((uint32_t*)rowStart, byteSize + alignmentOffset);
paint::invalidateTextureCache();
glyphsAllocated++;
BitmapFontCacheKey* key = const_cast<BitmapFontCacheKey*>(end - glyphsAllocated);
key->glyphNode = glyph;
key->pixels = glyphData;
return glyphData;
}
} // namespace touchgfx
@@ -0,0 +1,42 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_COMPRESSEDFONTCACHE_HPP
#define TOUCHGFX_COMPRESSEDFONTCACHE_HPP
#include <touchgfx/hal/Types.hpp>
#include <touchgfx/Font.hpp>
namespace touchgfx
{
class CompressedFontCache
{
public:
static void clearCache();
static const uint8_t* hasCachedGlyph(const GlyphNode* glyphNode);
static void unableToCache(const GlyphNode* glyphNode, int byteSize);
static const uint8_t* cacheGlyph(const GlyphNode* glyph, const uint8_t* compressedData);
static int usedMemory()
{
return pixelsTop - (uint8_t*)bitmapFontCache + glyphsAllocated * sizeof(BitmapFontCacheKey);
}
static int cacheClearCounter;
private:
static uint8_t* decompressGlyph(uint8_t* pixelsTop, const GlyphNode* glyphNode, const uint8_t* compressedData);
struct BitmapFontCacheKey
{
const void* glyphNode;
const uint8_t* pixels;
};
static const int cacheSizeBytes = <%= get_cache_size %>;
static const int cacheWords = (cacheSizeBytes + 3) / 4;
static uint32_t bitmapFontCache[cacheWords];
static uint8_t* pixelsTop;
static int glyphsAllocated;
};
} // namespace touchgfx
#endif // TOUCHGFX_COMPRESSEDFONTCACHE_HPP
@@ -0,0 +1,263 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <fonts/CompressedUnmappedFontCache.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/hal/Paint.hpp>
namespace touchgfx
{
LOCATION_PRAGMA_32("TouchGFX_CompressedUnmappedFontCache")
uint32_t CompressedUnmappedFontCache::bitmapFontCache[cacheWords] LOCATION_ATTRIBUTE_32("TouchGFX_CompressedUnmappedFontCache");
uint8_t* CompressedUnmappedFontCache::pixelsTop = (uint8_t*)CompressedUnmappedFontCache::bitmapFontCache;
int CompressedUnmappedFontCache::glyphsAllocated = 0;
int CompressedUnmappedFontCache::cacheClearCounter = 0;
namespace
{
/* Read nibbles from compressed data in unmapped flash. Must read through reader object */
struct NibUnmapReader
{
NibUnmapReader(const uint8_t* srcAddress, touchgfx::FlashDataReader* reader)
: address(srcAddress), reader(reader), byteIndex(0), low(true)
{
address += bufferSize;
reader->copyData(srcAddress, buffer, sizeof(buffer));
}
const uint8_t* address; //next reading address
touchgfx::FlashDataReader* reader;
static const int bufferSize = 16;
uint8_t buffer[bufferSize];
uint8_t value;
int byteIndex;
bool low;
uint8_t getNext()
{
if (low)
{
value = buffer[byteIndex];
const uint8_t val = value & 0xF;
low = false;
return val;
}
const uint8_t val = value >> 4;
low = true;
if (byteIndex == bufferSize - 1)
{
reader->copyData(address, buffer, bufferSize);
address += bufferSize;
byteIndex = 0;
}
else
{
byteIndex++;
}
return val;
}
};
struct NibWriter
{
NibWriter(uint8_t* buffer, int size)
: buffer(buffer), bufferEnd(buffer + size), low(true) {}
uint8_t* buffer;
uint8_t* bufferEnd;
int low;
void put(uint8_t v)
{
if (low)
{
*buffer = v;
low = false;
return;
}
*buffer |= (v << 4);
buffer++;
low = true;
}
bool eof() { return buffer >= bufferEnd; }
};
} // anonymous namespace
uint8_t* CompressedUnmappedFontCache::decompressGlyph(uint8_t* pixelsTop, const GlyphNode* glyphNode, const uint8_t* compressedData, touchgfx::FlashDataReader* flashReader)
{
const int byteSize = (glyphNode->width() + 1) / 2 * glyphNode->height();
NibWriter writer(pixelsTop, byteSize);
NibUnmapReader reader(compressedData, flashReader);
uint8_t* const pixelsEnd = pixelsTop + byteSize;
const int algorithm = glyphNode->dataOffset >> 30;
if (algorithm == 1)
{
// RLE1
while (!writer.eof())
{
const uint8_t value = reader.getNext();
if (value == 0)
{
int zeroCount = reader.getNext();
while (zeroCount)
{
writer.put(0);
zeroCount--;
}
}
writer.put(value);
}
}
else if (algorithm == 2)
{
// RLE2
while (!writer.eof())
{
const uint8_t value = reader.getNext();
if (value == 0 || value == 0xF)
{
int count = reader.getNext();
while (count)
{
writer.put(value);
count--;
}
}
writer.put(value);
}
}
else
{
// Uncompressed
flashReader->copyData(compressedData, pixelsTop, byteSize);
}
return pixelsEnd;
}
void CompressedUnmappedFontCache::clearCache()
{
// Wait for DMA2D/GPU2D to finish drawing
HAL::getInstance()->lockUnlockFrameBuffer();
glyphsAllocated = 0;
cacheClearCounter++;
pixelsTop = (uint8_t*)bitmapFontCache;
}
void CompressedUnmappedFontCache::unableToCache(const GlyphNode* glyphNode, int byteSize)
{
while(1);
}
const GlyphNode* CompressedUnmappedFontCache::hasCachedGlyphNode(const GlyphNode* glyphNode)
{
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
const BitmapFontCacheKey* first = end - glyphsAllocated;
while (first < end)
{
if (first->glyphNodeSrc == glyphNode)
{
return &first->glyphNodeCopy;
}
first++;
}
return 0;
}
const GlyphNode* CompressedUnmappedFontCache::hasCachedGlyphData(const GlyphNode* glyphNode, const uint8_t*& pixelData)
{
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
const BitmapFontCacheKey* first = end - glyphsAllocated;
while (first < end)
{
if (first->glyphNodeSrc == glyphNode)
{
//Pixel data can be zero!
pixelData = first->pixels;
return &first->glyphNodeCopy;
}
first++;
}
return 0;
}
GlyphNode* CompressedUnmappedFontCache::cacheGlyphNode(const GlyphNode* glyph)
{
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
if (pixelsTop + sizeof(BitmapFontCacheKey) > (const uint8_t*)&end[-glyphsAllocated])
{
// Unable to fit GlyphNode in data, clear cache
clearCache();
}
glyphsAllocated++;
BitmapFontCacheKey* key = const_cast<BitmapFontCacheKey*>(end - glyphsAllocated);
key->glyphNodeSrc = glyph;
key->pixels = 0;
return &key->glyphNodeCopy;
}
const uint8_t* CompressedUnmappedFontCache::cacheGlyphData(const GlyphNode* glyph, const uint8_t* compressedData, touchgfx::FlashDataReader* reader)
{
// Search keys for glyph
BitmapFontCacheKey* end = (BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
BitmapFontCacheKey* it = end - glyphsAllocated;
while (it < end)
{
if (it->glyphNodeSrc == glyph)
{
break;
}
it++;
}
if (it == end)
{
// broken invariant!
return 0;
}
const int byteSize = (it->glyphNodeCopy.width() + 1) / 2 * it->glyphNodeCopy.height();
// Check if pixels can fit in cache
if (pixelsTop + byteSize > (const uint8_t*)&end[-glyphsAllocated])
{
// Can it fit in a clean cache?
if (byteSize + sizeof(BitmapFontCacheKey) > cacheSizeBytes)
{
unableToCache(glyph, byteSize);
return 0;
}
// Unable to fit pixel in data, must clear cache
// Save address of GlyphNode in cache
const GlyphNode* cachedGn = &it->glyphNodeCopy;
// Now clear (reset pointer)
clearCache();
// Insert glyph node again
glyphsAllocated++;
it = const_cast<BitmapFontCacheKey*>(end - 1);
it->glyphNodeSrc = glyph;
it->pixels = 0;
// Copy GlyphNode content from previous position in cache
it->glyphNodeCopy = *cachedGn;
}
//Now decompress data
const uint8_t* glyphData = pixelsTop;
pixelsTop = decompressGlyph(pixelsTop, &it->glyphNodeCopy, compressedData, reader);
// Flush the cache lines, must be 32byte aligned
uint8_t* rowStart = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(glyphData) & ~0x1F);
int alignmentOffset = glyphData - rowStart;
paint::flushLine((uint32_t*)rowStart, byteSize + alignmentOffset);
paint::invalidateTextureCache();
it->pixels = glyphData;
return glyphData;
}
} // namespace touchgfx
@@ -0,0 +1,46 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_COMPRESSEDUNMAPPEDFONTCACHE_HPP
#define TOUCHGFX_COMPRESSEDUNMAPPEDFONTCACHE_HPP
#include <touchgfx/hal/FlashDataReader.hpp>
#include <touchgfx/hal/Types.hpp>
#include <touchgfx/Font.hpp>
namespace touchgfx
{
class CompressedUnmappedFontCache
{
public:
static void clearCache();
static const GlyphNode* hasCachedGlyphNode(const GlyphNode* glyphNode);
static const GlyphNode* hasCachedGlyphData(const GlyphNode* glyphNode, const uint8_t*& pixelData);
static void unableToCache(const GlyphNode* glyphNode, int byteSize);
static GlyphNode* cacheGlyphNode(const GlyphNode* glyph);
static const uint8_t* cacheGlyphData(const GlyphNode* glyph, const uint8_t* compressedData, touchgfx::FlashDataReader* reader);
static int usedMemory()
{
return pixelsTop - (uint8_t*)bitmapFontCache + glyphsAllocated * sizeof(BitmapFontCacheKey);
}
static int cacheClearCounter;
private:
static uint8_t* decompressGlyph(uint8_t* pixelsTop, const GlyphNode* glyphNode, const uint8_t* compressedData, touchgfx::FlashDataReader* reader);
struct BitmapFontCacheKey
{
const void* glyphNodeSrc;
GlyphNode glyphNodeCopy;
const uint8_t* pixels;
};
static const int cacheSizeBytes = <%= get_cache_size %>;
static const int cacheWords = (cacheSizeBytes + 3) / 4;
static uint32_t bitmapFontCache[cacheWords];
static uint8_t* pixelsTop;
static int glyphsAllocated;
};
} // namespace touchgfx
#endif // TOUCHGFX_COMPRESSEDUNMAPPEDFONTCACHE_HPP
@@ -0,0 +1,424 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <cstring>
#include <touchgfx/TextProvider.hpp>
#include <touchgfx/Utils.hpp>
#include <fonts/CachedFont.hpp>
#include <fonts/FontCache.hpp>
#include <texts/TypedTextDatabase.hpp>
namespace touchgfx
{
FontCache::FontCache()
: memorySize(0), memory(0), top(0), gsubStart(0), reader(0)
{
}
void FontCache::clear(bool keepGsubOrContextTable /* = false */)
{
memset(fontTable, 0, sizeof(fontTable));
// Top is beginning of memory, no glyphs are cached yet
top = memory;
if (!keepGsubOrContextTable)
{
// gsubStart points to end of memory (nothing loaded yet)
gsubStart = memory + memorySize;
// Round down to 32bit address
gsubStart = (uint8_t*)((uintptr_t)gsubStart & ~(sizeof(void*) - 1));
}
}
void FontCache::setMemory(uint8_t* _memory, uint32_t size)
{
memory = _memory;
memorySize = size;
clear();
}
void FontCache::setReader(FontDataReader* _reader)
{
reader = _reader;
}
const GlyphNode* FontCache::getGlyph(Unicode::UnicodeChar unicode, FontId font) const
{
GlyphNode* g = (GlyphNode*)fontTable[font].first;
while (g)
{
if (g->unicode == unicode)
{
return g;
}
GlyphNode** next = (GlyphNode**)((uint8_t*)g + SizeGlyphNode);
g = *next;
}
return 0;
}
void FontCache::open()
{
if (reader)
{
reader->open();
}
}
void FontCache::close()
{
if (reader)
{
reader->close();
}
}
void FontCache::initializeCachedFont(TypedText t, CachedFont* font, bool loadGsubOrContextTable /*= false*/)
{
// Get font index from typed text
FontId fontId = t.getFontId();
// Reset to start of file
open();
setPosition(0);
assert(sizeof(touchgfx::BinaryFontData) < MAX_BUFFER_SIZE);
readData(buffer, sizeof(touchgfx::BinaryFontData));
const struct touchgfx::BinaryFontData* binaryFontData = reinterpret_cast<const struct touchgfx::BinaryFontData*>(buffer);
const Font** flashFonts = TypedTextDatabase::getFonts();
const GeneratedFont* flashFont = static_cast<const GeneratedFont*>(flashFonts[fontId]);
*font = CachedFont(reinterpret_cast<const struct touchgfx::BinaryFontData*>(buffer), fontId, this, flashFont);
if (loadGsubOrContextTable && (binaryFontData->offsetToGSUB != 0))
{
setPosition(binaryFontData->offsetToGSUB);
const uint32_t sizeOfGSUB = (binaryFontData->offsetToArabicTable != 0 ? binaryFontData->offsetToArabicTable : binaryFontData->sizeOfFontData) - binaryFontData->offsetToGSUB;
if (top + sizeOfGSUB < gsubStart) // Room for this GSUB table
{
// Round down to aligned address
uint8_t* const gsubPosition = (uint8_t*)((uintptr_t)(gsubStart - sizeOfGSUB) & ~(sizeof(void*) - 1));
readData(gsubPosition, sizeOfGSUB);
font->setGSUBTable(reinterpret_cast<uint16_t*>(gsubPosition));
gsubStart = gsubPosition;
}
else
{
font->setGSUBTable(0);
}
}
if (loadGsubOrContextTable && (binaryFontData->offsetToArabicTable != 0))
{
setPosition(binaryFontData->offsetToArabicTable);
const uint32_t sizeTableData = binaryFontData->sizeOfFontData - binaryFontData->offsetToArabicTable;
if (top + sizeTableData + sizeof(FontContextualFormsTable) < gsubStart) // Room for the ContextualFormsTables
{
// Allocate FontContextualFormsTable first
gsubStart -= sizeof(FontContextualFormsTable);
// Round down to 32bit address
gsubStart = (uint8_t*)((uintptr_t)gsubStart & ~(sizeof(void*) - 1));
FontContextualFormsTable* table = (FontContextualFormsTable*)gsubStart;
font->setContextualFormsTable(table);
gsubStart -= sizeTableData;
readData(gsubStart, sizeTableData);
// Set pointers in table
const uint16_t* const base = (const uint16_t*)gsubStart;
// First elements in binary font are offsets to arrays in 16bit words
table->contextualForms4Long = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[0]);
table->contextualForms3Long = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[1]);
table->contextualForms2Long = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[2]);
table->contextualForms0621_063a = (FontContextualFormsTable::arrayOf4UnicodesPtr)(base + base[3]);
table->contextualForms0641_064a = (FontContextualFormsTable::arrayOf4UnicodesPtr)(base + base[4]);
table->contextualForms06XX = (FontContextualFormsTable::arrayOf5UnicodesPtr)(base + base[5]);
table->contextualForms4LongSize = base[6];
table->contextualForms3LongSize = base[7];
table->contextualForms2LongSize = base[8];
table->contextualForms06XXSize = base[9];
}
else
{
font->setContextualFormsTable(0);
}
}
close();
}
bool FontCache::cacheString(TypedText t, const Unicode::UnicodeChar* string)
{
open();
if (!createSortedString(string))
{
close();
return false;
}
const bool result = cacheSortedString(t);
close();
return result;
}
bool FontCache::cacheLigatures(CachedFont* font, TypedText t, const Unicode::UnicodeChar* string)
{
open();
if (!createSortedLigatures(font, t, string, 0, 0))
{
close();
return false;
}
const bool result = cacheSortedString(t);
close();
return result;
}
bool FontCache::cacheSortedString(TypedText t)
{
setPosition(8); // Skip font index and size
uint32_t glyphNodeOffset;
uint32_t dummy;
readData(&glyphNodeOffset, sizeof(uint32_t)); // offsetToTable
readData(&dummy, sizeof(uint32_t)); // offsetToKerning
readData(&glyphDataOffset, sizeof(uint32_t)); // offsetToGlyphs
readData(&dummy, sizeof(uint32_t)); // offsetToGlyphs
readData(&dummy, sizeof(uint32_t)); // offsetToArabicTable
readData(&numGlyphs, sizeof(uint16_t)); // numberOfGlyphs
FontId fontId = t.getFontId(); // Get font index from typed text
bpp = t.getFont()->getBitsPerPixel(); // Get BPP from standard font
byteAlignRow = t.getFont()->getByteAlignRow(); // Get ByteAlign from 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, outOfMemory);
if (outOfMemory)
{
break;
}
if (firstNewGlyph == 0)
{
firstNewGlyph = (GlyphNode*)fontTable[fontId].last;
}
}
}
last = ch;
string++;
}
cacheData(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, bool& outOfMemory)
{
// Insert new glyphnode and glyph after last for font.
uint8_t* oldTop = top;
top = copyGlyph(top, unicode, font, 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, 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 = getGlyphSize(&currentFileGlyphNode);
const int alignment = sizeof(void*);
glyphSize = (glyphSize + (alignment - 1)) & ~(alignment - 1);
uint32_t requiredMem = SizeGlyphNode + sizeof(void*) + 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(GlyphNode* first)
{
GlyphNode* gn = first;
while (gn)
{
uint8_t* p = (uint8_t*)gn;
if (gn->dataOffset != 0xFFFFFFFF)
{
p += SizeGlyphNode;
// Next pointer
p += sizeof(void*);
// Seek and copy
setPosition(glyphDataOffset + gn->dataOffset);
readData(p, getGlyphSize(gn));
// Mark glyphNode as cached
gn->dataOffset = 0xFFFFFFFF;
}
GlyphNode** next = (GlyphNode**)((uint8_t*)gn + SizeGlyphNode);
gn = *next;
}
}
bool FontCache::createSortedString(const Unicode::UnicodeChar* string)
{
int length = Unicode::strlen(string);
// Sorted string is allocated at end of buffer
sortedString = (Unicode::UnicodeChar*)(gsubStart - (length + 1) * 2);
if ((uint8_t*)sortedString < top)
{
// Unable to allocate string buffer in end of memory
return false;
}
int n = 0;
Unicode::UnicodeChar* uc = sortedString;
while (*string)
{
*uc++ = *string++;
n++;
}
*uc = 0;
return sortSortedString(n);
}
bool FontCache::createSortedLigatures(CachedFont* font, TypedText t, const Unicode::UnicodeChar* string, ...)
{
va_list pArg;
va_start(pArg, string);
TextProvider tp;
tp.initialize(string, pArg, font->getGSUBTable(), font->getContextualFormsTable());
va_end(pArg);
Unicode::UnicodeChar ligature;
sortedString = (Unicode::UnicodeChar*)(gsubStart);
if ((uint8_t*)(sortedString - 1) < top)
{
return false;
}
*--sortedString = 0;
int n = 0;
while ((ligature = tp.getNextLigature(t.getTextDirection())) != 0)
{
if ((uint8_t*)(sortedString - 1) < top)
{
return false;
}
*--sortedString = ligature;
n++;
}
return sortSortedString(n);
}
bool FontCache::sortSortedString(int n)
{
Unicode::UnicodeChar* uc = sortedString;
for (int i = 0; i < n - 1; i++)
{
bool swapped = false;
for (int j = 0; j < n - i - 1; j++)
{
if (uc[j] > uc[j + 1])
{
Unicode::UnicodeChar temp = uc[j];
uc[j] = uc[j + 1];
uc[j + 1] = temp;
swapped = true;
}
}
// If no two elements were swapped by inner loop, then break
if (!swapped)
{
break;
}
}
return true;
}
void FontCache::setPosition(uint32_t position)
{
if (reader)
{
reader->setPosition(position);
}
}
void FontCache::readData(void* out, uint32_t numberOfBytes)
{
if (reader)
{
reader->readData(out, numberOfBytes);
}
}
} // namespace touchgfx
@@ -0,0 +1,112 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_FONTCACHE_HPP
#define TOUCHGFX_FONTCACHE_HPP
#include <touchgfx/Font.hpp>
#include <touchgfx/TypedText.hpp>
#include <fonts/ApplicationFontProvider.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 keepGsubOrContextTable = false);
void setMemory(uint8_t* memory, uint32_t size);
void initializeCachedFont(TypedText t, CachedFont* font, bool loadGsubOrContextTable = 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 + sizeof(void*);
}
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, bool& outOfMemory);
uint8_t* copyGlyph(uint8_t* top, Unicode::UnicodeChar unicode, FontId font, bool& outOfMemory);
void cacheData(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);
uint32_t getGlyphSize(const GlyphNode* gn)
{
if (byteAlignRow)
{
// Round up line width to byte boundary and multiply by height
return (gn->width() * bpp + 7) / 8 * gn->height();
}
// Calculate number of pixels and round up to byte bounday
return (gn->width() * gn->height() * bpp + 7) / 8;
}
struct
{
uint8_t* first; // First GlyphNode, glyph in cache;
uint8_t* last; // Last 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;
uint8_t bpp;
uint8_t byteAlignRow;
GlyphNode currentFileGlyphNode;
};
} // namespace touchgfx
#endif // TOUCHGFX_FONTCACHE_HPP
@@ -0,0 +1,310 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <fonts/GeneratedFont.hpp>
#include <fonts/CompressedFontCache.hpp>
#include <math.h>
#include <stddef.h>
namespace touchgfx
{
GeneratedFont::GeneratedFont(const GlyphNode* glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable)
: ConstFont(glyphs, numGlyphs, height, baseline, pixAboveTop, pixBelowBottom, bitsPerPixel, byteAlignRow, maxLeft, maxRight, fallbackChar, ellipsisChar),
glyphData(glyphDataInternalFlash),
kerningData(kerningList),
gsubTable(gsubData),
arabicTable(formsTable)
{
}
const uint8_t* GeneratedFont::getPixelData(const GlyphNode* glyph) const
{
// Read dataOffset as 16bit, as it may be unaligned
volatile const uint16_t* dataOffset = (const uint16_t*)((const uint8_t*)glyph + offsetof(GlyphNode, dataOffset));
uint32_t offset = dataOffset[0];
offset |= dataOffset[1] << 16;
const uint8_t* const* table = (const uint8_t* const*)glyphData;
const uint8_t* pixels = table[glyph->unicode / 2048];
return pixels + offset;
}
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;
}
const GlyphNode* FusedFont::getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const
{
if (unicode < 0xAC00 || unicode > 0xD7A3)
{
return GeneratedFont::getGlyph(unicode, pixelData, bitsPerPixel);
}
else
{
fusedNode.unicode = unicode;
bitsPerPixel = 1;
pixelData = 0;
return const_cast<const GlyphNode*>(&fusedNode);
}
}
GlyphNode GeneratedVectorFont::glyphNode; // Static member
GeneratedVectorFont::GeneratedVectorFont(uint16_t baseline, float scale, const VectorFontNode* vectorGlyphs, const VectorFontData& fontData,
const uint16_t* const* glyphData, const VectorKerningNode* kerning,
const uint16_t* const gsubData, const FontContextualFormsTable* formsTable)
: Font((int)ceilf((fontData.maxBelowBottom + fontData.baselineHeight) * scale), baseline,
(uint8_t)ceilf(fontData.maxAboveTop * scale),
(uint8_t)ceilf(fontData.maxBelowBottom * scale), 0 /*bitsPerPixel*/, 0 /*byteAlignRow*/,
(uint8_t)ceilf(fontData.maxLeft * scale),
(uint8_t)ceilf(fontData.maxRight * scale),
fontData.fallbackChar,
fontData.ellipsisChar),
scaleFactor(scale), vectorNodes(vectorGlyphs), vectorTable(glyphData), kerningTable(kerning),
arabicTable(formsTable), numberOfGlyphs(fontData.numberOfGlyphs)
{
if (gsubData[0] != 0)
{
gsubTable = gsubData;
}
else
{
gsubTable = 0;
}
}
const GlyphNode* GeneratedVectorFont::getGlyph(Unicode::UnicodeChar unicode) const
{
const VectorFontNode* const node = find(unicode);
if (node == 0)
{
return 0;
}
else
{
return getGlyphNode(node);
}
}
const GlyphNode* GeneratedVectorFont::getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const
{
const VectorFontNode* const node = find(unicode);
if (node == 0)
{
return 0;
}
else
{
const uint16_t* contourData = &(vectorTable[unicode / 2048][node->dataOffset]);
pixelData = (const uint8_t*)contourData;
bitsPerPixel = 0xFF;
return getGlyphNode(node);
}
}
const GlyphNode* GeneratedVectorFont::getGlyphNode(const VectorFontNode* node) const
{
glyphNode.dataOffset = 0;
uint8_t flags = 0;
//Convert data from VectorFontNode to glyphNode using scaleFactor
glyphNode.unicode = node->unicode;
const int width = (node->width == 0) ? 0 : ((int)ceilf(node->width * scaleFactor) + 1);
glyphNode._width = width; // Save low 8 bit
// Set flags bits for values above 8 bit
if (width > 255)
{
flags |= GLYPH_DATA_WIDTH_BIT8;
}
const int height = (int)ceilf(node->height * scaleFactor);
glyphNode._height = height;
if (height > 255)
{
flags |= GLYPH_DATA_HEIGHT_BIT8;
}
const int top = (int)ceilf(node->top * scaleFactor);
glyphNode._top = top;
if (top > 255)
{
flags |= ((top & 0x300) >> 3); // GLYPH_DATA_TOP_BIT8 + 9
}
const int left = (int)(node->left * scaleFactor);
glyphNode.left = left;
const int advance = (int)(node->advance * scaleFactor + 0.5f);
glyphNode._advance = advance;
if (advance > 255)
{
flags |= GLYPH_DATA_ADVANCE_BIT8;
}
glyphNode._kerningTablePos = (uint8_t)node->kerningTablePos;
if (node->kerningTablePos > 255)
{
flags |= (node->kerningTablePos >> 8) & GLYPH_DATA_KERNINGTABLEPOS_BIT8_10;
}
glyphNode.kerningTableSize = node->kerningTableSize;
glyphNode.flags = flags;
return &glyphNode;
}
int8_t GeneratedVectorFont::getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const
{
if (!glyph || glyph->kerningTableSize == 0)
{
return 0;
}
const VectorKerningNode* kerndata = kerningTable + glyph->kerningTablePos();
for (uint16_t i = glyph->kerningTableSize; i > 0; i--, kerndata++)
{
if (prevChar == kerndata->unicodePrevChar)
{
const float scaledDistance = kerndata->distance * scaleFactor;
return (int)(scaledDistance >= 0.0f ? (scaledDistance + 0.5f) : (scaledDistance - 0.5f));
}
if (prevChar < kerndata->unicodePrevChar)
{
break;
}
}
return 0;
}
const VectorFontNode* GeneratedVectorFont::find(Unicode::UnicodeChar unicode) const
{
// Some fonts does not have a glyphList. Cannot be searched...
if (vectorNodes == 0)
{
return 0;
}
int32_t min = 0;
int32_t max = numberOfGlyphs - 1;
int32_t mid = min + (unicode - vectorNodes[min].unicode); // Linear up from [min].unicode
if (mid < min)
{
// Unicode < [min].unicode => not found
return (VectorFontNode*)0;
}
if (mid > max)
{
// Linear up ends too high
mid = max - (vectorNodes[max].unicode - unicode); // Linear down from [max].unicode
if (mid > max)
{
// Unicode > [max].unicode => not found
return (VectorFontNode*)0;
}
if (mid < min)
{
// Linear down ends too low, take the middle element
mid = (min + max) / 2;
}
}
while (min <= max)
{
const Unicode::UnicodeChar midUnicode = vectorNodes[mid].unicode;
if (unicode == midUnicode)
{
// Found at [mid]
return vectorNodes + mid;
}
if (unicode < midUnicode)
{
// 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 - (vectorNodes[max].unicode - 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 - vectorNodes[min].unicode);
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 (VectorFontNode*)0;
}
CompressedMappedFont::CompressedMappedFont(const GlyphNode* glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable)
: GeneratedFont(glyphs, numGlyphs, height, baseline, pixAboveTop, pixBelowBottom, bitsPerPixel, byteAlignRow, maxLeft, maxRight, glyphDataInternalFlash, kerningList, fallbackChar, ellipsisChar, gsubData, formsTable)
{
}
const GlyphNode* CompressedMappedFont::getGlyph(Unicode::UnicodeChar unicode) const
{
return find(unicode);
}
const uint8_t* CompressedMappedFont::getPixelData(const GlyphNode* glyph) const
{
const uint8_t* pixelData = CompressedFontCache::hasCachedGlyph(glyph);
if (pixelData)
{
return pixelData;
}
const uint8_t* const* table = (const uint8_t* const*)glyphData;
const uint8_t* compressedData = &(table[glyph->unicode / 2048][glyph->dataOffset & 0x3FFFFFFF]);
return CompressedFontCache::cacheGlyph(glyph, compressedData);
}
} // namespace touchgfx
@@ -0,0 +1,227 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_GENERATEDFONT_HPP
#define TOUCHGFX_GENERATEDFONT_HPP
#include <touchgfx/ConstFont.hpp>
namespace touchgfx
{
class GeneratedFont : public ConstFont
{
public:
GeneratedFont(const GlyphNode* glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable);
using ConstFont::getGlyph;
virtual const uint8_t* getPixelData(const GlyphNode* glyph) const;
virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const;
virtual const uint16_t* getGSUBTable() const
{
return gsubTable;
}
virtual const FontContextualFormsTable* getContextualFormsTable() const
{
return arabicTable;
}
protected:
GeneratedFont()
: ConstFont(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), glyphData(0), kerningData(0), gsubTable(0), arabicTable(0)
{
}
const void* glyphData; ///< The glyphs
const KerningNode* kerningData; ///< The kerning
const uint16_t* gsubTable; ///< The GSUB tables
const FontContextualFormsTable* arabicTable; ///< Contextual forms
};
class FusedFont : public GeneratedFont
{
public:
FusedFont(const GlyphNode* glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable, GlyphNode& fontFusedNode)
: GeneratedFont(glyphs, numGlyphs, height, baseline, pixAboveTop, pixBelowBottom, bitsPerPixel, byteAlignRow,
maxLeft, maxRight, glyphDataInternalFlash, kerningList, fallbackChar, ellipsisChar,
gsubData, formsTable), fusedNode(fontFusedNode)
{ }
using GeneratedFont::getGlyph;
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const;
private:
GlyphNode& fusedNode;
};
struct VectorFontNode
{
uint32_t dataOffset; ///< The index to the data of this glyph in words
Unicode::UnicodeChar unicode; ///< The Unicode of this glyph.
uint16_t width; ///< Width of the actual glyph data
uint16_t height; ///< Height of the actual glyph data
int16_t top; ///< Vertical offset from baseline of the glyph
int16_t left; ///< Horizontal offset from the left of the glyph
uint16_t advance; ///< Width of the glyph (including space to the left and right)
uint16_t kerningTablePos; ///< Where are the kerning information for this glyph stored in the kerning table
uint8_t kerningTableSize; ///< How many entries are there in the kerning table (following kerningTablePos) for this glyph
};
struct VectorKerningNode
{
Unicode::UnicodeChar unicodePrevChar; ///< The Unicode for the first character in the kerning pair
int16_t distance; ///< The kerning distance
};
struct VectorFontData
{
uint16_t numberOfGlyphs;
uint16_t baselineHeight;
uint16_t maxLeft;
uint16_t maxRight;
uint16_t maxAboveTop;
uint16_t maxBelowBottom;
const Unicode::UnicodeChar fallbackChar;
const Unicode::UnicodeChar ellipsisChar;
};
class GeneratedVectorFont : public Font
{
public:
GeneratedVectorFont(uint16_t baseline, float scale, const VectorFontNode* vectorGlyphs, const VectorFontData& fontData,
const uint16_t* const* glyphData, const VectorKerningNode* kerningTable,
const uint16_t* const gsubData, const FontContextualFormsTable* formsTable);
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode) const;
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const;
virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const;
virtual bool isVectorBasedFont() const { return true; }
virtual float getScaleFactor() const { return scaleFactor; }
virtual const uint16_t* getGSUBTable() const { return gsubTable; }
virtual const FontContextualFormsTable* getContextualFormsTable() const { return arabicTable; }
private:
const VectorFontNode* find(Unicode::UnicodeChar unicode) const;
const GlyphNode* getGlyphNode(const VectorFontNode* node) const;
float scaleFactor;
const VectorFontNode* vectorNodes;
const uint16_t* const* vectorTable;
const VectorKerningNode* kerningTable;
const uint16_t* gsubTable;
const FontContextualFormsTable* arabicTable;
uint16_t numberOfGlyphs;
static GlyphNode glyphNode;
};
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[]
uint32_t offsetToArabicTable; // FontContextualFormsTable
uint16_t numberOfGlyphs; // Number of glyphs in Table and Glyphs
uint16_t fontHeight; // Font height
uint16_t baseline; // Distance to baseline
uint8_t pixAboveTop; // Max pixels above top
uint8_t pixBelowBottom; // Max pixels below bottom
uint8_t bitsPerPixel; // Bpp
uint8_t byteAlignRow; // A4/A2/A1
uint8_t maxLeft; // The maximum a glyph extends to the left
uint8_t maxRight; // The maximum a glyph 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->fontHeight,
data->baseline,
data->pixAboveTop,
data->pixBelowBottom,
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),
0),
glyphData((const uint8_t*)data + data->offsetToGlyphs)
{
if (data->offsetToArabicTable > 0)
{
setupContextualTable(data);
}
}
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;
FontContextualFormsTable contextualForms;
private:
typedef const Unicode::UnicodeChar (*array5ptr)[5];
typedef const Unicode::UnicodeChar (*array4ptr)[4];
void setupContextualTable(const struct touchgfx::BinaryFontData* data)
{
const uint16_t* const base = (const uint16_t*)(((const uint8_t*)data) + data->offsetToArabicTable);
// First elements in binary font are offsets to arrays in 16bit words
contextualForms.contextualForms4Long = (array5ptr)(base + base[0]);
contextualForms.contextualForms3Long = (array5ptr)(base + base[1]);
contextualForms.contextualForms2Long = (array5ptr)(base + base[2]);
contextualForms.contextualForms0621_063a = (array4ptr)(base + base[3]);
contextualForms.contextualForms0641_064a = (array4ptr)(base + base[4]);
contextualForms.contextualForms06XX = (array5ptr)(base + base[5]);
contextualForms.contextualForms4LongSize = base[6];
contextualForms.contextualForms3LongSize = base[7];
contextualForms.contextualForms2LongSize = base[8];
contextualForms.contextualForms06XXSize = base[9];
arabicTable = &contextualForms;
}
};
class CompressedMappedFont : public GeneratedFont
{
public:
CompressedMappedFont(const GlyphNode* glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable);
using GeneratedFont::getGlyph;
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode) const;
virtual const uint8_t* getPixelData(const GlyphNode* glyph) const;
};
} // namespace touchgfx
#endif // TOUCHGFX_GENERATEDFONT_HPP
@@ -0,0 +1,4 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
// Empty Language file
@@ -0,0 +1,48 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <stdint.h>
#include <touchgfx/Unicode.hpp>
<%= get_pragma %>
KEEP extern const uint32_t indices<%= get_language %>[]<%= get_attribute%>;
<% if remap_global? %>
// Remap all strings
TEXT_LOCATION_FLASH_PRAGMA
KEEP extern const uint32_t indices<%= get_language %>[] TEXT_LOCATION_FLASH_ATTRIBUTE = {
<% text_entries = get_text_entries %>
<% if text_entries.empty? %>
0
<% else %>
<% text_entries.each_with_index do |entry, index| %>
<%= get_string_index(entry) %><%= ((index == text_entries.length - 1) ? (index == 0 ? '' : ' '): ',') %><%= get_string_index_spaces(entry)%>// <%= entry.text_id %>: "<%= unicode_array_to_string(entry.int_array) %>"
<% end %>
<% end %>
};
<% else %>
// Remap local strings
TEXT_LOCATION_FLASH_PRAGMA
KEEP extern const touchgfx::Unicode::UnicodeChar texts<%= get_language %>[] TEXT_LOCATION_FLASH_ATTRIBUTE = {
<% substrings_and_offset = get_substrings_and_offsets(@language_index) %>
<% if substrings_and_offset.empty? %>
0
<% else %>
<% get_substrings_and_offsets(@language_index).each do |unicode_array, offset, last| %>
<%= unicode_array.map{|x|"0x%x"%x} * ', ' %><%= last ? '' : ',' %> // @<%= offset %> "<%= unicode_array_to_string(unicode_array) %>"
<% end %>
<% end %>
};
<%= get_pragma %>
KEEP extern const uint32_t indices<%= get_language %>[]<%= get_attribute%> = {
<% text_entries = get_text_entries %>
<% if text_entries.empty? %>
0
<% else %>
<% text_entries.each_with_index do |entry, index| %>
<%= get_string_index(entry) %><%= ((index == text_entries.length-1) ? ' ': ',') %><%= get_string_index_spaces(entry)%>// <%= entry.text_id %>: "<%= unicode_array_to_string(entry.int_array) %>"
<% end %>
<% end %>
};
<% end %>
@@ -0,0 +1,23 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_TEXTKEYSANDLANGUAGES_HPP
#define TOUCHGFX_TEXTKEYSANDLANGUAGES_HPP
enum LANGUAGES
{
<% get_languages.each do |language| %>
<%= language %>,
<% end %>
NUMBER_OF_LANGUAGES
};
enum TEXTS
{
<% get_texts.each do |text| %>
<%= text.upcase %>,
<% end %>
NUMBER_OF_TEXT_KEYS
};
#endif // TOUCHGFX_TEXTKEYSANDLANGUAGES_HPP
@@ -0,0 +1,224 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <stdarg.h>
#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>
#include <texts/TypedTextDatabase.hpp>
<% if copy_translations? %>
#include <touchgfx/hal/FlashDataReader.hpp>
#include <fonts/ApplicationFontProvider.hpp>
<% end %>
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 TypedTextDatabase
extern const touchgfx::TypedText::TypedTextData* const typedTextDatabaseArray[];
<% if generate_binary_files? %>
extern const touchgfx::Unicode::UnicodeChar EmptyLanguageTexts[];
extern const uint32_t EmptyLanguageIndices[];
<% else %>
<% if remap_global? %>
TEXT_LOCATION_FLASH_PRAGMA
KEEP extern const touchgfx::Unicode::UnicodeChar texts_all_languages[] TEXT_LOCATION_FLASH_ATTRIBUTE = {
<% substrings_and_offsets = get_substrings_and_offsets %>
<% if substrings_and_offsets.empty? %>
0 // No texts in application
<% else %>
<% substrings_and_offsets.each do |(unicode_array, offset, last)| %>
<%= unicode_array.map{|x|"0x%x"%x} * ', ' %><%= last ? '' : ',' %> // @<%= offset %> "<%= unicode_array_to_string(unicode_array) %>"
<% end %>
<% end %>
};
<% end %>
<% get_capitalized_languages.each do |lang| %>
<%= get_pragma %>
KEEP extern const uint32_t indices<%= lang %>[]<%= get_attribute%>;
<% if !remap_global? %>
<%= get_pragma %>
KEEP extern const touchgfx::Unicode::UnicodeChar texts<%= lang %>[]<%= get_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[<%= has_languages? ? get_number_of_languages : 1 %>] = { 0 };
// Compiled and linked in languages
static const uint32_t* const staticLanguageIndices[] = {
<% if generate_binary_files? %>
EmptyLanguageIndices
<% else %>
<% if !has_languages? %>
0
<% else %>
<% get_capitalized_languages.each_with_index do |lang, index| %>
indices<%= lang %><%= (index == get_number_of_languages - 1) ? '': ',' %>
<% end %>
<% end %>
<% end %>
};
<% if generate_binary_files? %>
static const touchgfx::Unicode::UnicodeChar* const staticLanguageTexts[] = {
EmptyLanguageTexts
};
<% else %>
<% if not remap_global? %>
static const touchgfx::Unicode::UnicodeChar* const staticLanguageTexts[] = {
<% if !has_languages? %>
0
<% else %>
<% get_capitalized_languages.each_with_index do |lang, index| %>
texts<%= lang %><%= (index == get_number_of_languages - 1) ? '': ',' %>
<% end %>
<% end %>
};
<% end %>
<% end %>
<% if copy_translations? %>
static const uint32_t staticLanguageSizes[] = {
<% get_capitalized_languages.each_with_index do |lang, index| %>
<%= language_length(index) %><%= (index == get_number_of_languages - 1) ? '': ',' %>
<% end %>
};
static const uint32_t maxStaticLanguageSize = <%= get_max_language_length %>;
static touchgfx::Unicode::UnicodeChar translationBuffer[maxStaticLanguageSize];
<% 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 < <%= has_languages? ? get_number_of_languages : 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_global? %>
currentLanguagePtr = texts_all_languages;
currentLanguageIndices = staticLanguageIndices[id];
<% else %>
<% if not copy_translations? %>
currentLanguagePtr = staticLanguageTexts[id];
<% else %>
// Read translations from unmapped flash
#ifdef SIMULATOR
memcpy(translationBuffer, staticLanguageTexts[id], staticLanguageSizes[id] * 2);
#else
touchgfx::FlashDataReader* const flashReader = ApplicationFontProvider::getFlashReader();
if (flashReader)
{
flashReader->copyData(staticLanguageTexts[id], translationBuffer, staticLanguageSizes[id] * 2);
}
#endif
currentLanguagePtr = translationBuffer;
<% end %>
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]];
}
@@ -0,0 +1,138 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <touchgfx/TypedText.hpp>
<% get_font_class_names.each do |name| %>
#include <fonts/<%= name %>.hpp>
<% end %>
#include <texts/TypedTextDatabase.hpp>
<% get_fonts.each do |font| %>
extern touchgfx::<%= get_font_class_name(font) %>& <%= font %>();
<% end %>
const touchgfx::Font* touchgfx_fonts[] = {
<% if get_fonts.empty? %>
0
<% else %>
<% get_fonts.each_with_index do |font, index| %>
&(<%= font %>())<%= index == get_fonts.length-1 ? '' : ',' %>
<% end %>
<% end %>
};
<% 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 = {
<% get_layouts.each do |layout| %>
<% get_typed_texts(layout).each_with_index do |entry, index| %>
0<%= ((index == get_typed_texts(layout).length-1) ? '': ',') %>
<% end %>
<% break %>
<% end %>
};
TEXT_LOCATION_FLASH_PRAGMA
KEEP extern const uint32_t EmptyLanguageIndices[] TEXT_LOCATION_FLASH_ATTRIBUTE = {
<% get_layouts.each do |layout| %>
<% get_typed_texts(layout).each_with_index do |entry, index| %>
<%= index %><%= ((index == get_typed_texts(layout).length-1) ? '': ',') %>
<% end %>
<% break %>
<% end %>
};
TEXT_LOCATION_FLASH_PRAGMA
const touchgfx::TypedText::TypedTextData typedText_database_EMPTY[] TEXT_LOCATION_FLASH_ATTRIBUTE = {
<% get_layouts.each do |layout| %>
<% get_typed_texts(layout).each_with_index do |entry, index| %>
<%= ('{ 0, touchgfx::LEFT, touchgfx::TEXT_DIRECTION_LTR }').to_s %><%= ((index == get_typed_texts(layout).length-1) ? '': ',') %>
<% end %>
<% break %>
<% end %>
};
<% else %>
<% get_layouts.each do |layout| %>
<%= get_pragma %>
const touchgfx::TypedText::TypedTextData typedText_database_<%= layout %>[]<%= get_attribute %> = {
<% if get_typed_texts(layout).empty? %>
{ 0, touchgfx::LEFT, touchgfx::TEXT_DIRECTION_LTR }
<% else %>
<% get_typed_texts(layout).each_with_index do |typed_text, index| %>
<% fontIdx = get_font_index(typed_text.typography) %>
<% alignment = get_touchgfx_aligment(typed_text.alignment) %>
<% direction = get_touchgfx_direction(typed_text.direction) %>
{ <%= fontIdx %>, <%= alignment %>, <%= direction %> }<%= index == get_typed_texts(layout).length-1 ? '' : ',' %>
<% end %>
<% end %>
};
<% end %>
<% end %>
const touchgfx::TypedText::TypedTextData* const typedTextDatabaseArray[] = {
<% if generate_binary_files? %>
<% get_languages.each_with_index do |entry,index| %>
typedText_database_EMPTY<%= index == get_languages.length-1 ? '' : ',' %>
<% end %>
<% elsif languages.empty? %>
typedText_database_DEFAULT
<% else %>
<% get_languages.each_with_index do |language, index| %>
typedText_database_<%= get_layouts.find { |l| l == language } || 'DEFAULT' %><%= index == get_languages.length-1 ? '' : ',' %>
<% end %>
<% end %>
};
namespace TypedTextDatabase
{
const touchgfx::TypedText::TypedTextData* getInstance(touchgfx::LanguageId id)
{
return typedTextDatabaseArray[id];
}
uint16_t getInstanceSize()
{
<% if has_text_entries? %>
<% if generate_binary_files? %>
return sizeof(typedText_database_EMPTY) / sizeof(touchgfx::TypedText::TypedTextData);
<% else %>
return sizeof(typedText_database_DEFAULT) / sizeof(touchgfx::TypedText::TypedTextData);
<% end %>
<% else %>
return 0;
<% 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 !get_fonts.empty? %>
switch (fontId)
{
<% get_fonts.each_with_index do |font, index| %>
case <%= index %>:
touchgfx_fonts[<%= index %>] = &(<%= font %>());
break;
<% end %>
}
<% end %>
}
} // namespace TypedTextDatabase
@@ -0,0 +1,21 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_TYPEDTEXTDATABASE_HPP
#define TOUCHGFX_TYPEDTEXTDATABASE_HPP
#include <touchgfx/TypedText.hpp>
#include <touchgfx/hal/Types.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();
} // namespace TypedTextDatabase
#endif // TOUCHGFX_TYPEDTEXTDATABASE_HPP
@@ -0,0 +1,236 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <touchgfx/hal/FlashDataReader.hpp>
#include <fonts/ApplicationFontProvider.hpp>
#include <fonts/CompressedUnmappedFontCache.hpp>
#include <fonts/UnmappedDataFont.hpp>
namespace touchgfx
{
GlyphNode UnmappedDataFont::glyphNodeBuffer;
UnmappedDataFont::UnmappedDataFont(const GlyphNode* glyphs, const uint16_t* unicodeList, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable)
: Font(height, baseline, pixAboveTop, pixBelowBottom, bitsPerPixel, byteAlignRow, maxLeft, maxRight, fallbackChar, ellipsisChar),
glyphList(glyphs),
listSize(numGlyphs),
unicodes(unicodeList),
glyphDataList(glyphDataList),
kerningData(kerningList),
gsubTable(gsubData),
arabicTable(formsTable)
{
}
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();
if (flashReader)
{
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;
}
CompressedUnmappedDataFont::CompressedUnmappedDataFont(const GlyphNode* glyphs, const uint16_t* unicodes, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable)
: UnmappedDataFont(glyphs, unicodes, numGlyphs, height, baseline, pixAboveTop, pixBelowBottom, bitsPerPixel, byteAlignRow, maxLeft, maxRight, glyphDataList, kerningList, fallbackChar, ellipsisChar, gsubData, formsTable)
{
}
const GlyphNode* CompressedUnmappedDataFont::getGlyph(Unicode::UnicodeChar unicode) const
{
const int index = lookupUnicode(unicode);
if (index != -1)
{
const GlyphNode* glyphNode = glyphList + index;
// Is the GlyphNode already cached
const GlyphNode* cachedNode = CompressedUnmappedFontCache::hasCachedGlyphNode(glyphNode);
if (cachedNode)
{
return cachedNode;
}
// Read glyphNode from unmapped flash
touchgfx::FlashDataReader* const flashReader = ApplicationFontProvider::getFlashReader();
if (flashReader)
{
GlyphNode* newGlyphNode = CompressedUnmappedFontCache::cacheGlyphNode(glyphNode);
flashReader->copyData(glyphList + index, (uint8_t*)newGlyphNode, sizeof(GlyphNode));
return newGlyphNode;
}
}
return 0;
}
const GlyphNode* CompressedUnmappedDataFont::getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const
{
const int index = lookupUnicode(unicode);
if (index != -1)
{
const GlyphNode* glyphNode = glyphList + index;
const uint8_t* pixels = 0;
const GlyphNode* cachedNode = CompressedUnmappedFontCache::hasCachedGlyphData(glyphNode, pixels);
if (pixels)
{
pixelData = pixels;
bitsPerPixel = 4;
return cachedNode;
}
// Cache glyphNode if not found already
if (cachedNode == 0)
{
cachedNode = getGlyph(unicode);
}
if (cachedNode->width() == 0)
{
bitsPerPixel = 4;
pixelData = 0;
return cachedNode;
}
// Read data from unmapped flash
touchgfx::FlashDataReader* const flashReader = ApplicationFontProvider::getFlashReader();
if (flashReader)
{
const uint8_t* const* table = (const uint8_t* const*)glyphDataList;
const uint32_t dataOffset = cachedNode->dataOffset & 0x3FFFFFFF;
const uint8_t* compressedData = &(table[unicode / 2048][dataOffset]);
const uint8_t* cachedData = CompressedUnmappedFontCache::cacheGlyphData(glyphNode, compressedData, flashReader);
if (cachedData)
{
bitsPerPixel = 4;
pixelData = cachedData;
return cachedNode;
}
}
}
return 0;
}
const uint8_t* CompressedUnmappedDataFont::getPixelData(const GlyphNode* glyph) const
{
return 0;
}
} // namespace touchgfx
@@ -0,0 +1,137 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TOUCHGFX_UNMAPPEDDATAFONT_HPP
#define TOUCHGFX_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 glyphs The array of glyphs known to this font (indirect).
* @param unicodes The array of unicodes known to this font (direct).
* @param numGlyphs The number of glyphs in list.
* @param height The height in pixels of the highest character in this font.
* @param baseline The height of the baseline in pixels.
* @param pixBelowBottom The maximum number of pixels that can be drawn below the
* bottom 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* glyphs, const uint16_t* unicodes, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable);
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;
}
/**
* Gets the contextual forms table used in arabic fonts.
*
* @return The FontContextualFormsTable or null if the font has no table.
*/
virtual const FontContextualFormsTable* getContextualFormsTable() const
{
return arabicTable;
}
protected:
UnmappedDataFont()
: Font(0, 0, 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; ///< The glyphs (list of pointers)
const KerningNode* kerningData; ///< The kerning
const uint16_t* gsubTable; ///< The GSUB tables
const FontContextualFormsTable* arabicTable; ///< Contextual forms
static GlyphNode glyphNodeBuffer; ///< Buffer for GlyphNodes read from unmapped flash
};
class CompressedUnmappedDataFont : public UnmappedDataFont
{
public:
CompressedUnmappedDataFont(const GlyphNode* glyphs, const uint16_t* unicodes, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, 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, const FontContextualFormsTable* formsTable);
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode) const;
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const;
virtual const uint8_t* getPixelData(const GlyphNode* glyph) const;
};
} // namespace touchgfx
#endif // TOUCHGFX_UNMAPPEDDATAFONT_HPP
@@ -0,0 +1,24 @@
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <touchgfx/VectorFontRendererImpl.hpp>
<% if get_num_commands != 0 %>
static float ptArray[<%= get_num_floats %>];
static uint8_t cmdArray[<%= get_num_commands %>];
void touchgfx::VectorFontRendererImpl::getVectorFontBuffers(float*& pointArray, int& pointArraySize, uint8_t*& commandArray, int& commandArraySize)
{
pointArray = ptArray;
pointArraySize = <%= get_num_floats %>;
commandArray = cmdArray;
commandArraySize = <%= get_num_commands %>;
}
<% else %>
void touchgfx::VectorFontRendererImpl::getVectorFontBuffers(float*& pointArray, int& pointArraySize, uint8_t*& commandArray, int& commandArraySize)
{
pointArray = 0;
pointArraySize = 0;
commandArray = 0;
commandArraySize = 0;
}
<% end %>