// Copyright (c) Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Types/StringView.h" #include "Engine/Content/AssetReference.h" #include "Engine/Scripting/ScriptingObject.h" #include "TextLayoutOptions.h" class FontAsset; struct FontCharacterEntry; // The default DPI that engine is using #define DefaultDPI 96 /// /// The text range. /// API_STRUCT(NoDefault) struct FLAXENGINE_API TextRange { DECLARE_SCRIPTING_TYPE_MINIMAL(TextRange); /// /// The start index (inclusive). /// API_FIELD() int32 StartIndex; /// /// The end index (exclusive). /// API_FIELD() int32 EndIndex; /// /// Gets the range length. /// FORCE_INLINE int32 Length() const { return EndIndex - StartIndex; } /// /// Gets a value indicating whether range is empty. /// FORCE_INLINE bool IsEmpty() const { return (EndIndex - StartIndex) <= 0; } /// /// Determines whether this range contains the character index. /// /// The index. /// true if range contains the specified character index; otherwise, false. FORCE_INLINE bool Contains(int32 index) const { return index >= StartIndex && index < EndIndex; } /// /// Determines whether this range intersects with the other range. /// /// The other text range. /// true if range intersects with the specified range index;, false. bool Intersect(const TextRange& other) const { return Math::Min(EndIndex, other.EndIndex) > Math::Max(StartIndex, other.StartIndex); } /// /// Gets the substring from the source text. /// /// The text. /// The substring of the original text of the defined range. StringView Substring(const StringView& text) const { return StringView(text.Get() + StartIndex, EndIndex - StartIndex); } }; template<> struct TIsPODType { enum { Value = true }; }; /// /// The font line info generated during text processing. /// API_STRUCT(NoDefault) struct FLAXENGINE_API FontLineCache { DECLARE_SCRIPTING_TYPE_MINIMAL(FontLineCache); /// /// The root position of the line (upper left corner). /// API_FIELD() Float2 Location; /// /// The line bounds (width and height). /// API_FIELD() Float2 Size; /// /// The first character index (from the input text). /// API_FIELD() int32 FirstCharIndex; /// /// The last character index (from the input text), inclusive. /// API_FIELD() int32 LastCharIndex; }; template<> struct TIsPODType { enum { Value = true }; }; /// /// Represents font object that can be using during text rendering (it uses Font Asset but with pre-cached data for chosen font properties). /// API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API Font : public ManagedScriptingObject { DECLARE_SCRIPTING_TYPE_NO_SPAWN(Font); friend FontAsset; private: FontAsset* _asset; float _size; int32 _height; int32 _ascender; int32 _descender; int32 _lineGap; bool _hasKerning; mutable Dictionary _kerningTable; public: /// /// Initializes a new instance of the class. /// /// The parent asset. /// The size. Font(FontAsset* parentAsset, float size); /// /// Finalizes an instance of the class. /// ~Font(); public: /// /// The active fallback fonts. /// API_FIELD() static Array, HeapAllocation> FallbackFonts; /// /// Gets parent font asset that contains font family used by this font. /// API_PROPERTY() FORCE_INLINE FontAsset* GetAsset() const { return _asset; } /// /// Gets font size. /// API_PROPERTY() FORCE_INLINE float GetSize() const { return _size; } /// /// Gets characters height. /// API_PROPERTY() FORCE_INLINE int32 GetHeight() const { return _height; } /// /// Gets the largest vertical distance above the baseline for any character in the font. /// API_PROPERTY() FORCE_INLINE int32 GetAscender() const { return _ascender; } /// /// Gets the largest vertical distance below the baseline for any character in the font. /// API_PROPERTY() FORCE_INLINE int32 GetDescender() const { return _descender; } /// /// Gets the line gap property. /// API_PROPERTY() FORCE_INLINE int32 GetLineGap() const { return _lineGap; } public: /// /// Gets character entry. /// /// The character. /// The output character entry. /// True if fallback to secondary font when the primary font doesn't contain this character. void GetCharacter(Char c, FontCharacterEntry& result, bool enableFallback = true); /// /// Gets the kerning amount for a pair of characters. /// /// The first character in the pair. /// The second character in the pair. /// The kerning amount or 0 if no kerning. API_FUNCTION() int32 GetKerning(Char first, Char second) const; /// /// Caches the given text to prepared for the rendering. /// /// The text witch characters to cache. API_FUNCTION() void CacheText(const StringView& text); /// /// Refresh cached metrics and invalidates all cached characters (in atlases). Can be used after changing font asset options. /// API_FUNCTION() void Invalidate(); public: /// /// Gets the scale factor that maps the rasterized font size to the actual rendered size. /// /// The layout scale. /// The scale factor. float GetScale(float layoutScale) const; /// /// Processes text to get cached lines for rendering. /// /// The input text. /// The layout properties. /// The output lines list. void ProcessText(const StringView& text, Array>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout); /// /// Processes text to get cached lines for rendering. /// /// The input text. /// The layout properties. /// The output lines list. API_FUNCTION() Array> ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout) { Array> lines; ProcessText(text, lines, layout); return lines; } /// /// Processes text to get cached lines for rendering. /// /// The input text. /// The input text range (substring range of the input text parameter). /// The layout properties. /// The output lines list. API_FUNCTION() Array> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout) { Array> lines; ProcessText(textRange.Substring(text), lines, layout); return lines; } /// /// Processes text to get cached lines for rendering. /// /// The input text. /// The output lines list. API_FUNCTION() FORCE_INLINE Array> ProcessText(const StringView& text) { return ProcessText(text, TextLayoutOptions()); } /// /// Processes text to get cached lines for rendering. /// /// The input text. /// The input text range (substring range of the input text parameter). /// The output lines list. API_FUNCTION() FORCE_INLINE Array> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange) { return ProcessText(textRange.Substring(text), TextLayoutOptions()); } /// /// Measures minimum size of the rectangle that will be needed to draw given text. /// /// The input text to test. /// The layout properties. /// The minimum size for that text and font to render properly. API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout); /// /// Measures minimum size of the rectangle that will be needed to draw given text. /// /// The input text to test. /// The input text range (substring range of the input text parameter). /// The layout properties. /// The minimum size for that text and font to render properly. API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout) { return MeasureText(textRange.Substring(text), layout); } /// /// Measures minimum size of the rectangle that will be needed to draw given text /// . /// The input text to test. /// The minimum size for that text and font to render properly. API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text) { return MeasureText(text, TextLayoutOptions()); } /// /// Measures minimum size of the rectangle that will be needed to draw given text /// . /// The input text to test. /// The input text range (substring range of the input text parameter). /// The minimum size for that text and font to render properly. API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange) { return MeasureText(textRange.Substring(text), TextLayoutOptions()); } /// /// Calculates hit character index at given location. /// /// The input text to test. /// The input text range (substring range of the input text parameter). /// The input location to test. /// The text layout properties. /// The selected character position index (can be equal to text length if location is outside of the layout rectangle). API_FUNCTION() int32 HitTestText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout) { return HitTestText(textRange.Substring(text), location, layout); } /// /// Calculates hit character index at given location. /// /// The input text to test. /// The input location to test. /// The text layout properties. /// The selected character position index (can be equal to text length if location is outside of the layout rectangle). API_FUNCTION() int32 HitTestText(const StringView& text, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout); /// /// Calculates hit character index at given location. /// /// The input text to test. /// The input location to test. /// The selected character position index (can be equal to text length if location is outside of the layout rectangle). API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, const Float2& location) { return HitTestText(text, location, TextLayoutOptions()); } /// /// Calculates hit character index at given location. /// /// The input text to test. /// The input text range (substring range of the input text parameter). /// The input location to test. /// The selected character position index (can be equal to text length if location is outside of the layout rectangle). API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location) { return HitTestText(textRange.Substring(text), location, TextLayoutOptions()); } /// /// Calculates character position for given text and character index. /// /// The input text to test. /// The text position to get coordinates of. /// The text layout properties. /// The character position (upper left corner which can be used for a caret position). API_FUNCTION() Float2 GetCharPosition(const StringView& text, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout); /// /// Calculates character position for given text and character index. /// /// The input text to test. /// The input text range (substring range of the input text parameter). /// The text position to get coordinates of. /// The text layout properties. /// The character position (upper left corner which can be used for a caret position). API_FUNCTION() Float2 GetCharPosition(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout) { return GetCharPosition(textRange.Substring(text), index, layout); } /// /// Calculates character position for given text and character index /// /// The input text to test. /// The text position to get coordinates of. /// The character position (upper left corner which can be used for a caret position). API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, int32 index) { return GetCharPosition(text, index, TextLayoutOptions()); } /// /// Calculates character position for given text and character index /// /// The input text to test. /// The input text range (substring range of the input text parameter). /// The text position to get coordinates of. /// The character position (upper left corner which can be used for a caret position). API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index) { return GetCharPosition(textRange.Substring(text), index, TextLayoutOptions()); } /// /// Flushes the size of the face with the Free Type library backend. /// void FlushFaceSize() const; public: // [Object] String ToString() const override; };