0029122: Visualization - improve Font_BRepFont to handle one-line-fonts
authorkgv <kgv@opencascade.com>
Tue, 19 Sep 2017 13:53:39 +0000 (16:53 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 28 Sep 2017 07:40:29 +0000 (10:40 +0300)
Font_SystemFont - added a new property SingleStrokeFont().
Font_BRepFont::renderGlyph() has been extended to not close contours
when flag SingleStrokeFont() has been set.

src/Font/Font_BRepFont.cxx
src/Font/Font_FTFont.cxx
src/Font/Font_FTFont.hxx
src/Font/Font_FontMgr.cxx
src/Font/Font_SystemFont.cxx
src/Font/Font_SystemFont.hxx
src/ViewerTest/ViewerTest_ObjectCommands.cxx
tests/3rdparty/fonts/B6 [new file with mode: 0644]

index ff3e47e..01476bb 100755 (executable)
@@ -265,7 +265,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
 
   TopLoc_Location aLoc;
   TopoDS_Face aFaceDraft;
-  myBuilder.MakeFace (aFaceDraft, mySurface, myPrecision);
+  TopoDS_Compound aFaceCompDraft;
 
   // Get orientation is useless since it doesn't retrieve any in-font information and just computes orientation.
   // Because it fails in some cases - leave this to ShapeFix.
@@ -277,7 +277,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
     const short anEndIndex = anOutline.contours[aContour];
     const short aPntsNb    = (anEndIndex - aStartIndex) + 1;
     aStartIndex = anEndIndex + 1;
-    if (aPntsNb < 3)
+    if (aPntsNb < 3 && !myIsSingleLine)
     {
       // closed contour can not be constructed from < 3 points
       continue;
@@ -289,7 +289,8 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
     gp_XY aPntCurr = readFTVec (aPntList[aPntsNb - 1], myScaleUnits);
     gp_XY aPntNext = readFTVec (aPntList[0], myScaleUnits);
 
-    Standard_Integer aLinePnts = (FT_CURVE_TAG(aTags[aPntsNb - 1]) == FT_Curve_Tag_On) ? 1 : 0;
+    bool isLineSeg = !myIsSingleLine
+                  && FT_CURVE_TAG(aTags[aPntsNb - 1]) == FT_Curve_Tag_On;
     gp_XY aPntLine1 = aPntCurr;
 
     // see http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html
@@ -303,10 +304,10 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
       // process tags
       if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_On)
       {
-        if (aLinePnts < 1)
+        if (!isLineSeg)
         {
           aPntLine1 = aPntCurr;
-          aLinePnts = 1;
+          isLineSeg = true;
           continue;
         }
 
@@ -315,7 +316,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
         if (aLen <= myPrecision)
         {
           aPntLine1 = aPntCurr;
-          aLinePnts = 1;
+          isLineSeg = true;
           continue;
         }
 
@@ -339,7 +340,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
       }
       else if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_Conic)
       {
-        aLinePnts = 0;
+        isLineSeg = false;
         gp_XY aPntPrev2 = aPntPrev;
         gp_XY aPntNext2 = aPntNext;
 
@@ -378,7 +379,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
       else if (FT_CURVE_TAG(aTags[aPntId])                 == FT_Curve_Tag_Cubic
             && FT_CURVE_TAG(aTags[(aPntId + 1) % aPntsNb]) == FT_Curve_Tag_Cubic)
       {
-        aLinePnts = 0;
+        isLineSeg = false;
         my4Poles.SetValue (1, aPntPrev);
         my4Poles.SetValue (2, aPntCurr);
         my4Poles.SetValue (3, aPntNext);
@@ -411,7 +412,8 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
 
       const gp_Pnt2d aFirstPnt = aDraft2d->StartPoint();
       const gp_Pnt2d aLastPnt  = aDraft2d->EndPoint();
-      if (!aFirstPnt.IsEqual (aLastPnt, myPrecision))
+      if (!myIsSingleLine
+       && !aFirstPnt.IsEqual (aLastPnt, myPrecision))
       {
         Handle(Geom2d_TrimmedCurve) aLine = GCE2d_MakeSegment (aLastPnt, aFirstPnt);
         myConcatMaker.Add (aLine, myPrecision);
@@ -438,7 +440,8 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
       TopExp::Vertices (aWireMaker.Wire(), aFirstV, aLastV);
       gp_Pnt aFirstPoint = BRep_Tool::Pnt (aFirstV);
       gp_Pnt aLastPoint  = BRep_Tool::Pnt (aLastV);
-      if (!aFirstPoint.IsEqual (aLastPoint, myPrecision))
+      if (!myIsSingleLine
+       && !aFirstPoint.IsEqual (aLastPoint, myPrecision))
       {
         aWireMaker.Add (BRepLib_MakeEdge (aFirstV, aLastV));
       }
@@ -450,31 +453,64 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
     }
 
     TopoDS_Wire aWireDraft = aWireMaker.Wire();
-    //if (anOrient == FT_ORIENTATION_FILL_LEFT)
-    //{
-    // According to the TrueType specification, clockwise contours must be filled
-    aWireDraft.Reverse();
-    //}
-    myBuilder.Add (aFaceDraft, aWireDraft);
+    if (!myIsSingleLine)
+    {
+      //if (anOrient == FT_ORIENTATION_FILL_LEFT)
+      //{
+      // According to the TrueType specification, clockwise contours must be filled
+      aWireDraft.Reverse();
+      //}
+      if (aFaceDraft.IsNull())
+      {
+        myBuilder.MakeFace (aFaceDraft, mySurface, myPrecision);
+      }
+      myBuilder.Add (aFaceDraft, aWireDraft);
+    }
+    else
+    {
+      if (aFaceCompDraft.IsNull())
+      {
+        myBuilder.MakeCompound (aFaceCompDraft);
+      }
+      myBuilder.Add (aFaceCompDraft, aWireDraft);
+    }
   }
 
-  myFixer.Init (aFaceDraft);
-  myFixer.Perform();
-  theShape = myFixer.Result();
-  if (!theShape.IsNull()
-  &&  theShape.ShapeType() != TopAbs_FACE)
+  if (!aFaceDraft.IsNull())
   {
-    // shape fix can not fix orientation within the single call
-    TopoDS_Compound aComp;
-    myBuilder.MakeCompound (aComp);
-    for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+    myFixer.Init (aFaceDraft);
+    myFixer.Perform();
+    TopoDS_Shape aFixResult = myFixer.Result();
+    if (!aFixResult.IsNull()
+     &&  aFixResult.ShapeType() != TopAbs_FACE)
+    {
+      // shape fix can not fix orientation within the single call
+      if (aFaceCompDraft.IsNull())
+      {
+        myBuilder.MakeCompound (aFaceCompDraft);
+      }
+      for (TopExp_Explorer aFaceIter (aFixResult, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
+      {
+        TopoDS_Face aFace = TopoDS::Face (aFaceIter.Current());
+        myFixer.Init (aFace);
+        myFixer.Perform();
+        myBuilder.Add (aFaceCompDraft, myFixer.Result());
+      }
+      theShape = aFaceCompDraft;
+    }
+    else if (!aFaceCompDraft.IsNull())
     {
-      TopoDS_Face aFace = TopoDS::Face (aFaceIter.Current());
-      myFixer.Init (aFace);
-      myFixer.Perform();
-      myBuilder.Add (aComp, myFixer.Result());
+      myBuilder.Add (aFaceCompDraft, aFixResult);
+      theShape = aFaceCompDraft;
     }
-    theShape = aComp;
+    else
+    {
+      theShape = aFixResult;
+    }
+  }
+  else if (!aFaceCompDraft.IsNull())
+  {
+    theShape = aFaceCompDraft;
   }
 
   myCache.Bind (theChar, theShape);
index b51cac3..3687b74 100755 (executable)
@@ -33,6 +33,7 @@ Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib)
   myFTFace     (NULL),
   myPointSize  (0U),
   myLoadFlags  (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
+  myIsSingleLine(false),
   myKernAdvance(new FT_Vector()),
   myUChar      (0U)
 {
@@ -118,9 +119,12 @@ bool Font_FTFont::Init (const NCollection_String& theFontName,
 {
   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
   const Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (theFontName.ToCString());
-  Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, theFontAspect, thePointSize);
-  return !aRequestedFont.IsNull()
-      && Font_FTFont::Init (aRequestedFont->FontPath()->ToCString(), thePointSize, theResolution);
+  if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, theFontAspect, thePointSize))
+  {
+    myIsSingleLine = aRequestedFont->IsSingleStrokeFont();
+    return Font_FTFont::Init (aRequestedFont->FontPath()->ToCString(), thePointSize, theResolution);
+  }
+  return false;
 }
 
 // =======================================================================
index 4d500fe..f9583e0 100755 (executable)
@@ -73,6 +73,13 @@ public:
                              const unsigned int        thePointSize,
                              const unsigned int        theResolution);
 
+  //! Return TRUE if this is single-stroke (one-line) font, FALSE by default.
+  //! Such fonts define single-line glyphs instead of closed contours, so that they are rendered incorrectly by normal software.
+  bool IsSingleStrokeFont() const { return myIsSingleLine; }
+
+  //! Set if this font should be rendered as single-stroke (one-line).
+  void SetSingleStrokeFont (bool theIsSingleLine) { myIsSingleLine = theIsSingleLine; }
+
   //! Release currently loaded font.
   Standard_EXPORT virtual void Release();
 
@@ -159,6 +166,7 @@ protected:
   NCollection_String     myFontPath;    //!< font path
   unsigned int           myPointSize;   //!< point size set by FT_Set_Char_Size
   int32_t                myLoadFlags;   //!< default load flags
+  bool                   myIsSingleLine;//!< single stroke font flag, FALSE by default
 
   Image_PixMap           myGlyphImg;    //!< cached glyph plane
   FT_Vector*             myKernAdvance; //!< buffer variable
index 65f24d9..9b96602 100644 (file)
@@ -218,6 +218,8 @@ static Handle(Font_SystemFont) checkFont (const Handle(Font_FTLibrary)& theFTLib
     Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aFontFace->family_name);
     Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (theFontPath);
     aResult = new Font_SystemFont (aFontName, anAspect, aFontPath);
+    // automatically identify some known single-line fonts
+    aResult->SetSingleStrokeFont (aFontName->String().StartsWith ("OLF "));
   }
 
   FT_Done_Face (aFontFace);
