bug 454; use fallbacks for the popular windows-1252 characters on Unix;

for example, ellipsis is drawn using three dots "..."; r=rbs (Roger Sidje)
This commit is contained in:
erik%netscape.com 2000-03-12 23:13:49 +00:00
parent f6f5c41e1c
commit 5bef42992c
3 changed files with 320 additions and 133 deletions

View File

@ -27,6 +27,7 @@
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsICharsetConverterManager.h" #include "nsICharsetConverterManager.h"
#include "nsICharRepresentable.h" #include "nsICharRepresentable.h"
#include "nsISaveAsCharset.h"
#include "nsIPref.h" #include "nsIPref.h"
#include "nsILocale.h" #include "nsILocale.h"
#include "nsILocaleService.h" #include "nsILocaleService.h"
@ -44,6 +45,7 @@
#undef REALLY_NOISY_FONTS #undef REALLY_NOISY_FONTS
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_CID(kSaveAsCharsetCID, NS_SAVEASCHARSET_CID);
nsFontMetricsGTK::nsFontMetricsGTK() nsFontMetricsGTK::nsFontMetricsGTK()
{ {
@ -88,6 +90,11 @@ nsFontMetricsGTK::~nsFontMetricsGTK()
mLoadedFonts = nsnull; mLoadedFonts = nsnull;
} }
if (mSubstituteFont) {
delete mSubstituteFont;
mSubstituteFont = nsnull;
}
mFontHandle = nsnull; mFontHandle = nsnull;
} }
@ -1239,6 +1246,224 @@ nsFontGTK::LoadFont(nsFontCharSet* aCharSet, nsFontMetricsGTK* aMetrics)
} }
} }
nsFontGTK::nsFontGTK()
{
}
nsFontGTK::~nsFontGTK()
{
}
class nsFontGTKNormal : public nsFontGTK
{
public:
nsFontGTKNormal();
virtual ~nsFontGTKNormal();
virtual gint GetWidth(const PRUnichar* aString, PRUint32 aLength);
virtual gint DrawString(nsRenderingContextGTK* aContext,
nsDrawingSurfaceGTK* aSurface, nscoord aX,
nscoord aY, const PRUnichar* aString,
PRUint32 aLength);
#ifdef MOZ_MATHML
virtual nsresult GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics);
#endif
};
nsFontGTKNormal::nsFontGTKNormal()
{
}
nsFontGTKNormal::~nsFontGTKNormal()
{
}
gint
nsFontGTKNormal::GetWidth(const PRUnichar* aString, PRUint32 aLength)
{
XChar2b buf[512];
gint len = mCharSetInfo->Convert(mCharSetInfo, aString, aLength,
(char*) buf, sizeof(buf));
return ::gdk_text_width(mFont, (char*) buf, len);
}
gint
nsFontGTKNormal::DrawString(nsRenderingContextGTK* aContext,
nsDrawingSurfaceGTK* aSurface,
nscoord aX, nscoord aY,
const PRUnichar* aString, PRUint32 aLength)
{
XChar2b buf[512];
gint len = mCharSetInfo->Convert(mCharSetInfo, aString, aLength,
(char*) buf, sizeof(buf));
::gdk_draw_text(aSurface->GetDrawable(), mFont, aContext->GetGC(), aX,
aY + mBaselineAdjust, (char*) buf, len);
return ::gdk_text_width(mFont, (char*) buf, len);
}
#ifdef MOZ_MATHML
// bounding metrics for a string
// remember returned values are not in app units
nsresult
nsFontGTKNormal::GetBoundingMetrics (const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{
aBoundingMetrics.Clear();
if (aString && 0 < aLength) {
XChar2b buf[512]; // XXX watch buffer length !!!
gint len = mCharSetInfo->Convert(mCharSetInfo, aString, aLength,
(char*) buf, sizeof(buf));
gdk_text_extents (mFont, (char*) buf, len,
&aBoundingMetrics.leftBearing,
&aBoundingMetrics.rightBearing,
&aBoundingMetrics.width,
&aBoundingMetrics.ascent,
&aBoundingMetrics.descent);
// get italic correction
XFontStruct *fontInfo = (XFontStruct *) GDK_FONT_XFONT (mFont);
unsigned long pr = 0;
if (::XGetFontProperty(fontInfo, XA_ITALIC_ANGLE, &pr)) {
aBoundingMetrics.subItalicCorrection = (gint) pr;
aBoundingMetrics.supItalicCorrection = (gint) pr;
}
}
return NS_OK;
}
#endif
class nsFontGTKSubstitute : public nsFontGTK
{
public:
nsFontGTKSubstitute(nsFontGTK* aFont);
virtual ~nsFontGTKSubstitute();
virtual gint GetWidth(const PRUnichar* aString, PRUint32 aLength);
virtual gint DrawString(nsRenderingContextGTK* aContext,
nsDrawingSurfaceGTK* aSurface, nscoord aX,
nscoord aY, const PRUnichar* aString,
PRUint32 aLength);
#ifdef MOZ_MATHML
virtual nsresult GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics);
#endif
virtual PRUint32 Convert(const PRUnichar* aSrc, PRUint32 aSrcLen,
PRUnichar* aDest, PRUint32 aDestLen);
nsFontGTK* mSubstituteFont;
static int gCount;
static nsISaveAsCharset* gConverter;
};
int nsFontGTKSubstitute::gCount = 0;
nsISaveAsCharset* nsFontGTKSubstitute::gConverter = nsnull;
nsFontGTKSubstitute::nsFontGTKSubstitute(nsFontGTK* aFont)
{
gCount++;
mSubstituteFont = aFont;
}
nsFontGTKSubstitute::~nsFontGTKSubstitute()
{
if ((!--gCount) && gConverter) {
nsServiceManager::ReleaseService(kSaveAsCharsetCID, gConverter);
gConverter = nsnull;
}
// Do not free mSubstituteFont here. It is owned by somebody else.
}
PRUint32
nsFontGTKSubstitute::Convert(const PRUnichar* aSrc, PRUint32 aSrcLen,
PRUnichar* aDest, PRUint32 aDestLen)
{
nsresult res;
if (!gConverter) {
nsServiceManager::GetService(kSaveAsCharsetCID,
NS_GET_IID(nsISaveAsCharset), (nsISupports**) &gConverter);
if (gConverter) {
res = gConverter->Init("ISO-8859-1",
nsISaveAsCharset::attr_FallbackQuestionMark +
nsISaveAsCharset::attr_EntityBeforeCharsetConv,
nsIEntityConverter::transliterate);
if (NS_FAILED(res)) {
nsServiceManager::ReleaseService(kSaveAsCharsetCID, gConverter);
gConverter = nsnull;
}
}
}
if (gConverter) {
nsAutoString tmp(aSrc, aSrcLen);
char* conv = nsnull;
res = gConverter->Convert(tmp.GetUnicode(), &conv);
if (NS_SUCCEEDED(res) && conv) {
char* p = conv;
PRUint32 i;
for (i = 0; i < aDestLen; i++) {
if (*p) {
aDest[i] = *p;
}
else {
break;
}
p++;
}
nsAllocator::Free(conv);
conv = nsnull;
return i;
}
}
if (aSrcLen > aDestLen) {
aSrcLen = aDestLen;
}
for (PRUint32 i = 0; i < aSrcLen; i++) {
aDest[i] = '?';
}
return aSrcLen;
}
gint
nsFontGTKSubstitute::GetWidth(const PRUnichar* aString, PRUint32 aLength)
{
PRUnichar buf[512];
PRUint32 len = Convert(aString, aLength, buf, sizeof(buf)/2);
return mSubstituteFont->GetWidth(buf, len);
}
gint
nsFontGTKSubstitute::DrawString(nsRenderingContextGTK* aContext,
nsDrawingSurfaceGTK* aSurface,
nscoord aX, nscoord aY,
const PRUnichar* aString, PRUint32 aLength)
{
PRUnichar buf[512];
PRUint32 len = Convert(aString, aLength, buf, sizeof(buf)/2);
return mSubstituteFont->DrawString(aContext, aSurface, aX, aY, buf, len);
}
#ifdef MOZ_MATHML
// bounding metrics for a string
// remember returned values are not in app units
nsresult
nsFontGTKSubstitute::GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{
PRUnichar buf[512]; // XXX watch buffer length !!!
PRUint32 len = Convert(aString, aLength, buf, sizeof(buf)/2);
return mSubstituteFont->GetBoundingMetrics(buf, len, aBoundingMetrics);
}
#endif
void void
PickASizeAndLoad(nsFontSearch* aSearch, nsFontStretch* aStretch, PickASizeAndLoad(nsFontSearch* aSearch, nsFontStretch* aStretch,
nsFontCharSet* aCharSet) nsFontCharSet* aCharSet)
@ -1342,7 +1567,7 @@ PickASizeAndLoad(nsFontSearch* aSearch, nsFontStretch* aStretch,
} }
} }
if (p == endScaled) { if (p == endScaled) {
s = new nsFontGTK; s = new nsFontGTKNormal;
if (s) { if (s) {
/* /*
* XXX Instead of passing desiredSize, we ought to take underline * XXX Instead of passing desiredSize, we ought to take underline
@ -2062,7 +2287,7 @@ GetFontNames(char* aPattern)
} }
if (stretch->mSizesCount == stretch->mSizesAlloc) { if (stretch->mSizesCount == stretch->mSizesAlloc) {
int newSize = 2 * (stretch->mSizesAlloc ? stretch->mSizesAlloc : 1); int newSize = 2 * (stretch->mSizesAlloc ? stretch->mSizesAlloc : 1);
nsFontGTK* newPointer = new nsFontGTK[newSize]; nsFontGTK* newPointer = new nsFontGTKNormal[newSize];
if (newPointer) { if (newPointer) {
for (int j = stretch->mSizesAlloc - 1; j >= 0; j--) { for (int j = stretch->mSizesAlloc - 1; j >= 0; j--) {
newPointer[j] = stretch->mSizes[j]; newPointer[j] = stretch->mSizes[j];
@ -2233,6 +2458,22 @@ nsFontMetricsGTK::FindGenericFont(nsFontSearch* aSearch)
mTriedAllGenerics = 1; mTriedAllGenerics = 1;
} }
void
nsFontMetricsGTK::FindSubstituteFont(nsFontSearch* aSearch)
{
if (!mSubstituteFont) {
if (!mInFindSubstituteFont) { // to avoid infinite recursion
mInFindSubstituteFont = 1;
nsFontGTK* font = FindFont('a');
if (font) {
mSubstituteFont = new nsFontGTKSubstitute(font);
}
mInFindSubstituteFont = 0;
}
}
aSearch->mFont = mSubstituteFont;
}
/* /*
* XListFonts(*) is expensive. Delay this till the last possible moment. * XListFonts(*) is expensive. Delay this till the last possible moment.
* XListFontsWithInfo is expensive. Use XLoadQueryFont instead. * XListFontsWithInfo is expensive. Use XLoadQueryFont instead.
@ -2350,66 +2591,13 @@ nsFontMetricsGTK::FindFont(PRUnichar aChar)
return search.mFont; return search.mFont;
} }
// XXX Just return nsnull for now. // XXX Or pop up dialog like plug-in dialog.
// Need to draw boxes eventually. Or pop up dialog like plug-in dialog. FindSubstituteFont(&search);
return nsnull; if (search.mFont) {
} return search.mFont;
#ifdef MOZ_MATHML
// bounding metrics for a string
// remember returned values are not in app units
nsresult
nsFontMetricsGTK::GetBoundingMetrics (nsFontGTK* aFont,
const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{
aBoundingMetrics.Clear();
if (aString && 0 < aLength) {
XChar2b buf[512]; // XXX watch buffer length !!!
gint len = aFont->mCharSetInfo->Convert(aFont->mCharSetInfo, aString, aLength,
(char*) buf, sizeof(buf));
gdk_text_extents (aFont->mFont, (char*) buf, len,
&aBoundingMetrics.leftBearing,
&aBoundingMetrics.rightBearing,
&aBoundingMetrics.width,
&aBoundingMetrics.ascent,
&aBoundingMetrics.descent);
// get italic correction
XFontStruct *fontInfo = (XFontStruct *) GDK_FONT_XFONT (aFont->mFont);
unsigned long pr = 0;
if (::XGetFontProperty(fontInfo, XA_ITALIC_ANGLE, &pr)) {
aBoundingMetrics.subItalicCorrection = (gint) pr;
aBoundingMetrics.supItalicCorrection = (gint) pr;
}
} }
return NS_OK; return nsnull;
}
#endif
gint
nsFontMetricsGTK::GetWidth(nsFontGTK* aFont, const PRUnichar* aString,
PRUint32 aLength)
{
XChar2b buf[512];
gint len = aFont->mCharSetInfo->Convert(aFont->mCharSetInfo, aString, aLength,
(char*) buf, sizeof(buf));
return gdk_text_width(aFont->mFont, (char*) buf, len);
}
void
nsFontMetricsGTK::DrawString(nsRenderingContextGTK* aContext, nsDrawingSurfaceGTK* aSurface,
nsFontGTK* aFont,
nscoord aX, nscoord aY,
const PRUnichar* aString, PRUint32 aLength)
{
XChar2b buf[512];
gint len = aFont->mCharSetInfo->Convert(aFont->mCharSetInfo, aString, aLength,
(char*) buf, sizeof(buf));
::gdk_draw_text(aSurface->GetDrawable(), aFont->mFont, aContext->GetGC(), aX,
aY + aFont->mBaselineAdjust, (char*) buf, len);
} }
nsresult nsresult

View File

@ -56,11 +56,28 @@ typedef gint (*nsFontCharSetConverter)(nsFontCharSetInfo* aSelf,
struct nsFontCharSet; struct nsFontCharSet;
class nsFontMetricsGTK; class nsFontMetricsGTK;
struct nsFontGTK class nsFontGTK
{ {
public:
nsFontGTK();
virtual ~nsFontGTK();
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
void LoadFont(nsFontCharSet* aCharSet, nsFontMetricsGTK* aMetrics); void LoadFont(nsFontCharSet* aCharSet, nsFontMetricsGTK* aMetrics);
virtual gint GetWidth(const PRUnichar* aString, PRUint32 aLength) = 0;
virtual gint DrawString(nsRenderingContextGTK* aContext,
nsDrawingSurfaceGTK* aSurface, nscoord aX,
nscoord aY, const PRUnichar* aString,
PRUint32 aLength) = 0;
#ifdef MOZ_MATHML
// bounding metrics for a string
// remember returned values are not in app units
// - to emulate GetWidth () above
virtual nsresult
GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics) = 0;
#endif
GdkFont* mFont; GdkFont* mFont;
PRUint32* mMap; PRUint32* mMap;
@ -108,21 +125,7 @@ public:
nsFontGTK* FindFont(PRUnichar aChar); nsFontGTK* FindFont(PRUnichar aChar);
void FindGenericFont(nsFontSearch* aSearch); void FindGenericFont(nsFontSearch* aSearch);
static gint GetWidth(nsFontGTK* aFont, const PRUnichar* aString, void FindSubstituteFont(nsFontSearch* aSearch);
PRUint32 aLength);
#ifdef MOZ_MATHML
// bounding metrics for a string
// remember returned values are not in app units
// - to emulate GetWidth () above
static nsresult
GetBoundingMetrics(nsFontGTK* aFont,
const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics);
#endif
static void DrawString(nsRenderingContextGTK* aContext, nsDrawingSurfaceGTK* aSurface, nsFontGTK* aFont,
nscoord aX, nscoord aY, const PRUnichar* aString,
PRUint32 aLength);
static void InitFonts(void); static void InitFonts(void);
friend void PickASizeAndLoad(nsFontSearch* aSearch, nsFontStretch* aStretch, friend void PickASizeAndLoad(nsFontSearch* aSearch, nsFontStretch* aStretch,
@ -135,6 +138,9 @@ public:
PRUint16 mLoadedFontsAlloc; PRUint16 mLoadedFontsAlloc;
PRUint16 mLoadedFontsCount; PRUint16 mLoadedFontsCount;
int mInFindSubstituteFont;
nsFontGTK *mSubstituteFont;
nsString *mFonts; nsString *mFonts;
PRUint16 mFontsAlloc; PRUint16 mFontsAlloc;
PRUint16 mFontsCount; PRUint16 mFontsCount;

View File

@ -1157,31 +1157,29 @@ nsRenderingContextGTK::GetWidth(const PRUnichar* aString, PRUint32 aLength,
nsFontGTK** end = &metrics->mLoadedFonts[metrics->mLoadedFontsCount]; nsFontGTK** end = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
while (font < end) { while (font < end) {
if (IS_REPRESENTABLE((*font)->mMap, c)) { if (IS_REPRESENTABLE((*font)->mMap, c)) {
currFont = *font; currFont = *font;
goto FoundFont; // for speed -- avoid "if" statement goto FoundFont; // for speed -- avoid "if" statement
} }
font++; font++;
} }
currFont = metrics->FindFont(c); currFont = metrics->FindFont(c);
FoundFont: FoundFont:
// XXX avoid this test by duplicating code -- erik // XXX avoid this test by duplicating code -- erik
if (prevFont) { if (prevFont) {
if (currFont != prevFont) { if (currFont != prevFont) {
rawWidth += nsFontMetricsGTK::GetWidth(prevFont, &aString[start], rawWidth += prevFont->GetWidth(&aString[start], i - start);
i - start); prevFont = currFont;
prevFont = currFont; start = i;
start = i; }
}
} }
else { else {
prevFont = currFont; prevFont = currFont;
start = i; start = i;
} }
} }
if (prevFont) { if (prevFont) {
rawWidth += nsFontMetricsGTK::GetWidth(prevFont, &aString[start], rawWidth += prevFont->GetWidth(&aString[start], i - start);
i - start);
} }
aWidth = NSToCoordRound(rawWidth * mP2T); aWidth = NSToCoordRound(rawWidth * mP2T);
@ -1306,60 +1304,57 @@ nsRenderingContextGTK::DrawString(const PRUnichar* aString, PRUint32 aLength,
nsFontGTK** lastFont = &metrics->mLoadedFonts[metrics->mLoadedFontsCount]; nsFontGTK** lastFont = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
while (font < lastFont) { while (font < lastFont) {
if (IS_REPRESENTABLE((*font)->mMap, c)) { if (IS_REPRESENTABLE((*font)->mMap, c)) {
currFont = *font; currFont = *font;
goto FoundFont; // for speed -- avoid "if" statement goto FoundFont; // for speed -- avoid "if" statement
} }
font++; font++;
} }
currFont = metrics->FindFont(c); currFont = metrics->FindFont(c);
FoundFont: FoundFont:
// XXX avoid this test by duplicating code -- erik // XXX avoid this test by duplicating code -- erik
if (prevFont) { if (prevFont) {
if (currFont != prevFont) { if (currFont != prevFont) {
if (aSpacing) { if (aSpacing) {
const PRUnichar* str = &aString[start]; const PRUnichar* str = &aString[start];
const PRUnichar* end = &aString[i]; const PRUnichar* end = &aString[i];
while (str < end) { while (str < end) {
x = aX; x = aX;
y = aY; y = aY;
mTMatrix->TransformCoord(&x, &y); mTMatrix->TransformCoord(&x, &y);
nsFontMetricsGTK::DrawString(this, mSurface, prevFont, x, y, str, 1); prevFont->DrawString(this, mSurface, x, y, str, 1);
aX += *aSpacing++; aX += *aSpacing++;
str++; str++;
} }
} }
else { else {
nsFontMetricsGTK::DrawString(this, mSurface, prevFont, x, y, x += prevFont->DrawString(this, mSurface, x, y, &aString[start],
&aString[start], i - start);
x += nsFontMetricsGTK::GetWidth(prevFont, &aString[start],
i - start); i - start);
} }
prevFont = currFont; prevFont = currFont;
start = i; start = i;
} }
} }
else { else {
prevFont = currFont; prevFont = currFont;
start = i; start = i;
} }
} }
if (prevFont) { if (prevFont) {
if (aSpacing) { if (aSpacing) {
const PRUnichar* str = &aString[start]; const PRUnichar* str = &aString[start];
const PRUnichar* end = &aString[i]; const PRUnichar* end = &aString[i];
while (str < end) { while (str < end) {
x = aX; x = aX;
y = aY; y = aY;
mTMatrix->TransformCoord(&x, &y); mTMatrix->TransformCoord(&x, &y);
nsFontMetricsGTK::DrawString(this, mSurface, prevFont, x, y, str, 1); prevFont->DrawString(this, mSurface, x, y, str, 1);
aX += *aSpacing++; aX += *aSpacing++;
str++; str++;
} }
} }
else { else {
nsFontMetricsGTK::DrawString(this, mSurface, prevFont, x, y, &aString[start], prevFont->DrawString(this, mSurface, x, y, &aString[start], i - start);
i - start);
} }
} }
} }
@ -1619,9 +1614,8 @@ nsRenderingContextGTK::GetBoundingMetrics(const PRUnichar* aString,
// XXX avoid this test by duplicating code -- erik // XXX avoid this test by duplicating code -- erik
if (prevFont) { if (prevFont) {
if (currFont != prevFont) { if (currFont != prevFont) {
nsFontMetricsGTK::GetBoundingMetrics(prevFont, prevFont->GetBoundingMetrics((const PRUnichar*) &aString[start],
(const PRUnichar*) &aString[start], i - start, rawbm);
i - start, rawbm);
if (firstTime) { if (firstTime) {
firstTime = PR_FALSE; firstTime = PR_FALSE;
aBoundingMetrics = rawbm; aBoundingMetrics = rawbm;
@ -1640,9 +1634,8 @@ nsRenderingContextGTK::GetBoundingMetrics(const PRUnichar* aString,
} }
if (prevFont) { if (prevFont) {
nsFontMetricsGTK::GetBoundingMetrics(prevFont, prevFont->GetBoundingMetrics((const PRUnichar*) &aString[start],
(const PRUnichar*) &aString[start], i - start, rawbm);
i - start, rawbm);
if (firstTime) { if (firstTime) {
aBoundingMetrics = rawbm; aBoundingMetrics = rawbm;
} }