From d37aef5ccf1bcbf0f3b11f45d3a6d73ad29ecde4 Mon Sep 17 00:00:00 2001
From: kgv <kgv@opencascade.com>
Date: Wed, 14 Apr 2021 14:10:40 +0300
Subject: [PATCH] 0031678: Visualization - add option enabling hinting for
 textured fonts

Added new rendering parameter Graphic3d_RenderingParams::FontHinting
allowing to enable/disable hinting (default is no hinting preserving old behavior).

Command vrenderparams has been extended with arguments -fontHinting.
---
 src/AIS/AIS_TextLabel.cxx                    |   4 +-
 src/Font/FILES                               |   1 +
 src/Font/Font_FTFont.cxx                     |  23 +++-
 src/Font/Font_FTFont.hxx                     |  28 ++++-
 src/Font/Font_Hinting.hxx                    |  29 +++++
 src/Graphic3d/Graphic3d_RenderingParams.hxx  |  34 ++++--
 src/OpenGl/OpenGl_GraphicDriver.cxx          |   4 +-
 src/OpenGl/OpenGl_Text.cxx                   |  38 ++++---
 src/OpenGl/OpenGl_Text.hxx                   |  11 +-
 src/PrsDim/PrsDim_Dimension.cxx              |  12 ++-
 src/ViewerTest/ViewerTest_ViewerCommands.cxx | 107 ++++++++++++++++++-
 tests/opengl/data/text/A2                    |  21 ++--
 tests/opengl/data/text/A8                    |  17 ++-
 13 files changed, 282 insertions(+), 47 deletions(-)
 create mode 100644 src/Font/Font_Hinting.hxx

