mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 18:50:16 +03:00
Add configurable OpenType font features to text rendering:
Support explicit liga, calt, clig, and dlig shaping features and include text hints in layout caching, measurement, drawing, and character position calculations. Propagate scene-wide font feature defaults through UI text producers, with granular widget overrides and recursive cache invalidation. Update UICodeEditor and UIConsole to use shaped positioning when font features are enabled, including with monospaced fonts. Add separate UI and editor font feature settings to ecode, persist them as comma-separated OpenType tags, and apply changes immediately. Add localized menu labels, reusable Text feature conversion helpers, and regression coverage for shaping, positioning, propagation, and parsing.
This commit is contained in:
@@ -1363,6 +1363,12 @@ struct TextHints {
|
||||
AllAscii = 1 << 0,
|
||||
AllLatin1 = 1 << 1,
|
||||
NoKerning = 1 << 2,
|
||||
StandardLigatures = 1 << 3,
|
||||
ContextualAlternates = 1 << 4,
|
||||
ContextualLigatures = 1 << 5,
|
||||
DiscretionaryLigatures = 1 << 6,
|
||||
OpenTypeFeatures =
|
||||
StandardLigatures | ContextualAlternates | ContextualLigatures | DiscretionaryLigatures,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -163,6 +163,10 @@ class EE_API RichText : public Drawable {
|
||||
|
||||
Uint32 getTabWidth() const { return mTabWidth; }
|
||||
|
||||
void setTextHints( Uint32 textHints );
|
||||
|
||||
Uint32 getTextHints() const { return mTextHints; }
|
||||
|
||||
bool setExternalFloatExclusions( const std::vector<FloatExclusion>& exclusions );
|
||||
|
||||
const std::vector<FloatExclusion>& getExternalFloatExclusions() const {
|
||||
@@ -482,6 +486,7 @@ class EE_API RichText : public Drawable {
|
||||
bool mLineWrap{ true };
|
||||
WhiteSpaceWrapMode mWhiteSpaceWrapMode{ WhiteSpaceWrapMode::Normal };
|
||||
Uint32 mTabWidth{ 8 };
|
||||
Uint32 mTextHints{ 0 };
|
||||
};
|
||||
|
||||
}} // namespace EE::Graphics
|
||||
|
||||
@@ -42,7 +42,7 @@ class EE_API Text {
|
||||
};
|
||||
|
||||
static inline bool canSkipShaping( Uint32 textDrawHints ) {
|
||||
return Text::TextShaperOptimizations &&
|
||||
return Text::TextShaperOptimizations && !( textDrawHints & TextHints::OpenTypeFeatures ) &&
|
||||
( textDrawHints & ( TextHints::AllLatin1 | TextHints::AllAscii ) ) != 0;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ class EE_API Text {
|
||||
|
||||
static FontWeight stringToFontWeight( const std::string& str );
|
||||
|
||||
static Uint32 fontFeaturesFromString( const std::string& value );
|
||||
|
||||
static std::string fontFeaturesToString( Uint32 features );
|
||||
|
||||
static Float getTextWidth( Font* font, const Uint32& fontSize, const String& string,
|
||||
const Uint32& style, const Uint32& tabWidth = 4,
|
||||
const Float& outlineThickness = 0.f, Uint32 textDrawHints = 0,
|
||||
@@ -416,6 +420,7 @@ class EE_API Text {
|
||||
LineWrapMode mLineWrapMode{ LineWrapMode::NoWrap };
|
||||
TextDirection mDirection{ TextDirection::Unspecified };
|
||||
Vector2f mInitialOffset{ 0.f, 0.f };
|
||||
Uint32 mTextDrawHints{ 0 };
|
||||
|
||||
mutable SmallVector<Int64, 4> mVisualLines;
|
||||
mutable SmallVector<Float, 4> mLinesWidth;
|
||||
|
||||
@@ -26,10 +26,12 @@ class EE_API DocumentView {
|
||||
bool keepIndentation{ true };
|
||||
Uint32 tabWidth{ 4 };
|
||||
std::optional<Uint32> maxCharactersWidth{};
|
||||
Uint32 textHints{ 0 };
|
||||
bool tabStops{ false };
|
||||
bool operator==( const Config& other ) {
|
||||
return mode == other.mode && keepIndentation == other.keepIndentation &&
|
||||
tabWidth == other.tabWidth && maxCharactersWidth == other.maxCharactersWidth;
|
||||
tabWidth == other.tabWidth && maxCharactersWidth == other.maxCharactersWidth &&
|
||||
textHints == other.textHints && tabStops == other.tabStops;
|
||||
}
|
||||
bool operator!=( const Config& other ) { return !( *this == other ); }
|
||||
};
|
||||
@@ -49,7 +51,8 @@ class EE_API DocumentView {
|
||||
const FontStyleConfig& fontStyle, Float maxWidth,
|
||||
LineWrapMode mode, bool keepIndentation,
|
||||
Uint32 tabWidth = 4, Float whiteSpaceWidth = 0.f,
|
||||
bool tabStops = false, Float initialXOffset = 0.f );
|
||||
bool tabStops = false, Float initialXOffset = 0.f,
|
||||
Uint32 textHints = 0 );
|
||||
|
||||
DocumentView( std::shared_ptr<TextDocument> doc, FontStyleConfig fontStyle, Config config );
|
||||
|
||||
@@ -137,6 +140,8 @@ class EE_API DocumentView {
|
||||
|
||||
void setTabStops( bool enabled );
|
||||
|
||||
void setTextHints( Uint32 textHints );
|
||||
|
||||
bool usesTabStops() const { return mConfig.tabStops; }
|
||||
|
||||
const std::vector<Int64> getDocLineToVisibleIndex() const { return mDocLineToVisibleIndex; }
|
||||
|
||||
@@ -841,6 +841,14 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
|
||||
|
||||
bool isKerningEnabled() const;
|
||||
|
||||
void setLigatureFeatures( Uint32 features );
|
||||
|
||||
Uint32 getLigatureFeatures() const;
|
||||
|
||||
void clearLigaturesOverride();
|
||||
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
void setTextDirection( TextDirection direction );
|
||||
|
||||
TextDirection getTextDirection() const;
|
||||
@@ -909,6 +917,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
|
||||
bool mAllowSelectingTextFromGutter{ true };
|
||||
bool mTabStops{ false };
|
||||
bool mKerningEnabled{ false };
|
||||
bool mLigaturesOverride{ false };
|
||||
bool mDisableScrollInvalidation{ false };
|
||||
bool mDynamicTheming{ false };
|
||||
bool mUpdatingScrollBar{ false };
|
||||
@@ -917,6 +926,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
|
||||
Time mBlinkTime;
|
||||
Time mFoldsRefreshTime;
|
||||
Uint32 mTabWidth;
|
||||
Uint32 mLigatureFeatures{ 0 };
|
||||
std::atomic<size_t> mHighlightWordProcessing{ false };
|
||||
TextRange mLinkPosition;
|
||||
String mLink;
|
||||
@@ -1231,7 +1241,11 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
|
||||
void addCursorsFromCurrentToMousePosition();
|
||||
|
||||
inline Uint32 getWidgetTextDrawHints() const {
|
||||
return mKerningEnabled ? 0 : TextHints::NoKerning;
|
||||
const Uint32 ligatureFeatures = mLigaturesOverride
|
||||
? mLigatureFeatures
|
||||
: getDefaultTextHints() & TextHints::OpenTypeFeatures;
|
||||
return ( mKerningEnabled ? 0 : TextHints::NoKerning ) |
|
||||
( ligatureFeatures & TextHints::OpenTypeFeatures );
|
||||
}
|
||||
|
||||
bool setInternalFontSize( const Float& size );
|
||||
|
||||
@@ -153,6 +153,12 @@ class EE_API UIConsole : public UIWidget,
|
||||
|
||||
TextDocument& getDoc();
|
||||
|
||||
void setLigatureFeatures( Uint32 features );
|
||||
Uint32 getLigatureFeatures() const;
|
||||
void clearLigaturesOverride();
|
||||
Uint32 getTextHints() const;
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
Client::Type getTextDocumentClientType() { return TextDocument::Client::Core; }
|
||||
|
||||
protected:
|
||||
@@ -171,6 +177,7 @@ class EE_API UIConsole : public UIWidget,
|
||||
std::vector<TextCache> mTextCache;
|
||||
UIFontStyleConfig mFontStyleConfig;
|
||||
Uint32 mMaxLogLines{ 8192 };
|
||||
Uint32 mLigatureFeatures{ 0 };
|
||||
TextDocument mDoc;
|
||||
KeyBindings mKeyBindings;
|
||||
TextRange mSelection;
|
||||
@@ -192,6 +199,7 @@ class EE_API UIConsole : public UIWidget,
|
||||
Clock mBlinkTimer;
|
||||
Time mBlinkTime{ Seconds( 0.f ) };
|
||||
bool mCursorVisible{ true };
|
||||
bool mLigaturesOverride{ false };
|
||||
int mLastLogPos{ 0 };
|
||||
#if EE_PLATFORM == EE_PLATFORM_ANDROID || EE_PLATFORM == EE_PLATFORM_IOS
|
||||
Float mQuakeModeHeightPercent{ 0.5f };
|
||||
|
||||
@@ -185,6 +185,14 @@ class EE_API UIRichText : public UIHTMLWidget {
|
||||
|
||||
virtual RichText* getRichTextPtr() { return &mRichText; }
|
||||
|
||||
void setTextHintsOverride( Uint32 value, Uint32 mask = TextHints::OpenTypeFeatures );
|
||||
|
||||
void clearTextHintsOverride();
|
||||
|
||||
Uint32 getTextHints() const;
|
||||
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
protected:
|
||||
RichText mRichText;
|
||||
Int64 mSelCurInit{ 0 };
|
||||
@@ -197,6 +205,8 @@ class EE_API UIRichText : public UIHTMLWidget {
|
||||
mutable Float mTextIndentPxCache{ 0 };
|
||||
mutable bool mTextIndentPxDirty{ true };
|
||||
Uint32 mTabSize{ 8 };
|
||||
Uint32 mTextHintsOverride{ 0 };
|
||||
Uint32 mTextHintsOverrideMask{ 0 };
|
||||
WhiteSpaceCollapse mWhiteSpaceCollapse{ WhiteSpaceCollapse::Collapse };
|
||||
bool mLineWrap{ true };
|
||||
TextTransform::Value mTextTransform{ TextTransform::None };
|
||||
|
||||
@@ -742,6 +742,14 @@ class EE_API UISceneNode : public SceneNode {
|
||||
*/
|
||||
void setContrastPreference( const ContrastPreference& contrastPreference );
|
||||
|
||||
/** Sets the OpenType feature hints inherited by text-producing widgets in this scene. */
|
||||
void setDefaultTextHints( Uint32 textHints );
|
||||
|
||||
Uint32 getDefaultTextHints() const;
|
||||
|
||||
static Uint32 resolveTextHints( Uint32 defaultHints, Uint32 overrideValue,
|
||||
Uint32 overrideMask );
|
||||
|
||||
/**
|
||||
* @brief Gets the maximum invalidation depth.
|
||||
*
|
||||
@@ -983,6 +991,7 @@ class EE_API UISceneNode : public SceneNode {
|
||||
std::vector<UISceneNode*> mChildUISceneNodes;
|
||||
ColorSchemePreference mColorSchemePreference{ ColorSchemePreference::Dark };
|
||||
ContrastPreference mContrastPreference{ ContrastPreference::NoPreference };
|
||||
Uint32 mDefaultTextHints{ 0 };
|
||||
Uint32 mMaxInvalidationDepth{ 3 };
|
||||
Node* mCurParent{ nullptr };
|
||||
UISceneNode* mHostUISceneNode{ nullptr };
|
||||
|
||||
@@ -134,6 +134,8 @@ class EE_API UITextInput : public UITextView, public TextDocument::Client {
|
||||
Client::Type getTextDocumentClientType() { return TextDocument::Client::Core; }
|
||||
|
||||
protected:
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
TextDocument mDoc;
|
||||
Float mWaitCursorTime;
|
||||
Vector2f mCurPos;
|
||||
|
||||
@@ -37,10 +37,17 @@ class EE_API UITextNode : public UIWidget {
|
||||
|
||||
Float getBaseline() const;
|
||||
|
||||
void setTextHintsOverride( Uint32 value, Uint32 mask = TextHints::OpenTypeFeatures );
|
||||
void clearTextHintsOverride();
|
||||
Uint32 getTextHints() const;
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
protected:
|
||||
String mText;
|
||||
size_t mLayoutCharCount{ 0 };
|
||||
Text* mFlexText{ nullptr };
|
||||
Uint32 mTextHintsOverride{ 0 };
|
||||
Uint32 mTextHintsOverrideMask{ 0 };
|
||||
|
||||
UITextNode();
|
||||
};
|
||||
|
||||
@@ -134,6 +134,14 @@ class EE_API UITextView : public UIWidget {
|
||||
|
||||
void setTextSelectionRange( TextSelectionRange range );
|
||||
|
||||
void setTextHintsOverride( Uint32 value, Uint32 mask = TextHints::OpenTypeFeatures );
|
||||
|
||||
void clearTextHintsOverride();
|
||||
|
||||
Uint32 getTextHints() const;
|
||||
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
protected:
|
||||
Text mTextCache;
|
||||
String mString;
|
||||
@@ -142,6 +150,8 @@ class EE_API UITextView : public UIWidget {
|
||||
Int32 mSelCurInit;
|
||||
Int32 mSelCurEnd;
|
||||
Uint32 mTextDrawHints{ 0 };
|
||||
Uint32 mTextHintsOverride{ 0 };
|
||||
Uint32 mTextHintsOverrideMask{ 0 };
|
||||
SmallVector<Rectf> mSelRectsCache;
|
||||
Int32 mLastSelCurInit;
|
||||
Int32 mLastSelCurEnd;
|
||||
|
||||
@@ -135,6 +135,14 @@ class EE_API UITooltip : public UIWidget {
|
||||
|
||||
bool isWordWrap() const;
|
||||
|
||||
void setTextHintsOverride( Uint32 value, Uint32 mask = TextHints::OpenTypeFeatures );
|
||||
|
||||
void clearTextHintsOverride();
|
||||
|
||||
Uint32 getTextHints() const;
|
||||
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
protected:
|
||||
Text* mTextCache{ nullptr };
|
||||
UIFontStyleConfig mStyleConfig;
|
||||
@@ -145,6 +153,8 @@ class EE_API UITooltip : public UIWidget {
|
||||
TextTransform::Value mTextTransform{ TextTransform::None };
|
||||
bool mDontAutoHideOnMouseMove{ false };
|
||||
bool mUsingCustomStyling{ false };
|
||||
Uint32 mTextHintsOverride{ 0 };
|
||||
Uint32 mTextHintsOverrideMask{ 0 };
|
||||
|
||||
UITooltip();
|
||||
|
||||
|
||||
@@ -94,6 +94,12 @@ class EE_API UIWidget : public UINode {
|
||||
return UIWidget::getType() == type || UINode::isType( type );
|
||||
}
|
||||
|
||||
/** Returns the scene-level text rendering hints inherited by this widget. */
|
||||
Uint32 getDefaultTextHints() const;
|
||||
|
||||
/** Called when the scene-level text rendering hints change. */
|
||||
virtual void onTextHintsChanged();
|
||||
|
||||
/**
|
||||
* @brief Sets multiple flags on the widget.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user