Ramses Text API

using FontId = StronglyTypedValue<uint32_t, std::numeric_limits<uint32_t>::max(), FontIdTag>

A strongly typed integer to distinguish between different fonts.

using FontInstanceId = StronglyTypedValue<uint32_t, std::numeric_limits<uint32_t>::max(), FontInstanceIdTag>

A strongly typed integer to distinguish between different font instances.

StringBoundingBox GetBoundingBoxForString(GlyphMetricsVector::const_iterator first, GlyphMetricsVector::const_iterator last)

Compute a bounding box for a string represented by a range of GlyphMetrics.

Parameters:
  • first[in] Beginning of range of GlyphMetrics to compute bounding box

  • last[in] End of range of GlyphMetrics to compute bounding box, glyph pointed to by last is not included

Returns:

The bounding box of the provided string, or bounding box of Zero values on failure

StringBoundingBox GetBoundingBoxForString(const GlyphMetricsVector::const_reverse_iterator &first, const GlyphMetricsVector::const_reverse_iterator &last)

Compute a bounding box for a string represented by a range of GlyphMetrics.

Parameters:
  • first[in] Beginning of range of GlyphMetrics to compute bounding box

  • last[in] End of range of GlyphMetrics to compute bounding box, glyph pointed to by last is not included

Returns:

The bounding box of the provided string, or bounding box of Zero values on failure

struct FontCascade
#include <FontCascade.h>

struct to define a font cascade

Allows to define a list of fonts that are tried sequentially for character availability. The first font that supports a given character is returned. Also supports generic fallback characters and blacklisted characters.

Public Members

const IFontAccessor &fontAccessor

interface to use to resolve FontInstanceId to a FontInstance

std::u32string charsToRemove

String of characters that will be removed from a processed string.

OrderedFontList fontPriorityList

Ordered list of font instance ids to try for each character.

FontInstanceId fallbackFont

Fallback font used for fallbackChar when none in fontPriorityList matched.

char32_t fallbackChar

Fallback character when no match was found in fontPriorityList.

Public Static Functions

static std::u32string FilterAndFindFontInstancesForString(const FontCascade &fontCascade, const std::u32string &str, FontInstanceOffsets &fontOffsets)

Process a character string according to given FontCascade.

Creates a string with characters removed or replaced according to given FontInstance. Additionally creates FontInstanceOffsets specifying the font instance to use for all returned characters. Intended to be used in conjunction with TextCache::getPositionedGlyphs.

Parameters:
  • fontCascade[in] the font cascade used to process str

  • str[in] the character string to process

  • fontOffsets[out] vector of FontOffset describing the font to use

Returns:

The processed string

struct FontInstanceIdTag
#include <FontInstanceId.h>

An empty struct to make FontInstanceId a strong type.

struct FontInstanceOffset
#include <FontInstanceOffsets.h>

A list of tuples from font instances and offsets into a string.

Used to tell the text API which font should be used for which substring when creating glyphs for a string. The list is used as this: take entry N of the list, start at string offset ‘N:beginOffset’ and use font ‘N:fontInstance’ until offset ‘N+1:beginOffset’.

Public Members

FontInstanceId fontInstance

Font instance to use starting at this offset.

std::size_t beginOffset

Offset into string where to start.

class FontRegistry : public ramses::IFontAccessor
#include <FontRegistry.h>

Font registry can be used to load Freetype2 fonts and create font instances (optionally with Harfbuzz). These are owned and managed by FontRegistry.

Public Functions

FontRegistry()

Constructor for FontRegistry.

~FontRegistry() override

Destructor for FontRegistry. Destroys all created fonts.

virtual IFontInstance *getFontInstance(FontInstanceId fontInstanceId) const override

Get font instance object corresponding to given id.

Parameters:

fontInstanceId[in] The id of font instance

Returns:

The font instance object, nullptr if not found

FontId createFreetype2Font(std::string_view fontPath)

Load Freetype2 font from file.

Parameters:

fontPath[in] The file path to the font

Returns:

The font id, FontId::Invalid() on error

FontId createFreetype2FontFromFileDescriptor(int fd, size_t offset, size_t length)

Load Freetype2 font from an open file descriptor.

The font file must be in the already opened filedescriptor at absolute position offset within the file. The filedescriptor must be opened for read access and may not be modified anymore after this call. The filedescriptor must support seeking. Ramses takes ownership of the filedescriptor and will close it when not needed anymore.