index 29f1653..19c3c16 100644 (file)
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-// Updated:
-
 #include <Font_SystemFont.hxx>
+
 #include <OSD_Path.hxx>
 #include <Standard_Type.hxx>
 #include <TCollection_HAsciiString.hxx>
 
-IMPLEMENT_STANDARD_RTTIEXT(Font_SystemFont,Standard_Transient)
-
-Font_SystemFont::Font_SystemFont():
-MyFontName(),
-MyFontAspect(Font_FA_Undefined),
-MyFaceSize(-1),
-MyVerification(Standard_False)
+IMPLEMENT_STANDARD_RTTIEXT(Font_SystemFont, Standard_Transient)
+
+// =======================================================================
+// function : Font_SystemFont
+// purpose  :
+// =======================================================================
+Font_SystemFont::Font_SystemFont()
+: myFontAspect (Font_FA_Undefined),
+  myFaceSize (-1),
+  myIsSingleLine (Standard_False),
+  myIsDefined (Standard_False)
 {
+  //
 }
 
-Font_SystemFont::Font_SystemFont( const Handle(TCollection_HAsciiString)& FontName,
-                                const Font_FontAspect FontAspect,
-                                const Handle(TCollection_HAsciiString)& FilePath ):
-MyFontName(FontName),
-MyFontAspect(FontAspect),
-MyFaceSize(-1),
-MyFilePath(FilePath),
-MyVerification(Standard_True)
+// =======================================================================
+// function : Font_SystemFont
+// purpose  :
+// =======================================================================
+Font_SystemFont::Font_SystemFont (const Handle(TCollection_HAsciiString)& theFontName,
+                                  const Font_FontAspect theFontAspect,
+                                  const Handle(TCollection_HAsciiString)& theFilePath)
+: myFontName (theFontName),
+  myFontAspect (theFontAspect),
+  myFaceSize (-1),
+  myFilePath (theFilePath),
+  myIsSingleLine (Standard_False),
+  myIsDefined (Standard_True)
 {
-
+  //
 }
 
