Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Enumerations | Functions | Variables
nsMacUnicodeFontInfo.cpp File Reference
#include "nsMacUnicodeFontInfo.h"
#include "nsCRT.h"
#include "prmem.h"
#include <Fonts.h>
#include "nsICharRepresentable.h"
#include "nsCompressedCharMap.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsDependentString.h"
#include "nsLiteralString.h"
#include "nsDeviceContextMac.h"
#include "nsICharsetConverterManager.h"
#include "nsIPersistentProperties2.h"
#include "nsNetUtil.h"
#include "nsHashtable.h"
#include <ATSTypes.h>
#include <SFNTTypes.h>
#include <SFNTLayoutTypes.h>

Go to the source code of this file.

Classes

class  nsFontCleanupObserver

Defines

#define ADD_GLYPH(a, b)   SET_REPRESENTABLE(a,b)
#define FONT_HAS_GLYPH(a, b)   IS_REPRESENTABLE(a,b)
#define SET_SPACE(c)   ADD_GLYPH(spaces, c)
#define SHOULD_BE_SPACE(c)   FONT_HAS_GLYPH(spaces, c)

Enumerations

enum  { kFMOpenTypeFontTechnology = FOUR_CHAR_CODE('OTTO') }
enum  { headFontTableTag = FOUR_CHAR_CODE('head'), locaFontTableTag = FOUR_CHAR_CODE('loca') }

Functions

static NS_DEFINE_CID (kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID)
static PRInt8 GetIndexToLocFormat (FMFont aFont)
static PRUint8GetSpaces (FMFont aFont, PRUint32 *aMaxGlyph)
static void InitSpace ()
static void HandleFormat4 (PRUint16 *aEntry, PRUint8 *aEnd, PRUint8 *aIsSpace, PRUint32 aMaxGlyph, PRUint32 *aFontInfo)
static PRBool FillFontInfoFromCMAP (FMFont aFont, PRUint32 *aFontInfo, FourCharCode aFontFormat)
static PRUint16InitGlobalCCMap ()
static nsresult GetEncoding (const nsCString &aFontName, nsACString &aValue)
static nsresult GetConverter (const nsCString &aFontName, nsIUnicodeEncoder **aConverter)
static PRUint16GetCCMapThroughConverter (nsIUnicodeEncoder *converter)
static PRBool PR_CALLBACK HashtableFreeCCMap (nsHashKey *aKey, void *aData, void *closure)

Variables

static nsIPersistentPropertiesgFontEncodingProperties = nsnull
static nsICharsetConverterManagergCharsetManager = nsnull
static nsObjectHashtable * gFontMaps = nsnull
static nsFontCleanupObservergFontCleanupObserver = nsnull
static PRUint16gCCMap = nsnull
static int spacesInitialized = 0
static PRUint32 spaces [2048]

Define Documentation

#define ADD_GLYPH (   a,
  b 
)    SET_REPRESENTABLE(a,b)

Definition at line 121 of file nsMacUnicodeFontInfo.cpp.

#define FONT_HAS_GLYPH (   a,
  b 
)    IS_REPRESENTABLE(a,b)

Definition at line 122 of file nsMacUnicodeFontInfo.cpp.

#define SET_SPACE (   c)    ADD_GLYPH(spaces, c)

Definition at line 125 of file nsMacUnicodeFontInfo.cpp.

Definition at line 127 of file nsMacUnicodeFontInfo.cpp.


Enumeration Type Documentation

anonymous enum
Enumerator:
kFMOpenTypeFontTechnology 

Definition at line 111 of file nsMacUnicodeFontInfo.cpp.

     {
  kFMOpenTypeFontTechnology     = FOUR_CHAR_CODE('OTTO')
};
anonymous enum
Enumerator:
headFontTableTag 
locaFontTableTag 

Definition at line 116 of file nsMacUnicodeFontInfo.cpp.

     {
  headFontTableTag = FOUR_CHAR_CODE('head'),
  locaFontTableTag = FOUR_CHAR_CODE('loca')
};

Function Documentation

static PRBool FillFontInfoFromCMAP ( FMFont  aFont,
PRUint32 aFontInfo,
FourCharCode  aFontFormat 
) [static]