The behavior is undefined if the filedescriptor does not contain a complete and valid font at offset.

Parameters:
  • fd[in] Open and readable filedescriptor.

  • offset[in] Absolute starting position of the font data within fd.

  • length[in] Size of the font data within fd.

Returns:

The font id, FontId::Invalid() on error

FontInstanceId createFreetype2FontInstance(FontId fontId, uint32_t size, bool forceAutohinting = false)

Create Freetype2 font instance.

Parameters:
  • fontId[in] The id of the font from which to create a font instance

  • size[in] Size (height in rasterized texels of glyphs) of the font

  • forceAutohinting[in] Force autohinting (a flag for FT2 library)

Returns:

The font instance id, FontInstanceId::Invalid() on error

FontInstanceId createFreetype2FontInstanceWithHarfBuzz(FontId fontId, uint32_t size, bool forceAutohinting = false)

Create Freetype2 font instance with Harfbuzz shaping.

Parameters:
  • fontId[in] The id of the font from which to create a font instance

  • size[in] Size (in rasterized texels of glyphs) of the font

  • forceAutohinting[in] Force autohinting (a flag for FT2 library)

Returns:

The font instance id, FontInstanceId::Invalid() on error

bool deleteFont(FontId fontId)

Delete an existing font.

Parameters:

fontId[in] The id of the font to be deleted

Returns:

True on success, false otherwise

bool deleteFontInstance(FontInstanceId fontInstance)

Delete an existing font instance.

Parameters:

fontInstance[in] The id of the font instance to be deleted

Returns:

True on success, false otherwise

FontRegistry(const FontRegistry &other) = delete

Deleted copy constructor.

Parameters:

other – unused

FontRegistry &operator=(const FontRegistry &other) = delete

Deleted copy assignment.

Parameters:

other – unused

Returns:

unused

Public Members

class internal::FontRegistryImpl &impl

Stores internal data for implementation specifics of FontRegistry.

struct GlyphKey
#include <Glyph.h>

GlyphKey identifies a glyph with a specific font instance.

Public Functions

GlyphKey() = default

Constructor for GlyphKey that initializes members to default values.

inline GlyphKey(GlyphId _identifier, FontInstanceId _fontInstanceId)

Constructor for GlyphKey that initializes members to passed values.

Parameters:
  • _identifier[in] The glyph id

  • _fontInstanceId[in] The font instance id

inline bool operator==(const GlyphKey &rhs) const

Equal comparison operator.

Parameters:

rhs[in] The glyph key to be compared with

Returns:

True if glyph keys are identical, false otherwise

inline bool operator!=(const GlyphKey &rhs) const

Unequal comparison operator.

Parameters:

rhs[in] The glyph key to be compared with

Returns:

False if glyph keys are identical, true otherwise

Public Members

GlyphId identifier

Glyph id.

FontInstanceId fontInstanceId

Font instance id.

struct GlyphMetrics
#include <GlyphMetrics.h>

GlyphMetrics describes a glyph’s position and dimensions in the rasterized glyph bitmap space.

Width and height are the pixel dimensions of the glyph - must match the pixel data of the glyph provided by its corresponding font instance. GlyphKey uniquely identifies the glyph by referencing its origin character and font instance. The posX/posY values are local pixel values in the coordinate system of the text line. The advance value is the local advance (see Freetype2 docs) for each glyph.

Public Members

GlyphKey key

Glyph key (GlyphId + FontInstanceId)

uint32_t width = 0u

Glyph width.

uint32_t height = 0u

Glyph height.

int32_t posX = 0

Glyph offset on x-axis.

int32_t posY = 0

Glyph offset on y-axis.

int32_t advance = 0

Glyph advance (distance from origin of this glyph to where origin of next glyph should start)

class IFontAccessor
#include <IFontAccessor.h>

Interface for getting font instances using font instance ids.

This interface allows overriding the standard Freetype/Harfbuzz logic to create and access fonts and e.g. replace with other implementations, or just override behavior/settings. Can be also used to pre-load font instances and a predefined set of glyphs statically (or load from file).

Subclassed by ramses::FontRegistry

Public Functions

virtual ~IFontAccessor() = default

Empty destructor.

virtual IFontInstance *getFontInstance(FontInstanceId fontInstanceId) const = 0

Gets a font instance object using font instance id.

Parameters:

fontInstanceId[in] The id of font instance

Returns:

The font instance object

