1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set cindent ts=2 sts=2 sw=2 et: */
3
/* ***** BEGIN LICENSE BLOCK *****
4
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
6
* The contents of this file are subject to the Netscape Public License
7
* Version 1.1 (the "License"); you may not use this file except in
8
* compliance with the License. You may obtain a copy of the License at
9
* http://www.mozilla.org/NPL/
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
16
* The Original Code is mozilla.org code.
18
* The Initial Developer of the Original Code is
19
* Netscape Communications Corporation.
20
* Portions created by the Initial Developer are Copyright (C) 1998
21
* the Initial Developer. All Rights Reserved.
24
* Yannick Koehler <koehler@mythrium.com>
25
* Christian M Hoffman <chrmhoffmann@web.de>
26
* Makoto hamanaka <VYA04230@nifty.com>
27
* Paul Ashford <arougthopher@lizardland.net>
30
* Alternatively, the contents of this file may be used under the terms of
31
* either the GNU General Public License Version 2 or later (the "GPL"), or
32
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33
* in which case the provisions of the GPL or the LGPL are applicable instead
34
* of those above. If you wish to allow use of your version of this file only
35
* under the terms of either the GPL or the LGPL, and not to allow others to
36
* use your version of this file under the terms of the NPL, indicate your
37
* decision by deleting the provisions above and replace them with the notice
38
* and other provisions required by the GPL or the LGPL. If you do not delete
39
* the provisions above, a recipient may use your version of this file under
40
* the terms of any one of the NPL, the GPL or the LGPL.
42
* ***** END LICENSE BLOCK ***** */
44
#include "nsQuickSort.h"
45
#include "nsFontMetricsBeOS.h"
46
#include "nsIServiceManager.h"
47
#include "nsICharsetConverterManager.h"
48
#include "nsISaveAsCharset.h"
49
#include "nsIPrefService.h"
50
#include "nsIPrefBranch.h"
53
#include "nsHashtable.h"
54
#include "nsReadableUtils.h"
56
#include <UnicodeBlockObjects.h>
59
#define USER_DEFINED "x-user-def"
62
#undef REALLY_NOISY_FONTS
64
nsFontMetricsBeOS::nsFontMetricsBeOS()
65
:mEmulateBold(PR_FALSE)
69
nsFontMetricsBeOS::~nsFontMetricsBeOS()
78
// Notify our device context that owns us so that it can update its font cache
79
mDeviceContext->FontMetricsDeleted(this);
80
mDeviceContext = nsnull;
84
NS_IMPL_ISUPPORTS1(nsFontMetricsBeOS, nsIFontMetrics)
86
// a structure to hold a font family list
87
typedef struct nsFontEnumParamsBeOS {
88
nsFontMetricsBeOS *metrics;
90
nsVoidArray isgeneric;
91
} NS_FONT_ENUM_PARAMS_BEOS;
93
// a callback func to get a font family list from a nsFont object
94
static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
96
NS_FONT_ENUM_PARAMS_BEOS *param = (NS_FONT_ENUM_PARAMS_BEOS *) aData;
97
param->family.AppendString(aFamily);
98
param->isgeneric.AppendElement((void*) aGeneric);
105
NS_IMETHODIMP nsFontMetricsBeOS::Init(const nsFont& aFont, nsIAtom* aLangGroup,
106
nsIDeviceContext* aContext)
108
NS_ASSERTION(!(nsnull == aContext), "attempt to init fontmetrics with null device context");
110
mLangGroup = aLangGroup;
111
mDeviceContext = aContext;
113
// get font family list
114
NS_FONT_ENUM_PARAMS_BEOS param;
115
param.metrics = this;
116
aFont.EnumerateFamilies(FontEnumCallback, ¶m);
120
mFont = new nsFont(aFont);
122
return NS_ERROR_OUT_OF_MEMORY;
124
float app2dev, app2twip;
125
app2dev = aContext->AppUnitsToDevUnits();
126
app2twip = aContext->DevUnitsToTwips();
129
float rounded = ((float)NSIntPointsToTwips(NSTwipsToFloorIntPoints(nscoord(mFont->size * app2twip)))) / app2twip;
131
// process specified fonts from first item of the array.
132
// stop processing next when a real font found;
133
PRBool fontfound = PR_FALSE;
134
PRBool isfixed = PR_FALSE;
135
for (int i=0 ; i<param.family.Count() && !fontfound ; i++)
137
nsString *fam = param.family.StringAt(i);
138
PRBool isgeneric = ( param.isgeneric[i] ) ? PR_TRUE: PR_FALSE;
139
NS_ConvertUTF16toUTF8 family(*fam);
141
isfixed = family.Equals("monospace") || family.Equals("fixed");
145
if (count_font_styles((font_family)family.get()) <= 0)
147
// the specified font does not exist on this computer.
150
mFontHandle.SetFamilyAndStyle( (font_family)family.get(), NULL );
156
// family is generic string like
157
// "serif" "sans-serif" "cursive" "fantasy" "monospace" "-moz-fixed"
158
// so look up preferences and get real family name
160
aLangGroup->GetUTF8String( &lang );
162
snprintf( prop, sizeof(prop), "%s.%s", family.get(), lang );
165
nsXPIDLCString real_family;
167
//NS_WITH_SERVICE( nsIPref, prefs, kPrefCID, &res );
168
nsCOMPtr<nsIPrefService> prefs = do_GetService( NS_PREFSERVICE_CONTRACTID, &res );
169
if (NS_SUCCEEDED(res))
171
nsCOMPtr<nsIPrefBranch> branch;
172
prefs->GetBranch("font.name.", getter_AddRefs(branch));
173
branch->GetCharPref(prop, getter_Copies(real_family));
175
if (!real_family.IsEmpty() && real_family.Length() <= B_FONT_FAMILY_LENGTH && count_font_styles((font_family)real_family.get()) > 0)
177
mFontHandle.SetFamilyAndStyle( (font_family)real_family.get(), NULL );
182
// not successful. use system font.
184
mFontHandle = be_fixed_font;
186
mFontHandle = be_plain_font;
192
// if got no font, then use system font.
196
mFontHandle = be_fixed_font;
198
mFontHandle = be_plain_font;
201
if (aFont.style == NS_FONT_STYLE_ITALIC)
202
face |= B_ITALIC_FACE;
204
if ( aFont.weight > NS_FONT_WEIGHT_NORMAL )
207
// I don't think B_UNDERSCORE_FACE and B_STRIKEOUT_FACE really works...
208
// instead, nsTextFrame do them for us. ( my guess... Makoto Hamanaka )
209
if ( aFont.decorations & NS_FONT_DECORATION_UNDERLINE )
210
face |= B_UNDERSCORE_FACE;
212
if ( aFont.decorations & NS_FONT_DECORATION_LINE_THROUGH )
213
face |= B_STRIKEOUT_FACE;
215
mFontHandle.SetFace( face );
216
// emulate italic and bold if the selected family has no such style
217
if (aFont.style == NS_FONT_STYLE_ITALIC
218
&& !(mFontHandle.Face() & B_ITALIC_FACE))
219
mFontHandle.SetShear(105.0);
220
if ( aFont.weight > NS_FONT_WEIGHT_NORMAL
221
&& !(mFontHandle.Face() & B_BOLD_FACE))
222
mEmulateBold = PR_TRUE;
224
mFontHandle.SetSize( rounded * app2dev );
228
fprintf(stderr, "looking for font %s (%d)", wildstring, aFont.size / app2twip);
232
RealizeFont(aContext);
237
NS_IMETHODIMP nsFontMetricsBeOS::Destroy()
239
mDeviceContext = nsnull;
244
void nsFontMetricsBeOS::RealizeFont(nsIDeviceContext* aContext)
247
f = aContext->DevUnitsToAppUnits();
249
struct font_height height;
250
mFontHandle.GetHeight( &height );
252
struct font_height emHeight;
253
mFontHandle.GetHeight(&emHeight);
254
//be_plain_font->GetHeight(&emHeight);
256
int lineSpacing = nscoord(height.ascent + height.descent);
257
if (lineSpacing > (emHeight.ascent + emHeight.descent))
258
mLeading = nscoord((lineSpacing - (emHeight.ascent + emHeight.descent)) * f);
262
mEmHeight = PR_MAX(1, nscoord((emHeight.ascent + emHeight.descent) * f));
263
mEmAscent = nscoord(height.ascent * (emHeight.ascent + emHeight.descent) * f / lineSpacing);
264
mEmDescent = mEmHeight - mEmAscent;
266
mMaxHeight = nscoord((height.ascent +
267
height.descent) * f) ;
268
mMaxAscent = nscoord(height.ascent * f) ;
269
mMaxDescent = nscoord(height.descent * f);
271
mMaxAdvance = nscoord((mFontHandle.BoundingBox().Width()+1) * f); //fyy +1
273
float rawWidth = mFontHandle.StringWidth("x");
274
mAveCharWidth = NSToCoordRound(rawWidth * f);
276
// 56% of ascent, best guess for non-true type
277
mXHeight = NSToCoordRound((float) height.ascent* f * 0.56f);
279
rawWidth = mFontHandle.StringWidth(" ");
280
mSpaceWidth = NSToCoordRound(rawWidth * f);
283
mUnderlineOffset = -NSToIntRound(MAX (1, floor (0.1 * (height.ascent + height.descent + height.leading) + 0.5)) * f);
285
mUnderlineSize = NSToIntRound(MAX(1, floor (0.05 * (height.ascent + height.descent + height.leading) + 0.5)) * f);
287
mSuperscriptOffset = mXHeight;
289
mSubscriptOffset = mXHeight;
291
/* need better way to calculate this */
292
mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0);
293
mStrikeoutSize = mUnderlineSize;
297
NS_IMETHODIMP nsFontMetricsBeOS::GetXHeight(nscoord& aResult)
303
NS_IMETHODIMP nsFontMetricsBeOS::GetSuperscriptOffset(nscoord& aResult)
305
aResult = mSuperscriptOffset;
309
NS_IMETHODIMP nsFontMetricsBeOS::GetSubscriptOffset(nscoord& aResult)
311
aResult = mSubscriptOffset;
315
NS_IMETHODIMP nsFontMetricsBeOS::GetStrikeout(nscoord& aOffset, nscoord& aSize)
317
aOffset = mStrikeoutOffset;
318
aSize = mStrikeoutSize;
319
// aOffset = nscoord( ( mAscent / 2 ) - mDescent );
320
// aSize = nscoord( 20 ); // FIXME Put 1 pixel which equal 20 twips..
324
NS_IMETHODIMP nsFontMetricsBeOS::GetUnderline(nscoord& aOffset, nscoord& aSize)
326
aOffset = mUnderlineOffset;
327
aSize = mUnderlineSize;
328
//aOffset = nscoord( 0 ); // FIXME
329
//aSize = nscoord( 20 ); // FIXME
333
NS_IMETHODIMP nsFontMetricsBeOS::GetHeight(nscoord &aHeight)
335
aHeight = mMaxHeight;
339
NS_IMETHODIMP nsFontMetricsBeOS::GetNormalLineHeight(nscoord &aHeight)
341
aHeight = mEmHeight + mLeading;
345
NS_IMETHODIMP nsFontMetricsBeOS::GetLeading(nscoord &aLeading)
351
NS_IMETHODIMP nsFontMetricsBeOS::GetEmHeight(nscoord &aHeight)
357
NS_IMETHODIMP nsFontMetricsBeOS::GetEmAscent(nscoord &aAscent)
363
NS_IMETHODIMP nsFontMetricsBeOS::GetEmDescent(nscoord &aDescent)
365
aDescent = mEmDescent;
369
NS_IMETHODIMP nsFontMetricsBeOS::GetMaxHeight(nscoord &aHeight)
371
aHeight = mMaxHeight;
375
NS_IMETHODIMP nsFontMetricsBeOS::GetMaxAscent(nscoord &aAscent)
377
aAscent = mMaxAscent;
381
NS_IMETHODIMP nsFontMetricsBeOS::GetMaxDescent(nscoord &aDescent)
383
aDescent = mMaxDescent;
387
NS_IMETHODIMP nsFontMetricsBeOS::GetMaxAdvance(nscoord &aAdvance)
389
aAdvance = mMaxAdvance;
393
NS_IMETHODIMP nsFontMetricsBeOS::GetAveCharWidth(nscoord &aAveCharWidth)
395
aAveCharWidth = mAveCharWidth;
399
NS_IMETHODIMP nsFontMetricsBeOS::GetSpaceWidth(nscoord &aSpaceWidth)
401
aSpaceWidth = mSpaceWidth;
405
NS_IMETHODIMP nsFontMetricsBeOS::GetFont(const nsFont*& aFont)
411
NS_IMETHODIMP nsFontMetricsBeOS::GetLangGroup(nsIAtom** aLangGroup)
414
return NS_ERROR_NULL_POINTER;
416
*aLangGroup = mLangGroup;
417
NS_IF_ADDREF(*aLangGroup);
422
NS_IMETHODIMP nsFontMetricsBeOS::GetFontHandle(nsFontHandle &aHandle)
424
aHandle = (nsFontHandle)&mFontHandle;
429
nsFontMetricsBeOS::FamilyExists(const nsString& aName)
431
//Do we really need it here? BeOS supports UTF-8 overall natively,
432
//including UTF-8 fonts names with non-ascii chars inside
434
return NS_ERROR_FAILURE;
437
name.AssignWithConversion(aName.get());
439
PRBool isthere = PR_FALSE;
441
int32 numFamilies = count_font_families();
442
for (int32 i = 0; i < numFamilies; i++)
446
if (get_font_family(i, &family, &flags) == B_OK)
448
if (name.Equals(family) == 0)
456
//printf("%s there? %s\n", name.get(), isthere?"Yes":"No" );
458
if (PR_TRUE == isthere)
461
return NS_ERROR_FAILURE;
464
// The Font Enumerator
466
nsFontEnumeratorBeOS::nsFontEnumeratorBeOS()
470
NS_IMPL_ISUPPORTS1(nsFontEnumeratorBeOS, nsIFontEnumerator)
473
CompareFontNames(const void* aArg1, const void* aArg2, void* aClosure)
475
const PRUnichar* str1 = *((const PRUnichar**) aArg1);
476
const PRUnichar* str2 = *((const PRUnichar**) aArg2);
478
// XXX add nsICollation stuff
480
return nsCRT::strcmp(str1, str2);
484
FontMatchesGenericType(font_family family, uint32 flags, const char* aGeneric,
485
const char* aLangGroup)
487
//Call from EnumerateAllFonts. Matches all.
488
//Return 1 immediately, because nsnull as argument of strstr causes crashes
489
if(aGeneric == nsnull || aLangGroup == nsnull)
491
if (!strcmp(aLangGroup, "ja"))
493
if (strstr(aLangGroup, "zh"))
495
if (!strcmp(aLangGroup, "ko"))
497
if (!strcmp(aLangGroup, "th"))
499
if (!strcmp(aLangGroup, "he"))
501
if (!strcmp(aLangGroup, "ar"))
503
if (strstr(aLangGroup, "user-def"))
505
if (!strcmp(aLangGroup, "unicode"))
508
if (strstr(aGeneric, "fantasy")
509
// Let's use all possible fonts as decorative
511
&& (strstr(family, "Baskerville") ||
512
strstr(family, "Chicago") ||
513
strstr(family, "Copprpl") ||
514
strstr(family, "Embassy") ||
515
strstr(family, "Europe") ||
516
strstr(family, "Garmnd") ||
517
strstr(family, "Impact") ||
518
strstr(family, "ProFont") ||
519
strstr(family, "VAGRounded"))
523
// Hack. Sniffing is based on wide-spread names for serif and sansserif. No function in BeOS to get full font-info.
524
// NB! "Haru Tohaba" and "Haru" need EXACT match - !strcmp seems suspicious in that case, timeless !!!
525
if (!strcmp(aGeneric, "serif") &&
526
(strstr(family, "Dutch") || strstr(family, "Times") || strstr(family, "Roman") ||
527
strstr(family, "CentSchbook") || strstr(family, "Georgia") || strstr(family, "Baskerville") ||
528
strstr(family, "Garmnd") || strstr(family, "Cyberbit") || strcmp(family, "Haru Tohaba") == 0))
530
if (!strcmp(aGeneric, "sans-serif") &&
531
(strstr(family, "Arial") || strstr(family, "Chianti") || strstr(family, "Helv") ||
532
strstr(family, "Humnst") || strstr(family, "Swiss") || strstr(family, "Tahoma") ||
533
strstr(family, "Sans") || strstr(family, "sans") || strstr(family, "Verdana") ||
534
strstr(family, "Zurich") || strcmp(family, "Haru") == 0))
536
if ((strstr(aGeneric, "monospace") || strstr(aGeneric, "-moz-fixed")) &&
537
(flags & B_IS_FIXED || strstr(family, "Cour") || strstr(family, "Consol") ||
538
strstr(family, "Fixed") || strstr(family, "Kurier") || strstr(family, "Lucida") ||
539
strstr(family, "Mono") || strstr(family, "console") || strstr(family, "mono") ||
540
strstr(family, "fixed")))
542
if (strstr(aGeneric, "cursive") &&
543
(strstr(family, "Cursiv") || strstr(family, "Kursiv") || strstr(family, "Script") ||
544
strstr(family, "kursiv") || strstr(family, "Embassy") || strstr(family, "script") ||
545
strstr(family, "Brush")))
551
static int MatchesLangGroup(font_family family, const char* aLangGroup)
554
font.SetFamilyAndStyle(family, NULL);
555
unicode_block lang = font.Blocks();
559
if ((strstr(aLangGroup, "user-def") || strstr(aLangGroup, "unicode")))
561
// "tr" and "central-euro" need more testing, but seems OK
562
if ((strstr(aLangGroup, "baltic") || strstr(aLangGroup, "central-euro") || strstr(aLangGroup, "western")) &&
563
lang.Includes(B_LATIN1_SUPPLEMENT_BLOCK))
565
if (strstr(aLangGroup, "tr") && lang.Includes(B_LATIN_EXTENDED_A_BLOCK))
567
if (strstr(aLangGroup, "el") && lang.Includes(B_BASIC_GREEK_BLOCK))
569
if (strstr(aLangGroup, "cyrillic") && lang.Includes(B_CYRILLIC_BLOCK))
571
if (strstr(aLangGroup, "he") && lang.Includes(B_BASIC_HEBREW_BLOCK))
573
if (strstr(aLangGroup, "ar") && lang.Includes(B_BASIC_ARABIC_BLOCK))
575
if (strstr(aLangGroup, "th") && lang.Includes(B_THAI_BLOCK))
577
// CKJ settings need more verification
578
if ((strstr(aLangGroup, "ja") || strstr(aLangGroup, "ko") || strstr(aLangGroup, "zh") ) &&
579
(lang.Includes(B_CJK_UNIFIED_IDEOGRAPHS_BLOCK) ||
580
lang.Includes(B_CJK_MISCELLANEOUS_BLOCK) ||
581
lang.Includes(B_ENCLOSED_CJK_LETTERS_AND_MONTHS_BLOCK) ||
582
lang.Includes(B_CJK_COMPATIBILITY_BLOCK) ||
583
lang.Includes(B_CJK_COMPATIBILITY_IDEOGRAPHS_BLOCK) ||
584
lang.Includes(B_CJK_COMPATIBILITY_FORMS_BLOCK)))
586
// additional check for partial CKJ blocks
587
if (strstr(aLangGroup, "ja") && (lang.Includes(B_HIRAGANA_BLOCK) || lang.Includes(B_KATAKANA_BLOCK) ))
589
if (strstr(aLangGroup, "ko") && (lang.Includes(B_HANGUL_BLOCK)))
591
if (strstr(aLangGroup, "zh") && (lang.Includes(B_HIGH_SURROGATES_BLOCK) || lang.Includes(B_LOW_SURROGATES_BLOCK) ))
598
static nsresult EnumFonts(const char * aLangGroup, const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult)
602
int32 numFamilies = count_font_families();
605
(PRUnichar**) nsMemory::Alloc(numFamilies * sizeof(PRUnichar*));
607
return NS_ERROR_OUT_OF_MEMORY;
609
for(int32 i = 0; i < numFamilies; i++)
613
if (get_font_family(i, &family, &flags) == B_OK)
615
if (family && (!aLangGroup || MatchesLangGroup(family, aLangGroup)))
617
if(FontMatchesGenericType(family, flags, aGeneric, aLangGroup))
619
font_name.AssignWithConversion(family);
620
if (!(array[j] = ToNewUnicode(font_name)))
628
NS_QuickSort(array, j, sizeof(PRUnichar*), CompareFontNames, nsnull);
634
nsMemory::Free(array);
640
nsFontEnumeratorBeOS::EnumerateAllFonts(PRUint32* aCount, PRUnichar*** aResult)
642
NS_ENSURE_ARG_POINTER(aResult);
644
NS_ENSURE_ARG_POINTER(aCount);
647
return EnumFonts(nsnull, nsnull, aCount, aResult);
651
nsFontEnumeratorBeOS::EnumerateFonts(const char* aLangGroup,
652
const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult)
654
NS_ENSURE_ARG_POINTER(aResult);
656
NS_ENSURE_ARG_POINTER(aCount);
659
// aLangGroup=null or "" means any (i.e., don't care)
660
// aGeneric=null or "" means any (i.e, don't care)
661
const char* langGroup = nsnull;
662
if (aLangGroup && *aLangGroup)
663
langGroup = aLangGroup;
664
const char* generic = nsnull;
665
if (aGeneric && *aGeneric)
668
return EnumFonts(langGroup, generic, aCount, aResult);
672
nsFontEnumeratorBeOS::HaveFontFor(const char* aLangGroup, PRBool* aResult)
674
NS_ENSURE_ARG_POINTER(aLangGroup);
675
NS_ENSURE_ARG_POINTER(aResult);
682
nsFontEnumeratorBeOS::GetDefaultFont(const char *aLangGroup,
683
const char *aGeneric, PRUnichar **aResult)
685
// aLangGroup=null or "" means any (i.e., don't care)
686
// aGeneric=null or "" means any (i.e, don't care)
688
NS_ENSURE_ARG_POINTER(aResult);
695
nsFontEnumeratorBeOS::UpdateFontList(PRBool *updateFontList)
697
*updateFontList = PR_FALSE; // always return false for now