1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18 
19 #include <pcl/common/utils.h> // pcl::utils::ignore
20 
21 
22 ON_OBJECT_IMPLEMENT( ON_Font, ON_Object, "4F0F51FB-35D0-4865-9998-6D2C6A99721D" );
23 
ON_Font()24 ON_Font::ON_Font()
25 {
26   Defaults();
27 }
28 
~ON_Font()29 ON_Font::~ON_Font()
30 {
31 }
32 
CreateFontFromFaceName(const wchar_t * facename,bool bBold,bool bItalic)33 bool ON_Font::CreateFontFromFaceName(
34   const wchar_t* facename,
35   bool bBold,
36   bool bItalic
37   )
38 {
39   PurgeUserData();
40   Defaults();
41 
42   if ( 0 == facename || 0 == facename[0] )
43     facename = L"Arial";
44 
45   bool rc = SetFontFaceName(facename);
46 
47   HeightOfI();
48 
49   m_font_name = facename;
50   if ( bBold )
51   {
52     SetBold(true);
53     m_font_name += "L Bold";
54   }
55   if ( bItalic )
56   {
57     SetItalic(true);
58     m_font_name += "L Italic";
59   }
60 
61   return rc;
62 }
63 
64 
Defaults()65 void ON_Font::Defaults()
66 {
67   m_font_name.Empty();
68   m_font_weight = ON_Font::normal_weight;
69   m_font_italic = false;
70   m_font_underlined = false;
71   m_linefeed_ratio = m_default_linefeed_ratio;
72   m_font_index = -1;
73   memset(&m_font_id,0,sizeof(m_font_id));
74   memset( &m_facename, 0, sizeof( m_facename));
75   m_I_height = 0;
76 #if defined(ON_OS_WINDOWS_GDI)
77   memset(&m_logfont,0,sizeof(m_logfont));
78   m_logfont.lfHeight = normal_font_height;
79   m_logfont.lfCharSet = default_charset;
80 #endif
81   SetFontFaceName(L"Arial");
82 }
83 
84 //////////////////////////////////////////////////////////////////////
85 //
86 // ON_Object overrides
87 
IsValid(ON_TextLog *) const88 ON_BOOL32 ON_Font::IsValid( ON_TextLog* ) const
89 {
90   return ( m_font_name.Length() > 0
91            && m_font_index >= 0
92            && m_facename[0] > 32
93            && m_facename[64] == 0
94            );
95 }
96 
Dump(ON_TextLog & dump) const97 void ON_Font::Dump( ON_TextLog& dump ) const
98 {
99   const wchar_t* name = FontName();
100   if ( !name )
101     name = L"";
102   dump.Print("font index = %d\n",m_font_index);
103   dump.Print("font name = \"%ls\"\n",name);
104   dump.Print("font face name = \"%ls\"\n",m_facename);
105   dump.Print("font weight = \"%d\"\n",m_font_weight);
106   dump.Print("font is italic = \"%d\"\n",m_font_italic);
107   dump.Print("font is underlined = \"%d\"\n",m_font_underlined);
108   dump.Print("font linefeed ratio = \"%g\"\n", m_linefeed_ratio);
109 }
110 
Write(ON_BinaryArchive & file) const111 ON_BOOL32 ON_Font::Write(
112        ON_BinaryArchive& file // serialize definition to binary archive
113      ) const
114 {
115   bool rc = file.Write3dmChunkVersion(1,2);
116   while(rc)
117   {
118     rc = file.WriteInt(m_font_index);
119     if  (!rc) break;
120     rc = file.WriteString(m_font_name);
121     if  (!rc) break;
122     {
123       // 18 October 2002 Dale Lear:
124       //   Lowell, wchar_t has different sizes on different OSs.
125       //   When writing a wchar_t string, you should use one
126       //   of the WriteString functions.  This function must continue
127       //   to use WriteShort(64,...) so old files will remain valid.
128       unsigned short sh[64];
129       memset(sh,0,sizeof(sh));
130       int i;
131       for ( i = 0; i < 64 && i < face_name_size-1; i++ )
132         sh[i] = m_facename[i];
133       rc = file.WriteShort(64, sh);
134       if  (!rc) break;
135     }
136 
137     // 1.1 additions
138     rc = file.WriteInt( m_font_weight);
139     if  (!rc) break;
140     rc = file.WriteInt( m_font_italic);
141     if  (!rc) break;
142     rc = file.WriteDouble( m_linefeed_ratio);
143     if  (!rc) break;
144 
145     // 1.2 addition
146     rc = file.WriteUuid( m_font_id);
147     if (!rc) break;
148 
149     // 1.3 addition
150 //    rc = file.WriteInt( m_font_underlined);
151 //    if  (!rc) break;
152 
153     break;
154   }
155 
156   return rc;
157 }
158 
Read(ON_BinaryArchive & file)159 ON_BOOL32 ON_Font::Read(
160        ON_BinaryArchive& file // restore definition from binary archive
161      )
162 {
163   Defaults();
164   m_font_index = -1;
165   int major_version = 0;
166   int minor_version = 0;
167   bool rc = file.Read3dmChunkVersion(&major_version,&minor_version);
168   if ( rc && major_version == 1 )
169   {
170     int i;
171     for(;;)
172     {
173       rc = file.ReadInt( &m_font_index );
174       if  (!rc) break;
175       rc = file.ReadString( m_font_name );
176       if  (!rc) break;
177 
178       {
179         // 18 October 2002 Dale Lear:
180         //   Lowell, wchar_t has different sizes on different OSs.
181         //   When writing a wchar_t string, you should use one
182         //   of the WriteString functions.  This function must continue
183         //   to use ReadShort(64,...) so old files will remain valid.
184         unsigned short sh[64];
185         rc = file.ReadShort(64, sh);
186         if (!rc) break;
187 
188         wchar_t facename[65];
189         for ( i = 0; i < 64; i++ )
190         {
191           facename[i] = sh[i];
192         }
193         facename[64] = 0;
194         SetFontFaceName(facename);
195       }
196 
197       if( minor_version >= 1 )
198       {
199         rc = file.ReadInt( &i );
200         if (!rc) break;
201         SetFontWeight(i);
202 
203         rc = file.ReadInt( &i);
204         if (!rc) break;
205         SetIsItalic(i?true:false);
206 
207         rc = file.ReadDouble( &m_linefeed_ratio );
208         if (!rc) break;
209 
210         if ( minor_version >= 2 )
211         {
212           rc = file.ReadUuid( m_font_id );
213           if (!rc) break;
214         }
215         //if ( minor_version >= 3 )
216         //{
217         //  rc = file.ReadInt( &i);
218         //  if (!rc) break;
219         //  SetUnderlined(i?true:false);
220         //}
221       }
222 
223       break;
224     }
225   }
226   else
227   {
228     ON_ERROR("ON_Font::Read - get newer version of opennurbs");
229     rc = false;
230   }
231 
232   return rc;
233 }
234 
235 // Ratio of linefeed to character height
236 const double ON_Font::m_default_linefeed_ratio = 1.6;
237 
238 // This must be an 'I' or 'H', but we have not tested 'H'.
239 // There are problems with any other upper case character.
240 // In particular, the standard 'M' does not work.
241 const int ON_Font::m_metrics_char = 'I';
242 
243 //////////////////////////////////////////////////////////////////////
244 //
245 // Interface
SetFontName(const wchar_t * s)246 void ON_Font::SetFontName( const wchar_t* s )
247 {
248   m_font_name = s;
249 }
250 
SetFontName(const char * s)251 void ON_Font::SetFontName( const char* s )
252 {
253   m_font_name = s;
254 }
255 
GetFontName(ON_wString & s) const256 void ON_Font::GetFontName( ON_wString& s ) const
257 {
258   s = m_font_name;
259 }
260 
FontName() const261 const wchar_t* ON_Font::FontName() const
262 {
263   const wchar_t* s = m_font_name;
264   return s;
265 }
266 
267 #if defined(ON_OS_WINDOWS_GDI)
268 static
ON__IsSymbolFontFaceNameHelper(ENUMLOGFONTEX *,NEWTEXTMETRICEX *,DWORD,LPARAM)269 int CALLBACK ON__IsSymbolFontFaceNameHelper( ENUMLOGFONTEX*, NEWTEXTMETRICEX*, DWORD, LPARAM)
270 {
271   // If the fontname in the logfont structure has
272   // a corresponding symbol font on the system,
273   // set the  lfCharSet member to SYMBOL_CHARSET,
274   // otherwise DEFAULT_CHARSET
275   // The input logfont structure may be modified.
276   return 7;
277 }
278 #endif
279 
IsSymbolFontFaceName(const wchar_t * s)280 bool ON_Font::IsSymbolFontFaceName( const wchar_t* s)
281 {
282   bool rc = false;
283   pcl::utils::ignore(s);
284 #if defined(ON_OS_WINDOWS_GDI)
285   if( s && s[0])
286   {
287     HDC hdc = ::GetDC( NULL);
288     if( hdc)
289     {
290       LOGFONT logfont;
291       memset( &logfont, 0, sizeof( logfont));
292       int i;
293       for ( i = 0; i < LF_FACESIZE && s[i]; i++ )
294       {
295         logfont.lfFaceName[i] = s[i];
296       }
297       logfont.lfCharSet = ON_Font::symbol_charset;
298       if( 7 == ::EnumFontFamiliesEx( hdc, &logfont, (FONTENUMPROC)ON__IsSymbolFontFaceNameHelper, 0, 0))
299       {
300         rc = true;
301       }
302       ::ReleaseDC( NULL, hdc);
303     }
304   }
305 #endif
306 
307   return rc;
308 }
309 
SetFontFaceName(const wchar_t * s)310 bool ON_Font::SetFontFaceName( const wchar_t* s )
311 {
312   int i;
313   memset( &m_facename, 0, sizeof(m_facename) );
314   if ( s)
315   {
316     for ( i = 0; i < face_name_size-1 && s[i]; i++ )
317     {
318       m_facename[i] = s[i];
319     }
320   }
321 
322 #if defined(ON_OS_WINDOWS_GDI)
323   memset( &m_logfont.lfFaceName, 0, sizeof(m_logfont.lfFaceName) );
324 #endif
325 
326   m_I_height = 0;
327 
328   UpdateImplementationSettings();
329 
330   return( m_facename[0] ? true : false);
331 }
332 
SetFontFaceName(const char * s)333 bool ON_Font::SetFontFaceName( const char* s )
334 {
335   ON_wString wstr(s);
336   const wchar_t* w = wstr;
337   return SetFontFaceName(w);
338 }
339 
AscentRatio() const340 double ON_Font::AscentRatio() const
341 {
342   return ((double)normal_font_height) / ((double)HeightOfI());
343 }
344 
GetFontFaceName(ON_wString & s) const345 void ON_Font::GetFontFaceName( ON_wString& s ) const
346 {
347   s = m_facename;
348 }
349 
FontFaceName() const350 const wchar_t* ON_Font::FontFaceName() const
351 {
352   const wchar_t* s = m_facename;
353   return s;
354 }
355 
SetFontIndex(int i)356 void ON_Font::SetFontIndex(int i)
357 {
358   m_font_index = i;
359 }
360 
FontIndex() const361 int ON_Font::FontIndex() const
362 {
363   return m_font_index;
364 }
365 
LinefeedRatio() const366 double ON_Font::LinefeedRatio() const
367 {
368   return m_linefeed_ratio;
369 }
370 
SetLinefeedRatio(double d)371 void ON_Font::SetLinefeedRatio( double d)
372 {
373   m_linefeed_ratio = d;
374 }
375 
FontWeight() const376 int ON_Font::FontWeight() const
377 {
378   return m_font_weight;
379 }
380 
SetFontWeight(int w)381 void ON_Font::SetFontWeight( int w)
382 {
383   if ( w != m_font_weight )
384   {
385     if ( w < 0 )
386       w = 0;
387     m_font_weight = w;
388     m_I_height = 0;
389     UpdateImplementationSettings();
390   }
391 }
392 
IsItalic() const393 bool ON_Font::IsItalic() const
394 {
395   return m_font_italic;
396 }
397 
SetIsItalic(bool b)398 void ON_Font::SetIsItalic( bool b)
399 {
400   SetItalic( b);
401 }
402 
403 
SetItalic(bool b)404 void ON_Font::SetItalic( bool b)
405 {
406   if ( m_font_italic != b )
407   {
408     m_font_italic = b?true:false;
409     m_I_height = 0;
410     UpdateImplementationSettings();
411   }
412 }
413 
IsBold() const414 bool ON_Font::IsBold() const
415 {
416   return (FontWeight() >= bold_weight);
417 }
418 
419 
SetBold(bool bBold)420 void ON_Font::SetBold( bool bBold )
421 {
422   SetFontWeight( bBold ? bold_weight : normal_weight);
423 }
424 
425 
IsUnderlined() const426 bool ON_Font::IsUnderlined() const
427 {
428   return m_font_underlined;
429 }
430 
431 
SetUnderlined(bool b)432 void ON_Font::SetUnderlined( bool b)
433 {
434   if ( m_font_underlined != b )
435   {
436     m_font_underlined = b?true:false;
437     UpdateImplementationSettings();
438   }
439 }
440 
UpdateImplementationSettings()441 void ON_Font::UpdateImplementationSettings()
442 {
443 #if defined(ON_OS_WINDOWS_GDI)
444   BYTE b;
445   LONG w;
446   std::size_t cap0, cap1, cap, i;
447 
448   w = m_font_weight;
449   if ( w < 0 )
450     w = 0;
451   if ( w != m_logfont.lfWeight )
452   {
453     m_logfont.lfWeight = w;
454     m_I_height = 0;
455   }
456 
457   b = m_font_italic ? 1 : 0;
458   if ( b != m_logfont.lfItalic )
459   {
460     m_logfont.lfItalic = b;
461     m_I_height = 0;
462   }
463 
464   b = m_font_underlined ? 1 : 0;
465   if ( b != m_logfont.lfUnderline )
466   {
467     m_logfont.lfUnderline = b;
468     m_I_height = 0;
469   }
470 
471   b = 0;
472   cap0 = sizeof(m_facename)/sizeof(m_facename[0]);
473   cap1 = sizeof(m_logfont.lfFaceName)/sizeof(m_logfont.lfFaceName[0]);
474   cap = cap0 < cap1 ? cap0 : cap1;
475   for ( i = 0; i < cap; i++ )
476   {
477     if ( m_logfont.lfFaceName[i] != m_facename[i] )
478     {
479       m_logfont.lfFaceName[i] = m_facename[i];
480       b = 1;
481     }
482   }
483   if ( b )
484   {
485     for ( i = cap; i < cap1; i++ )
486       m_logfont.lfFaceName[i] = 0;
487 
488     m_logfont.lfCharSet = ON_Font::IsSymbolFontFaceName( m_logfont.lfFaceName )
489                       ? ((unsigned char)ON_Font::symbol_charset)
490                       : ((unsigned char)ON_Font::default_charset);
491 
492     m_I_height = 0;
493   }
494 
495 #endif
496 }
497 
498 /*
499 Returns:
500   Height of the 'I' character when the font is drawn
501   with m_logfont.lfHeight = 256.
502 */
HeightOfI() const503 int ON_Font::HeightOfI() const
504 {
505   if ( m_I_height  <= 0 )
506   {
507     // Default is height of Arial 'I'.  If we are running
508     // on Windows, then we calculate the actual height of
509     // an 'I' in the font.
510     //   The ..ON_Font::normal_font_height/256 is here
511     //   so this code will continue to work correctly
512     //   if somebody changes ON_Font::normal_font_height.
513     int I_height = (166*ON_Font::normal_font_height)/256;
514 
515 #if defined(ON_OS_WINDOWS_GDI)
516     if ( m_logfont.lfFaceName[0] )
517     {
518       // Get the height of an 'I'
519       HDC hdc = ::GetDC( NULL);
520       if (hdc)
521       {
522         LOGFONT logfont = m_logfont;
523         logfont.lfHeight = normal_font_height;
524         HFONT font = ::CreateFontIndirect( &logfont);
525         if ( font )
526         {
527           wchar_t str[2];
528           str[0] = ON_Font::m_metrics_char;
529           str[1] = 0;
530           HFONT oldfont = (HFONT)::SelectObject( hdc, font);
531           ::SetBkMode( hdc, TRANSPARENT);
532           ::BeginPath(hdc);
533           ::ExtTextOut( hdc, 0, 0, 0, NULL, str, 1, NULL);
534           ::EndPath( hdc);
535           int numPoints = ::GetPath( hdc, NULL, NULL, 0);
536 
537           if( numPoints > 2)
538           {
539             // Allocate room for the points & point types
540             LPPOINT pPoints = (LPPOINT)onmalloc( numPoints * sizeof(*pPoints) );
541             LPBYTE pTypes = (LPBYTE)onmalloc( numPoints * sizeof(*pTypes) );
542             if ( pTypes && pPoints)
543             {
544               // Get the points and types from the current path
545               numPoints = ::GetPath( hdc, pPoints, pTypes, numPoints);
546               if( numPoints > 2)
547               {
548                 int ymin = pPoints[0].y;
549                 int ymax = ymin;
550                 int k;
551                 for( k = 1; k < numPoints; k++)
552                 {
553                   if( pPoints[k].y < ymin)
554                     ymin = pPoints[k].y;
555                   else if( pPoints[k].y > ymax)
556                     ymax = pPoints[k].y;
557                 }
558                 I_height = ymax - ymin + 1;
559               }
560             }
561             onfree( pPoints);
562             onfree( pTypes);
563           }
564           ::SelectObject( hdc, oldfont);
565           ::DeleteObject( font);
566         }
567       }
568       ::ReleaseDC( NULL, hdc);
569     }
570 #endif
571     const_cast<ON_Font*>(this)->m_I_height = I_height;
572   }
573   return m_I_height;
574 }
575 
576 
HeightOfLinefeed() const577 int ON_Font::HeightOfLinefeed() const
578 {
579   return ( (int)( ceil(m_linefeed_ratio*HeightOfI()) ) );
580 }
581 
582 #if defined(ON_OS_WINDOWS_GDI)
583 
584 #pragma message( " --- OpenNURBS including Windows LOGFONT support in ON_Font" )
585 
SetLogFont(const LOGFONT & logfont)586 bool ON_Font::SetLogFont( const LOGFONT& logfont )
587 {
588   if ( &m_logfont != &logfont )
589   {
590     memcpy(&m_logfont,&logfont,sizeof(m_logfont));
591   }
592 
593   // synch persistent fields
594   m_font_weight = m_logfont.lfWeight;
595   m_font_italic = (m_logfont.lfItalic?true:false);
596   m_font_underlined = (m_logfont.lfUnderline?true:false);
597   memset(&m_facename[0],0,sizeof(m_facename));
598   int i;
599   for ( i = 0; i < face_name_size && i < LF_FACESIZE; i++ )
600   {
601     m_facename[i] = (wchar_t)m_logfont.lfFaceName[i];
602   }
603   m_facename[face_name_size-1] = 0;
604 
605 
606   m_I_height = 0;
607 
608   return true;
609 }
610 
LogFont() const611 const LOGFONT& ON_Font::LogFont() const
612 {
613   return m_logfont;
614 }
615 
ON_Font(const LOGFONT & logfont)616 ON_Font::ON_Font( const LOGFONT& logfont )
617 {
618   Defaults();
619   SetLogFont(logfont);
620 }
621 
operator =(const LOGFONT & logfont)622 ON_Font& ON_Font::operator=( const LOGFONT& logfont )
623 {
624   if ( &m_logfont == &logfont )
625   {
626     LOGFONT lf = logfont;
627     SetLogFont(lf);
628   }
629   else
630   {
631     SetLogFont(logfont);
632   }
633   return *this;
634 }
635 
CompareFontCharacteristics(ON_Font & other_font,bool bCompareName) const636 bool ON_Font::CompareFontCharacteristics( ON_Font& other_font, bool bCompareName) const
637 {
638   if( bCompareName && m_font_name.CompareNoCase( other_font.m_font_name))
639     return false;
640 
641   if( m_font_weight != other_font.m_font_weight)
642     return false;
643 
644   if( m_font_italic != other_font.m_font_italic)
645     return false;
646 
647   if( m_font_underlined != other_font.m_font_underlined)
648     return false;
649 
650   if( m_linefeed_ratio != other_font.m_linefeed_ratio)
651     return false;
652 
653   if( _wcsicmp( m_facename, other_font.m_facename))
654     return false;
655 
656   return true;
657 }
658 
659 
660 #endif
661 
662