class IFontInstance
#include <IFontInstance.h>

Interface for font instance that can be used to query glyph metadata and bitmaps.

Public Functions

virtual ~IFontInstance() = default

Empty destructor.

virtual bool supportsCharacter(char32_t character) const = 0

Check if font instance supports a char using it’s UTF32 char code and cache the result.

Parameters:

character[in] The UTF32 char code of the character

Returns:

True if the character is supported, false otherwise

virtual std::unordered_set<char32_t> getAllSupportedCharacters() = 0

Get all characters that are supported (mapped to a glyph) by IFontInstance.

Returns:

set with all supported UTF32 char codes

virtual int getHeight() const = 0

Get the line height of the font instance.

Returns:

Line height (in rasterized texels of glyphs)

virtual int getAscender() const = 0

Get the line ascender of the font instance (see Freetype2 docs)

Returns:

Line ascender (in rasterized texels of glyphs)

virtual int getDescender() const = 0

Get the line descender of the font instance (see Freetype2 docs)

Returns:

Line descender (in rasterized texels of glyphs)

virtual void loadAndAppendGlyphMetrics(std::u32string::const_iterator charsBegin, std::u32string::const_iterator charsEnd, GlyphMetricsVector &positionedGlyphs) = 0

Load the glyphs metrics for all characters in a string and appends them to the provided vector of GLYPHS.

Parameters:
  • charsBegin[in] Iterator for the beginning of characters from UTF32 string that should be loaded

  • charsEnd[in] Iterator for the end of characters from UTF32 string that should be loaded

  • positionedGlyphs[out] Vector of glyphs to which newly loaded glyph metrics are appended

virtual GlyphData loadGlyphBitmapData(GlyphId glyphId, uint32_t &sizeX, uint32_t &sizeY) = 0

Load the glyph data for a specific glyph id.

Parameters:
  • glyphId[in] Id of glyph for which to load data

  • sizeX[out] Width of glyph data

  • sizeY[out] Height of glyph data

Returns:

The glyph data if glyphId is found, or empty glyph data otherwise

struct StringBoundingBox
#include <LayoutUtils.h>

Helper data structure describing multiple glyphs metrics.

StringBoundingBox is essentially a union of a set of GlyphMetrics. It describes a bounding box of renderable glyphs (glyphs with non-empty bitmap data). Width and height are dimensions of the bounding box. The bounding box can be offset from origin using offsetX/Y. Combined advance is X axis offset from origin where next StringBoundingBox would be if put on same line. Similarly to GlyphMetrics, even when StringBoundingBox have zero width/height (which means there is no renderable data) it can still have non-zero advance which should be taken into account by other StringBoundingBox if combined.

Public Members

int32_t offsetX = 0

X axis offset of bounding box from origin.

int32_t offsetY = 0

Y axis offset of bounding box from origin.

uint32_t width = 0

Bounding box width.

uint32_t height = 0

Bounding box height.

int32_t combinedAdvance = 0

Advance to next StringBoundingBox.

class TextCache
#include <TextCache.h>

Stores text data - texture atlas, meshes, glyph bitmap data. It is a cache because the content can be re-generated when necessary, e.g. when cached glyphs take up too much memory.

The TextCache class keeps hold of following data:

  • The texture atlas pages (array of textures) which holds the glyph bitmaps for different glyphs

  • The scene objects which represent a “text line” - an array of sized and positioned characters

The TextCache uses IFontAccessor (provided in constructor) to obtain glyph data for various fonts but has otherwise no dependencies to fonts - it treats glyphs as a simple bitmap image placed in one of the texture atlas pages.

The scene objects created for each texture atlas page with glyphs is:

  • A 2D texture with a single channel (intensity of text pixel)

  • A texture sampler with bilinear filtering (to blur out edges)

The scene objects created for each text line are:

  • a Geometry with Vertex/Index arrays (holding a list of quads for each glyph in the text line)

  • an Appearance (based off the effect provided in createTextLine()). The appearance will have it’s semantic texture sampler pointing to the texture atlas page where the text line’s glyphs are located

  • a MeshNode which holds above objects together for rendering

It’s important to note that the Appearance of each TextLine has a reference to the texture page holding its glyph data, and the Geometry has links to the texture quad data generated by TextCache. We highly recommend not to tamper with these objects, unless you have in-depth understanding of how text rendering works and know what you are doing. However, setting custom uniforms in the Appearance is valid, as long as you are not touching the semantic texture sampler which was provided when creating the text line.

