Mozilla/mozilla/widget/src/mac/nsDeviceContextMac.cpp

913 lines
24 KiB
C++
Raw Blame History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsDeviceContextMac.h"
#include "nsRenderingContextMac.h"
#include "nsDeviceContextSpecMac.h"
#include "nsString.h"
#include "nsHashtable.h"
#include <TextEncodingConverter.h>
#include <TextCommon.h>
#include <StringCompare.h>
#include <Fonts.h>
#include <Resources.h>
#include <MacWindows.h>
#include "il_util.h"
#include <FixMath.h>
#include "nsIPref.h"
#include "nsIServiceManager.h"
#include "nsQuickSort.h"
#include "nsUnicodeMappingUtil.h"
PRUint32 nsDeviceContextMac::mPixelsPerInch = 96;
PRBool nsDeviceContextMac::mDisplayVerySmallFonts = true;
static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID);
//------------------------------------------------------------------------
nsDeviceContextMac :: nsDeviceContextMac()
{
NS_INIT_REFCNT();
mSpec = nsnull;
}
//------------------------------------------------------------------------
nsDeviceContextMac :: ~nsDeviceContextMac()
{
}
//------------------------------------------------------------------------
NS_IMPL_QUERY_INTERFACE(nsDeviceContextMac, kDeviceContextIID);
NS_IMPL_ADDREF(nsDeviceContextMac);
NS_IMPL_RELEASE(nsDeviceContextMac);
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac :: Init(nsNativeWidget aNativeWidget)
{
GDHandle thegd;
PixMapHandle thepix;
double pix_inch;
// this is a windowptr, or grafptr, native to macintosh only
mSurface = aNativeWidget;
// get depth and resolution
thegd = ::GetMainDevice();
thepix = (**thegd).gdPMap; // dereferenced handle: don't move memory below!
mDepth = (**thepix).pixelSize;
pix_inch = GetScreenResolution(); //Fix2X((**thepix).hRes);
mTwipsToPixels = pix_inch/(float)NSIntPointsToTwips(72);
mPixelsToTwips = 1.0f/mTwipsToPixels;
return DeviceContextImpl::Init(aNativeWidget);
}
/** ---------------------------------------------------
* See documentation in nsIDeviceContext.h
* @update 12/9/98 dwc
*/
NS_IMETHODIMP nsDeviceContextMac :: CreateRenderingContext(nsIRenderingContext *&aContext)
{
nsRenderingContextMac *pContext;
nsresult rv;
GrafPtr thePort;
pContext = new nsRenderingContextMac();
if (nsnull != pContext){
NS_ADDREF(pContext);
::GetPort(&thePort);
if (nsnull != thePort){
rv = pContext->Init(this,thePort);
}
else
rv = NS_ERROR_OUT_OF_MEMORY;
}
else
rv = NS_ERROR_OUT_OF_MEMORY;
if (NS_OK != rv){
NS_IF_RELEASE(pContext);
}
aContext = pContext;
return rv;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac :: SupportsNativeWidgets(PRBool &aSupportsWidgets)
{
//XXX it is very critical that this not lie!! MMP
// <20><><EFBFBD> VERY IMPORTANT (pinkerton)
// This routine should return true if the widgets behave like Win32
// "windows", that is they paint themselves and the app never knows about
// them or has to send them update events. We were returning false which
// meant that raptor needed to make sure to redraw them. However, if we
// return false, the widgets never get created because the CreateWidget()
// call in nsView never creates the widget. If we return true (which makes
// things work), we are lying because the controls really need those
// precious update/repaint events.
//
// The situation we need is the following:
// - return false from SupportsNativeWidgets()
// - Create() is called on widgets when the above case is true.
//
// Raptor currently doesn't work this way and needs to be fixed.
// (please remove this comment when this situation is rectified)
//if (nsnull == mSurface)
aSupportsWidgets = PR_TRUE;
//else
//aSupportsWidgets = PR_FALSE;
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac :: GetScrollBarDimensions(float &aWidth, float &aHeight) const
{
// XXX Should we push this to widget library
aWidth = 16 * mDevUnitsToAppUnits;
aHeight = 16 * mDevUnitsToAppUnits;
return NS_OK;
}
NS_IMETHODIMP nsDeviceContextMac :: GetSystemAttribute(nsSystemAttrID anID, SystemAttrStruct * aInfo) const
{
nsresult status = NS_OK;
switch (anID) {
//---------
// Colors
//---------
case eSystemAttr_Color_WindowBackground:
*aInfo->mColor = NS_RGB(0xdd,0xdd,0xdd);
break;
case eSystemAttr_Color_WindowForeground:
*aInfo->mColor = NS_RGB(0x00,0x00,0x00);
break;
case eSystemAttr_Color_WidgetBackground:
*aInfo->mColor = NS_RGB(0xdd,0xdd,0xdd);
break;
case eSystemAttr_Color_WidgetForeground:
*aInfo->mColor = NS_RGB(0x00,0x00,0x00);
break;
case eSystemAttr_Color_WidgetSelectBackground:
*aInfo->mColor = NS_RGB(0x80,0x80,0x80);
break;
case eSystemAttr_Color_WidgetSelectForeground:
*aInfo->mColor = NS_RGB(0x00,0x00,0x80);
break;
case eSystemAttr_Color_Widget3DHighlight:
*aInfo->mColor = NS_RGB(0xa0,0xa0,0xa0);
break;
case eSystemAttr_Color_Widget3DShadow:
*aInfo->mColor = NS_RGB(0x40,0x40,0x40);
break;
case eSystemAttr_Color_TextBackground:
*aInfo->mColor = NS_RGB(0xff,0xff,0xff);
break;
case eSystemAttr_Color_TextForeground:
*aInfo->mColor = NS_RGB(0x00,0x00,0x00);
break;
case eSystemAttr_Color_TextSelectBackground:
*aInfo->mColor = NS_RGB(0x00,0x00,0x80);
break;
case eSystemAttr_Color_TextSelectForeground:
*aInfo->mColor = NS_RGB(0xff,0xff,0xff);
break;
//---------
// Size
//---------
case eSystemAttr_Size_ScrollbarHeight :
aInfo->mSize = 16; //21;
break;
case eSystemAttr_Size_ScrollbarWidth :
aInfo->mSize = 16; //21;
break;
case eSystemAttr_Size_WindowTitleHeight:
aInfo->mSize = 0;
break;
case eSystemAttr_Size_WindowBorderWidth:
aInfo->mSize = 4;
break;
case eSystemAttr_Size_WindowBorderHeight:
aInfo->mSize = 4;
break;
case eSystemAttr_Size_Widget3DBorder:
aInfo->mSize = 4;
break;
//---------
// Fonts
//---------
case eSystemAttr_Font_Caption :
case eSystemAttr_Font_Icon :
case eSystemAttr_Font_Menu :
case eSystemAttr_Font_MessageBox :
case eSystemAttr_Font_SmallCaption :
case eSystemAttr_Font_StatusBar :
case eSystemAttr_Font_Tooltips :
status = NS_ERROR_FAILURE;
break;
} // switch
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac :: GetDrawingSurface(nsIRenderingContext &aContext, nsDrawingSurface &aSurface)
{
aContext.CreateDrawingSurface(nsnull, 0, aSurface);
return nsnull == aSurface ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::GetDepth(PRUint32& aDepth)
{
aDepth = mDepth;
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac :: ConvertPixel(nscolor aColor, PRUint32 & aPixel)
{
aPixel = aColor;
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::CreateILColorSpace(IL_ColorSpace*& aColorSpace)
{
nsresult result = NS_OK;
return result;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::GetILColorSpace(IL_ColorSpace*& aColorSpace)
{
if (nsnull == mColorSpace) {
IL_RGBBits colorRGBBits;
// Default is to create a 32-bit color space
colorRGBBits.red_shift = 16;
colorRGBBits.red_bits = 8;
colorRGBBits.green_shift = 8;
colorRGBBits.green_bits = 8;
colorRGBBits.blue_shift = 0;
colorRGBBits.blue_bits = 8;
mColorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 32);
if (nsnull == mColorSpace) {
aColorSpace = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
}
NS_POSTCONDITION(nsnull != mColorSpace, "null color space");
aColorSpace = mColorSpace;
IL_AddRefToColorSpace(aColorSpace);
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac :: CheckFontExistence(const nsString& aFontName)
{
short fontNum;
if (GetMacFontNumber(aFontName, fontNum))
return NS_OK;
else
return NS_ERROR_FAILURE;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::GetDeviceSurfaceDimensions(PRInt32 &aWidth, PRInt32 &aHeight)
{
// FIXME: could just union all of the GDevice rectangles together.
RgnHandle grayRgn = ::GetGrayRgn();
Rect bounds = (**grayRgn).rgnBBox;
//aWidth = bounds.right - bounds.left;
//aHeight = bounds.bottom - bounds.top;
aHeight = NSToIntRound((bounds.bottom - bounds.top)*mDevUnitsToAppUnits);
aWidth = NSToIntRound((bounds.right - bounds.left) * mDevUnitsToAppUnits);
return NS_OK;
}
NS_IMETHODIMP nsDeviceContextMac::GetClientRect(nsRect &aRect)
{
// FIXME: equally as broken as GetDeviceSurfaceDimensions,
// this doesn't do what you want with multiple screens.
RgnHandle grayRgn = ::GetGrayRgn();
Rect bounds = (**grayRgn).rgnBBox;
aRect.x = NSToIntRound(bounds.left * mDevUnitsToAppUnits);
aRect.y = NSToIntRound(bounds.top * mDevUnitsToAppUnits);
aRect.width = NSToIntRound((bounds.right - bounds.left) * mDevUnitsToAppUnits);
aRect.height = NSToIntRound((bounds.bottom - bounds.top) * mDevUnitsToAppUnits);
return NS_OK;
}
#pragma mark -
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::GetDeviceContextFor(nsIDeviceContextSpec *aDevice,nsIDeviceContext *&aContext)
{
GrafPtr curPort;
double pix_Inch;
THPrint thePrintRecord; // handle to print record
aContext = new nsDeviceContextMac();
((nsDeviceContextMac*)aContext)->mSpec = aDevice;
NS_ADDREF(aDevice);
::GetPort(&curPort);
thePrintRecord = ((nsDeviceContextSpecMac*)aDevice)->mPrtRec;
pix_Inch = (**thePrintRecord).prInfo.iHRes;
((nsDeviceContextMac*)aContext)->Init(curPort);
((nsDeviceContextMac*)aContext)->mPageRect = (**thePrintRecord).prInfo.rPage;
((nsDeviceContextMac*)aContext)->mTwipsToPixels = pix_Inch/(float)NSIntPointsToTwips(72);
((nsDeviceContextMac*)aContext)->mPixelsToTwips = 1.0f/mTwipsToPixels;
((nsDeviceContextMac*)aContext)->mAppUnitsToDevUnits = mTwipsToPixels;
((nsDeviceContextMac*)aContext)->mDevUnitsToAppUnits = 1.0f / mAppUnitsToDevUnits;
//((nsDeviceContextMac*)aContext)->Init(this);
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::BeginDocument(void)
{
#if !TARGET_CARBON
GrafPtr thePort;
if(((nsDeviceContextSpecMac*)(this->mSpec))->mPrintManagerOpen) {
::GetPort(&mOldPort);
thePort = (GrafPtr)::PrOpenDoc(((nsDeviceContextSpecMac*)(this->mSpec))->mPrtRec,nsnull,nsnull);
((nsDeviceContextSpecMac*)(this->mSpec))->mPrinterPort = (TPrPort*)thePort;
SetDrawingSurface(((nsDeviceContextSpecMac*)(this->mSpec))->mPrtRec);
SetPort(thePort);
}
#endif
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::EndDocument(void)
{
if(((nsDeviceContextSpecMac*)(this->mSpec))->mPrintManagerOpen){
::SetPort(mOldPort);
#if !TARGET_CARBON
::PrCloseDoc(((nsDeviceContextSpecMac*)(this->mSpec))->mPrinterPort);
#endif
}
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::BeginPage(void)
{
#if !TARGET_CARBON
if(((nsDeviceContextSpecMac*)(this->mSpec))->mPrintManagerOpen)
::PrOpenPage(((nsDeviceContextSpecMac*)(this->mSpec))->mPrinterPort,nsnull);
#endif
return NS_OK;
}
//------------------------------------------------------------------------
NS_IMETHODIMP nsDeviceContextMac::EndPage(void)
{
#if !TARGET_CARBON
if(((nsDeviceContextSpecMac*)(this->mSpec))->mPrintManagerOpen) {
::SetPort((GrafPtr)(((nsDeviceContextSpecMac*)(this->mSpec))->mPrinterPort));
::PrClosePage(((nsDeviceContextSpecMac*)(this->mSpec))->mPrinterPort);
}
#endif
return NS_OK;
}
#pragma mark -
//------------------------------------------------------------------------
nsHashtable* nsDeviceContextMac :: gFontInfoList = nsnull;
class FontNameKey : public nsHashKey
{
public:
FontNameKey(const nsString& aString);
virtual PRUint32 HashValue(void) const;
virtual PRBool Equals(const nsHashKey *aKey) const;
virtual nsHashKey *Clone(void) const;
nsAutoString mString;
};
FontNameKey::FontNameKey(const nsString& aString)
{
mString = aString;
}
PRUint32 FontNameKey::HashValue(void) const
{
nsString str;
mString.ToLowerCase(str);
return nsCRT::HashValue(str.GetUnicode());
}
PRBool FontNameKey::Equals(const nsHashKey *aKey) const
{
return mString.EqualsIgnoreCase(((FontNameKey*)aKey)->mString);
}
nsHashKey* FontNameKey::Clone(void) const
{
return new FontNameKey(mString);
}
#pragma mark -
//------------------------------------------------------------------------
void nsDeviceContextMac :: InitFontInfoList()
{
OSStatus err;
if (!gFontInfoList)
{
gFontInfoList = new nsHashtable();
if (!gFontInfoList)
return;
short numFONDs = ::CountResources('FOND');
#if !TARGET_CARBON
TextEncoding unicodeEncoding = ::CreateTextEncoding(kTextEncodingUnicodeDefault,
kTextEncodingDefaultVariant,
kTextEncodingDefaultFormat);
#endif
TECObjectRef converter = nil;
ScriptCode lastscript = smUninterp;
for (short i = 1; i <= numFONDs ; i++)
{
Handle fond = ::GetIndResource('FOND', i);
if (fond)
{
short fondID;
OSType resType;
Str255 fontName;
::GetResInfo(fond, &fondID, &resType, fontName);
#if !TARGET_CARBON
ScriptCode script = ::FontToScript(fondID);
if (script != lastscript)
{
lastscript = script;
TextEncoding sourceEncoding;
err = ::UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
kTextRegionDontCare, NULL, &sourceEncoding);
if (converter)
err = ::TECDisposeConverter(converter);
err = ::TECCreateConverter(&converter, sourceEncoding, unicodeEncoding);
if (err != noErr)
converter = nil;
}
if (converter)
{
PRUnichar unicodeFontName[sizeof(fontName)];
ByteCount actualInputLength, actualOutputLength;
err = ::TECConvertText(converter, &fontName[1], fontName[0], &actualInputLength,
(TextPtr)unicodeFontName , sizeof(unicodeFontName), &actualOutputLength);
unicodeFontName[actualOutputLength / sizeof(PRUnichar)] = '\0';
FontNameKey key(unicodeFontName);
gFontInfoList->Put(&key, (void*)fondID);
}
#else
// pinkerton - CreateTextEncoding() makes a carbon app exit. this is a smarmy hack
char buffer[500];
::BlockMoveData ( &fontName[1], buffer, *fontName );
buffer[*fontName] = NULL;
printf("font buffer is %s\n", buffer);
FontNameKey key(buffer);
gFontInfoList->Put(&key, (void*)fondID);
#endif
::ReleaseResource(fond);
}
}
if (converter)
err = ::TECDisposeConverter(converter);
}
}
//------------------------------------------------------------------------
bool nsDeviceContextMac :: GetMacFontNumber(const nsString& aFontName, short &aFontNum)
{
//<2F>TODO?: Maybe we shouldn't call that function so often. If nsFont could store the
// fontNum, nsFontMetricsMac::SetFont() wouldn't need to call this at all.
InitFontInfoList();
#if TARGET_CARBON
char* fontNameC = aFontName.ToNewCString();
Str255 fontNamePascal;
fontNamePascal[0] = strlen(fontNameC);
::BlockMoveData ( fontNameC, &fontNamePascal[1], fontNamePascal[0] );
::GetFNum ( fontNamePascal, &aFontNum );
delete[] fontNameC;
#else
FontNameKey key(aFontName);
aFontNum = (short)gFontInfoList->Get(&key);
#endif
return (aFontNum != 0);
}
//------------------------------------------------------------------------
// Override to tweak font settings
nsresult nsDeviceContextMac::CreateFontAliasTable()
{
nsresult result = NS_OK;
if (nsnull == mFontAliasTable) {
mFontAliasTable = new nsHashtable();
if (nsnull != mFontAliasTable)
{
nsAutoString fontTimes("Times");
nsAutoString fontTimesNewRoman("Times New Roman");
nsAutoString fontTimesRoman("Times Roman");
nsAutoString fontArial("Arial");
nsAutoString fontHelvetica("Helvetica");
nsAutoString fontCourier("Courier");
nsAutoString fontCourierNew("Courier New");
nsAutoString fontUnicode("Unicode");
nsAutoString fontBitstreamCyberbit("Bitstream Cyberbit");
nsAutoString fontNullStr;
AliasFont(fontTimes, fontTimesNewRoman, fontTimesRoman, PR_FALSE);
AliasFont(fontTimesRoman, fontTimesNewRoman, fontTimes, PR_FALSE);
AliasFont(fontTimesNewRoman, fontTimesRoman, fontTimes, PR_FALSE);
AliasFont(fontArial, fontHelvetica, fontNullStr, PR_FALSE);
AliasFont(fontHelvetica, fontArial, fontNullStr, PR_FALSE);
AliasFont(fontCourier, fontCourierNew, fontNullStr, PR_FALSE); // changed from DeviceContextImpl
AliasFont(fontCourierNew, fontCourier, fontNullStr, PR_FALSE);
AliasFont(fontUnicode, fontBitstreamCyberbit, fontNullStr, PR_FALSE); // XXX ????
}
else {
result = NS_ERROR_OUT_OF_MEMORY;
}
}
return result;
}
#pragma mark -
//------------------------------------------------------------------------
//
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
PRUint32 nsDeviceContextMac::GetScreenResolution()
{
static PRBool initialized = PR_FALSE;
if (initialized)
return mPixelsPerInch;
initialized = PR_TRUE;
nsIPref* prefs;
nsresult rv = nsServiceManager::GetService(kPrefCID, kIPrefIID, (nsISupports**)&prefs);
if (NS_SUCCEEDED(rv) && prefs) {
PRInt32 intVal;
if (NS_SUCCEEDED(prefs->GetIntPref("browser.screen_resolution", &intVal))) {
mPixelsPerInch = intVal;
}
#if 0
else {
short hppi, vppi;
::ScreenRes(&hppi, &vppi);
mPixelsPerInch = hppi * 1.17f;
}
#endif
nsServiceManager::ReleaseService(kPrefCID, prefs);
}
return mPixelsPerInch;
}
PRBool nsDeviceContextMac::DisplayVerySmallFonts()
{
static PRBool initialized = PR_FALSE;
if (initialized)
return mDisplayVerySmallFonts;
initialized = PR_TRUE;
nsIPref* prefs;
nsresult rv = nsServiceManager::GetService(kPrefCID, kIPrefIID, (nsISupports**)&prefs);
if (NS_SUCCEEDED(rv) && prefs) {
PRBool boolVal;
if (NS_SUCCEEDED(prefs->GetBoolPref("browser.display_very_small_fonts", &boolVal))) {
mDisplayVerySmallFonts = boolVal;
}
nsServiceManager::ReleaseService(kPrefCID, prefs);
}
return mDisplayVerySmallFonts;
}
#pragma mark -
//------------------------------------------------------------------------
nsFontEnumeratorMac::nsFontEnumeratorMac()
{
NS_INIT_REFCNT();
}
NS_IMPL_ISUPPORTS(nsFontEnumeratorMac,
nsCOMTypeInfo<nsIFontEnumerator>::GetIID());
typedef struct EnumerateFamilyInfo
{
PRUnichar** mArray;
int mIndex;
} EnumerateFamilyInfo;
typedef struct EnumerateFontInfo
{
PRUnichar** mArray;
int mIndex;
int mCount;
ScriptCode mScript;
nsGenericFontNameType mType;
} EnumerateFontInfo;
static ScriptCode MapLangGroupToScriptCode(const char* aLangGroup)
{
if(0==nsCRT::strcmp(aLangGroup, "x-western")) {
return smRoman;
} else
if(0==nsCRT::strcmp(aLangGroup, "x-central-euro")) {
return smCentralEuroRoman;
} else
if(0==nsCRT::strcmp(aLangGroup, "x-cyrillic")) {
return smCyrillic;
} else
if(0==nsCRT::strcmp(aLangGroup, "el")) {
return smGreek;
} else
if(0==nsCRT::strcmp(aLangGroup, "tr")) {
return smRoman;
} else
if(0==nsCRT::strcmp(aLangGroup, "he")) {
return smHebrew;
} else
if(0==nsCRT::strcmp(aLangGroup, "ar")) {
return smArabic;
} else
if(0==nsCRT::strcmp(aLangGroup, "x-baltic")) {
return smRoman;
} else
if(0==nsCRT::strcmp(aLangGroup, "th")) {
return smThai;
} else
if(0==nsCRT::strcmp(aLangGroup, "ja")) {
return smJapanese;
} else
if(0==nsCRT::strcmp(aLangGroup, "zh-CN")) {
return smSimpChinese;
} else
if(0==nsCRT::strcmp(aLangGroup, "ko")) {
return smKorean;
} else
if(0==nsCRT::strcmp(aLangGroup, "zh-TW")) {
return smTradChinese;
} else
{
return smRoman;
}
}
static int
CompareFontNames(const void* aArg1, const void* aArg2, void* aClosure)
{
const PRUnichar* str1 = *((const PRUnichar**) aArg1);
const PRUnichar* str2 = *((const PRUnichar**) aArg2);
// XXX add nsICollation stuff
return nsCRT::strcmp(str1, str2);
}
static PRBool
EnumerateFamily(nsHashKey *aKey, void *aData, void* closure)
{
EnumerateFamilyInfo* info = (EnumerateFamilyInfo*) closure;
PRUnichar** array = info->mArray;
int j = info->mIndex;
PRUnichar* str = (((FontNameKey*)aKey)->mString).ToNewUnicode();
if (!str) {
for (j = j - 1; j >= 0; j--) {
nsAllocator::Free(array[j]);
}
info->mIndex = 0;
return PR_FALSE;
}
array[j] = str;
info->mIndex++;
return PR_TRUE;
}
NS_IMETHODIMP
nsFontEnumeratorMac::EnumerateAllFonts(PRUint32* aCount, PRUnichar*** aResult)
{
if (aCount) {
*aCount = 0;
}
else {
return NS_ERROR_NULL_POINTER;
}
if (aResult) {
*aResult = nsnull;
}
else {
return NS_ERROR_NULL_POINTER;
}
nsDeviceContextMac::InitFontInfoList();
nsHashtable* list = nsDeviceContextMac::gFontInfoList;
if(!list) {
return NS_ERROR_FAILURE;
}
PRInt32 items = list->Count();
PRUnichar** array = (PRUnichar**)
nsAllocator::Alloc(items * sizeof(PRUnichar*));
if (!array) {
return NS_ERROR_OUT_OF_MEMORY;
}
EnumerateFamilyInfo info = { array, 0 };
list->Enumerate ( EnumerateFamily, &info);
NS_ASSERTION( items == info.mIndex, "didn't get all the fonts");
if (!info.mIndex) {
nsAllocator::Free(array);
return NS_ERROR_OUT_OF_MEMORY;
}
NS_QuickSort(array, info.mIndex, sizeof(PRUnichar*),
CompareFontNames, nsnull);
*aCount = info.mIndex;
*aResult = array;
return NS_OK;
}
static PRBool
EnumerateFont(nsHashKey *aKey, void *aData, void* closure)
{
EnumerateFontInfo* info = (EnumerateFontInfo*) closure;
PRUnichar** array = info->mArray;
int j = info->mCount;
short fondID = (short) aData;
ScriptCode script = ::FontToScript(fondID);
if(script == info->mScript) {
PRUnichar* str = (((FontNameKey*)aKey)->mString).ToNewUnicode();
if (!str) {
for (j = j - 1; j >= 0; j--) {
nsAllocator::Free(array[j]);
}
info->mIndex = 0;
return PR_FALSE;
}
array[j] = str;
info->mCount++;
}
info->mIndex++;
return PR_TRUE;
}
NS_IMETHODIMP
nsFontEnumeratorMac::EnumerateFonts(const char* aLangGroup,
const char* aGeneric, PRUint32* aCount, PRUnichar*** aResult)
{
if ((! aLangGroup) ||( !aGeneric ))
return NS_ERROR_NULL_POINTER;
if (aCount) {
*aCount = 0;
}
else {
return NS_ERROR_NULL_POINTER;
}
if (aResult) {
*aResult = nsnull;
}
else {
return NS_ERROR_NULL_POINTER;
}
if ((!strcmp(aLangGroup, "x-unicode")) ||
(!strcmp(aLangGroup, "x-user-def"))) {
return EnumerateAllFonts(aCount, aResult);
}
nsDeviceContextMac::InitFontInfoList();
nsHashtable* list = nsDeviceContextMac::gFontInfoList;
if(!list) {
return NS_ERROR_FAILURE;
}
PRInt32 items = list->Count();
PRUnichar** array = (PRUnichar**)
nsAllocator::Alloc(items * sizeof(PRUnichar*));
if (!array) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsUnicodeMappingUtil* gUtil = nsUnicodeMappingUtil::GetSingleton();
if(!gUtil) {
return NS_ERROR_FAILURE;
}
nsAutoString GenName(aGeneric);
EnumerateFontInfo info = { array, 0 , 0, MapLangGroupToScriptCode(aLangGroup) ,gUtil->MapGenericFontNameType(GenName) };
list->Enumerate ( EnumerateFont, &info);
if (!info.mIndex) {
nsAllocator::Free(array);
return NS_ERROR_OUT_OF_MEMORY;
}
NS_QuickSort(array, info.mCount, sizeof(PRUnichar*),
CompareFontNames, nsnull);
*aCount = info.mCount;
*aResult = array;
return NS_OK;
}