diff --git a/src/AIS/AIS_TextLabel.cxx b/src/AIS/AIS_TextLabel.cxx
index f20758e852..76fb8f1c33 100644
--- a/src/AIS/AIS_TextLabel.cxx
+++ b/src/AIS/AIS_TextLabel.cxx
@@ -404,9 +404,11 @@ Standard_Boolean AIS_TextLabel::calculateLabelParams (const gp_Pnt& thePosition,
 {
   // Get width and height of text
   Handle(Prs3d_TextAspect) anAsp = myDrawer->TextAspect();
+  const Graphic3d_RenderingParams& aRendParams = GetContext()->CurrentViewer()->DefaultRenderingParams();
   Font_FTFontParams aFontParams;
   aFontParams.PointSize = (unsigned int) anAsp->Height();
-  aFontParams.Resolution = GetContext()->CurrentViewer()->DefaultRenderingParams().Resolution;
+  aFontParams.Resolution = aRendParams.Resolution;
+  aFontParams.FontHinting = aRendParams.FontHinting;
 
   Handle(Font_FTFont) aFont = Font_FTFont::FindAndCreate (anAsp->Aspect()->Font(),
                                                           anAsp->Aspect()->GetTextFontAspect(),
diff --git a/src/Font/FILES b/src/Font/FILES
index c173a250d0..968a807a2d 100644
--- a/src/Font/FILES
+++ b/src/Font/FILES
@@ -7,6 +7,7 @@ Font_FTFont.cxx
 Font_FTFont.hxx
 Font_FTLibrary.cxx
 Font_FTLibrary.hxx
+Font_Hinting.hxx
 Font_NameOfFont.hxx
 Font_NListOfSystemFont.hxx
 Font_Rect.hxx
diff --git a/src/Font/Font_FTFont.cxx b/src/Font/Font_FTFont.cxx
index 02c6cff538..5ae9899f0a 100755
--- a/src/Font/Font_FTFont.cxx
+++ b/src/Font/Font_FTFont.cxx
@@ -96,6 +96,26 @@ bool Font_FTFont::Init (const Handle(NCollection_Buffer)& theData,
   myBuffer = theData;
   myFontPath = theFileName;
   myFontParams = theParams;
+
+  // manage hinting style
+  if ((theParams.FontHinting & Font_Hinting_Light)  != 0
+   && (theParams.FontHinting & Font_Hinting_Normal) != 0)
+  {
+    throw Standard_ProgramError ("Font_FTFont, Light and Normal hinting styles are mutually exclusive");
+  }
+  setLoadFlag (FT_LOAD_TARGET_LIGHT,   (theParams.FontHinting & Font_Hinting_Light) != 0);
+  setLoadFlag (FT_LOAD_NO_HINTING,     (theParams.FontHinting & Font_Hinting_Normal) == 0
+                                    && (theParams.FontHinting & Font_Hinting_Light)  == 0);
+
+  // manage native / autohinting
+  if ((theParams.FontHinting & Font_Hinting_ForceAutohint) != 0
+   && (theParams.FontHinting & Font_Hinting_NoAutohint) != 0)
+  {
+    throw Standard_ProgramError ("Font_FTFont, ForceAutohint and NoAutohint are mutually exclusive");
+  }
+  setLoadFlag (FT_LOAD_FORCE_AUTOHINT, (theParams.FontHinting & Font_Hinting_ForceAutohint) != 0);
+  setLoadFlag (FT_LOAD_NO_AUTOHINT,    (theParams.FontHinting & Font_Hinting_NoAutohint) != 0);
+
   if (!myFTLib->IsValid())
   {
     Message::SendTrace ("FreeType library is unavailable");
@@ -597,7 +617,8 @@ float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const
 #ifdef HAVE_FREETYPE
   FT_Vector aKern;
   getKerning (aKern, myUChar, theUCharNext);
-  return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x);
+  return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x
+                                             + myActiveFTFace->glyph->lsb_delta - myActiveFTFace->glyph->rsb_delta);
 #else
   (void )theUCharNext;
   return 0.0f;
diff --git a/src/Font/Font_FTFont.hxx b/src/Font/Font_FTFont.hxx
index c3fad616c7..751dfaba40 100755
--- a/src/Font/Font_FTFont.hxx
+++ b/src/Font/Font_FTFont.hxx
@@ -17,6 +17,7 @@
 #define _Font_FTFont_H__
 
 #include <Font_FontAspect.hxx>
+#include <Font_Hinting.hxx>
 #include <Font_Rect.hxx>
 #include <Font_StrictLevel.hxx>
 #include <Font_UnicodeSubset.hxx>
@@ -37,16 +38,26 @@ struct Font_FTFontParams
 {
   unsigned int PointSize;                  //!< face size in points (1/72 inch)
   unsigned int Resolution;                 //!< resolution of the target device in dpi for FT_Set_Char_Size()
+  Font_Hinting FontHinting;                //!< request hinting (exclude FT_LOAD_NO_HINTING flag), Font_Hinting_Off by default;
+                                           //!  hinting improves readability of thin text on low-resolution screen,
+                                           //!  but adds distortions to original font depending on font family and font library version
   bool         ToSynthesizeItalic;         //!< generate italic style (e.g. for font family having no italic style); FALSE by default
   bool         IsSingleStrokeFont;         //!< single-stroke (one-line) font, FALSE by default
 
   //! Empty constructor.
-  Font_FTFontParams() : PointSize (0), Resolution (72u), ToSynthesizeItalic (false), IsSingleStrokeFont (false) {}
+  Font_FTFontParams()
+  : PointSize (0), Resolution (72u),
+    FontHinting (Font_Hinting_Off),
+    ToSynthesizeItalic (false),
+    IsSingleStrokeFont (false)  {}
 
   //! Constructor.
   Font_FTFontParams (unsigned int thePointSize,
                      unsigned int theResolution)
-  : PointSize (thePointSize), Resolution (theResolution), ToSynthesizeItalic (false), IsSingleStrokeFont (false) {}
+  : PointSize (thePointSize), Resolution (theResolution),
+    FontHinting (Font_Hinting_Off),
+    ToSynthesizeItalic (false),
+    IsSingleStrokeFont (false) {}
 };
 
 DEFINE_STANDARD_HANDLE(Font_FTFont, Standard_Transient)
@@ -359,6 +370,19 @@ protected:
   //! Initialize fallback font.
   Standard_EXPORT bool findAndInitFallback (Font_UnicodeSubset theSubset);
 
+  //! Enable/disable load flag.
+  void setLoadFlag (int32_t theFlag, bool theToEnable)
+  {
+    if (theToEnable)
+    {
+      myLoadFlags |= theFlag;
+    }
+    else
+    {
+      myLoadFlags &= ~theFlag;
+    }
+  }
+
 protected:
 
   Handle(Font_FTLibrary)     myFTLib;        //!< handle to the FT library object
diff --git a/src/Font/Font_Hinting.hxx b/src/Font/Font_Hinting.hxx
new file mode 100644
index 0000000000..ef49829915
--- /dev/null
+++ b/src/Font/Font_Hinting.hxx
@@ -0,0 +1,29 @@
+// Copyright (c) 2021 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Font_Hinting_HeaderFile
+#define _Font_Hinting_HeaderFile
+
+//! Enumeration defining font hinting options.
+enum Font_Hinting
+{
+  // hinting style
+  Font_Hinting_Off           = 0x00, //!< no      hinting (FT_LOAD_NO_HINTING)
+  Font_Hinting_Normal        = 0x01, //!< default hinting (FT_LOAD_TARGET_NORMAL)
+  Font_Hinting_Light         = 0x02, //!< light   hinting (FT_LOAD_TARGET_LIGHT)
+  // native/autohinting flags
+  Font_Hinting_ForceAutohint = 0x10, //!< prefer autohinting over native hinting (FT_LOAD_FORCE_AUTOHINT)
+  Font_Hinting_NoAutohint    = 0x20, //!< disallow autohinting (FT_LOAD_NO_AUTOHINT)
+};
+
+#endif // _Font_Hinting_HeaderFile
diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx
index 602967d2a0..78982b1942 100644
--- a/src/Graphic3d/Graphic3d_RenderingParams.hxx
+++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx
@@ -16,6 +16,7 @@
 #ifndef _Graphic3d_RenderingParams_HeaderFile
 #define _Graphic3d_RenderingParams_HeaderFile
 
+#include <Font_Hinting.hxx>
 #include <Graphic3d_AspectText3d.hxx>
 #include <Graphic3d_TransformPers.hxx>
 #include <Graphic3d_RenderTransparentMethod.hxx>
@@ -97,6 +98,8 @@ public:
   : Method                      (Graphic3d_RM_RASTERIZATION),
     ShadingModel                (Graphic3d_TOSM_FRAGMENT),
     TransparencyMethod          (Graphic3d_RTM_BLEND_UNORDERED),
+    Resolution                  (THE_DEFAULT_RESOLUTION),
+    FontHinting                 (Font_Hinting_Off),
     LineFeather                 (1.0f),
     // PBR parameters
     PbrEnvPow2Size              (9),
@@ -154,9 +157,7 @@ public:
     StatsNbFrames (1),
     StatsMaxChartTime (0.1f),
     CollectedStats (PerfCounters_Basic),
-    ToShowStats (Standard_False),
-    //
-    Resolution (THE_DEFAULT_RESOLUTION)
+    ToShowStats (Standard_False)
   {
     const Graphic3d_Vec4 aZero (0.0f, 0.0f, 0.0f, 0.0f);
     AnaglyphLeft .SetRow (0, Graphic3d_Vec4 (1.0f,  0.0f,  0.0f, 0.0f));
@@ -181,18 +182,28 @@ public:
   {
     return Resolution / static_cast<Standard_ShortReal> (THE_DEFAULT_RESOLUTION);
   }
-  
+
   //! Dumps the content of me into the stream
   Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
 
-public:
+public: //! @name general parameters
 
   Graphic3d_RenderingMode           Method;                      //!< specifies rendering mode, Graphic3d_RM_RASTERIZATION by default
   Graphic3d_TypeOfShadingModel      ShadingModel;                //!< specified default shading model, Graphic3d_TOSM_FRAGMENT by default
   Graphic3d_RenderTransparentMethod TransparencyMethod;          //!< specifies rendering method for transparent graphics
-  Standard_ShortReal                LineFeather;                 //!< line feater width in pixels (> 0.0), 1.0 by default;
+  unsigned int                      Resolution;                  //!< Pixels density (PPI), defines scaling factor for parameters like text size
+                                                                 //!  (when defined in screen-space units rather than in 3D) to be properly displayed
+                                                                 //!  on device (screen / printer). 72 is default value.
+                                                                 //!  Note that using difference resolution in different Views in same Viewer
+                                                                 //!  will lead to performance regression (for example, text will be recreated every time).
+  Font_Hinting                      FontHinting;                 //!< enables/disables text hinting within textured fonts, Font_Hinting_Off by default;
+                                                                 //!  hinting improves readability of thin text on low-resolution screen,
+                                                                 //!  but adds distortions to original font depending on font family and font library version
+  Standard_ShortReal                LineFeather;                 //!< line feather width in pixels (> 0.0), 1.0 by default;
                                                                  //!  high values produce blurred results, small values produce sharp (aliased) edges
 
+public: //! @name rendering resolution parameters
+
   Standard_Integer                  PbrEnvPow2Size;              //!< size of IBL maps side can be calculated as 2^PbrEnvPow2Size (> 0), 9 by default
   Standard_Integer                  PbrEnvSpecMapNbLevels;       //!< number of levels used in specular IBL map (> 1), 6 by default
   Standard_Integer                  PbrEnvBakingDiffNbSamples;   //!< number of samples used in Monte-Carlo integration during diffuse IBL map's
@@ -211,6 +222,8 @@ public:
   Standard_Boolean                  ToEnableDepthPrepass;        //!< enables/disables depth pre-pass, False by default
   Standard_Boolean                  ToEnableAlphaToCoverage;     //!< enables/disables alpha to coverage, True by default
 
+public: //! @name Ray-Tracing/Path-Tracing parameters
+
   Standard_Boolean                  IsGlobalIlluminationEnabled; //!< enables/disables global illumination effects (path tracing)
   Standard_Integer                  SamplesPerPixel;             //!< number of samples per pixel (SPP)
   Standard_Integer                  RaytracingDepth;             //!< maximum ray-tracing depth, 3 by default
@@ -239,6 +252,8 @@ public:
   Standard_ShortReal                Exposure;                    //!< exposure value used for tone mapping (path tracing), 0.0 by default
   Standard_ShortReal                WhitePoint;                  //!< white point value used in filmic tone mapping (path tracing), 1.0 by default
 
+public: //! @name VR / stereoscopic parameters
+
   Graphic3d_StereoMode              StereoMode;                  //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
   Standard_ShortReal                HmdFov2d;                    //!< sharp field of view range in degrees for displaying on-screen 2D elements, 30.0 by default;
   Anaglyph                          AnaglyphFilter;              //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default
@@ -247,6 +262,8 @@ public:
   Standard_Boolean                  ToReverseStereo;             //!< flag to reverse stereo pair, FALSE by default
   Standard_Boolean                  ToMirrorComposer;            //!< if output device is an external composer - mirror rendering results in window in addition to sending frame to composer, TRUE by default
 
+public: //! @name on-screen display parameters
+
   Handle(Graphic3d_TransformPers)   StatsPosition;               //!< location of stats, upper-left position by default
   Handle(Graphic3d_TransformPers)   ChartPosition;               //!< location of stats chart, upper-right position by default
   Graphic3d_Vec2i                   ChartSize;                   //!< chart size in pixels, (-1, -1) by default which means that chart will occupy a portion of viewport
@@ -265,11 +282,6 @@ public:
                                                                  //!  note that counters specified within CollectedStats will be updated nevertheless
                                                                  //!  of visibility of widget managed by ToShowStats flag (e.g. stats can be retrieved by application for displaying using other methods)
 
-  unsigned int                      Resolution;                  //!< Pixels density (PPI), defines scaling factor for parameters like text size
-                                                                 //!  (when defined in screen-space units rather than in 3D) to be properly displayed
-                                                                 //!  on device (screen / printer). 72 is default value.
-                                                                 //!  Note that using difference resolution in different Views in same Viewer
-                                                                 //!  will lead to performance regression (for example, text will be recreated every time).
 };
 
 #endif // _Graphic3d_RenderingParams_HeaderFile
diff --git a/src/OpenGl/OpenGl_GraphicDriver.cxx b/src/OpenGl/OpenGl_GraphicDriver.cxx
index e212d6480f..33bf69c7f1 100644
--- a/src/OpenGl/OpenGl_GraphicDriver.cxx
+++ b/src/OpenGl/OpenGl_GraphicDriver.cxx
@@ -651,7 +651,9 @@ void OpenGl_GraphicDriver::TextSize (const Handle(Graphic3d_CView)& theView,
   OpenGl_Aspects aTextAspect;
   TCollection_ExtendedString anExtText = theText;
   NCollection_String aText (anExtText.ToExtString());
-  OpenGl_Text::StringSize(aCtx, aText, aTextAspect, aHeight, theView->RenderingParams().Resolution, theWidth, theAscent, theDescent);
+  OpenGl_Text::StringSize (aCtx, aText, aTextAspect, aHeight,
+                           theView->RenderingParams().Resolution, theView->RenderingParams().FontHinting,
+                           theWidth, theAscent, theDescent);
 }
 
 //=======================================================================
diff --git a/src/OpenGl/OpenGl_Text.cxx b/src/OpenGl/OpenGl_Text.cxx
index f7dd0cedc9..5fa52b6568 100644
--- a/src/OpenGl/OpenGl_Text.cxx
+++ b/src/OpenGl/OpenGl_Text.cxx
@@ -262,6 +262,7 @@ void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
                               const OpenGl_Aspects&         theTextAspect,
                               const Standard_ShortReal      theHeight,
                               const unsigned int            theResolution,
+                              const Font_Hinting            theFontHinting,
                               Standard_ShortReal&           theWidth,
                               Standard_ShortReal&           theAscent,
                               Standard_ShortReal&           theDescent)
@@ -269,8 +270,8 @@ void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
   theWidth   = 0.0f;
   theAscent  = 0.0f;
   theDescent = 0.0f;
-  const TCollection_AsciiString aFontKey = FontKey (theTextAspect, (Standard_Integer)theHeight, theResolution);
-  Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, (Standard_Integer)theHeight, theResolution, aFontKey);
+  const TCollection_AsciiString aFontKey = FontKey (theTextAspect, (Standard_Integer)theHeight, theResolution, theFontHinting);
+  Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, (Standard_Integer)theHeight, theResolution, theFontHinting, aFontKey);
   if (aFont.IsNull() || !aFont->IsValid())
   {
     return;
@@ -348,7 +349,8 @@ void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
           *aTextAspect,
           theWorkspace->TextColor(),
           theWorkspace->TextSubtitleColor(),
-          aCtx->Resolution());
+          aCtx->Resolution(),
+          theWorkspace->View()->RenderingParams().FontHinting);
 
   // restore aspects
   if (!aPrevTexture.IsNull())