Definition at line 290 of file nsMacUnicodeFontInfo.cpp.

{
  ByteCount len;
  OSErr err = ::FMGetFontTable(aFont, cmapFontTableTag, 0, 0, NULL, &len);
  if((err!=noErr) || (!len))
    return PR_FALSE;

  PRUint8* buf = (PRUint8*) nsMemory::Alloc(len);
  NS_ASSERTION(buf, "cannot read cmap because out of memory");
  if (!buf) 
    return PR_FALSE;

  ByteCount newLen;
  err = ::FMGetFontTable(aFont, cmapFontTableTag, 0, len,  buf, &newLen);
  NS_ASSERTION(newLen == len, "cannot read cmap from the font");
  if (newLen != len) 
  {
    nsMemory::Free(buf);
    return PR_FALSE;
  }
  
  PRUint8* p = buf + sizeof(PRUint16); // skip version, move to numberSubtables
  PRUint16 n = GET_SHORT(p); // get numberSubtables
  p += sizeof(PRUint16); // skip numberSubtables, move to the encoding subtables

  PRUint16 i;
  PRUint32 offset;
  PRUint32 platformUnicodeOffset = 0;
  // we look for platform =3 and encoding =1, 
  // if we cannot find it but there are a platform = 0 there, we 
  // remmeber that one and use it.
  
  for (i = 0; i < n; i++) 
  {
    PRUint16 platformID = GET_SHORT(p); // get platformID
    p += sizeof(PRUint16); // move to platformSpecificID
    PRUint16 encodingID = GET_SHORT(p); // get platformSpecificID
    p += sizeof(PRUint16); // move to offset
    offset = GET_LONG(p);  // get offset
    p += sizeof(PRUint32); // move to next entry
#ifdef DEBUG_TRUE_TYPE
    printf("p=%d e=%d offset=%x\n", platformID, encodingID, offset);
#endif
    if (platformID == kFontMicrosoftPlatform) 
    { 
      if (encodingID == kFontMicrosoftStandardScript) 
      { // Unicode
        // Some fonts claim to be unicode when they are actually
        // 'pseudo-unicode' fonts that require a converter...
        break;  // break out from for(;;) loop
      } //if (encodingID == kFontMicrosoftStandardScript)
#if 0
      // if we have other encoding, we can still handle it, so... don't return this early
      else if (encodingID == kFontMicrosoftSymbolScript) 
      { // symbol      
        NS_ASSERTION(false, "cannot handle symbol font");
        nsMemory::Free(buf);
        return PR_FALSE;
      } 
#endif
    } // if (platformID == kFontMicrosoftPlatform)  
    else {
      if (platformID == kFontUnicodePlatform) 
      { // Unicode
        platformUnicodeOffset = offset;
      }
    }
  } // for loop
  
  NS_ASSERTION((i != n) || ( 0 != platformUnicodeOffset), "do not know the TrueType encoding");
  if ((i == n) && ( 0 == platformUnicodeOffset)) 
  {  
    nsMemory::Free(buf);
    return PR_FALSE;
  }

  // usually, we come here for the entry platform = 3 encoding = 1
  // or if we don't have it but we have a platform = 0 (platformUnicodeOffset != 0)
  if(platformUnicodeOffset)
    offset = platformUnicodeOffset;

  p = buf + offset;
  PRUint16 format = GET_SHORT(p);
  NS_ASSERTION((kSFNTLookupSegmentArray == format), "hit some unknow format");
  switch(format) {
    case kSFNTLookupSegmentArray: // format 4
    {
      PRUint32 maxGlyph;
      PRUint8* isSpace = GetSpaces(aFont, &maxGlyph);
      // isSpace could be nsnull if the font do not have 'loca' table on Mac.
      // Two reason for that:
      // First, 'loca' table is not required in OpenType font.
      // 
      // Second, on Mac, the sfnt-housed font may not have 'loca' table. 
      // exmaple are Beijing and Taipei font.
      // see the WARNING section at the following link for details
      // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html

      HandleFormat4((PRUint16*) (buf + offset), buf+len, isSpace, maxGlyph, aFontInfo);

      if (isSpace)
        nsMemory::Free(isSpace);
      nsMemory::Free(buf);                                
      return PR_TRUE;
    }
    break;
    default:
    {
      nsMemory::Free(buf);
      return PR_FALSE;
    }
    break;    
  }
  
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRUint16* GetCCMapThroughConverter ( nsIUnicodeEncoder converter) [static]

Definition at line 546 of file nsMacUnicodeFontInfo.cpp.

{
  // see if we know something about the converter of this font 
  nsCOMPtr<nsICharRepresentable> mapper(do_QueryInterface(converter));
  return (mapper ? MapperToCCMap(mapper) : nsnull);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult GetConverter ( const nsCString aFontName,
nsIUnicodeEncoder **  aConverter 
) [static]

Definition at line 522 of file nsMacUnicodeFontInfo.cpp.

{
  *aConverter = nsnull;

  nsCAutoString value;
  nsresult rv = GetEncoding(aFontName, value);
  if (NS_FAILED(rv)) return rv;
  
  if (!gCharsetManager)
  {
    rv = CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
    if(NS_FAILED(rv)) return rv;
  }
  
  rv = gCharsetManager->GetUnicodeEncoderRaw(value.get(), aConverter);
  if (NS_FAILED(rv)) return rv;

  nsIUnicodeEncoder* tmp = *aConverter;
  return tmp->SetOutputErrorBehavior(tmp->kOnError_Replace, nsnull, '?');
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult GetEncoding ( const nsCString aFontName,
nsACString &  aValue 
) [static]

Definition at line 481 of file nsMacUnicodeFontInfo.cpp.

{
  nsresult rv;
  // see if we should init the property
  if (! gFontEncodingProperties) {
    // but bail out for common fonts used at startup...
    if (aFontName.EqualsLiteral("Lucida Grande") ||
        aFontName.EqualsLiteral("Charcoal") ||
        aFontName.EqualsLiteral("Chicago") ||
        aFontName.EqualsLiteral("Capitals") ||
        aFontName.EqualsLiteral("Gadget") ||
        aFontName.EqualsLiteral("Sand") ||
        aFontName.EqualsLiteral("Techno") ||
        aFontName.EqualsLiteral("Textile") ||
        aFontName.EqualsLiteral("Geneva") )
      return NS_ERROR_NOT_AVAILABLE; // error mean do not get a special encoding

    // init the property now
    rv = NS_LoadPersistentPropertiesFromURISpec(&gFontEncodingProperties,
         NS_LITERAL_CSTRING("resource://gre/res/fonts/fontEncoding.properties"));
    if NS_FAILED(rv)
      return rv;
  }

  nsCAutoString name(NS_LITERAL_CSTRING("encoding.") +
                     aFontName +
                     NS_LITERAL_CSTRING(".ttf"));
  name.StripWhitespace();
  ToLowerCase(name);

  nsAutoString value;
  rv = gFontEncodingProperties->GetStringProperty(name, value);
  if (NS_SUCCEEDED(rv))
    CopyUCS2toASCII(value, aValue);
  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt8 GetIndexToLocFormat ( FMFont  aFont) [static]

Definition at line 130 of file nsMacUnicodeFontInfo.cpp.

{
  PRUint16 indexToLocFormat;
  ByteCount len = 0;
  OSStatus err = ::FMGetFontTable(aFont, headFontTableTag, 50, 2, &indexToLocFormat, nsnull);
  if (err != noErr) 
    return -1;
    
  if (!indexToLocFormat) 
    return 0;
    
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRUint8* GetSpaces ( FMFont  aFont,
PRUint32 aMaxGlyph 
) [static]

Definition at line 145 of file nsMacUnicodeFontInfo.cpp.

{
  PRInt8 isLong = GetIndexToLocFormat(aFont);
  if (isLong < 0) 
    return nsnull;

  ByteCount len = 0;
  OSStatus err = ::FMGetFontTable(aFont, locaFontTableTag, 0, 0,  NULL, &len);
  
  if ((err != noErr) || (!len))
    return nsnull;
  
  PRUint8* buf = (PRUint8*) nsMemory::Alloc(len);
  NS_ASSERTION(buf, "cannot read 'loca' table because out of memory");
  if (!buf) 
    return nsnull;
  
  ByteCount newLen = 0;
  err = ::FMGetFontTable(aFont, locaFontTableTag, 0, len, buf, &newLen);
  NS_ASSERTION((newLen == len), "cannot read 'loca' table from the font");
  
  if (newLen != len) 
  {
    nsMemory::Free(buf);
    return nsnull;
  }

  if (isLong) 
  {
    PRUint32 longLen = ((len / 4) - 1);
    *aMaxGlyph = longLen;
    PRUint32* longBuf = (PRUint32*) buf;
    for (PRUint32 i = 0; i < longLen; i++) 
    {
      if (longBuf[i] == longBuf[i+1]) 
        buf[i] = 1;
      else 
        buf[i] = 0;
    }
  }
  else 
  {
    PRUint32 shortLen = ((len / 2) - 1);
    *aMaxGlyph = shortLen;
    PRUint16* shortBuf = (PRUint16*) buf;
    for (PRUint16 i = 0; i < shortLen; i++) 
    {
      if (shortBuf[i] == shortBuf[i+1]) 
        buf[i] = 1;
      else 
        buf[i] = 0;
    }
  }

  return buf;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void HandleFormat4 ( PRUint16 aEntry,
PRUint8 aEnd,
PRUint8 aIsSpace,
PRUint32  aMaxGlyph,
PRUint32 aFontInfo 
) [static]

Definition at line 217 of file nsMacUnicodeFontInfo.cpp.

{
  // notice aIsSpace could be nsnull in case of OpenType font
  PRUint8* end = aEnd;  
  PRUint16* s = aEntry;
  PRUint16 segCount = CFSwapInt16BigToHost(s[3]) / 2;
  PRUint16* endCode = &s[7];
  PRUint16* startCode = endCode + segCount + 1;
  PRUint16* idDelta = startCode + segCount;
  PRUint16* idRangeOffset = idDelta + segCount;
  PRUint16* glyphIdArray = idRangeOffset + segCount;

  PRUint16 i;
  InitSpace();
  
  for (i = 0; i < segCount; i++) 
  {
    if (idRangeOffset[i]) 
    {
      PRUint16 startC = CFSwapInt16BigToHost(startCode[i]);
      PRUint16 endC = CFSwapInt16BigToHost(endCode[i]);
      for (PRUint32 c = startC; c <= endC; c++) 
      {
        PRUint16* g = (CFSwapInt16BigToHost(idRangeOffset[i])/2 + (c - startC) + &idRangeOffset[i]);
        if ((PRUint8*) g < end) 
        {
          if (*g) 
          {
            PRUint16 glyph = CFSwapInt16BigToHost(idDelta[i]) + *g;
            if (glyph < aMaxGlyph) 
            {
              if (aIsSpace && aIsSpace[glyph]) 
              {
                if (SHOULD_BE_SPACE(c)) 
                  ADD_GLYPH(aFontInfo, c);
              }
              else 
              {
                ADD_GLYPH(aFontInfo, c);
              }
            }
          }
        }
        else 
        {
          // XXX should we trust this font at all if it does this?
        }
      }
    }
    else 
    {
      PRUint16 endC = CFSwapInt16BigToHost(endCode[i]);
      for (PRUint32 c = CFSwapInt16BigToHost(startCode[i]); c <= endC; c++) 
      {
        PRUint16 glyph = CFSwapInt16BigToHost(idDelta[i]) + c;
        if (glyph < aMaxGlyph) 
        {
          if (aIsSpace && aIsSpace[glyph]) 
          {
            if (SHOULD_BE_SPACE(c)) 
              ADD_GLYPH(aFontInfo, c);
          }
          else 
          {
            ADD_GLYPH(aFontInfo, c);
          }
        }
      }
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool PR_CALLBACK HashtableFreeCCMap ( nsHashKey *  aKey,
void aData,
void closure 
) [static]

Definition at line 554 of file nsMacUnicodeFontInfo.cpp.

{
    PRUint16* ccmap = (PRUint16*)aData;
    FreeCCMap(ccmap);
    return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRUint16* InitGlobalCCMap ( ) [static]

Definition at line 408 of file nsMacUnicodeFontInfo.cpp.

{
  PRUint32 info[2048];
  memset(info, 0, sizeof(info));

#ifdef TRACK_INIT_PERFORMANCE
  AbsoluteTime startTime;
  AbsoluteTime endTime;
  startTime = UpTime();
#endif  
  
  FMFontFamilyIterator aFontIterator;
  OSStatus status = 0;
  FMFont aFont; 
  FMFontFamily aFontFamily;
  status = ::FMCreateFontFamilyIterator(NULL, NULL, kFMDefaultOptions,
                                        &aFontIterator);
  while (status == noErr)
  {
    FourCharCode aFormat;
    status = ::FMGetNextFontFamily(&aFontIterator, &aFontFamily);
    OSStatus status2;
    FMFontStyle aStyle;
    status2 = ::FMGetFontFromFontFamilyInstance(aFontFamily, 0, &aFont, &aStyle);
    NS_ASSERTION(status2 == noErr, "cannot get font from family");
    if (status2 == noErr)
    {
      status2 = ::FMGetFontFormat(aFont, &aFormat);
#ifdef DEBUG_TRUE_TYPE
      OSStatus status3 = ::FMGetFontFormat(aFont, &aFormat);
      const char *four = (const char*) &aFormat;
      Str255 familyName;
      status3 = ::FMGetFontFamilyName(aFontFamily, familyName);
      familyName[familyName[0]+1] = '\0';
      printf("%s format = %c%c%c%c\n", familyName+1, *four, *(four+1), *(four+2), *(four+3));
#endif
     if ((status2 == noErr) && 
         ((kFMTrueTypeFontTechnology == aFormat) ||
          (kFMOpenTypeFontTechnology == aFormat)))
     {
       PRBool ret = FillFontInfoFromCMAP(aFont, info, aFormat);
     }
    }
  }
  // Dispose of the contents of the font iterator.
  status = ::FMDisposeFontFamilyIterator(&aFontIterator);  
  
  PRUint16* map = MapToCCMap(info);
  NS_ASSERTION(map, "cannot create the compressed map");

  //register an observer to take care of cleanup
  gFontCleanupObserver = new nsFontCleanupObserver();
  NS_ASSERTION(gFontCleanupObserver, "failed to create observer");
  if (gFontCleanupObserver) {
    // register for shutdown
    nsresult rv;
    nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1", &rv));
    if (NS_SUCCEEDED(rv)) {
      rv = observerService->AddObserver(gFontCleanupObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
    }    
  }
    
#ifdef TRACK_INIT_PERFORMANCE
  endTime = UpTime();
  Nanoseconds diff = ::AbsoluteToNanoseconds(SubAbsoluteFromAbsolute(endTime, startTime));
  printf("nsMacUnicodeFontInfo::InitGolbal take %d %d nanosecond\n", diff.hi, diff.lo);
#endif

  return map;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void InitSpace ( ) [static]

Definition at line 204 of file nsMacUnicodeFontInfo.cpp.

{
  if (!spacesInitialized) 
  {
    spacesInitialized = 1;
    SET_SPACE(0x0020);
    SET_SPACE(0x00A0);
    for (PRUint16 c = 0x2000; c <= 0x200B; c++) 
      SET_SPACE(c);
    SET_SPACE(0x3000);
  }
}

Here is the caller graph for this function:

static NS_DEFINE_CID ( kCharsetConverterManagerCID  ,
NS_ICHARSETCONVERTERMANAGER_CID   
) [static]

Variable Documentation

PRUint16* gCCMap = nsnull [static]

Definition at line 93 of file nsMacUnicodeFontInfo.cpp.

Definition at line 90 of file nsMacUnicodeFontInfo.cpp.

Definition at line 92 of file nsMacUnicodeFontInfo.cpp.

Definition at line 89 of file nsMacUnicodeFontInfo.cpp.

nsObjectHashtable* gFontMaps = nsnull [static]

Definition at line 91 of file nsMacUnicodeFontInfo.cpp.

PRUint32 spaces[2048] [static]

Definition at line 203 of file nsMacUnicodeFontInfo.cpp.

int spacesInitialized = 0 [static]

Definition at line 202 of file nsMacUnicodeFontInfo.cpp.