+// =======================================================================
+// function : Font_SystemFont
+// purpose  :
+// =======================================================================
 Font_SystemFont::Font_SystemFont (const Handle(TCollection_HAsciiString)& theXLFD,
-                                  const Handle(TCollection_HAsciiString)& theFilePath) :
-MyFontAspect(Font_FA_Regular),
-MyFaceSize(-1),
-MyFilePath(theFilePath)
+                                  const Handle(TCollection_HAsciiString)& theFilePath)
+: myFontAspect (Font_FA_Regular),
+  myFaceSize (-1),
+  myFilePath (theFilePath),
+  myIsSingleLine (Standard_False),
+  myIsDefined (Standard_True)
 {
-  MyVerification = Standard_True;
-  if (theXLFD.IsNull())
+  if (theXLFD.IsNull()
+   || theXLFD->IsEmpty())
   {
-    MyVerification = Standard_False; // empty font description handler
+    myIsDefined = Standard_False;
+    return;
   }
-  if (theXLFD->IsEmpty())
+
+  myFontName = theXLFD->Token ("-", 2);
+  const TCollection_AsciiString& aXLFD = theXLFD->String();
+
+  // Getting font size for fixed size fonts
+  if (aXLFD.Search ("-0-0-0-0-") >= 0)
   {
-    MyVerification = Standard_False; // empty font description
+    myFaceSize = -1; // Scalable font
   }
-
-  if (MyVerification)
+  else
   {
-    MyFontName = theXLFD->Token ("-", 2);
-    TCollection_AsciiString aXLFD (theXLFD->ToCString());
-
-    // Getting font size for fixed size fonts
-    if (aXLFD.Search ("-0-0-0-0-") >= 0)
-      MyFaceSize = -1; // Scalable font
-    else
-      //TODO catch exeption
-      MyFaceSize = aXLFD.Token ("-", 7).IntegerValue();
-
-    // Detect font aspect
-    if (aXLFD.Token ("-", 3).IsEqual ("bold") &&
-       (aXLFD.Token ("-", 4).IsEqual ("i") || aXLFD.Token ("-", 4).IsEqual ("o")))
-    {
-      MyFontAspect = Font_FA_BoldItalic;
-    }
-    else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
-    {
-      MyFontAspect = Font_FA_Bold;
-    }
-    else if (aXLFD.Token ("-", 4).IsEqual ("i") || aXLFD.Token ("-", 4).IsEqual ("o"))
-    {
-      MyFontAspect = Font_FA_Italic;
-    }
+    myFaceSize = aXLFD.Token ("-", 7).IntegerValue();
   }
-}
-
-Standard_Boolean Font_SystemFont::IsValid() const{
-  if ( !MyVerification)
-    return Standard_False;
-
-  if ( MyFontAspect == Font_FA_Undefined )
-    return Standard_False;
 
-  if ( MyFontName->IsEmpty() || !MyFontName->IsAscii() )
-    return Standard_False;
-
-  OSD_Path path;
-  return path.IsValid( MyFilePath->String() );
-}
-
-Handle(TCollection_HAsciiString) Font_SystemFont::FontPath() const{
-  return MyFilePath;
-}
-
-Handle(TCollection_HAsciiString) Font_SystemFont::FontName() const{
-  return MyFontName;
-}
-
-Font_FontAspect Font_SystemFont::FontAspect() const{
-  return MyFontAspect;
-}
-
-Standard_Integer Font_SystemFont::FontHeight() const {
-  return MyFaceSize;
-}
-
-Standard_Boolean Font_SystemFont::IsEqual(const Handle(Font_SystemFont)& theOtherFont) const
-{
-  if (!MyFontName->IsSameString (theOtherFont->FontName(), Standard_False))
+  // Detect font aspect
+  if (aXLFD.Token ("-", 3).IsEqual ("bold")
+   && (aXLFD.Token ("-", 4).IsEqual ("i")
+    || aXLFD.Token ("-", 4).IsEqual ("o")))
   {
-    return Standard_False;
+    myFontAspect = Font_FA_BoldItalic;
   }
-
-  if (MyFontAspect != theOtherFont->FontAspect())
+  else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
   {
-    return Standard_False;
+    myFontAspect = Font_FA_Bold;
   }
-
-  if (MyFaceSize != theOtherFont->FontHeight())
+  else if (aXLFD.Token ("-", 4).IsEqual ("i")
+        || aXLFD.Token ("-", 4).IsEqual ("o"))
   {
-    return Standard_False;
+    myFontAspect = Font_FA_Italic;
   }
+}
 
