0031118: Visualization - Font_FontMgr skips fonts with unknown styles like Narrow...
authorkgv <kgv@opencascade.com>
Fri, 8 Nov 2019 11:13:53 +0000 (14:13 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 13 Nov 2019 15:34:33 +0000 (18:34 +0300)
Extended Style name is now appended to Family name for unique identification of the font.
vfont -find now accepts mask to search the font and returns family name.

src/Font/Font_FontMgr.cxx
src/ViewerTest/ViewerTest_ObjectCommands.cxx
tests/3rdparty/fonts/C4 [new file with mode: 0644]

index 0032a43..86d239d 100644 (file)
@@ -150,35 +150,114 @@ static Handle(Font_SystemFont) checkFont (const Handle(Font_FTLibrary)& theFTLib
   FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath, 0, &aFontFace);
   if (aFaceError != FT_Err_Ok)
   {
   FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath, 0, &aFontFace);
   if (aFaceError != FT_Err_Ok)
   {
-    return NULL;
+    return Handle(Font_SystemFont)();
+  }
+  if (aFontFace->family_name == NULL // skip broken fonts (error in FreeType?)
+   || FT_Select_Charmap (aFontFace, ft_encoding_unicode) != 0) // Font_FTFont supports only UNICODE fonts
+  {
+    FT_Done_Face (aFontFace);
+    return Handle(Font_SystemFont)();
   }
 
   }
 
+  // FreeType decomposes font definition into Family Name and Style Name,
+  // so that fonts within the same Family and different Styles can be identified.
+  // OCCT Font Manager natively handles 4 basic styles: Regular, Bold, Italic and Bold+Italic.
+  // To include other non-standard Styles, their names can be appended to Family Name; for this, names of normal Styles should be removed.
+  TCollection_AsciiString aFamily (aFontFace->family_name);
+  TCollection_AsciiString aStyle (aFontFace->style_name != NULL ? aFontFace->style_name : "");
   Font_FontAspect anAspect = Font_FA_Regular;
   if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
   {
     anAspect = Font_FA_BoldItalic;
   Font_FontAspect anAspect = Font_FA_Regular;
   if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
   {
     anAspect = Font_FA_BoldItalic;
+    const Standard_Integer aRemoveItalic = aStyle.Search ("Italic");
+    if (aRemoveItalic != -1)
+    {
+      aStyle.Remove (aRemoveItalic, 6);
+    }
+    else
+    {
+      // synonym
+      const Standard_Integer aRemoveOblique = aStyle.Search ("Oblique");
+      if (aRemoveOblique != -1)
+      {
+        aStyle.Remove (aRemoveOblique, 7);
+      }
+    }
+
+    const Standard_Integer aRemoveBold = aStyle.Search ("Bold");
+    if (aRemoveBold != -1)
+    {
+      aStyle.Remove (aRemoveBold, 4);
+    }
   }
   else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
   {
     anAspect = Font_FA_Italic;
   }
   else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
   {
     anAspect = Font_FA_Italic;
+    const Standard_Integer aRemoveItalic = aStyle.Search ("Italic");
+    if (aRemoveItalic != -1)
+    {
+      aStyle.Remove (aRemoveItalic, 6);
+    }
+    else
+    {
+      // synonym
+      const Standard_Integer aRemoveOblique = aStyle.Search ("Oblique");
+      if (aRemoveOblique != -1)
+      {
+        aStyle.Remove (aRemoveOblique, 7);
+      }
+    }
   }
   else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
   {
     anAspect = Font_FA_Bold;
   }
   else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
   {
     anAspect = Font_FA_Bold;
+    const Standard_Integer aRemoveBold = aStyle.Search ("Bold");
+    if (aRemoveBold != -1)
+    {
+      aStyle.Remove (aRemoveBold, 4);
+    }
   }
 
   }
 
