Font Renderer
Principle
The Font Renderer is a module of the MicroUI runtime that reads and draws the strings with a font. It calls Abstraction Layer APIs to draw and transform the strings, the MicroUI RenderableString and single characters (with an optional transformation like a rotation or a scaling). In addition, the Graphics Engine provides some software algorithms to perform the rendering of the strings with the internal font format.
Functional Description
All MicroUI string drawings are redirected to a set of Abstraction Layer APIs. All Abstraction Layer APIs are implemented by weak functions, which call software algorithms. The BSP can override this default behavior:
To use an advanced complex layout manager.
To use a custom drawer.
To handle Custom Fonts.
Font Formats
Internal Font Format
The Graphics Engine’s software algorithms are by default able to draw an internal font. No extra support in the VEE Port is required to draw strings with this kind of font.
The string drawing resembles a shape drawing. The drawing is performed by default by the Graphics Engine Software Algorithms and can be overridden. This allows to enrich the language support by using a third-party library that provides an advanced complex layout manager.
Custom Font Format
The VEE Port must extend the Font Renderer to support the drawing of strings with a Custom Font. This extension can consist in:
Decoding the font at runtime to draw it.
Using an advanced complex layout manager.
Using a command interpreter to perform some shape drawings.
etc.
To draw strings with custom fonts, the Font Renderer introduces the notion of custom font drawer.
This drawer is an engine that has the responsibility to draw the string with the font.
Each custom font format (0
to 7
) has its own font drawer.
Each drawing of a string with a custom font is redirected to the associated font drawer.
Hint
A custom font drawer can call the UI Shapes Drawing API to draw its elements in the destination.
The implementation is not the same between the Embedded side and the Simulation. However, the concepts are the same and are described in dedicated chapters.
MicroUI C Module
Principle
As described above, a font drawer allows drawing strings with a font which format is custom. The MicroUI C module is designed to manage the notion of drawers: it does not support the custom formats but allows adding some additional drawers.
This support uses several weak functions and tables to redirect the string drawings. When custom drawers are not used (when the VEE Port does not need to support custom fonts), this redirection can be removed to reduce the memory footprint (by removing the indirection tables) and improve the performances (by reducing the number of runtime function calls).
Internal Font Format Only (Default)
The default implementation can only draw strings with internal fonts. In other words, the application cannot draw with a custom font. This is the most frequent use case, the only one available with MicroUI before version 3.6.
Attention
To select this implementation (to disable the custom font support), the define LLUI_FONT_CUSTOM_FORMATS
must be unset.
The font drawing is similar to UI_DRAWING_GPU_drawLine
(see MicroUI C Module), except that the drawing consists in decoding the string first (to optionally apply a complex layout manager), and then calling the Graphics Engine’s software algorithms to draw the string.
Theoretically, the weak drawer should let the font drawer handle the font instead of calling the software drawer directly.
However the MicroUI C Module takes advantage of the define LLUI_FONT_CUSTOM_FORMATS
: as it is not set, the C Module bypasses the indirection to the font drawer, and as a consequence the implementation of the weak function only consists in calling the Graphics Engine’s software algorithm (basic string layouter, see Languages and software drawings).
This tip reduces the footprint and the CPU usage.
An implementation of a third-party complex layouter can optionally take advantage of the define LLUI_FONT_CUSTOM_FORMATS
.
The following diagrams illustrate the drawing of a string with or without taking advantage of the define LLUI_FONT_CUSTOM_FORMATS
(respectively default and optimized implementation).
LLUI_PAINTER_IMPL_drawString (available in MicroUI C Module)
Similar to LLUI_PAINTER_IMPL_drawLine
, see MicroUI C Module.
UI_DRAWING_drawString
// Available in MicroUI C Module
#define UI_DRAWING_DEFAULT_drawString UI_DRAWING_drawString
// To write in the BSP (optional)
#define UI_DRAWING_LAYOUT_drawString UI_DRAWING_drawString
The function names are set with preprocessor macros. These name redirections are helpful when the VEE Port features more than one destination format (which is not the case here).
UI_DRAWING_LAYOUT_drawString (to write in the BSP)
Similar to UI_DRAWING_GPU_drawLine
(see MicroUI C Module), but lets the font drawer manage the font instead of calling the software drawer directly (Default Implementation) or takes advantage of the define LLUI_FONT_CUSTOM_FORMATS
(Optimized Implementation):
// Unlike the MicroUI C Module, this function is not "weak".
DRAWING_Status UI_DRAWING_LAYOUT_drawString(MICROUI_GraphicsContext *gc, jchar *chars, jint length, MICROUI_Font *font, jint x, jint y) {
DRAWING_Status status;
jchar *transformed_chars = [...] ;
// Let the font drawer manages the string (available in the C module)
status = UI_FONT_DRAWING_drawString(gc, transformed_chars, length, font, x, y);
return status;
}
// Unlike the MicroUI C Module, this function is not "weak".
DRAWING_Status UI_DRAWING_LAYOUT_drawString(MICROUI_GraphicsContext *gc, jchar *chars, jint length, MICROUI_Font *font, jint x, jint y) {
DRAWING_Status status;
jchar *transformed_chars = [...] ;
#if !defined(UI_FEATURE_FONT_CUSTOM_FORMATS)
status = UI_DRAWING_SOFT_drawString(gc, transformed_chars, length, font, x, y);
#else
// Let the font drawer manages the string (available in the C module)
status = UI_FONT_DRAWING_drawString(gc, transformed_chars, length, font, x, y);
#endif
return status;
}
UI_DRAWING_DEFAULT_drawString (available in MicroUI C Module)
// Use the compiler's 'weak' attribute
__weak DRAWING_Status UI_DRAWING_DEFAULT_drawString(MICROUI_GraphicsContext *gc, jchar *chars, jint length, MICROUI_Font *font, jint x, jint y) {
#if !defined(LLUI_FONT_CUSTOM_FORMATS)
return UI_DRAWING_SOFT_drawString(gc, chars, length, font, x, y);
#else
return UI_FONT_DRAWING_drawString(gc, chars, length, font, x, y);
#endif
}
The define LLUI_FONT_CUSTOM_FORMATS
is not set, so the implementation of the weak function only consists in calling the Graphics Engine’s software algorithm.
Custom Font Format
In addition to the internal font format, this implementation allows drawing strings with a custom font format. This advanced use case is available only with MicroUI 3.6 or higher.
Attention
To select this implementation, the define LLUI_FONT_CUSTOM_FORMATS
must be set (no specific value).
The MicroUI C module uses some tables to redirect the font management to the expected extension. There is one table per Font Abstraction Layer API (draw, rotate, scale) to embed only the necessary algorithms (a table and its functions are only embedded in the final binary file if and only if the MicroUI drawing method is called).
Each table contains ten elements:
static const UI_FONT_DRAWING_drawString_t UI_FONT_DRAWING_drawString_custom[] = {
&UI_DRAWING_STUB_drawString,
&UI_DRAWING_SOFT_drawString,
&UI_FONT_DRAWING_drawString_custom0,
&UI_FONT_DRAWING_drawString_custom1,
&UI_FONT_DRAWING_drawString_custom2,
&UI_FONT_DRAWING_drawString_custom3,
&UI_FONT_DRAWING_drawString_custom4,
&UI_FONT_DRAWING_drawString_custom5,
&UI_FONT_DRAWING_drawString_custom6,
&UI_FONT_DRAWING_drawString_custom7,
};
UI_DRAWING_STUB_drawString
is the drawing function called when the drawing function is not implemented,UI_DRAWING_SOFT_drawString
is the drawing function that redirects the drawing to the Graphics Engine Software Algorithms,UI_FONT_DRAWING_drawString_customX
(0
to7
) are the drawing functions for each custom format.
The MicroUI C Module retrieves the table index according to the font format.
The implementation of UI_DRAWING_drawString
can have two behaviors:
It only manages the characters layouting; the drawing is performed by another C file.
It manages the layouting and the drawing; in that case, the implementation has to check if it supports the font.
The following diagram illustrates the drawing of a string:
Take the same example as the Internal Font Formats Only implementation (draw a string):
UI_DRAWING_DEFAULT_drawString (available in MicroUI C Module)
// Use the compiler's 'weak' attribute
__weak DRAWING_Status UI_DRAWING_DEFAULT_drawString(MICROUI_GraphicsContext *gc, jchar *chars, jint length, MICROUI_Font *font, jint x, jint y) {
#if !defined(LLUI_FONT_CUSTOM_FORMATS)
return UI_DRAWING_SOFT_drawString(gc, chars, length, font, x, y);
#else
return UI_FONT_DRAWING_drawString(gc, chars, length, font, x, y);
#endif
}
The define LLUI_FONT_CUSTOM_FORMATS
is set so the implementation of the weak function redirects the string drawing to the font drawer manager (ui_font_drawing.h
).
UI_FONT_DRAWING_draw (available in MicroUI C Module)
static const UI_FONT_DRAWING_drawString_t UI_FONT_DRAWING_drawString_custom[] = {
&UI_DRAWING_STUB_drawString,
&UI_DRAWING_SOFT_drawString,
&UI_FONT_DRAWING_drawString_custom0,
&UI_FONT_DRAWING_drawString_custom1,
&UI_FONT_DRAWING_drawString_custom2,
&UI_FONT_DRAWING_drawString_custom3,
&UI_FONT_DRAWING_drawString_custom4,
&UI_FONT_DRAWING_drawString_custom5,
&UI_FONT_DRAWING_drawString_custom6,
&UI_FONT_DRAWING_drawString_custom7,
};
DRAWING_Status UI_FONT_DRAWING_drawString(MICROUI_GraphicsContext *gc, jchar *chars, jint length, MICROUI_Font *font, jint x, jint y){
return (*UI_FONT_DRAWING_drawString_custom[_get_table_index(gc, font)])(gc, chars, length, font, x, y);
}
The implementation in the MicroUI C module redirects the drawing to the expected drawer.
The drawer is retrieved using the font format (function _get_table_index()
):
The format is internal but the destination is not the display format: index
0
is returned.The format is internal and the destination is the display format: index
1
is returned.The format is custom: an index from
2
to9
is returned.
UI_FONT_DRAWING_drawString_custom0 (available in MicroUI C Module)
// Use the compiler's 'weak' attribute
__weak DRAWING_Status UI_FONT_DRAWING_drawString_custom0(MICROUI_GraphicsContext *gc, jchar *chars, jint length, MICROUI_Font *font, jint x, jint y){
return UI_DRAWING_STUB_drawString(gc, chars, length, font, x, y);
}
The default implementation of UI_FONT_DRAWING_drawString_custom0
(same behavior for 0
to 7
) consists in calling the stub implementation.
UI_DRAWING_STUB_drawString (available in MicroUI C Module)
DRAWING_Status UI_DRAWING_STUB_drawString(MICROUI_GraphicsContext *gc, jchar *chars, jint length, MICROUI_Font *font, jint x, jint y){
// Set the drawing log flag "not implemented"
LLUI_DISPLAY_reportError(gc, DRAWING_LOG_NOT_IMPLEMENTED);
return DRAWING_DONE;
}
The implementation only consists in setting the Drawing log flag DRAWING_LOG_NOT_IMPLEMENTED
to notify the application that the drawing has not been performed.
Simulation
Principle
The simulation behavior is similar to the MicroUI C Module for the Embedded side.
The Front Panel defines support for the drawers based on the Java service loader.
Internal Font Format Only (Default)
The default implementation can only draw strings with internal fonts.
Note
Contrary to the MicroUI C Module, the simulation does not (and doesn’t need to) provide an option to disable the use of custom font.
The following diagram illustrates the drawing of a string:
It is possible to override the font drawers for the internal format in the same way as the custom formats.
Custom Font Format
It is possible to draw fonts with a custom format by implementing the UIFontDrawing
interface.
This advanced use case is available only with MicroUI 3.6 or higher.
The UIFontDrawing
interface contains one method for each font drawing primitive (draw, getWidth, RenderableString, rotate, scale).
Only the necessary methods have to be implemented.
Each non-implemented method will result in calling the stub implementation.
The method handledFormat()
must be implemented and returns the font format handled by the drawer.
Once created, the UIFontDrawing
implementation must be registered as a service.
The following diagram illustrates the drawing of a string:
Let’s implement the font drawer for the CUSTOM_0 format.
public class MyCustomFontDrawer implements UIFontDrawing {
@Override
public MicroUIFontFormat handledFormat() {
return MicroUIFontFormat.MICROUI_FONT_FORMAT_CUSTOM_0;
}
@Override
public void draw(MicroUIGraphicsContext gc, char[] chars, int offset, int length, MicroUIFont font, int x, int y) {
byte[] fontData = font.getFontData();
MyCustomFont customFont = MyCustomFont.get(fontData);
customFont.drawOn(gc, chars, offset, length, customFont, x, y);
}
}
Now, this drawer needs to be registered as a service.
This can be achieved by creating a file in the resources of the Front Panel project named META-INF/services/ej.microui.display.UIFontDrawing
and containing the fully qualified name of the previously created font drawer.
com.mycompany.MyCustomFontDrawer
It is also possible to declare it programmatically (see where a drawer is registered in the drawing custom section):
LLUIDisplay.Instance.registerUIFontDrawer(new MyCustomFontDrawer());
Installation
The Font Renderer is part of the MicroUI module and Display module. You must install them in order to be able to use some fonts.
Use
The MicroUI font APIs are available in the class ej.microui.display.Font.