-  return Standard_True;
+// =======================================================================
+// function : IsValid
+// purpose  :
+// =======================================================================
+Standard_Boolean Font_SystemFont::IsValid() const
+{
+  return myIsDefined
+     &&  myFontAspect != Font_FA_Undefined
+     && !myFontName->IsEmpty()
+     &&  OSD_Path::IsValid (myFilePath->String());
+}
+
+// =======================================================================
+// function : IsEqual
+// purpose  :
+// =======================================================================
+Standard_Boolean Font_SystemFont::IsEqual (const Handle(Font_SystemFont)& theOtherFont) const
+{
+  return myFontName->IsSameString (myFontName, Standard_False)
+      && myFontAspect == theOtherFont->myFontAspect
+      && myFaceSize   == theOtherFont->myFaceSize;
 }
index 062f916..7cb13e2 100644 (file)
 #include <Standard_Transient.hxx>
 class TCollection_HAsciiString;
 
-
-class Font_SystemFont;
-DEFINE_STANDARD_HANDLE(Font_SystemFont, Standard_Transient)
-
-//! Structure for store of Font System Information
+//! This class stores information about the font, which is merely a file path and cached metadata about the font.
 class Font_SystemFont : public Standard_Transient
 {
-
+  DEFINE_STANDARD_RTTIEXT(Font_SystemFont, Standard_Transient)
 public:
 
-  
-  //! Creates empty font object
+  //! Creates an empty font object.
   Standard_EXPORT Font_SystemFont();
+
+  //! Creates a new font object.
+  Standard_EXPORT Font_SystemFont (const Handle(TCollection_HAsciiString)& theFontName,
+                                   const Font_FontAspect theFontAspect,
+                                   const Handle(TCollection_HAsciiString)& theFilePath);
+
+  //! Creates a font object and initialize class fields with values taken from XLFD (X Logical Font Description)
+  Standard_EXPORT Font_SystemFont (const Handle(TCollection_HAsciiString)& theXLFD,
+                                   const Handle(TCollection_HAsciiString)& theFilePath);
+
+  //! Returns font family name.
+  const Handle(TCollection_HAsciiString)& FontName() const { return myFontName; }
   
-  //! Creates Font object initialized with <FontName> as name
-  //! <FontAspect>.... TODO
-  Standard_EXPORT Font_SystemFont(const Handle(TCollection_HAsciiString)& theFontName, const Font_FontAspect theFontAspect, const Handle(TCollection_HAsciiString)& theFilePath);
-  
-  //! Creates Font object and initialize class fields with
-  //! values taken from XLFD (X Logical Font Description)
-  Standard_EXPORT Font_SystemFont(const Handle(TCollection_HAsciiString)& theXLFD, const Handle(TCollection_HAsciiString)& theFilePath);
-  
-  //! Returns font family name
-  Standard_EXPORT Handle(TCollection_HAsciiString) FontName() const;
-  
-  //! Returns font file path
-  //! Level: Public
-  Standard_EXPORT Handle(TCollection_HAsciiString) FontPath() const;
-  
-  //! Returns font aspect
-  //! Level: Public
-  Standard_EXPORT Font_FontAspect FontAspect() const;
+  //! Returns font file path.
+  const Handle(TCollection_HAsciiString)& FontPath() const { return myFilePath; }
   
-  //! Returns font height
-  //! If returned value is equal -1 it means that font is resizable
-  //! Level: Public
-  Standard_EXPORT Standard_Integer FontHeight() const;
+  //! Returns font aspect.
+  Font_FontAspect FontAspect() const { return myFontAspect; }
   
+  //! Returns font height.
+  //! If returned value is equal -1 it means that font is resizable.
+  Standard_Integer FontHeight() const { return myFaceSize; }
+
   Standard_EXPORT Standard_Boolean IsValid() const;
   
   //! Return true if the FontName, FontAspect and FontSize are the same.
-  //! Level: Public
   Standard_EXPORT Standard_Boolean IsEqual (const Handle(Font_SystemFont)& theOtherFont) const;
 
+  //! Return TRUE if this is single-stroke (one-line) font, FALSE by default.
+  //! Such fonts define single-line glyphs instead of closed contours, so that they are rendered incorrectly by normal software.
+  Standard_Boolean IsSingleStrokeFont() const { return myIsSingleLine; }
 
-
-
-  DEFINE_STANDARD_RTTIEXT(Font_SystemFont,Standard_Transient)
-
-protected:
-
-
-
+  //! Set if this font should be rendered as single-stroke (one-line).
+  void SetSingleStrokeFont (Standard_Boolean theIsSingleLine) { myIsSingleLine = theIsSingleLine; }
 
 private:
 
-
-  Handle(TCollection_HAsciiString) MyFontName;
-  Font_FontAspect MyFontAspect;
-  Standard_Integer MyFaceSize;
-  Handle(TCollection_HAsciiString) MyFilePath;
-  Standard_Boolean MyVerification;
-
+  Handle(TCollection_HAsciiString) myFontName;
+  Font_FontAspect                  myFontAspect;
+  Standard_Integer                 myFaceSize;
+  Handle(TCollection_HAsciiString) myFilePath;
+  Standard_Boolean                 myIsSingleLine; //!< single stroke font flag, FALSE by default
+  Standard_Boolean                 myIsDefined;
 
 };
 