-  Handle(Font_SystemFont) aResult;
-  if (aFontFace->family_name != NULL                           // skip broken fonts (error in FreeType?)
-   && FT_Select_Charmap (aFontFace, ft_encoding_unicode) == 0) // Font_FTFont supports only UNICODE fonts
+  const Standard_Integer aRemoveReg = aStyle.Search ("Regular");
+  if (aRemoveReg != -1)
   {
   {
-    aResult = new Font_SystemFont (aFontFace->family_name);
-    aResult->SetFontPath (anAspect, theFontPath);
-    // automatically identify some known single-line fonts
-    aResult->SetSingleStrokeFont (aResult->FontKey().StartsWith ("olf "));
+    aStyle.Remove (aRemoveReg, 7);
+  }
+  else
+  {
+    // synonym
+    const Standard_Integer aRemoveBook = aStyle.Search ("Book");
+    if (aRemoveBook != -1)
+    {
+      aStyle.Remove (aRemoveBook, 4);
+    }
   }
 
   }
 
-  FT_Done_Face (aFontFace);
+  aStyle.LeftAdjust();
+  aStyle.RightAdjust();
+  for (;;)
+  {
+    // remove double spaces after removal of several keywords in-between, like "Condensed Bold Italic Oblique"
+    const Standard_Integer aRemoveSpace = aStyle.Search ("  ");
+    if (aRemoveSpace == -1)
+    {
+      break;
+    }
 
 
+    aStyle.Remove (aRemoveSpace, 1);
+  }
+
+  if (!aStyle.IsEmpty())
+  {
+    aFamily = aFamily + " " + aStyle;
+  }
+
+  Handle(Font_SystemFont) aResult = new Font_SystemFont (aFamily);
+  aResult->SetFontPath (anAspect, theFontPath);
+  // automatically identify some known single-line fonts
+  aResult->SetSingleStrokeFont (aResult->FontKey().StartsWith ("olf "));
+
+  FT_Done_Face (aFontFace);
   return aResult;
 }
 
   return aResult;
 }
 