The TextCache has a limitation that all characters of a TextLine must fit in one (empty) texture atlas page. This means that if a TextCache was created with size 16x16 and a TextLine with single glyph of size 32 is created, the call to createTextLine() will fail because it can’t fit a single glyph in a texture atlas page - it’s too small. Therefore, pay special attention to the size of TextCache and the size of text rendered. If you want to optimize memory usage across different and wildly heterogeneous text sizes, it’s suggested to use multiple TextCache instances with different sizes if in order to avoid inefficient memory partitioning.

To understand better how TextCache internally works, consider following case. You create a TextCache with size 20x20. You use a latin font with uniform character size 10x10 for all letters. You can thus only create TextLine’s with a maximum of 4 letters. If you create two lines with size 4 which use the same 4 characters, the TextCache will create a single texture page and use the glyphs for both lines. If you create two lines with different, but partially overlapping characters, like this: line1 = ‘ABC’ line2 = ‘AXY’

the TextCache will not be able to create a page with all 5 characters (A, B, C, X and Y) and will need to create two pages. The first page will put the letters ‘ABC’ in one page which will have one empty slot. The second line will not fit in the first page, so the TextCache will create a second page and put the characters ‘AXY’ there. Note that the character ‘A’ will be in in both pages, so that each line can be rendered with a single draw call using exactly one mesh and one texture. One may argue that copying glyphs across different pages is bad, but trying to implement a TextCache which creates multiple MeshNodes and partitions them in the worst case across all texture pages quickly leads to the awareness that it’s much better to just forbid it and sacriface a bit of memory in favor of much simpler implementation.

The above limitation ensures that each TextLine receives exactly one MeshNode which makes the rendering setup much easier. However, it requires that multi-language texts with large amount of glyphs may result in suboptimal texture atlas layout. This memory overhead can be overcome by either using a texture atlas size large enough to hold any text line or implementing a more sophisticated partitioning of TextLine’s to ensure atlas pages are filled proportionally.

Finally, the TextLine object holds pointers to the original vector of glyphs which were used to create it. Be careful to not tamper with it, as it is used when destroying the text line to obtain information which glyphs can be freed.

Public Functions

TextCache(Scene &scene, IFontAccessor &fontAccessor, uint32_t atlasTextureWidth, uint32_t atlasTextureHeight)

Constructor for text cache.

Choose carefully the size of the atlas textures. Too small will prevent creation of larger strings, because not all of the glyphs will fit on a single page. Too large pages take up more memory than actually needed.

Parameters:
  • scene[in] Scene to use when creating meshes from string glyphs.

  • fontAccessor[in] Font accessor to be used for getting font instance objects

  • atlasTextureWidth[in] Width for the texture atlas that gets created to store glyphs

  • atlasTextureHeight[in] Height for the texture atlas that gets created to store glyphs

~TextCache()

Destructor for text cache that cleans up any objects created using the text cache. The scene object passed to the text cache constructor must be still valid at the time of the text cache destruction.

GlyphMetricsVector getPositionedGlyphs(const std::u32string &str, FontInstanceId font)

Create and get glyph metrics for a string using a font instance.

Use this call to obtain glyph metadata - positions, sizes, language and font origin (contained in GlyphKey). You can change the positions if you need to, e.g. if you need to do funky things like re-aligning glyphs coming from different fonts with incompatible baselines. But in the regular case, you just pass the glyphs to createTextLine() as-is.

Parameters:
  • str[in] The string for which to create glyph metrics

  • font[in] Id of the font instance to be used for creating the glyph metrics vector. The font instance must be available at the font accessor passed in the constructor of the text cache.

Returns:

The glyph metrics vector created

GlyphMetricsVector getPositionedGlyphs(const std::u32string &str, const FontInstanceOffsets &fontOffsets)

Create and get glyph metrics for a string using a list of font instances and offsets.

Use this version of getPositionedGlyphs if you need more fine-grained control over how glyphs are resolved from multiple fonts. See also documentation of FontInstanceOffset.

Parameters:
  • str[in] The string for which to create glyph metrics

  • fontOffsets[in] The font offsets created from font cascade to be used for creating the glyph metrics vector. The font instances within the font cascade must all be available at the font accessor passed in the constructor of the text cache. Also see docs of FontInstanceOffsets

Returns:

The glyph metrics created