@@ -369,7 +371,8 @@ void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
 // =======================================================================
 void OpenGl_Text::Render (const Handle(OpenGl_Context)& theCtx,
                           const OpenGl_Aspects& theTextAspect,
-                          unsigned int theResolution) const
+                          unsigned int theResolution,
+                          Font_Hinting theFontHinting) const
 {
 #if !defined(GL_ES_VERSION_2_0)
   const Standard_Integer aPrevPolygonMode  = theCtx->SetPolygonMode (GL_FILL);
@@ -379,7 +382,8 @@ void OpenGl_Text::Render (const Handle(OpenGl_Context)& theCtx,
   render (theCtx, theTextAspect,
           theTextAspect.Aspect()->ColorRGBA(),
           theTextAspect.Aspect()->ColorSubTitleRGBA(),
-          theResolution);
+          theResolution,
+          theFontHinting);
 
 #if !defined(GL_ES_VERSION_2_0)
   theCtx->SetPolygonMode         (aPrevPolygonMode);
@@ -535,16 +539,21 @@ void OpenGl_Text::drawText (const Handle(OpenGl_Context)& theCtx,
 // =======================================================================
 TCollection_AsciiString OpenGl_Text::FontKey (const OpenGl_Aspects& theAspect,
                                               Standard_Integer theHeight,
-                                              unsigned int theResolution)
+                                              unsigned int theResolution,
+                                              Font_Hinting theFontHinting)
 {
   const Font_FontAspect anAspect = theAspect.Aspect()->TextFontAspect() != Font_FA_Undefined
                                  ? theAspect.Aspect()->TextFontAspect()
                                  : Font_FA_Regular;
   const TCollection_AsciiString& aFont = !theAspect.Aspect()->TextFont().IsNull() ? theAspect.Aspect()->TextFont()->String() : THE_DEFAULT_FONT;
-  return aFont
-       + TCollection_AsciiString(":") + Standard_Integer(anAspect)
-       + TCollection_AsciiString(":") + Standard_Integer(theResolution)
-       + TCollection_AsciiString(":") + theHeight;
+
+  char aSuff[64];
+  Sprintf (aSuff, ":%d:%d:%d:%d",
+           Standard_Integer(anAspect),
+           Standard_Integer(theResolution),
+           theHeight,
+           Standard_Integer(theFontHinting));
+  return aFont + aSuff;
 }
 
 // =======================================================================
@@ -555,6 +564,7 @@ Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx,
                                            const OpenGl_Aspects& theAspect,
                                            Standard_Integer theHeight,
                                            unsigned int theResolution,
+                                           Font_Hinting theFontHinting,
                                            const TCollection_AsciiString& theKey)
 {
   Handle(OpenGl_Font) aFont;
@@ -575,6 +585,7 @@ Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx,
     Font_FTFontParams aParams;
     aParams.PointSize  = theHeight;
     aParams.Resolution = theResolution;
+    aParams.FontHinting = theFontHinting;
     if (Handle(Font_FTFont) aFontFt = Font_FTFont::FindAndCreate (aFontName, anAspect, aParams, Font_StrictLevel_Any))
     {
       aFont = new OpenGl_Font (aFontFt, theKey);
@@ -658,7 +669,8 @@ void OpenGl_Text::render (const Handle(OpenGl_Context)& theCtx,
                           const OpenGl_Aspects& theTextAspect,
                           const OpenGl_Vec4& theColorText,
                           const OpenGl_Vec4& theColorSubs,
-                          unsigned int theResolution) const
+                          unsigned int theResolution,
+                          Font_Hinting theFontHinting) const
 {
   if (myText->Text().IsEmpty() && myText->TextFormatter().IsNull())
   {
@@ -667,7 +679,7 @@ void OpenGl_Text::render (const Handle(OpenGl_Context)& theCtx,
 
   // Note that using difference resolution in different Views in same Viewer
   // will lead to performance regression (for example, text will be recreated every time).
-  const TCollection_AsciiString aFontKey = FontKey (theTextAspect, (Standard_Integer)myText->Height(), theResolution);
+  const TCollection_AsciiString aFontKey = FontKey (theTextAspect, (Standard_Integer)myText->Height(), theResolution, theFontHinting);
   if (!myFont.IsNull()
    && !myFont->ResourceKey().IsEqual (aFontKey))
   {
@@ -677,7 +689,7 @@ void OpenGl_Text::render (const Handle(OpenGl_Context)& theCtx,
 
   if (myFont.IsNull())
   {
-    myFont = FindFont (theCtx, theTextAspect, (Standard_Integer)myText->Height(), theResolution, aFontKey);
+    myFont = FindFont (theCtx, theTextAspect, (Standard_Integer)myText->Height(), theResolution, theFontHinting, aFontKey);
   }
   if (myFont.IsNull()
   || !myFont->WasInitialized())
diff --git a/src/OpenGl/OpenGl_Text.hxx b/src/OpenGl/OpenGl_Text.hxx
index a42a736058..29741ed4dd 100755
--- a/src/OpenGl/OpenGl_Text.hxx
+++ b/src/OpenGl/OpenGl_Text.hxx
@@ -82,13 +82,15 @@ public: //! @name methods for compatibility with layers
   //! Create key for shared resource
   Standard_EXPORT static TCollection_AsciiString FontKey (const OpenGl_Aspects& theAspect,
                                                           Standard_Integer theHeight,
-                                                          unsigned int theResolution);
+                                                          unsigned int theResolution,
+                                                          Font_Hinting theFontHinting);
 
   //! Find shared resource for specified font or initialize new one
   Standard_EXPORT static Handle(OpenGl_Font) FindFont (const Handle(OpenGl_Context)& theCtx,
                                                        const OpenGl_Aspects& theAspect,
                                                        Standard_Integer theHeight,
                                                        unsigned int theResolution,
+                                                       Font_Hinting theFontHinting,
                                                        const TCollection_AsciiString& theKey);
 
   //! Compute text width
@@ -97,6 +99,7 @@ public: //! @name methods for compatibility with layers
                                           const OpenGl_Aspects&         theTextAspect,
                                           const Standard_ShortReal      theHeight,
                                           const unsigned int            theResolution,
+                                          const Font_Hinting            theFontHinting,
                                           Standard_ShortReal&           theWidth,
                                           Standard_ShortReal&           theAscent,
                                           Standard_ShortReal&           theDescent);
@@ -104,7 +107,8 @@ public: //! @name methods for compatibility with layers
   //! Perform rendering
   Standard_EXPORT void Render (const Handle(OpenGl_Context)& theCtx,
                                const OpenGl_Aspects& theTextAspect,
-                               unsigned int theResolution = Graphic3d_RenderingParams::THE_DEFAULT_RESOLUTION) const;
+                               unsigned int theResolution = Graphic3d_RenderingParams::THE_DEFAULT_RESOLUTION,
+                               Font_Hinting theFontHinting = Font_Hinting_Off) const;
 
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
@@ -151,7 +155,8 @@ private:
                const OpenGl_Aspects& theTextAspect,
                const OpenGl_Vec4& theColorText,
                const OpenGl_Vec4& theColorSubs,
-               unsigned int theResolution) const;
+               unsigned int theResolution,
+               Font_Hinting theFontHinting) const;
 
 protected:
 
diff --git a/src/PrsDim/PrsDim_Dimension.cxx b/src/PrsDim/PrsDim_Dimension.cxx
index eea797ce7f..deba152a40 100644
--- a/src/PrsDim/PrsDim_Dimension.cxx
+++ b/src/PrsDim/PrsDim_Dimension.cxx
@@ -18,6 +18,7 @@
 #include <PrsDim.hxx>
 #include <PrsDim_DimensionOwner.hxx>
 #include <Adaptor3d_Curve.hxx>
+#include <AIS_InteractiveContext.hxx>
 #include <BRepAdaptor_Curve.hxx>
 #include <BRepAdaptor_Surface.hxx>
 #include <BRepBndLib.hxx>
@@ -67,6 +68,7 @@
 #include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Vertex.hxx>
+#include <V3d_Viewer.hxx>
 #include <Units.hxx>
 #include <Units_UnitsDictionary.hxx>
 #include <UnitsAPI.hxx>
@@ -82,7 +84,6 @@ namespace
 
   // default text margin and resolution
   static const Standard_Real THE_3D_TEXT_MARGIN    = 0.1;
-  static const unsigned int  THE_2D_TEXT_RESOLUTION = 72;
 
   // default selection priorities
   static const Standard_Integer THE_NEUTRAL_SEL_PRIORITY = 5;
@@ -329,9 +330,14 @@ TCollection_ExtendedString PrsDim_Dimension::GetValueString (Standard_Real& theW
   {
     // Text width for 1:1 scale 2D case
     Font_FTFontParams aFontParams;
+    const Graphic3d_RenderingParams& aRendParams = GetContext()->CurrentViewer()->DefaultRenderingParams();
     aFontParams.PointSize  = (unsigned int )aTextAspect->Height();
-    aFontParams.Resolution = THE_2D_TEXT_RESOLUTION;
-    if (Handle(Font_FTFont) aFont = Font_FTFont::FindAndCreate (aTextAspect->Aspect()->Font(), aTextAspect->Aspect()->GetTextFontAspect(), aFontParams, Font_StrictLevel_Any))
+    aFontParams.Resolution = aRendParams.Resolution;
+    aFontParams.FontHinting = aRendParams.FontHinting;
+    if (Handle(Font_FTFont) aFont = Font_FTFont::FindAndCreate (aTextAspect->Aspect()->Font(),
+                                                                aTextAspect->Aspect()->GetTextFontAspect(),
+                                                                aFontParams,
+                                                                Font_StrictLevel_Any))
     {
       for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
       {
diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx
index b92e090b81..32d0d0c9a9 100644
--- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx
+++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx
@@ -11757,6 +11757,107 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
         return 1;
       }
     }
+    else if (aFlag == "-fonthinting"
+          || aFlag == "-fonthint")
+    {
+      if (toPrint)
+      {
+        if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
+        {
+          theDI << "normal" << " ";
+        }
+        else if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
+        {
+          theDI << "light" << " ";
+        }
+        else
+        {
+          theDI << "off" << " ";
+        }
+        continue;
+      }
+      else if (anArgIter + 1 >= theArgNb)
+      {
+        theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
+        return 1;
+      }
+
+      TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
+      aHintStyle.LowerCase();
+      if (aHintStyle == "normal"
+       || aHintStyle == "on"
+       || aHintStyle == "1")
+      {
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Normal);
+      }
+      else if (aHintStyle == "light")
+      {
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Light);
+      }
+      else if (aHintStyle == "no"
+            || aHintStyle == "off"
+            || aHintStyle == "0")
+      {
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
+      }
+      else
+      {
+        theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
+        return 1;
+      }
+    }
+    else if (aFlag == "-fontautohinting"
+          || aFlag == "-fontautohint")
+    {
+      if (toPrint)
+      {
+        if ((aParams.FontHinting & Font_Hinting_ForceAutohint) != 0)
+        {
+          theDI << "force" << " ";
+        }
+        else if ((aParams.FontHinting & Font_Hinting_NoAutohint) != 0)
+        {
+          theDI << "disallow" << " ";
+        }
+        else
+        {
+          theDI << "auto" << " ";
+        }
+        continue;
+      }
+      else if (anArgIter + 1 >= theArgNb)
+      {
+        theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
+        return 1;
+      }
+
+      TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
+      aHintStyle.LowerCase();
+      if (aHintStyle == "force")
+      {
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_ForceAutohint);
+      }
+      else if (aHintStyle == "disallow"
+            || aHintStyle == "no")
+      {
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_NoAutohint);
+      }
+      else if (aHintStyle == "auto")
+      {
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
+        aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
+      }
+      else
+      {
+        theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
+        return 1;
+      }
+    }
     else if (aFlag == "-depthprepass")
     {
       if (toPrint)
@@ -15023,7 +15124,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t: Should be applied taking into account GPU hardware capabilities and performance."
     "\n\t\t: Common parameters:"
     "\n\t\t: vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]"
-    "\n\t\t:               [-msaa 0..8=0] [-rendScale scale=1] [-resolution value=72]"
+    "\n\t\t:               [-msaa 0..8=0] [-rendScale scale=1]"
+    "\n\t\t:               [-resolution value=72] [-fontHinting {off|normal|light}=off]"
+    "\n\t\t:               [-fontAutoHinting {auto|force|disallow}=auto]"
     "\n\t\t:               [-oit {off|0.0-1.0}=off]"
     "\n\t\t:               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]"
     "\n\t\t:               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]"
@@ -15034,6 +15137,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:   -msaa            Specifies number of samples for MSAA."
     "\n\t\t:   -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA)."
     "\n\t\t:   -resolution      Sets new pixels density (PPI) used as text scaling factor."
+    "\n\t\t:   -fontHinting     Enables/disables font hinting for better readability on low-resolution screens."
+    "\n\t\t:   -fontAutoHinting Manages font autohinting."
     "\n\t\t:   -lineFeather     Sets line feather factor while displaying mesh edges."
     "\n\t\t:   -alphaToCoverage Enables/disables alpha to coverage (needs MSAA)."
     "\n\t\t:   -oit             Enables/disables order-independent transparency (OIT) rendering;"
diff --git a/tests/opengl/data/text/A2 b/tests/opengl/data/text/A2
index ae71ca2ca1..483eb45d62 100644
--- a/tests/opengl/data/text/A2
+++ b/tests/opengl/data/text/A2
@@ -1,6 +1,5 @@
 puts "============"
-puts "OCC21091"
-puts "OCC21450"
+puts "0024387: Draw the text with different fonts"
 puts "============"
 puts ""
 
@@ -64,12 +63,22 @@ vdrawtext OC16 OpenCascade -pos -100 -300 -100 -color GREEN -halign left -valign
 
 vdrawtext OC17 OpenCascade -pos -200 -200 100 -color MAGENTA -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect regular -font sans-serif
 vdrawtext OC18 OpenCascade -pos -200 -200 150 -color CYAN    -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect regular -font serif
-vdrawtext OC19 OpenCascade -pos -200 -200 200 -color YELLOW   -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect italic -font serif
-vdrawtext OC20 OpenCascade -pos -200 -200 250 -color 00FF05   -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect bolditalic -font monospace
-vdrawtext OC21 OpenCascade -pos -200 -200 300 -color FF0005   -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect regular -font monospace
+vdrawtext OC19 OpenCascade -pos -200 -200 200 -color YELLOW  -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect italic  -font serif
+vdrawtext OC20 OpenCascade -pos -200 -200 250 -color 00FF05  -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect bolditalic -font monospace
+vdrawtext OC21 OpenCascade -pos -200 -200 300 -color FF0005  -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect regular -font monospace
 
 vglinfo
-vdump $imagedir/${casename}.png
+vrenderparams -fontHinting normal
+vbackground -color WHITE
+vdump ${imagedir}/${test_image}_white_hinted.png
+vbackground -color BLACK
+vdump ${imagedir}/${test_image}_hinted.png
+
+vrenderparams -fontHinting off
+vbackground -color WHITE
+vdump ${imagedir}/${test_image}_white.png
+vbackground -color BLACK
+vdump ${imagedir}/${test_image}.png
 
 vsensdis
 vdump $imagedir/${casename}_sensitive.png
diff --git a/tests/opengl/data/text/A8 b/tests/opengl/data/text/A8
index 8c7b718b1d..f33eac1457 100644
--- a/tests/opengl/data/text/A8
+++ b/tests/opengl/data/text/A8
@@ -1,10 +1,7 @@
 puts "============"
-puts "OCC24387"
+puts "0021091: Draw the text with different fonts"
 puts "============"
 puts ""
-#################################################
-# Draw the text with different fonts.
-#################################################
 
 pload TOPTEST VISUALIZATION
 vinit View1
@@ -67,4 +64,14 @@ vdrawtext OC20 OpenCascade -pos -200 -200 250 -color 00FF05  -halign left -valig
 vdrawtext OC21 OpenCascade -pos -200 -200 300 -color FF0005  -halign left -valign bottom -angle 010 -zoom 0 -height 15 -aspect regular -font Arial
 
 vglinfo
-vdump $imagedir/${casename}.png
+vrenderparams -fontHinting normal
+vbackground -color WHITE
+vdump ${imagedir}/${test_image}_white_hinted.png
+vbackground -color BLACK
+vdump ${imagedir}/${test_image}_hinted.png
+
+vrenderparams -fontHinting off
+vbackground -color WHITE
+vdump ${imagedir}/${test_image}_white.png
+vbackground -color BLACK
+vdump ${imagedir}/${test_image}.png