Back to index

lightning-sunbird  0.9+nobinonly
nsFontMetricsBeOS.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set cindent ts=2 sts=2 sw=2 et: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Yannick Koehler <koehler@mythrium.com>
00025  *   Christian M Hoffman <chrmhoffmann@web.de>
00026  *   Makoto hamanaka <VYA04230@nifty.com>
00027  *   Paul Ashford <arougthopher@lizardland.net>
00028  *   Sergei Dolgov <sergei_d@fi.tartu.ee>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either of the GNU General Public License Version 2 or later (the "GPL"),
00032  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 
00044 #include "nsQuickSort.h" 
00045 #include "nsFontMetricsBeOS.h" 
00046 #include "nsIServiceManager.h" 
00047 #include "nsICharsetConverterManager.h" 
00048 #include "nsISaveAsCharset.h" 
00049 #include "nsIPrefService.h" 
00050 #include "nsIPrefBranch.h"
00051 #include "nsCOMPtr.h" 
00052 #include "nspr.h" 
00053 #include "nsReadableUtils.h"
00054  
00055 #include <UnicodeBlockObjects.h>
00056 
00057 #undef USER_DEFINED 
00058 #define USER_DEFINED "x-user-def" 
00059  
00060 #undef NOISY_FONTS
00061 #undef REALLY_NOISY_FONTS
00062 
00063 nsFontMetricsBeOS::nsFontMetricsBeOS()
00064 {
00065 }
00066 
00067 nsFontMetricsBeOS::~nsFontMetricsBeOS()
00068 {
00069   if (mDeviceContext) 
00070   {
00071     // Notify our device context that owns us so that it can update its font cache
00072     mDeviceContext->FontMetricsDeleted(this);
00073     mDeviceContext = nsnull;
00074   }
00075 }
00076  
00077 NS_IMPL_ISUPPORTS1(nsFontMetricsBeOS, nsIFontMetrics) 
00078  
00079 // a structure to hold a font family list
00080 typedef struct nsFontEnumParamsBeOS {
00081   nsFontMetricsBeOS *metrics;
00082   nsStringArray family;
00083   nsVoidArray isgeneric;
00084 } NS_FONT_ENUM_PARAMS_BEOS;
00085 
00086 // a callback func to get a font family list from a nsFont object
00087 static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
00088 {
00089   NS_FONT_ENUM_PARAMS_BEOS *param = (NS_FONT_ENUM_PARAMS_BEOS *) aData;
00090   param->family.AppendString(aFamily);
00091   param->isgeneric.AppendElement((void*) aGeneric);
00092   if (aGeneric)
00093     return PR_FALSE;
00094 
00095   return PR_TRUE;
00096 }
00097 
00098 NS_IMETHODIMP nsFontMetricsBeOS::Init(const nsFont& aFont, nsIAtom* aLangGroup,
00099   nsIDeviceContext* aContext)
00100 {
00101   NS_ASSERTION(!(nsnull == aContext), "attempt to init fontmetrics with null device context");
00102 
00103   mLangGroup = aLangGroup;
00104   mDeviceContext = aContext;
00105 
00106   // get font family list
00107   NS_FONT_ENUM_PARAMS_BEOS param;
00108   param.metrics = this;
00109   aFont.EnumerateFamilies(FontEnumCallback, &param);
00110  
00111   PRInt16  face = 0;
00112 
00113   mFont = aFont;
00114 
00115   float app2twip = aContext->DevUnitsToTwips();
00116 
00117   // process specified fonts from first item of the array.
00118   // stop processing next when a real font found;
00119   PRBool fontfound = PR_FALSE;
00120   PRBool isfixed = PR_FALSE;
00121   for (int i=0 ; i<param.family.Count() && !fontfound ; i++) 
00122   {
00123     nsString *fam = param.family.StringAt(i);
00124     PRBool isgeneric = ( param.isgeneric[i] ) ? PR_TRUE: PR_FALSE;
00125     NS_ConvertUTF16toUTF8 family(*fam);
00126     // Fallback
00127     isfixed = family.Equals("monospace") || family.Equals("fixed");
00128     if (!isgeneric) 
00129     {
00130       // non-generic font
00131       if (count_font_styles((font_family)family.get()) <= 0) 
00132       {
00133         // the specified font does not exist on this computer.
00134         continue;
00135       }
00136       mFontHandle.SetFamilyAndStyle( (font_family)family.get(), NULL );
00137       fontfound = PR_TRUE;
00138       break;
00139     } 
00140     else 
00141     {
00142       // family is generic string like 
00143       // "serif" "sans-serif" "cursive" "fantasy" "monospace" "-moz-fixed"
00144       // so look up preferences and get real family name
00145       const char *lang;
00146       aLangGroup->GetUTF8String( &lang );
00147       char prop[256];
00148       snprintf( prop, sizeof(prop), "%s.%s", family.get(), lang );
00149 
00150       // look up prefs
00151       nsXPIDLCString real_family;
00152       nsresult res;
00153       //NS_WITH_SERVICE( nsIPref, prefs, kPrefCID, &res );
00154       nsCOMPtr<nsIPrefService> prefs = do_GetService( NS_PREFSERVICE_CONTRACTID, &res );
00155       if (NS_SUCCEEDED(res)) 
00156       {
00157         nsCOMPtr<nsIPrefBranch> branch;
00158         prefs->GetBranch("font.name.", getter_AddRefs(branch));
00159         branch->GetCharPref(prop, getter_Copies(real_family));
00160 
00161         if (!real_family.IsEmpty() && real_family.Length() <= B_FONT_FAMILY_LENGTH  && count_font_styles((font_family)real_family.get()) > 0) 
00162         {
00163           mFontHandle.SetFamilyAndStyle( (font_family)real_family.get(), NULL );
00164           fontfound = PR_TRUE;
00165           break;        
00166         }
00167       } 
00168       // not successful. use system font.
00169       if (isfixed)
00170         mFontHandle = BFont(be_fixed_font);
00171       else
00172         mFontHandle = BFont(be_plain_font);
00173       fontfound = PR_TRUE;
00174       break;
00175     }
00176   }
00177 
00178   // if got no font, then use system font.
00179   if (!fontfound)
00180   {
00181     if (isfixed)
00182       mFontHandle = BFont(be_fixed_font);
00183     else
00184       mFontHandle = BFont(be_plain_font);
00185   } 
00186  
00187   if (aFont.style == NS_FONT_STYLE_ITALIC)
00188     face |= B_ITALIC_FACE;
00189 
00190   if ( aFont.weight > NS_FONT_WEIGHT_NORMAL )
00191   {
00192     mIsBold = PR_TRUE;
00193        face |= B_BOLD_FACE;
00194   }
00195   else
00196     mIsBold = PR_FALSE;
00197         
00198   // I don't think B_UNDERSCORE_FACE and B_STRIKEOUT_FACE really works...
00199   // instead, nsTextFrame do them for us. ( my guess... Makoto Hamanaka )
00200   if ( aFont.decorations & NS_FONT_DECORATION_UNDERLINE )
00201        face |= B_UNDERSCORE_FACE;
00202        
00203   if ( aFont.decorations & NS_FONT_DECORATION_LINE_THROUGH )
00204        face |= B_STRIKEOUT_FACE;
00205 
00206   mFontHandle.SetFace( face );
00207   // emulate italic the selected family has no such style
00208   if (aFont.style == NS_FONT_STYLE_ITALIC
00209     && !(mFontHandle.Face() & B_ITALIC_FACE)) 
00210     mFontHandle.SetShear(105.0);
00211 
00212   mFontHandle.SetSize(mFont.size/app2twip);
00213   mFontHandle.SetSpacing(B_FIXED_SPACING);
00214 
00215 #ifdef NOISY_FONTS
00216 #ifdef DEBUG
00217   fprintf(stderr, "looking for font %s (%d)", wildstring, aFont.size / app2twip);
00218 #endif
00219 #endif
00220   //UTF8 charspace in BeOS is 0xFFFF, 256 is by "pighole rule" sqrt(0xFFFF), 
00221   // actually rare font contains more glyphs
00222   mFontWidthCache.Init(256);
00223   
00224   RealizeFont(aContext);
00225 
00226   return NS_OK;
00227 }
00228 
00229 NS_IMETHODIMP  nsFontMetricsBeOS::Destroy()
00230 {
00231   mDeviceContext = nsnull;
00232   return NS_OK;
00233 }
00234 
00235 
00236 void nsFontMetricsBeOS::RealizeFont(nsIDeviceContext* aContext)
00237 {
00238   float f;
00239   f = aContext->DevUnitsToAppUnits();
00240   
00241   struct font_height height;
00242   mFontHandle.GetHeight( &height );
00243  
00244   struct font_height emHeight; 
00245   mFontHandle.GetHeight(&emHeight);
00246   //be_plain_font->GetHeight(&emHeight); 
00247  
00248   int lineSpacing = nscoord(height.ascent + height.descent); 
00249   if (lineSpacing > (emHeight.ascent + emHeight.descent))
00250     mLeading = nscoord((lineSpacing - (emHeight.ascent + emHeight.descent)) * f); 
00251   else
00252     mLeading = 0; 
00253 
00254   mEmHeight = PR_MAX(1, nscoord((emHeight.ascent + emHeight.descent) * f)); 
00255   mEmAscent = nscoord(height.ascent * (emHeight.ascent + emHeight.descent) * f / lineSpacing); 
00256   mEmDescent = mEmHeight - mEmAscent; 
00257 
00258   mMaxHeight = nscoord((height.ascent + 
00259                         height.descent) * f) ; 
00260   mMaxAscent = nscoord(height.ascent * f) ;
00261   mMaxDescent = nscoord(height.descent * f);
00262   
00263   mMaxAdvance = nscoord((mFontHandle.BoundingBox().Width()+1) * f); //fyy +1
00264 
00265   float rawWidth = mFontHandle.StringWidth("x"); 
00266   mAveCharWidth = NSToCoordRound(rawWidth * f); 
00267 
00268   // 56% of ascent, best guess for non-true type 
00269   mXHeight = NSToCoordRound((float) height.ascent* f * 0.56f); 
00270 
00271   rawWidth = mFontHandle.StringWidth(" "); 
00272   mSpaceWidth = NSToCoordRound(rawWidth * f); 
00273  
00274 /* Temp */ 
00275   mUnderlineOffset = -NSToIntRound(MAX (1, floor (0.1 * (height.ascent + height.descent + height.leading) + 0.5)) * f); 
00276   
00277   mUnderlineSize = NSToIntRound(MAX(1, floor (0.05 * (height.ascent + height.descent + height.leading) + 0.5)) * f); 
00278  
00279   mSuperscriptOffset = mXHeight; 
00280  
00281   mSubscriptOffset = mXHeight; 
00282  
00283   /* need better way to calculate this */ 
00284   mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0); 
00285   mStrikeoutSize = mUnderlineSize; 
00286 }
00287 
00288 NS_IMETHODIMP  nsFontMetricsBeOS::GetXHeight(nscoord& aResult)
00289 {
00290   aResult = mXHeight;
00291   return NS_OK;
00292 }
00293 
00294 NS_IMETHODIMP  nsFontMetricsBeOS::GetSuperscriptOffset(nscoord& aResult)
00295 {
00296   aResult = mSuperscriptOffset;
00297   return NS_OK;
00298 }
00299 
00300 NS_IMETHODIMP  nsFontMetricsBeOS::GetSubscriptOffset(nscoord& aResult)
00301 {
00302   aResult = mSubscriptOffset;
00303   return NS_OK;
00304 }
00305 
00306 NS_IMETHODIMP  nsFontMetricsBeOS::GetStrikeout(nscoord& aOffset, nscoord& aSize)
00307 {
00308   aOffset = mStrikeoutOffset; 
00309   aSize = mStrikeoutSize; 
00310 //  aOffset = nscoord( ( mAscent / 2 ) - mDescent ); 
00311 //  aSize = nscoord( 20 );  // FIXME Put 1 pixel which equal 20 twips.. 
00312   return NS_OK;
00313 }
00314 
00315 NS_IMETHODIMP  nsFontMetricsBeOS::GetUnderline(nscoord& aOffset, nscoord& aSize)
00316 {
00317   aOffset = mUnderlineOffset;
00318   aSize = mUnderlineSize;
00319   //aOffset = nscoord( 0 ); // FIXME
00320   //aSize = nscoord( 20 );  // FIXME
00321   return NS_OK;
00322 }
00323 
00324 NS_IMETHODIMP  nsFontMetricsBeOS::GetHeight(nscoord &aHeight)
00325 { 
00326   aHeight = mMaxHeight; 
00327   return NS_OK; 
00328 } 
00329  
00330 NS_IMETHODIMP  nsFontMetricsBeOS::GetNormalLineHeight(nscoord &aHeight) 
00331 {
00332   aHeight = mEmHeight + mLeading; 
00333   return NS_OK;
00334 }
00335 
00336 NS_IMETHODIMP  nsFontMetricsBeOS::GetLeading(nscoord &aLeading)
00337 {
00338   aLeading = mLeading;
00339   return NS_OK;
00340 }
00341 
00342 NS_IMETHODIMP  nsFontMetricsBeOS::GetEmHeight(nscoord &aHeight) 
00343 { 
00344   aHeight = mEmHeight; 
00345   return NS_OK; 
00346 } 
00347  
00348 NS_IMETHODIMP  nsFontMetricsBeOS::GetEmAscent(nscoord &aAscent) 
00349 { 
00350   aAscent = mEmAscent; 
00351   return NS_OK; 
00352 } 
00353  
00354 NS_IMETHODIMP  nsFontMetricsBeOS::GetEmDescent(nscoord &aDescent) 
00355 { 
00356   aDescent = mEmDescent; 
00357   return NS_OK; 
00358 } 
00359  
00360 NS_IMETHODIMP  nsFontMetricsBeOS::GetMaxHeight(nscoord &aHeight) 
00361 { 
00362   aHeight = mMaxHeight; 
00363   return NS_OK; 
00364 } 
00365  
00366 NS_IMETHODIMP  nsFontMetricsBeOS::GetMaxAscent(nscoord &aAscent)
00367 {
00368   aAscent = mMaxAscent;
00369   return NS_OK;
00370 }
00371 
00372 NS_IMETHODIMP  nsFontMetricsBeOS::GetMaxDescent(nscoord &aDescent)
00373 {
00374   aDescent = mMaxDescent;
00375   return NS_OK;
00376 }
00377 
00378 NS_IMETHODIMP  nsFontMetricsBeOS::GetMaxAdvance(nscoord &aAdvance)
00379 {
00380   aAdvance = mMaxAdvance;
00381   return NS_OK;
00382 }
00383 
00384 NS_IMETHODIMP nsFontMetricsBeOS::GetAveCharWidth(nscoord &aAveCharWidth)
00385 {
00386   aAveCharWidth = mAveCharWidth;
00387   return NS_OK;
00388 }
00389 
00390 NS_IMETHODIMP  nsFontMetricsBeOS::GetSpaceWidth(nscoord &aSpaceWidth) 
00391 { 
00392   aSpaceWidth = mSpaceWidth; 
00393   return NS_OK; 
00394 } 
00395 
00396 NS_IMETHODIMP  nsFontMetricsBeOS::GetLangGroup(nsIAtom** aLangGroup)
00397 {
00398   if (!aLangGroup)
00399     return NS_ERROR_NULL_POINTER;
00400 
00401   *aLangGroup = mLangGroup;
00402   NS_IF_ADDREF(*aLangGroup);
00403 
00404   return NS_OK;
00405 }
00406 
00407 NS_IMETHODIMP  nsFontMetricsBeOS::GetFontHandle(nsFontHandle &aHandle)
00408 {
00409   aHandle = (nsFontHandle)&mFontHandle;
00410   return NS_OK;
00411 } 
00412  
00413 nsresult 
00414 nsFontMetricsBeOS::FamilyExists(const nsString& aName) 
00415 { 
00416   NS_ConvertUTF16toUTF8 family(aName);
00417   printf("exists? %s", (font_family)family.get()); 
00418   return  (count_font_styles((font_family)family.get()) > 0) ? NS_OK : NS_ERROR_FAILURE;
00419 } 
00420 
00421 // useful UTF-8 utility
00422 inline uint32 utf8_char_len(uchar byte) 
00423 {
00424        return (((0xE5000000 >> ((byte >> 3) & 0x1E)) & 3) + 1);
00425 }
00426 
00427 // nsHashKeys has trouble with char* substring conversion
00428 // it likes 0-terminated, plus conversion to nsACString overhead.
00429 // So KISS
00430 inline PRUint32 utf8_to_index(char *utf8char)
00431 {
00432        PRUint32 ch = 0;
00433        switch (utf8_char_len(*utf8char) - 1) 
00434        {
00435               case 3: ch += *utf8char++; ch <<= 6;
00436               case 2: ch += *utf8char++; ch <<= 6;
00437               case 1: ch += *utf8char++; ch <<= 6;
00438               case 0: ch += *utf8char++;
00439        }
00440        return ch;
00441 }
00442 // Using cached widths
00443 float  nsFontMetricsBeOS::GetStringWidth(char *utf8str, uint32 bytelen)
00444 {
00445        float retwidth = 0;
00446        uint32 charlen = 1;
00447        // Traversing utf8string - get, cache and sum widths for all utf8 chars
00448        for (uint32 i =0; i < bytelen && *utf8str  != '\0'; i += charlen)
00449        {
00450               float width = 0;
00451               // Calculating utf8 char bytelength
00452               charlen = ((0xE5000000 >> ((*utf8str >> 3) & 0x1E)) & 3) + 1;
00453               // Converting multibyte sequence to index
00454               PRUint32 index = utf8_to_index(utf8str);
00455               if (!mFontWidthCache.Get(index, &width))
00456               {
00457                      width = mFontHandle.StringWidth(utf8str, charlen);
00458                      mFontWidthCache.Put(index, width);
00459               }
00460               retwidth +=  width;
00461               utf8str += charlen;
00462        }
00463        if (mIsBold && !(mFontHandle.Face() & B_BOLD_FACE))
00464               retwidth += 1.0;
00465        return retwidth;
00466 }
00467  
00468 // The Font Enumerator 
00469  
00470 nsFontEnumeratorBeOS::nsFontEnumeratorBeOS() 
00471 { 
00472 } 
00473  
00474 NS_IMPL_ISUPPORTS1(nsFontEnumeratorBeOS, nsIFontEnumerator)
00475  
00476 static int 
00477 CompareFontNames(const void* aArg1, const void* aArg2, void* aClosure) 
00478 { 
00479   const PRUnichar* str1 = *((const PRUnichar**) aArg1); 
00480   const PRUnichar* str2 = *((const PRUnichar**) aArg2); 
00481  
00482   // XXX add nsICollation stuff 
00483  
00484   return nsCRT::strcmp(str1, str2); 
00485 } 
00486 
00487 static int
00488 FontMatchesGenericType(font_family family, uint32 flags, const char* aGeneric,
00489   const char* aLangGroup)
00490 {
00491   //Call from EnumerateAllFonts. Matches all.
00492   //Return 1 immediately, because nsnull as argument of strstr causes crashes
00493   if(aGeneric == nsnull || aLangGroup == nsnull)
00494     return 1;
00495   if (!strcmp(aLangGroup, "ja"))    
00496     return 1;
00497   if (strstr(aLangGroup, "zh"))
00498     return 1;
00499   if (!strcmp(aLangGroup, "ko"))
00500     return 1;
00501   if (!strcmp(aLangGroup, "th"))
00502     return 1;
00503   if (!strcmp(aLangGroup, "he"))
00504     return 1;
00505   if (!strcmp(aLangGroup, "ar"))
00506     return 1;
00507   if (strstr(aLangGroup, "user-def"))
00508     return 1;
00509   if (!strcmp(aLangGroup, "unicode"))
00510     return 1;
00511 
00512   if (strstr(aGeneric, "fantasy") 
00513   // Let's use all possible fonts as decorative
00514 #if 0
00515     && (strstr(family, "Baskerville") || 
00516         strstr(family, "Chicago") ||
00517         strstr(family, "Copprpl") ||
00518         strstr(family, "Embassy") ||
00519         strstr(family, "Europe") ||
00520         strstr(family, "Garmnd") ||
00521         strstr(family, "Impact") ||
00522         strstr(family, "ProFont") ||
00523         strstr(family, "VAGRounded"))
00524 #endif      
00525     )
00526     return 1;
00527   // Hack. Sniffing is based on wide-spread names for serif and sansserif.   No function in BeOS to get full font-info.
00528   // NB! "Haru Tohaba" and "Haru" need EXACT match - !strcmp seems suspicious in that case, timeless !!!
00529   if (!strcmp(aGeneric, "serif") && 
00530      (strstr(family, "Dutch") || strstr(family, "Times") || strstr(family, "Roman") ||
00531       strstr(family, "CentSchbook") || strstr(family, "Georgia") || strstr(family, "Baskerville") ||
00532       strstr(family, "Garmnd") || strstr(family, "Cyberbit") || strcmp(family, "Haru Tohaba") == 0))
00533     return 1;
00534   if (!strcmp(aGeneric, "sans-serif") && 
00535      (strstr(family, "Arial") || strstr(family, "Chianti") || strstr(family, "Helv") ||
00536       strstr(family, "Humnst") || strstr(family, "Swiss") || strstr(family, "Tahoma") ||
00537       strstr(family, "Sans") || strstr(family, "sans") || strstr(family, "Verdana") || 
00538       strstr(family, "Zurich") || strcmp(family, "Haru") == 0))
00539     return 1;
00540   if ((strstr(aGeneric, "monospace") || strstr(aGeneric, "-moz-fixed")) && 
00541     (flags & B_IS_FIXED || strstr(family, "Cour") || strstr(family, "Consol") ||
00542      strstr(family, "Fixed") || strstr(family, "Kurier") || strstr(family, "Lucida") ||
00543      strstr(family, "Mono") || strstr(family, "console") || strstr(family, "mono") ||
00544      strstr(family, "fixed")))
00545     return 1;
00546   if (strstr(aGeneric, "cursive") && 
00547     (strstr(family, "Cursiv") || strstr(family, "Kursiv") || strstr(family, "Script") ||
00548      strstr(family, "kursiv") || strstr(family, "Embassy") || strstr(family, "script") || 
00549      strstr(family, "Brush")))
00550     return 1;
00551 
00552   return 0;
00553 }
00554 
00555 static int MatchesLangGroup(font_family family,  const char* aLangGroup) 
00556 {
00557   BFont font;
00558   font.SetFamilyAndStyle(family, NULL);
00559   unicode_block lang = font.Blocks();
00560   int match = 0;
00561 
00562   //No restrictions
00563   if ((strstr(aLangGroup, "user-def") || strstr(aLangGroup, "unicode")))
00564     return 1; 
00565   // "tr" and "central-euro" need more testing, but seems OK
00566   if ((strstr(aLangGroup, "baltic") || strstr(aLangGroup, "central-euro") || strstr(aLangGroup, "western")) && 
00567     lang.Includes(B_LATIN1_SUPPLEMENT_BLOCK))
00568     return 1;
00569   if (strstr(aLangGroup, "tr") && lang.Includes(B_LATIN_EXTENDED_A_BLOCK))
00570     return 1;
00571   if (strstr(aLangGroup, "el") && lang.Includes(B_BASIC_GREEK_BLOCK))
00572     return 1;
00573   if (strstr(aLangGroup, "cyrillic") && lang.Includes(B_CYRILLIC_BLOCK))
00574     return 1;
00575   if (strstr(aLangGroup, "he") && lang.Includes(B_BASIC_HEBREW_BLOCK))
00576     return 1;
00577   if (strstr(aLangGroup, "ar") && lang.Includes(B_BASIC_ARABIC_BLOCK))
00578     return 1;
00579   if (strstr(aLangGroup, "th") && lang.Includes(B_THAI_BLOCK))
00580     return 1;
00581   // CKJ settings need more verification
00582   if ((strstr(aLangGroup, "ja") || strstr(aLangGroup, "ko") || strstr(aLangGroup, "zh") ) &&
00583     (lang.Includes(B_CJK_UNIFIED_IDEOGRAPHS_BLOCK) ||
00584      lang.Includes(B_CJK_MISCELLANEOUS_BLOCK) ||
00585      lang.Includes(B_ENCLOSED_CJK_LETTERS_AND_MONTHS_BLOCK) ||
00586      lang.Includes(B_CJK_COMPATIBILITY_BLOCK) ||
00587      lang.Includes(B_CJK_COMPATIBILITY_IDEOGRAPHS_BLOCK) ||
00588      lang.Includes(B_CJK_COMPATIBILITY_FORMS_BLOCK))) 
00589     match = 1;  
00590   // additional check for partial CKJ blocks
00591   if (strstr(aLangGroup, "ja") && (lang.Includes(B_HIRAGANA_BLOCK) || lang.Includes(B_KATAKANA_BLOCK) ))
00592     match = 1; 
00593   if (strstr(aLangGroup, "ko") && (lang.Includes(B_HANGUL_BLOCK)))
00594     match = 1;   
00595   if (strstr(aLangGroup, "zh") && (lang.Includes(B_HIGH_SURROGATES_BLOCK) || lang.Includes(B_LOW_SURROGATES_BLOCK) ))
00596     match = 1; 
00597    
00598 
00599  return match; 
00600 }
00601 
00602 static nsresult EnumFonts(const char * aLangGroup, const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult) 
00603 { 
00604   int32 numFamilies = count_font_families(); 
00605  
00606   PRUnichar** array = (PRUnichar**) nsMemory::Alloc(numFamilies * sizeof(PRUnichar*)); 
00607   NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
00608 
00609   int j = 0;
00610   for(int32 i = 0; i < numFamilies; i++) 
00611   {
00612     font_family family; 
00613     uint32 flags; 
00614     if (get_font_family(i, &family, &flags) == B_OK) 
00615     {
00616       if (family && (!aLangGroup || MatchesLangGroup(family,  aLangGroup)))
00617       {
00618         if(FontMatchesGenericType(family, flags, aGeneric, aLangGroup))
00619         {
00620           if (!(array[j] = UTF8ToNewUnicode(nsDependentCString(family))))
00621             break; 
00622           ++j;
00623         }
00624       }
00625     }
00626   } 
00627   *aCount = j; 
00628 
00629   if (*aCount)
00630   {
00631     *aResult = array; 
00632     // Resizing array for real number of matching families after check for language and generic type
00633     if (*aCount < numFamilies)
00634     {
00635       array = (PRUnichar**) nsMemory::Realloc(array, *aCount * sizeof(PRUnichar*));
00636       NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
00637     }
00638     NS_QuickSort(array, j, sizeof(PRUnichar*), CompareFontNames, nsnull);
00639   }
00640   else 
00641   {
00642     nsMemory::Free(array); 
00643   }
00644 
00645   return NS_OK; 
00646 } 
00647  
00648 NS_IMETHODIMP 
00649 nsFontEnumeratorBeOS::EnumerateAllFonts(PRUint32* aCount, PRUnichar*** aResult) 
00650 { 
00651   NS_ENSURE_ARG_POINTER(aResult); 
00652   *aResult = nsnull; 
00653   NS_ENSURE_ARG_POINTER(aCount); 
00654   *aCount = 0; 
00655  
00656   return EnumFonts(nsnull, nsnull, aCount, aResult); 
00657 } 
00658  
00659 NS_IMETHODIMP 
00660 nsFontEnumeratorBeOS::EnumerateFonts(const char* aLangGroup, 
00661   const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult) 
00662 { 
00663   NS_ENSURE_ARG_POINTER(aResult); 
00664   *aResult = nsnull; 
00665   NS_ENSURE_ARG_POINTER(aCount); 
00666   *aCount = 0; 
00667 
00668   // aLangGroup=null or ""  means any (i.e., don't care)
00669   // aGeneric=null or ""  means any (i.e, don't care)
00670   const char* langGroup = nsnull;
00671   if (aLangGroup && *aLangGroup)
00672     langGroup = aLangGroup;
00673   const char* generic = nsnull;
00674   if (aGeneric && *aGeneric)
00675     generic = aGeneric;
00676 
00677   return EnumFonts(langGroup, generic, aCount, aResult); 
00678 }
00679 
00680 NS_IMETHODIMP
00681 nsFontEnumeratorBeOS::HaveFontFor(const char* aLangGroup, PRBool* aResult)
00682 {
00683   NS_ENSURE_ARG_POINTER(aLangGroup); 
00684   NS_ENSURE_ARG_POINTER(aResult); 
00685   *aResult = PR_FALSE;
00686 
00687   int32 numFamilies = count_font_families(); 
00688 
00689   for(int32 i = 0; i < numFamilies; i++) 
00690   {
00691     font_family family; 
00692     uint32 flags; 
00693     if (get_font_family(i, &family, &flags) == B_OK) 
00694     {
00695       if (family && (!aLangGroup || MatchesLangGroup(family,  aLangGroup)))
00696       {
00697          *aResult = PR_TRUE;
00698          return NS_OK;
00699          
00700       }
00701     }
00702   }
00703   return NS_OK;
00704 }
00705 
00706 NS_IMETHODIMP
00707 nsFontEnumeratorBeOS::GetDefaultFont(const char *aLangGroup, 
00708   const char *aGeneric, PRUnichar **aResult)
00709 {
00710   // aLangGroup=null or ""  means any (i.e., don't care)
00711   // aGeneric=null or ""  means any (i.e, don't care)
00712 
00713   NS_ENSURE_ARG_POINTER(aResult);
00714   *aResult = nsnull;
00715 
00716   return NS_OK;
00717 }
00718 
00719 NS_IMETHODIMP
00720 nsFontEnumeratorBeOS::UpdateFontList(PRBool *updateFontList)
00721 {
00722   *updateFontList = PR_FALSE; // always return false for now
00723   return NS_OK;
00724 }
00725