TextLineId createTextLine(const GlyphMetricsVector &glyphs, const Effect &effect)

Create the scene objects, e.g., mesh and appearance…etc, needed for rendering a text line (represented by glyph metrics). If the provided string of glyphs contains no render-able characters (e.g. it has only white spaces), the method will fail with an error. If you want to avoid having such errors, filter out the glyphs with no visual representation (e.g. control characters) and use the helper method ContainsRenderableGlyphs on top to check if the remaining glyphs contain at least one renderable (size not zero) glyph so they can be used as input for createTextLine.

This method will always produce exactly one MeshNode. We do this by enforcing that all glyphs are rendered in the same texture atlas page, thus making it possible to create one mesh instead of several. The effect argument has special requirements - it needs to have three semantic uniforms:

Parameters:
  • glyphs[in] The glyph metrics for which to create a text line

  • effect[in] The effect used for creating the appearance of the text line and rendering the meshes

Returns:

Id of the text line created

TextLine const *getTextLine(TextLineId textId) const

Get a const pointer to a (previously created) text line object.

Parameters:

textId[in] Id of the text line object to get

Returns:

A pointer to the text line object, or nullptr on failure

TextLine *getTextLine(TextLineId textId)

Get a (non-const) pointer to a (previously created) text line object.

Parameters:

textId[in] Id of the text line object to get

Returns:

A pointer to the text line object, or nullptr on failure

bool deleteTextLine(TextLineId textId)

Delete an existing text line object.

Parameters:

textId[in] Id of the text line object to delete

Returns:

True on success, false otherwise

TextCache(const TextCache &other) = delete

Deleted copy constructor.

Parameters:

other – unused

TextCache &operator=(const TextCache &other) = delete

Deleted copy assignment.

Parameters:

other – unused

Returns:

unused

Public Members

class internal::TextCacheImpl *impl

Stores internal data for implementation specifics of TextCache.

Public Static Functions

static bool ContainsRenderableGlyphs(const GlyphMetricsVector &glyphMetrics)

Check if provided GlyphMetricsVector contains at least one renderable glyph If this functions returns false, the provided input cannot be used as input for the function createTextLine. The function call will simply fail.

Parameters:

glyphMetrics[in] GlyphMetrics to be checked @ return True if the provided vector contains at least one renderable glyph

static void ApplyTrackingToGlyphs(GlyphMetricsVector &glyphMetrics, int32_t trackingFactor, int32_t fontSize)

Apply character tracking (positive or negative) to each glyph in provided GlyphMetricsVector. This means that that the space between the individual glyphs can be increased (positive tracking) or decreased (negative tracking). The tracking factor is calculated in em, so it’s relative to the font size (1/1000 of font size in pixels). So having a tracking factor of 1000 and a font size of 10 would result in an extra of 10 pixels space between every glyph (1000/1000 * 10 = 10px). Overdoing the negative tracking is not advised, as the glyphs will then potentially be printed on top of each other. This helper function should only be used on Latin fonts as for all other font types this kind of tracking may lead to unexpected visual output.

Parameters:
  • glyphMetrics[in] GlyphMetrics that get tracking applied on

  • trackingFactor[in] factor of tracking intensity (higher –> bigger tracking effect)

  • fontSize[in] size of the font that contains the glyphs to be tracked

struct TextLine
#include <TextLine.h>

Groups the scene objects needed to render a text line.

Public Members

MeshNode *meshNode = nullptr

Mesh node that represents the text.

std::size_t atlasPage = std::numeric_limits<std::size_t>::max()

Index to the atlas page containing the glyphs.

GlyphMetricsVector glyphs

Glyph metrics of the original string characters.

ArrayBuffer *positions = nullptr

Stores vertex data for the text line quads.

ArrayBuffer *textureCoordinates = nullptr

Stores texture coordinate data for the text line quads.

ArrayBuffer *indices = nullptr

Stores index data for the text line quads.

struct ExtractedUnicodePoint
#include <UtfUtils.h>

Stores an extracted Unicode/UTF32 code-point and corresponding meta-data resulting from the conversion to Unicode (see also UtfUtils)

Public Members

bool extractionSuccessful

true if the extraction was successful. Otherwise: false and codePoint is undefined

uint32_t codePoint

The unicode-point storing the unique id of a character (UTF32)

size_t inputCharsConsumed

Stores how many input characters were read to resolve the unicode point (bytes in UTF8 case and words in UTF16 case)