-
Notifications
You must be signed in to change notification settings - Fork 85
Adds CustomTypeface and Removes GlyphFace #640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ture/customTypeface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR removes the legacy GlyphFace implementation and replaces it with a new custom typeface API based on Font and CustomTypefaceBuilder. The changes include renaming and refactoring in core text rendering components, removal of GlyphFace-based methods, and updates to constructors and helper functions to use the new API.
- Removed GlyphFace-related functionality and headers.
- Updated TextBlob, GlyphRun*, Font, and Canvas to use Font-based APIs.
- Added new custom typeface builder interfaces (PathTypefaceBuilder and ImageTypefaceBuilder) and extended Typeface.
Reviewed Changes
Copilot reviewed 56 out of 56 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
src/core/TextBlob.cpp | Refactored creation methods to use Font instead of GlyphFace; renamed enum. |
src/core/ScalerContext.* | Removed legacy Make() method; updated calls to use createScalerContext. |
src/core/GlyphRunList.{h,cpp} | Updated to use Font APIs for glyph rendering and bounds extraction. |
src/core/Font.cpp | Updated scaler context creation with new typeface API. |
src/core/Canvas.cpp | Replaced drawing functions to use Font-based glyph runs. |
include/tgfx/core/{Typeface.h,GlyphRun.h} | Modified API signatures to accommodate Font instead of GlyphFace. |
include/tgfx/core/{PathTypefaceBuilder.h,ImageTypefaceBuilder.h,CustomTypefaceBuilder.h} | Added new custom typeface builder interfaces. |
CMakeLists.txt | Updated source file inclusion for new custom typeface builder implementations. |
Comments suppressed due to low confidence (3)
src/core/TextBlob.cpp:75
- [nitpick] The enum rename from GlyphFaceType to FontType is clear; please update any remaining comments or documentation referencing GlyphFaceType for consistency.
enum class FontType { Path, Color, Other };
include/tgfx/core/GlyphRun.h:37
- [nitpick] Update the documentation for this constructor to mention that it now directly uses a Font instance instead of wrapping a GlyphFace, ensuring users are aware of the API change.
GlyphRun(Font font, std::vector<GlyphID> glyphIDs, std::vector<Point> positions)
src/core/GlyphRunList.cpp:42
- Consider adding an assertion or guard to ensure that each GlyphRun's 'font' member is valid before calling hasColor(), to mitigate the risk of a null dereference.
[hasColor = _glyphRuns[0].font.hasColor()](const GlyphRun& glyphRun) {
explicit CustomTypefaceBuilder(const std::string& fontFamily = "", | ||
const std::string& fontStyle = "", | ||
const FontMetrics& metrics = {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不需要这个构造函数。已经有可选的set方法了。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
参考Skia,把ImageTypefaceBuilder和PathTypefaceBuilder都移动到CustomTypefaceBuilder同一个头文件里。并且把头文件命名为CustomTypeface.h
std::shared_ptr<Typeface> detach() const override; | ||
|
||
private: | ||
std::vector<std::shared_ptr<GlyphRecord>> glyphRecords; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
随手赋初始值
CMakeLists.txt
Outdated
@@ -126,6 +126,7 @@ file(GLOB_RECURSE SRC_FILES | |||
src/core/shaders/*.* | |||
src/core/shapes/*.* | |||
src/core/utils/*.* | |||
src/core/vectors/custom/*.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个不应该放在vectors下面,不属于任何一个后端,custom的直接放在core包下面就可以了。
*/ | ||
class ImageTypefaceBuilder : public CustomTypefaceBuilder { | ||
public: | ||
struct GlyphRecord { // logical union |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个结构体不要放在public区域暴露。可以直接挪到Cpp里定义。头文件这边只做个struct GlyphRecord;的声明。改为ImageGlyphRecord就行了,不用内嵌。
struct GlyphRecord { | ||
Path path = {}; | ||
GlyphRecord(const Path& path) : path(path) { | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个结构体有两个问题:1.不应该是存储Path,这样就被迫所有的PathProvider提前实例化了。会阻塞当前线程,并且占用过多内存。应该是存储PathProvider才对,把普通Path也包装为一个PathProvider。 2.只有一个属性,是不需要定义这个GlyphRecord的,直接用PathProvider的数组存储就行。
include/tgfx/core/Typeface.h
Outdated
/** | ||
* Returns a ScalerContext for the given size. | ||
*/ | ||
virtual std::shared_ptr<ScalerContext> createScalerContext(float size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个不能是public方法,改为private,然后友元访问。也不需要virtual吧?子类覆盖的是onCreateScalerContext()方法不是这个。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果有个onCreate方法了。这个方法建议命名为getScalerContext()
include/tgfx/core/Typeface.h
Outdated
/** | ||
* Returns the active ID for this typeface. for custom typefaces, this is the builderID, or returns uniqueID. | ||
*/ | ||
virtual uint32_t getActiveID() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getCacheID()好一点。注释更新一下:Returns the cache ID for this typeface. Typically, this is the uniqueID of the typeface; for custom typefaces, it returns the uniqueID of the associated typeface builder.
src/core/Typeface.cpp
Outdated
std::shared_ptr<ScalerContext> Typeface::createScalerContext(float size) { | ||
if (weakThis.lock() == nullptr || glyphsCount() <= 0 || size < 0.0f) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
前两个不应该判断,前两个条件是只要Typeface对象存在就不应该无效。第三个条件要改成 size <= 0.0f.
if (firstTime) { | ||
_fontMetrics.top = bounds.top; | ||
_fontMetrics.bottom = bounds.bottom; | ||
_fontMetrics.xMin = bounds.left; | ||
_fontMetrics.xMax = bounds.right; | ||
} else { | ||
_fontMetrics.top = std::min(_fontMetrics.top, bounds.top); | ||
_fontMetrics.bottom = std::max(_fontMetrics.bottom, bounds.bottom); | ||
_fontMetrics.xMin = std::min(_fontMetrics.xMin, bounds.left); | ||
_fontMetrics.xMax = std::max(_fontMetrics.xMax, bounds.right); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个方法是没有必要的,用户不设置metrics我们不用自己计算。
#include "tgfx/core/Typeface.h" | ||
|
||
namespace tgfx { | ||
class ImageTypeface final : public Typeface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个命名有点歧义,改为ImageUserTypeface吧,对应把PathTypeface改一下,以及其他相关的类。ImageTypefaceBuilder因为存在TypefaceBuilder的标识,还是能比较好区分出来是自定义字体的类,可以不改。
uint32_t uniqueID() const override { | ||
return _uniqueID; | ||
} | ||
|
||
std::string fontFamily() const override { | ||
return _fontFamily; | ||
} | ||
|
||
std::string fontStyle() const override { | ||
return _fontStyle; | ||
} | ||
|
||
const FontMetrics& fontMetrics() const { | ||
return _fontMetrics; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
建议是加个UserTypeface的基类,把公共的属性都实现到一起。避免代码存在重复。对应的ScalerContext也是。
static constexpr float StdFakeBoldInterpKeys[] = { | ||
9.f, | ||
36.f, | ||
}; | ||
static constexpr float StdFakeBoldInterpValues[] = { | ||
1.f / 24.f, | ||
1.f / 32.f, | ||
}; | ||
|
||
inline float Interpolate(const float& a, const float& b, const float& t) { | ||
return a + (b - a) * t; | ||
} | ||
|
||
/** | ||
* Interpolate along the function described by (keys[length], values[length]) | ||
* for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length] | ||
* clamp to the min or max value. This function assumes the number of pairs | ||
* (length) will be small and a linear search is used. | ||
* | ||
* Repeated keys are allowed for discontinuous functions (so long as keys is | ||
* monotonically increasing). If key is the value of a repeated scalar in | ||
* keys the first one will be used. | ||
*/ | ||
static float FloatInterpFunc(float searchKey, const float keys[], const float values[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这部分计算粗体的代码不要重复,提取一个工具类出来。任何时候都不应该写重复的代码。不好维护容易出bug。
if (record == nullptr || record->path.isEmpty()) { | ||
return false; | ||
} | ||
auto bounds = PathScalerContext::getImageTransform(glyphID, fauxBold, stroke, nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个getImageTransform的前缀PathScalerContext::是没必要的
@@ -75,7 +61,7 @@ Rect WebScalerContext::getImageTransform(GlyphID glyphID, bool fauxBold, const S | |||
return {}; | |||
} | |||
if (!hasColor() && stroke != nullptr) { | |||
stroke->applyToBounds(&bounds); | |||
ApplyStrokeToBounds(*stroke, &bounds, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这些都是流水线应该检查出来的,应该是npm那边的编译命令默认改成了编译多线程的原因,这块问题无法暴露了。到.github/workflows/build.xml 里找下web平台的编译命令,把 npm run build:debug 改为 npm run build:st:debug
#include "utils/TestUtils.h" | ||
|
||
namespace tgfx { | ||
TGFX_TEST(TypefaceTest, CustomPathTypeface) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应该主要构造继承PathProvider的测试用例,写个自定义的PathProvider子类,里面就是直接用那些lineTo之类的临时创建Path的代码。另外可以给PathProvider加个静态的Wrap方法,用来快速包装Path。
1.添加CustomTypeface, CustomTypefaceBuilder
2.删除GlyphFace