Motivation==========
With the rise of variable fonts, it's possible to derive many variation 
instances of a typeface with different combination of coordinate values or 
colors. FreeType has already provided support for these fonts. Currently, two 
ways come into mind for adding support for these variations from a client's 
perspective.
* Have a single `FT_Face` object per font and setup specified variation 
coordinates on it whenever there's a request to perform a variation specific 
operation.* Open a new `FT_Face` object per variation and reuse it when needed.
The first approach has following cons.1. There's a potential cost of context 
switching with each variation-specific operation.2. It's difficult to cache the 
face with variation-specific settings.
The second approach solves above drawbacks but it has following cons.1. 
Additional cost of face initialization and setup.2. Increased memory usage.

Proposal========
This proposal aims to take the best of both approaches by introducing a new 
function, `FT_Clone_Face`. This function would make a copy of the specified 
face by ensuring that the copied face shares as much memory as possible with 
the parent face. The output will be an exact copy of the source face leaving 
only glyph slot and size objects which will always be new. The client would be 
free to treat the cloned instance as any new face.
This would help in solving the drawbacks of 2nd approach effectively. As an 
addition, this would also help a client achieve immutability based on any 
combination of settings at `FT_Face` level.

Some Concepts=============
Before jumping into implementation details, there's a need to revise some 
concepts that would help understand the proposed solution.
A variable in a data structure can have the following traits.
Memory------* Static: The memory of this variable is statically allocated along 
with the parent struct and it has no life cycle of its own.* Dynamic: The 
memory of this variable is dynamically allocated / freed at runtime and it has 
a proper life cycle.
State-----* Immutable: This variable belongs to a data structure whose all 
members are set during initialization and not changed afterwards.* Mutable: 
This variable belongs to a data structure whose members are expected to be 
changed after initialization.
Assignment----------* ReadWrite: The value of this variable can be set / 
changed anytime.* Readonly: The value of this variable is set during 
initialaztion and not changed afterwards.* Lazy: This variable is only 
initialized when accessing it for the first time.

Implementation Guidelines=========================
The cloning can be done with the following set of rules.
Static & (Immutable | Mutable) & (ReadWrite | Readonly | 
Lazy)--------------------------------------------------------------Such 
variable can be copied in cloned instance with just simple assignment since it 
does not involve any kind of memory management.
Dynamic & Immutable & Readonly------------------------------Such variable can 
be shared in cloned instance provided that its lifecycle is only managed by the 
parent.
Dynamic & Immutable & Lazy--------------------------There are two ways to 
resolve such variable:* Reset it along with related variables to initial values 
so that they can be initialized again on demand. In this case the lifecycle 
should be managed by the cloned instance.* Copy its value with simple 
assignment in cloned instance. If it wasn't initialized during cloning, then on 
demand initializer function would be invoked when accessed for the first time. 
In this case, the cloned instance should check for the variable's existence in 
parent first. If it's already available in the parent, the values should be 
copied from there. If it's not available in the parent, then on demand 
initializer should be invoked on parent instance. After that, the values should 
be copied from the parent. Since the variable is only initialized in parent, 
its lifecycle should be managed by parent only.
Any Other Case--------------A new variable of same type must be created in 
cloned instance and the memory should be copied into it from the source 
variable. Needless to say, the cloned instance should also manage the lifecycle 
of new variable.

Implementation Details======================
As of now, the implementation of `FT_Clone_Face` is complete but currently it 
only covers the `truetype` format. It is available as part of merge request 
!134 
(https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/134/diffs).
The commit history will be revised where the first-ever commit will declare a 
new function, `FT_Face_CopyFunc` in `ftdrv.h`. It would take two parameters, a 
source face and a target face. The implementation would be responsible for 
copying format specific face properties into the target face. A new field 
`copy_face` would be declared in `FT_Driver_ClassRec`. Its data type would be 
`FT_Face_CopyFunc` and each format would set this to `NULL` initially. This 
`copy_face` would be used eventually to implement `FT_Clone_Face`.

Implementation Process======================
The `FT_Clone_Face` function will be implemented in multiple merge requests. 
The first MR will cover the base functionality and the `truetype` format. There 
will be subsequent MRs built on top of the first one. Each MR will cover a 
specific font format.

Limitations===========
The cloned instance will not be fully thread-safe. So a lock would need to be 
associated with the root face or more precisely, the input stream. This is due 
the fact that a single stream object can be used to open multiple faces. This 
lock would need to be acquired whenever a client wants to mutate any face 
associated with the input stream, including the distinct faces, the parent face 
and the derived faces. An example of face mutation include the call to 
@FT_Load_Glyph and similar API. And of course this lock would be only needed 
when accessing any of the related face from multiple threads.

Feedback========
Please feel free to ask any questions or give suggestions.

Thanks to Werner Lemberg & Alexei Podtelezhnikov who helped in refining the 
problem statement, the scope and the process.

Regards,Tayyab    On Sunday, January 23, 2022, 03:59:59 AM GMT+5, Tayyab Akram 
<[email protected]> wrote:  
 
 I have raised a PR for this feature.
Please Review: 
https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/134
Thanks,Tayyab  

Reply via email to