1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xlfd_attr.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
36 #include <sal/alloca.h>
37 #include "xlfd_attr.hxx"
38 #include <rtl/tencinfo.h>
39 #include <vcl/vclenum.hxx>
41 // ---------------------------------------------------------------------------
44 // Attribute is a container for simple name value pairs
45 // eg. ( "times", FAMILY_ROMAN ) or ( "demi bold", WEIGHT_SEMIBOLD )
46 // enriched with an annotation which is a pretty-printed version of the
47 // string, i.e. "itc avant garde" would get an annotation of "Itc Avant Garde"
50 // ---------------------------------------------------------------------------
52 // release the stored string
56 if ( mpAnnotation
!= NULL
)
58 if ( mpKeyName
!= NULL
)
61 free( (void*)mpName
);
64 // get a private copy of the given argument
66 Attribute::SetName( const char *p
, int nLen
)
68 mpName
= (char*)malloc( nLen
+ 1 );
70 memcpy( (void*)mpName
, p
, mnLength
);
71 ((char*)mpName
)[ mnLength
] = '\0';
74 // Compare whether two strings a equal for the first nLen bytes
75 // i.e. arial == arialnarrow
77 Attribute::Compare( const char *p
, int nLen
)
79 return strncmp( mpName
, p
, nLen
);
82 // Get a all lowercase name with all blanks removed
86 static rtl::OString aEmptyStr
;
88 if (mpKeyName
!= NULL
)
93 sal_Char
* pBuffer
= (sal_Char
*)alloca (mnLength
);
96 for (i
= 0, j
= 0; i
< mnLength
; i
++)
98 if ( mpName
[i
] != ' ' )
99 pBuffer
[j
++] = mpName
[i
];
101 mpKeyName
= new rtl::OString(pBuffer
, j
);
107 Attribute::InitKey ()
112 // Compare two strings, they have to be equal for nLen bytes, after nLen
113 // bytes both strings have to be terminated either by '\0' or by '-'
114 // this is for comparing a string being a substring in a Xlfd with a
115 // zeroterminated string
117 Attribute::ExactMatch( const char *p
, int nLen
)
121 bMatch
= Compare( p
, nLen
) == 0;
127 char c2
= mpName
[ nLen
];
128 bMatch
= (c1
== '-' || c1
== '\0') && (c2
== '-' || c2
== '\0');
135 Attribute::TagFeature( unsigned short nFeature
)
137 if ( (nFeature
& XLFD_FEATURE_NARROW
)
138 && (strstr(mpName
, "narrow") != NULL
) )
140 mnFeature
|= XLFD_FEATURE_NARROW
;
143 if ( (nFeature
& XLFD_FEATURE_OL_CURSOR
)
144 && (strcmp(mpName
, "open look cursor") == 0) )
146 mnFeature
|= XLFD_FEATURE_OL_CURSOR
;
149 if ( (nFeature
& XLFD_FEATURE_OL_GLYPH
)
150 && (strcmp(mpName
, "open look glyph") == 0) )
152 mnFeature
|= XLFD_FEATURE_OL_GLYPH
;
155 if ( (nFeature
& XLFD_FEATURE_APPLICATION_FONT
)
156 && ( (strcmp(mpName
, "interface user") == 0)
157 || (strcmp(mpName
, "interface system") == 0)))
159 mnFeature
|= XLFD_FEATURE_APPLICATION_FONT
;
162 if (nFeature
& XLFD_FEATURE_INTERFACE_FONT
)
165 if (strcmp(mpName
, "arial") == 0)
166 mnFeature
|= (XLFD_FEATURE_INTERFACE_FONT
| XLFD_FEATURE_HQ
| XLFD_FEATURE_MQ
);
168 if (strcmp(mpName
, "helvetica") == 0)
169 mnFeature
|= (XLFD_FEATURE_INTERFACE_FONT
| XLFD_FEATURE_HQ
);
171 if ( (strcmp(mpName
, "lucidux sans") == 0)
172 || (strcmp(mpName
, "luxi sans") == 0))
173 mnFeature
|= (XLFD_FEATURE_INTERFACE_FONT
| XLFD_FEATURE_MQ
| XLFD_FEATURE_LQ
);
175 if (strcmp(mpName
, "charter") == 0)
176 mnFeature
|= (XLFD_FEATURE_INTERFACE_FONT
| XLFD_FEATURE_MQ
);
179 if ( (strcmp(mpName
, "hg mincho l") == 0) /* Solaris: jisx0208 jisx0201 */
180 || (strcmp(mpName
, "heiseimin") == 0) /* Solaris: jisx0212 */
181 || (strcmp(mpName
, "minchol") == 0) /* TurboLinux */
182 || (strcmp(mpName
, "mincho") == 0)) /* Redhat 6.2 JP */
184 mnFeature
|= XLFD_FEATURE_INTERFACE_FONT
;
188 if ( (strcmp(mpName
, "kai") == 0) /* Solaris */
189 || (strcmp(mpName
, "ar pl mingti2l big5") == 0)) /* TurboLinux */
191 mnFeature
|= XLFD_FEATURE_INTERFACE_FONT
;
195 if ( (strcmp(mpName
, "myeongjo") == 0)) /* Solaris */
197 mnFeature
|= XLFD_FEATURE_INTERFACE_FONT
;
201 if ( nFeature
& XLFD_FEATURE_REDUNDANTSTYLE
)
206 mnFeature
|= XLFD_FEATURE_REDUNDANTSTYLE
;
210 if ( (strcmp(mpName
, "bold") == 0)
211 || (strcmp(mpName
, "bold italic") == 0)
212 || (strcmp(mpName
, "bold sans") == 0) )
213 mnFeature
|= XLFD_FEATURE_REDUNDANTSTYLE
;
217 if ( (strcmp(mpName
, "demi") == 0)
218 || (strcmp(mpName
, "demi italic") == 0) )
219 mnFeature
|= XLFD_FEATURE_REDUNDANTSTYLE
;
223 if ( strcmp(mpName
, "italic") == 0 )
224 mnFeature
|= XLFD_FEATURE_REDUNDANTSTYLE
;
228 if ( (strcmp(mpName
, "sans") == 0)
229 || (strcmp(mpName
, "serif") == 0) )
230 mnFeature
|= XLFD_FEATURE_REDUNDANTSTYLE
;
236 // given Attribute classifications, strings have to be in alphabetical
237 // order, since they are treated by binary search algorithm
239 #define InitializeAttributeWith( p, a ) p, sizeof(p) - 1, a, 0, NULL, NULL
240 #define MembersOf( p ) (sizeof(p) / sizeof(p[0]) )
242 const Attribute pFamilyAttribute
[] = {
243 { InitializeAttributeWith( "arial", FAMILY_SWISS
) },
244 { InitializeAttributeWith( "arioso", FAMILY_SCRIPT
) },
245 { InitializeAttributeWith( "avant garde", FAMILY_SWISS
) },
246 { InitializeAttributeWith( "avantgarde", FAMILY_SWISS
) },
247 { InitializeAttributeWith( "bembo", FAMILY_ROMAN
) },
248 { InitializeAttributeWith( "bookman", FAMILY_ROMAN
) },
249 { InitializeAttributeWith( "conga", FAMILY_ROMAN
) },
250 { InitializeAttributeWith( "courier", FAMILY_MODERN
) },
251 { InitializeAttributeWith( "curl", FAMILY_SCRIPT
) },
252 { InitializeAttributeWith( "fixed", FAMILY_MODERN
) },
253 { InitializeAttributeWith( "gill", FAMILY_SWISS
) },
254 { InitializeAttributeWith( "helmet", FAMILY_MODERN
) },
255 { InitializeAttributeWith( "helvetica", FAMILY_SWISS
) },
256 { InitializeAttributeWith( "international", FAMILY_MODERN
) },
257 { InitializeAttributeWith( "lucida", FAMILY_SWISS
) },
258 { InitializeAttributeWith( "new century schoolbook", FAMILY_ROMAN
) },
259 { InitializeAttributeWith( "palatino", FAMILY_ROMAN
) },
260 { InitializeAttributeWith( "roman", FAMILY_ROMAN
) },
261 { InitializeAttributeWith( "sans serif", FAMILY_SWISS
) },
262 { InitializeAttributeWith( "sansserif", FAMILY_SWISS
) },
263 { InitializeAttributeWith( "serf", FAMILY_ROMAN
) },
264 { InitializeAttributeWith( "serif", FAMILY_ROMAN
) },
265 { InitializeAttributeWith( "times", FAMILY_ROMAN
) },
266 { InitializeAttributeWith( "utopia", FAMILY_ROMAN
) },
267 { InitializeAttributeWith( "zapf chancery", FAMILY_SCRIPT
) },
268 { InitializeAttributeWith( "zapfchancery", FAMILY_SCRIPT
) }
271 const Attribute pWeightAttribute
[] = {
272 { InitializeAttributeWith( "black", WEIGHT_BLACK
) },
273 { InitializeAttributeWith( "bold", WEIGHT_BOLD
) },
274 { InitializeAttributeWith( "book", WEIGHT_LIGHT
) },
275 { InitializeAttributeWith( "demi", WEIGHT_SEMIBOLD
) },
276 { InitializeAttributeWith( "demi bold", WEIGHT_SEMIBOLD
) },
277 { InitializeAttributeWith( "demibold", WEIGHT_SEMIBOLD
) },
278 { InitializeAttributeWith( "light", WEIGHT_LIGHT
) },
279 { InitializeAttributeWith( "medium", WEIGHT_MEDIUM
) },
280 { InitializeAttributeWith( "normal", WEIGHT_NORMAL
) },
281 { InitializeAttributeWith( "regular", WEIGHT_NORMAL
) },
282 { InitializeAttributeWith( "roman", WEIGHT_NORMAL
) },
283 { InitializeAttributeWith( "semicondensed", WEIGHT_LIGHT
) },
284 { InitializeAttributeWith( "ultrabold", WEIGHT_ULTRABOLD
) }
287 const Attribute pSlantAttribute
[] = {
288 { InitializeAttributeWith( "i", ITALIC_NORMAL
) },
289 { InitializeAttributeWith( "o", ITALIC_OBLIQUE
) },
290 { InitializeAttributeWith( "r", ITALIC_NONE
) }
293 const Attribute pSetwidthAttribute
[] = {
294 { InitializeAttributeWith( "bold", WIDTH_SEMI_EXPANDED
) },
295 { InitializeAttributeWith( "condensed", WIDTH_CONDENSED
) },
296 { InitializeAttributeWith( "double wide", WIDTH_ULTRA_EXPANDED
) },
297 { InitializeAttributeWith( "expanded", WIDTH_EXPANDED
) },
298 { InitializeAttributeWith( "extracondensed", WIDTH_EXTRA_CONDENSED
) },
299 { InitializeAttributeWith( "extraexpanded", WIDTH_EXTRA_EXPANDED
) },
300 { InitializeAttributeWith( "medium", WIDTH_NORMAL
) },
301 { InitializeAttributeWith( "narrow", WIDTH_CONDENSED
) },
302 { InitializeAttributeWith( "normal", WIDTH_NORMAL
) },
303 { InitializeAttributeWith( "semicondensed", WIDTH_SEMI_CONDENSED
) },
304 { InitializeAttributeWith( "semiexpanded", WIDTH_SEMI_EXPANDED
) },
305 { InitializeAttributeWith( "ultracondensed", WIDTH_ULTRA_CONDENSED
) },
306 { InitializeAttributeWith( "ultraexpanded", WIDTH_ULTRA_EXPANDED
) },
307 { InitializeAttributeWith( "wide", WIDTH_EXPANDED
) }
310 const Attribute pEnhancedCharsetAttribute
[] = {
311 { InitializeAttributeWith( "iso8859-1", RTL_TEXTENCODING_MS_1252
) },
312 { InitializeAttributeWith( "iso8859_1", RTL_TEXTENCODING_MS_1252
) }
315 // -------------------------------------------------------------------------
317 // String handling utility functions
319 // -------------------------------------------------------------------------
323 AppendAttribute( Attribute
*pAttribute
, ByteString
&rString
)
325 if ( pAttribute
== NULL
)
328 int nLength
= pAttribute
->GetLength();
329 char *pBuffer
= (char*)alloca( nLength
+ 1);
332 memcpy( pBuffer
+ 1, pAttribute
->GetName(), nLength
);
333 rString
.Append( pBuffer
, nLength
+ 1);
337 // Prettify the font name: make each leading character of a fontname
338 // uppercase. For example
339 // times new roman -> Times New Roman
343 ToUpper( char *pCharacter
)
345 // replace [a,z] with [A,Z]
346 if ( (*pCharacter
>= 97) && (*pCharacter
<= 122) )
351 Capitalize( const char *pStr
, int nLength
)
353 char *pCopy
= (char*)alloca( nLength
+ 1 );
355 memcpy( pPtr
, pStr
, nLength
+ 1 );
357 // loop over string data and uppercase first char and all chars
358 // following a space (other white space would be unexpected here)
359 char nPreviousChar
= ' ';
362 if ( nPreviousChar
== ' ' )
364 nPreviousChar
= *pPtr
++;
367 return new String( pCopy
, RTL_TEXTENCODING_ISO_8859_1
);
371 AnnotateString( const Attribute
& rAttribute
)
373 return Capitalize(rAttribute
.GetName(), rAttribute
.GetLength());
377 AnnotateSlant( const Attribute
& rAttribute
)
379 const char* pStr
= rAttribute
.GetName();
380 int nLen
= rAttribute
.GetLength();
382 static const struct {
383 const char *pFrom
; const char *pTo
;
388 { "ri", "Reverse Italic" },
389 { "ro", "Reverse Oblique" },
393 for ( unsigned int i
= 0; i
< MembersOf(pTranslation
); i
++ )
394 if ( strcmp(pStr
, pTranslation
[i
].pFrom
) == 0 )
396 return new String( pTranslation
[i
].pTo
,
397 RTL_TEXTENCODING_ISO_8859_1
);
400 return Capitalize(pStr
, nLen
);
404 AnnotateNone( const Attribute
& )
409 // ---------------------------------------------------------------------------
412 // manage global lists of Attributes
413 // since XListFonts does never list more than 64K fonts this storage does
414 // handle array size and indices with unsigned short values for low
415 // memory consumption
418 // ---------------------------------------------------------------------------
420 AttributeStorage::AttributeStorage( unsigned short nDefaultValue
) :
425 mnDefaultValue( nDefaultValue
)
429 AttributeStorage::~AttributeStorage()
431 if ( mpList
!= NULL
)
433 for ( int i
= 0; i
< mnCount
; i
++ )
439 #if OSL_DEBUG_LEVEL > 1
441 AttributeStorage::Dump()
443 fprintf(stderr
, "AttributeStorage: size=%i, used=%i\n", mnSize
, mnCount
);
444 for ( int i
= 0; i
< mnCount
; i
++ )
446 ByteString aAnnotation
= ByteString(
447 mpList
[i
].GetAnnotation(),
448 RTL_TEXTENCODING_ISO_8859_1
);
449 fprintf(stderr
, "\t%4i: <%s><len=%i><val=%i><%s>\n", i
, mpList
[i
].GetName(),
450 mpList
[i
].GetLength(), mpList
[i
].GetValue(),
451 aAnnotation
.GetBuffer() );
453 fprintf(stderr
, "\n");
458 AttributeStorage::Retrieve( unsigned short nIndex
) const
460 return nIndex
< mnCount
? &mpList
[ nIndex
] : (Attribute
*)NULL
;
463 // pClassification contains a list of name-value pairs. If names in
464 // the AttributeStorage match those in the pClassification then
465 // the according value is copied. Matching means match for the length
466 // of the string in pClassification (i.e. arial matches arialnarrow)
467 // the strings in pClassification must be in alphabetical order, all
470 AttributeStorage::AddClassification( Attribute
*pClassification
,
471 unsigned short nNum
)
473 for ( int i
= 0; i
< mnCount
; i
++ )
475 unsigned int nLower
= 0;
476 unsigned int nUpper
= nNum
;
477 unsigned int nCurrent
;
479 Attribute
*pHaystack
= 0, *pNeedle
;
481 pNeedle
= &mpList
[ i
];
484 while ( nLower
< nUpper
)
486 nCurrent
= (nLower
+ nUpper
) / 2;
487 pHaystack
= &pClassification
[ nCurrent
];
488 nComparison
= pNeedle
->Compare( pHaystack
->GetName(),
489 pHaystack
->GetLength() );
494 nLower
= nCurrent
+ 1;
499 // if there's a match store the according classification in the
500 // Attribute storage, otherwise do nothing since defaults are
501 // already provided in AttributeStorage::Insert()
502 if ( nComparison
== 0 )
503 pNeedle
->SetValue( pHaystack
->GetValue() );
508 AttributeStorage::AddClassification( AttributeClassifierT Classify
)
510 for ( int i
= 0; i
< mnCount
; i
++ )
512 Attribute
& rCurrent
= mpList
[i
] ;
513 int nValue
= Classify( rCurrent
.GetName() );
514 rCurrent
.SetValue( nValue
);
519 AttributeStorage::AddAnnotation( AttributeAnnotatorT Annotate
)
521 for ( int i
= 0; i
< mnCount
; i
++ )
523 String
* pAnnotation
= Annotate( mpList
[i
] );
524 mpList
[i
].SetAnnotation( pAnnotation
);
529 AttributeStorage::TagFeature( unsigned short nFeature
)
531 for ( int i
= 0; i
< mnCount
; i
++ )
532 mpList
[i
].TagFeature( nFeature
);
535 // Enlarge the list of Attributes
537 AttributeStorage::Enlarge()
542 mpList
= (Attribute
*) malloc( mnSize
* sizeof(Attribute
) );
546 mnSize
= mnSize
< 32768 ? (mnSize
* 2) : 65535;
547 mpList
= (Attribute
*) realloc( mpList
, mnSize
* sizeof(Attribute
) );
551 // nLength is the length as it would be reported by strlen(3)
552 // for an null-terminated string. if a string is part of a Xlfd
553 // the field separator '-' is taken as '\0'
554 // the AttributeStorage itself is NOT sorted to make sure that the
555 // leased keys are still valid
557 AttributeStorage::Insert( const char *pString
, int nLength
)
559 // check whether the last match is still equal to the current
560 // string since XListFonts lists fonts in sets of similar fontnames
561 if ( mnLastmatch
< mnCount
)
563 if ( mpList
[mnLastmatch
].ExactMatch(pString
, nLength
) )
567 // otherwise search in list
568 for ( int i
= 0; i
< mnCount
; i
++ )
570 if ( mpList
[i
].ExactMatch(pString
, nLength
) )
571 return mnLastmatch
= i
;
574 // if still not found we have to Insert the new string
575 if ( mnSize
== mnCount
)
577 mpList
[mnCount
].SetName( pString
, nLength
);
578 mpList
[mnCount
].SetValue( mnDefaultValue
);
579 mpList
[mnCount
].SetAnnotation( NULL
);
580 mpList
[mnCount
].SetFeature( XLFD_FEATURE_NONE
);
581 mpList
[mnCount
].InitKey( );
582 mnLastmatch
= mnCount
;
583 mnCount
= mnCount
< 65535 ? mnCount
+ 1 : mnCount
;
589 // ---------------------------------------------------------------------------
592 // Attribute provider is a frame for a set of AttributeStorages.
595 // ---------------------------------------------------------------------------
597 AttributeProvider::AttributeProvider ()
599 mpField
[eXLFDFoundry
] = new AttributeStorage(0);
600 mpField
[eXLFDFamilyName
] = new AttributeStorage(FAMILY_DONTKNOW
);
601 mpField
[eXLFDWeightName
] = new AttributeStorage(WEIGHT_NORMAL
);
602 mpField
[eXLFDSlant
] = new AttributeStorage(ITALIC_NONE
);
603 mpField
[eXLFDSetwidthName
] = new AttributeStorage(WIDTH_NORMAL
);
604 mpField
[eXLFDAddstyleName
] = new AttributeStorage(RTL_TEXTENCODING_DONTKNOW
);
605 mpField
[eXLFDCharset
] = new AttributeStorage(RTL_TEXTENCODING_DONTKNOW
);
608 AttributeProvider::~AttributeProvider()
610 for ( int i
= 0; i
< eXLFDMaxEntry
; i
++ )
614 #if OSL_DEBUG_LEVEL > 1
616 AttributeProvider::Dump()
618 for ( int i
= 0; i
< eXLFDMaxEntry
; i
++ )
619 mpField
[ i
]->Dump();
623 extern "C" rtl_TextEncoding
624 GetTextEncodingFromAddStylename( const sal_Char
*pAddStylename
)
626 int nBufferLength
= strlen( pAddStylename
) + 1;
627 sal_Char
*pBuffer
= (sal_Char
*)alloca( nBufferLength
);
628 for ( int i
= 0; i
< nBufferLength
; i
++ )
629 pBuffer
[i
] = pAddStylename
[i
] == '_' ? '-' : pAddStylename
[i
] ;
631 return rtl_getTextEncodingFromUnixCharset( pBuffer
);
635 // classification information is needed before sorting because of course the
636 // classification is the sort criteria
638 AttributeProvider::AddClassification()
640 /* mpField[ eXLFDFoundry ] doesn't need classification */
641 mpField
[ eXLFDFamilyName
]->AddClassification(
642 (Attribute
*)pFamilyAttribute
,
643 MembersOf(pFamilyAttribute
) );
644 mpField
[ eXLFDWeightName
]->AddClassification(
645 (Attribute
*)pWeightAttribute
,
646 MembersOf(pWeightAttribute
) );
647 mpField
[ eXLFDSlant
]->AddClassification(
648 (Attribute
*)pSlantAttribute
,
649 MembersOf(pSlantAttribute
) );
650 mpField
[ eXLFDSetwidthName
]->AddClassification(
651 (Attribute
*)pSetwidthAttribute
,
652 MembersOf(pSetwidthAttribute
) );
653 mpField
[ eXLFDAddstyleName
]->AddClassification(
654 GetTextEncodingFromAddStylename
);
655 mpField
[ eXLFDCharset
]->AddClassification(
656 rtl_getTextEncodingFromUnixCharset
);
659 // add some pretty print description
661 AttributeProvider::AddAnnotation()
663 mpField
[ eXLFDFoundry
]->AddAnnotation( AnnotateNone
);
664 mpField
[ eXLFDFamilyName
]->AddAnnotation( AnnotateString
);
665 mpField
[ eXLFDWeightName
]->AddAnnotation( AnnotateString
);
666 mpField
[ eXLFDSlant
]->AddAnnotation( AnnotateSlant
);
667 mpField
[ eXLFDSetwidthName
]->AddAnnotation( AnnotateString
);
668 mpField
[ eXLFDAddstyleName
]->AddAnnotation( AnnotateNone
);
669 mpField
[ eXLFDCharset
]->AddAnnotation( AnnotateNone
);
672 // this is the misc or any section: dirty hacks for dirty xlfd usage
674 AttributeProvider::TagFeature()
676 mpField
[ eXLFDFamilyName
]->TagFeature(
677 XLFD_FEATURE_OL_GLYPH
678 | XLFD_FEATURE_OL_CURSOR
679 | XLFD_FEATURE_NARROW
680 | XLFD_FEATURE_INTERFACE_FONT
681 | XLFD_FEATURE_APPLICATION_FONT
);
683 mpField
[ eXLFDSetwidthName
]->TagFeature(
684 XLFD_FEATURE_NARROW
);
686 mpField
[ eXLFDAddstyleName
]->TagFeature(
687 XLFD_FEATURE_REDUNDANTSTYLE
);