-
-
-
-
-
+DEFINE_STANDARD_HANDLE(Font_SystemFont, Standard_Transient)
 
 #endif // _Font_SystemFont_HeaderFile
index c90e5ba..75950fd 100644 (file)
@@ -5594,26 +5594,37 @@ static int VFont (Draw_Interpretor& theDI,
     {
       if (++anArgIter >= theArgNb)
       {
-        std::cerr << "Wrong syntax at argument '" << anArg.ToCString() << "'!\n";
+        std::cerr << "Error: wrong syntax at argument '" << anArg << "'!\n";
         return 1;
       }
-      Standard_CString aFontPath   = theArgVec[anArgIter];
-      Standard_CString aFontName   = NULL;
+
+      Standard_CString aFontPath = theArgVec[anArgIter++];
+      TCollection_AsciiString aFontName;
       Font_FontAspect  aFontAspect = Font_FA_Undefined;
-      if (++anArgIter < theArgNb)
+      Standard_Integer isSingelStroke = -1;
+      for (; anArgIter < theArgNb; ++anArgIter)
       {
-        if (!parseFontStyle (anArgCase, aFontAspect))
+        anArgCase = theArgVec[anArgIter];
+        anArgCase.LowerCase();
+        if (aFontAspect == Font_FA_Undefined
+         && parseFontStyle (anArgCase, aFontAspect))
+        {
+          continue;
+        }
+        else if (anArgCase == "singlestroke"
+              || anArgCase == "singleline"
+              || anArgCase == "oneline")
+        {
+          isSingelStroke = 1;
+        }
+        else if (aFontName.IsEmpty())
         {
           aFontName = theArgVec[anArgIter];
         }
-        if (++anArgIter < theArgNb)
+        else
         {
-          anArgCase = theArgVec[anArgIter];
-          anArgCase.LowerCase();
-          if (!parseFontStyle (anArgCase, aFontAspect))
-          {
-            --anArgIter;
-          }
+          --anArgIter;
+          break;
         }
       }
 
@@ -5625,19 +5636,23 @@ static int VFont (Draw_Interpretor& theDI,
       }
 
       if (aFontAspect != Font_FA_Undefined
-       || aFontName   != NULL)
+      || !aFontName.IsEmpty())
       {
         if (aFontAspect == Font_FA_Undefined)
         {
           aFontAspect = aFont->FontAspect();
         }
         Handle(TCollection_HAsciiString) aName = aFont->FontName();
-        if (aFontName != NULL)
+        if (!aFontName.IsEmpty())
         {
           aName = new TCollection_HAsciiString (aFontName);
         }
         aFont = new Font_SystemFont (aName, aFontAspect, new TCollection_HAsciiString (aFontPath));
       }
+      if (isSingelStroke != -1)
+      {
+        aFont->SetSingleStrokeFont (isSingelStroke == 1);
+      }
 
       aMgr->RegisterFont (aFont, Standard_True);
       theDI << aFont->FontName()->String()
@@ -5646,7 +5661,7 @@ static int VFont (Draw_Interpretor& theDI,
     }
     else
     {
-      std::cerr << "Warning! Unknown argument '" << anArg.ToCString() << "'\n";
+      std::cerr << "Warning! Unknown argument '" << anArg << "'\n";
     }
   }
 