index e10f9a1..0ff7df4 100644 (file)
@@ -5490,32 +5490,7 @@ static int VFont (Draw_Interpretor& theDI,
                   const char**      theArgVec)
 {
   Handle(Font_FontMgr) aMgr = Font_FontMgr::GetInstance();
                   const char**      theArgVec)
 {
   Handle(Font_FontMgr) aMgr = Font_FontMgr::GetInstance();
-  if (theArgNb < 2)
-  {
-    // just print the list of available fonts
-    Standard_Boolean isFirst = Standard_True;
-    const Font_NListOfSystemFont aFonts = aMgr->GetAvailableFonts();
-    std::vector<Handle(Font_SystemFont)> aFontsSorted;
-    aFontsSorted.reserve (aFonts.Size());
-    for (Font_NListOfSystemFont::Iterator aFontIter (aFonts); aFontIter.More(); aFontIter.Next())
-    {
-      aFontsSorted.push_back (aFontIter.Value());
-    }
-    std::stable_sort (aFontsSorted.begin(), aFontsSorted.end(), FontComparator());
-    for (std::vector<Handle(Font_SystemFont)>::iterator aFontIter = aFontsSorted.begin(); aFontIter != aFontsSorted.end(); ++aFontIter)
-    {
-      const Handle(Font_SystemFont)& aFont = *aFontIter;
-      if (!isFirst)
-      {
-        theDI << "\n";
-      }
-
-      theDI << aFont->ToString();
-      isFirst = Standard_False;
-    }
-    return 0;
-  }
-
+  bool toPrintList = theArgNb < 2, toPrintNames = false;
   Font_StrictLevel aStrictLevel = Font_StrictLevel_Any;
   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
   Font_StrictLevel aStrictLevel = Font_StrictLevel_Any;
   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
@@ -5536,12 +5511,23 @@ static int VFont (Draw_Interpretor& theDI,
     {
       aMgr->InitFontDataBase();
     }
     {
       aMgr->InitFontDataBase();
     }
+    else if (anArgCase == "-list")
+    {
+      toPrintList = true;
+    }
+    else if (anArgCase == "-names")
+    {
+      toPrintList = true;
+      toPrintNames = true;
+    }
     else if (anArgIter + 1 < theArgNb
           && (anArgCase == "-find"
     else if (anArgIter + 1 < theArgNb
           && (anArgCase == "-find"
+           || anArgCase == "-findinfo"
+           || anArgCase == "-findall"
            || anArgCase == "find"))
     {
            || anArgCase == "find"))
     {
-      Standard_CString aFontName   = theArgVec[++anArgIter];
-      Font_FontAspect  aFontAspect = Font_FA_Undefined;
+      const TCollection_AsciiString aFontName (theArgVec[++anArgIter]);
+      Font_FontAspect aFontAspect = Font_FA_Undefined;
       if (++anArgIter < theArgNb)
       {
         anArgCase = theArgVec[anArgIter];
       if (++anArgIter < theArgNb)
       {
         anArgCase = theArgVec[anArgIter];
@@ -5552,9 +5538,52 @@ static int VFont (Draw_Interpretor& theDI,
         }
       }
 
         }
       }
 
-      if (Handle(Font_SystemFont) aFont = aMgr->FindFont (aFontName, aStrictLevel, aFontAspect))
+      const bool toFindAll   = (anArgCase == "-findall");
+      const bool toPrintInfo = (anArgCase == "-findinfo");
+      TCollection_AsciiString aResult;
+      if (toFindAll
+       || aFontName.Search ("*") != -1)
       {
       {
-        theDI << aFont->ToString();
+        const Font_NListOfSystemFont aFonts = aMgr->GetAvailableFonts();
+        std::vector<Handle(Font_SystemFont)> aFontsSorted;
+        aFontsSorted.reserve (aFonts.Size());
+        for (Font_NListOfSystemFont::Iterator aFontIter (aFonts); aFontIter.More(); aFontIter.Next())
+        {
+          aFontsSorted.push_back (aFontIter.Value());
+        }
+        std::stable_sort (aFontsSorted.begin(), aFontsSorted.end(), FontComparator());
+        for (std::vector<Handle(Font_SystemFont)>::iterator aFontIter = aFontsSorted.begin(); aFontIter != aFontsSorted.end(); ++aFontIter)
+        {
+          const Handle(Font_SystemFont)& aFont = *aFontIter;
+          const TCollection_AsciiString aCheck = TCollection_AsciiString ("string match -nocase \"") + aFontName + "\" \"" + aFont->FontName() + "\"";
+          if (theDI.Eval (aCheck.ToCString()) == 0
+          && *theDI.Result() != '1')
+          {
+            theDI.Reset();
+            continue;
+          }
+
+          theDI.Reset();
+          if (!aResult.IsEmpty())
+          {
+            aResult += "\n";
+          }
+
+          aResult += toPrintInfo ? aFont->ToString() : aFont->FontName();
+          if (!toFindAll)
+          {
+            break;
+          }
+        }
+      }
+      else if (Handle(Font_SystemFont) aFont = aMgr->FindFont (aFontName, aStrictLevel, aFontAspect))
+      {
+        aResult = toPrintInfo ? aFont->ToString() : aFont->FontName();
+      }
+
+      if (!aResult.IsEmpty())
+      {
+        theDI << aResult;
       }
       else
       {
       }
       else
       {
@@ -5664,6 +5693,43 @@ static int VFont (Draw_Interpretor& theDI,
     }
   }
 
     }
   }
 
+  if (toPrintList)
+  {
+    // just print the list of available fonts
+    Standard_Boolean isFirst = Standard_True;
+    const Font_NListOfSystemFont aFonts = aMgr->GetAvailableFonts();
+    std::vector<Handle(Font_SystemFont)> aFontsSorted;
+    aFontsSorted.reserve (aFonts.Size());
+    for (Font_NListOfSystemFont::Iterator aFontIter (aFonts); aFontIter.More(); aFontIter.Next())
+    {
+      aFontsSorted.push_back (aFontIter.Value());
+    }
+    std::stable_sort (aFontsSorted.begin(), aFontsSorted.end(), FontComparator());
+    for (std::vector<Handle(Font_SystemFont)>::iterator aFontIter = aFontsSorted.begin(); aFontIter != aFontsSorted.end(); ++aFontIter)
+    {
+      const Handle(Font_SystemFont)& aFont = *aFontIter;
+
+      if (toPrintNames)
+      {
+        if (!isFirst)
+        {
+          theDI << "\n";
+        }
+        theDI << "\"" << aFont->FontName() << "\"";
+      }
+      else
+      {
+        if (!isFirst)
+        {
+          theDI << "\n";
+        }
+        theDI << aFont->ToString();
+      }
+      isFirst = Standard_False;
+    }
+    return 0;
+  }
+
   return 0;
 }
 
   return 0;
 }
 
