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