@@ -6721,7 +6736,7 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
                    "\n\t\t: [-plane NormX NormY NormZ DirX DirY DirZ]",
                    __FILE__, TextToBRep, group);
   theCommands.Add ("vfont",
-                            "vfont [add pathToFont [fontName] [regular,bold,italic,bolditalic=undefined]]"
+                            "vfont [add pathToFont [fontName] [regular,bold,italic,bolditalic=undefined] [singleStroke]]"
                    "\n\t\t:        [find fontName [regular,bold,italic,bolditalic=undefined]]",
                    __FILE__, VFont, group);
   
diff --git a/tests/3rdparty/fonts/B6 b/tests/3rdparty/fonts/B6
new file mode 100644 (file)
index 0000000..f052599
--- /dev/null
@@ -0,0 +1,19 @@
+puts "============"
+puts "0029122: Visualization - improve Font_BRepFont to handle one-line-fonts"
+puts "============"
+puts ""
+
+pload MODELING VISUALIZATION
+vfont add [locate_data_file OLFTestFont-Regular.ttf]
+vfont add [locate_data_file machtgth.ttf] singleStroke machtgth
+vfont add [locate_data_file DejaVuSans.ttf] SansFont
+text2brep s1 "ABCDabcd123" -font "OLF TestFont" -height 48 -pos 0   0 0
+text2brep s2 "ABCDabcd123" -font "machtgth"     -height 48 -pos 0  50 0
+text2brep s3 "ABCDabcd123" -font "SansFont"     -height 48 -pos 0 100 0
+vclear
+vinit View1
+vtop
+vdisplay -dispMode 1 s1 s2 s3
+vfit
+
+vdump ${imagedir}/${casename}.png