@@ -6608,8 +6674,12 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
   theCommands.Add ("vfont",
                             "vfont [-add pathToFont [fontName] [regular,bold,italic,boldItalic=undefined] [singleStroke]]"
                    "\n\t\t:        [-strict {any|aliases|strict}] [-find fontName [regular,bold,italic,boldItalic=undefined]] [-verbose {on|off}]"
   theCommands.Add ("vfont",
                             "vfont [-add pathToFont [fontName] [regular,bold,italic,boldItalic=undefined] [singleStroke]]"
                    "\n\t\t:        [-strict {any|aliases|strict}] [-find fontName [regular,bold,italic,boldItalic=undefined]] [-verbose {on|off}]"
+                   "\n\t\t:        [-findAll fontNameMask] [-findInfo fontName]"
                    "\n\t\t:        [-unicodeFallback {on|off}]"
                    "\n\t\t:        [-unicodeFallback {on|off}]"
-                   "\n\t\t:        [-clear] [-init]",
+                   "\n\t\t:        [-clear] [-init] [-list] [-names]"
+                   "\n\t\t: Work with font registry - register font, list available fonts, find font."
+                   "\n\t\t: -findAll  is same as -find, but can print more than one font when mask is passed."
+                   "\n\t\t: -findInfo is same as -find, but prints complete font information instead of family name.",
                    __FILE__, VFont, group);
 
   theCommands.Add ("vvertexmode",
                    __FILE__, VFont, group);
 
   theCommands.Add ("vvertexmode",
diff --git a/tests/3rdparty/fonts/C4 b/tests/3rdparty/fonts/C4
new file mode 100644 (file)
index 0000000..121c54b
--- /dev/null
@@ -0,0 +1,26 @@
+puts "================"
+puts "0031118: Visualization - Font_FontMgr skips fonts with unknown styles like Narrow or Black"
+puts "================"
+puts ""
+
+dtracelevel trace
+pload VISUALIZATION
+
+# Do the trick - find any pair of fonts with and without "Narrow" style suffix.
+# On Windows it might be "Arial" and "Arial Narrow", on Linux "Liberation Sans" and "Liberation Sans Narrow".
+vfont -verbose 1
+set aFontN [vfont -strict -find "* Narrow"]
+set aFontR [string map {" Narrow" ""} $aFontN]
+vfont -strict -findInfo "$aFontN"
+vfont -strict -findInfo "$aFontR"
+
+vclear
+vinit View1
+vpoint p0 0 0  0
+vpoint p1 0 10 0
+vdrawtext t1 "My Text \[$aFontR\]" -font "$aFontR" -pos 0 5 0
+vdrawtext t2 "My Text \[$aFontN\]" -font "$aFontN" -pos 0 6 0 
+vtop
+vfit
+
+vdump $imagedir/${casename}.png