Simple stuff for QT fonts (no crash)

This commit is contained in:
Oleg Romashin 2008-04-19 18:14:11 +03:00
Родитель 5e0a95ec9d
Коммит 8262ab2fd7
2 изменённых файлов: 302 добавлений и 6 удалений

Просмотреть файл

@ -42,9 +42,11 @@
#include "cairo.h" #include "cairo.h"
#include "gfxTypes.h" #include "gfxTypes.h"
#include "gfxFont.h" #include "gfxFont.h"
#include "gfxContext.h"
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "nsClassHashtable.h" #include "nsClassHashtable.h"
//#include <QFont>
class gfxQtFont : public gfxFont { class gfxQtFont : public gfxFont {
@ -53,7 +55,31 @@ public:
const gfxFontStyle *aFontStyle); const gfxFontStyle *aFontStyle);
virtual ~gfxQtFont (); virtual ~gfxQtFont ();
virtual nsString GetUniqueName ();
virtual PRUint32 GetSpaceGlyph ()
{
NS_ASSERTION (GetStyle ()->size != 0,
"forgot to short-circuit a text run with zero-sized font?");
GetMetrics ();
return mSpaceGlyph;
}
static void Shutdown(); static void Shutdown();
virtual const gfxFont::Metrics& GetMetrics();
protected:
void *mQFont;
cairo_scaled_font_t *mCairoFont;
PRBool mHasMetrics;
PRUint32 mSpaceGlyph;
Metrics mMetrics;
gfxFloat mAdjustedSize;
virtual PRBool SetupCairoFont(gfxContext *aContext);
}; };
class THEBES_API gfxQtFontGroup : public gfxFontGroup { class THEBES_API gfxQtFontGroup : public gfxFontGroup {
@ -69,6 +95,19 @@ public:
const Parameters *aParams, PRUint32 aFlags); const Parameters *aParams, PRUint32 aFlags);
virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength, virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags); const Parameters *aParams, PRUint32 aFlags);
gfxQtFont * GetFontAt (PRInt32 i) {
return static_cast < gfxQtFont * >(static_cast < gfxFont * >(mFonts[i]));
}
protected:
void InitTextRun (gfxTextRun * aTextRun, const char * aUTF8Text,
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength,
PRBool aTake8BitPath);
static PRBool FontCallback (const nsAString & fontName, const nsACString & genericName, void *closure);
}; };
#endif /* GFX_QTFONTS_H */ #endif /* GFX_QTFONTS_H */

Просмотреть файл

@ -43,6 +43,7 @@
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "gfxPlatformQt.h" #include "gfxPlatformQt.h"
#include "gfxTypes.h"
#include "gfxQtFonts.h" #include "gfxQtFonts.h"
#include "qdebug.h" #include "qdebug.h"
@ -50,35 +51,217 @@
* gfxQtFontGroup * gfxQtFontGroup
*/ */
static int
FFRECountHyphens (const nsAString &aFFREName)
{
int h = 0;
PRInt32 hyphen = 0;
while ((hyphen = aFFREName.FindChar('-', hyphen)) >= 0) {
++h;
++hyphen;
}
return h;
}
PRBool
gfxQtFontGroup::FontCallback (const nsAString& fontName,
const nsACString& genericName,
void *closure)
{
qDebug(">>>>>>Func:%s::%d, fontname:%s, genName:%s\n", __PRETTY_FUNCTION__, __LINE__, NS_ConvertUTF16toUTF8(fontName).get(), nsCString(genericName).get());
nsStringArray *sa = static_cast<nsStringArray*>(closure);
// We ignore prefs that have three hypens since they are X style prefs.
if (genericName.Length() && FFRECountHyphens(fontName) >= 3)
return PR_TRUE;
if (sa->IndexOf(fontName) < 0) {
sa->AppendString(fontName);
}
return PR_TRUE;
}
/**
* Look up the font in the gfxFont cache. If we don't find it, create one.
* In either case, add a ref, append it to the aFonts array, and return it ---
* except for OOM in which case we do nothing and return null.
*/
static already_AddRefed<gfxQtFont>
GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle)
{
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aName, aStyle);
if (!font) {
font = new gfxQtFont(aName, aStyle);
if (!font)
return nsnull;
gfxFontCache::GetCache()->AddNew(font);
}
gfxFont *f = nsnull;
font.swap(f);
return static_cast<gfxQtFont *>(f);
}
gfxQtFontGroup::gfxQtFontGroup (const nsAString& families, gfxQtFontGroup::gfxQtFontGroup (const nsAString& families,
const gfxFontStyle *aStyle) const gfxFontStyle *aStyle)
: gfxFontGroup(families, aStyle) : gfxFontGroup(families, aStyle)
{ {
qDebug("Func:%s::%d, fam:%s\n\tNeed to create font metrics, otherwise - CRASH\n\n", __PRETTY_FUNCTION__, __LINE__, NS_ConvertUTF16toUTF8(families).get()); qDebug("Func:%s::%d, fam:%s\n\tNeed to create font metrics, otherwise - CRASH\n\n", __PRETTY_FUNCTION__, __LINE__, NS_ConvertUTF16toUTF8(families).get());
nsStringArray familyArray;
// Leave non-existing fonts in the list so that fontconfig can get the
// best match.
ForEachFontInternal(families, aStyle->langGroup, PR_TRUE, PR_FALSE,
FontCallback, &familyArray);
// Construct a string suitable for fontconfig
nsAutoString fcFamilies;
if (familyArray.Count()) {
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
int i = 0;
while (1) {
fcFamilies.Append(*familyArray[i]);
++i;
if (i >= familyArray.Count())
break;
fcFamilies.Append(NS_LITERAL_STRING(","));
}
}
else {
// XXX If there are no fonts, we should use dummy family.
// Pango will resolve from this.
// behdad: yep, looks good.
// printf("%s(%s)\n", NS_ConvertUTF16toUTF8(families).get(),
// aStyle->langGroup.get());
fcFamilies.Append(NS_LITERAL_STRING("sans-serif"));
}
nsRefPtr<gfxQtFont> font = GetOrMakeFont(fcFamilies, &mStyle);
if (font) {
mFonts.AppendElement(font);
}
} }
gfxQtFontGroup::~gfxQtFontGroup() gfxQtFontGroup::~gfxQtFontGroup()
{ {
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
} }
gfxFontGroup * gfxFontGroup *
gfxQtFontGroup::Copy(const gfxFontStyle *aStyle) gfxQtFontGroup::Copy(const gfxFontStyle *aStyle)
{ {
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
return new gfxQtFontGroup(mFamilies, aStyle); return new gfxQtFontGroup(mFamilies, aStyle);
} }
#if defined(ENABLE_FAST_PATH_8BIT)
PRBool
gfxQtFontGroup::CanTakeFastPath(PRUint32 aFlags)
{
// Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't.
// We need to always use Pango for RTL text, in case glyph mirroring is
// required.
PRBool speed = aFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
PRBool isRTL = aFlags & gfxTextRunFactory::TEXT_IS_RTL;
return speed && !isRTL
//&& PANGO_IS_FC_FONT(GetFontAt(0)->GetPangoFont())
;
}
#endif
void
gfxQtFontGroup::InitTextRun(gfxTextRun *aTextRun, const char *aUTF8Text,
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength,
PRBool aTake8BitPath)
{
qDebug(">>>>>>Func:%s::%d, Text:'%s'\n", __PRETTY_FUNCTION__, __LINE__, aUTF8Text);
#if defined(ENABLE_FAST_PATH_ALWAYS)
// CreateGlyphRunsFast(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength);
#else
#if defined(ENABLE_FAST_PATH_8BIT)
if (aTake8BitPath && CanTakeFastPath(aTextRun->GetFlags())) {
// nsresult rv = CreateGlyphRunsFast(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength);
if (NS_SUCCEEDED(rv))
return;
}
#endif
// CreateGlyphRunsItemizing(aTextRun, aUTF8Text, aUTF8Length, aUTF8HeaderLength);
#endif
}
/**
* We use this to append an LTR or RTL Override character to the start of the
* string. This forces Pango to honour our direction even if there are neutral characters
* in the string.
*/
static PRInt32 AppendDirectionalIndicatorUTF8(PRBool aIsRTL, nsACString& aString)
{
static const PRUnichar overrides[2][2] =
{ { 0x202d, 0 }, { 0x202e, 0 }}; // LRO, RLO
AppendUTF16toUTF8(overrides[aIsRTL], aString);
return 3; // both overrides map to 3 bytes in UTF8
}
gfxTextRun * gfxTextRun *
gfxQtFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength, gfxQtFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags) const Parameters *aParams, PRUint32 aFlags)
{ {
return nsnull; qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
NS_ASSERTION(aFlags & TEXT_IS_8BIT, "8bit should have been set");
gfxTextRun *run = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
if (!run)
return nsnull;
PRBool isRTL = run->IsRightToLeft();
if ((aFlags & TEXT_IS_ASCII) && !isRTL) {
// We don't need to send an override character here, the characters must be all LTR
const char *utf8Chars = reinterpret_cast<const char*>(aString);
InitTextRun(run, utf8Chars, aLength, 0, PR_TRUE);
} else {
// this is really gross...
const char *chars = reinterpret_cast<const char*>(aString);
NS_ConvertASCIItoUTF16 unicodeString(chars, aLength);
nsCAutoString utf8;
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(isRTL, utf8);
AppendUTF16toUTF8(unicodeString, utf8);
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, PR_TRUE);
}
run->FetchGlyphExtents(aParams->mContext);
return run;
} }
gfxTextRun * gfxTextRun *
gfxQtFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength, gfxQtFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags) const Parameters *aParams, PRUint32 aFlags)
{ {
return nsnull; qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
gfxTextRun *run = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
if (!run)
return nsnull;
run->RecordSurrogates(aString);
nsCAutoString utf8;
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(run->IsRightToLeft(), utf8);
AppendUTF16toUTF8(Substring(aString, aString + aLength), utf8);
PRBool is8Bit = PR_FALSE;
#if defined(ENABLE_FAST_PATH_8BIT)
if (CanTakeFastPath(aFlags)) {
PRUint32 allBits = 0;
PRUint32 i;
for (i = 0; i < aLength; ++i) {
allBits |= aString[i];
}
is8Bit = (allBits & 0xFF00) == 0;
}
#endif
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, is8Bit);
run->FetchGlyphExtents(aParams->mContext);
return run;
} }
/** /**
@ -86,19 +269,93 @@ gfxQtFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
*/ */
gfxQtFont::gfxQtFont(const nsAString &aName, gfxQtFont::gfxQtFont(const nsAString &aName,
const gfxFontStyle *aFontStyle) const gfxFontStyle *aFontStyle)
: gfxFont(aName, aFontStyle) : gfxFont(aName, aFontStyle),
mQFont(nsnull), mCairoFont(nsnull),
mHasMetrics(PR_FALSE), mAdjustedSize(0)
{ {
qDebug(">>>>>>Func:%s::%d, name:%s\n", __PRETTY_FUNCTION__, __LINE__, NS_ConvertUTF16toUTF8(aName).get());
} }
gfxQtFont::~gfxQtFont() gfxQtFont::~gfxQtFont()
{ {
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
}
const gfxFont::Metrics&
gfxQtFont::GetMetrics()
{
if (mHasMetrics)
return mMetrics;
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
#if 0
// printf("font name: %s %f %f\n", NS_ConvertUTF16toUTF8(mName).get(), GetStyle()->size, mAdjustedSize);
// printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(mName).get());
fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
fprintf (stderr, " maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
#endif
mHasMetrics = PR_TRUE;
return mMetrics;
}
nsString
gfxQtFont::GetUniqueName()
{
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
nsString result;
/*
PangoFont *font = GetPangoFont();
PangoFontDescription *desc = pango_font_describe(font);
pango_font_description_unset_fields (desc, PANGO_FONT_MASK_SIZE);
char *str = pango_font_description_to_string(desc);
pango_font_description_free (desc);
CopyUTF8toUTF16(str, result);
g_free(str);*/
return result;
} }
/* static */ void /* static */ void
gfxQtFont::Shutdown() gfxQtFont::Shutdown()
{ {
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
}
PRBool
gfxQtFont::SetupCairoFont(gfxContext *aContext)
{
qDebug(">>>>>>Func:%s::%d\n", __PRETTY_FUNCTION__, __LINE__);
cairo_t *cr = aContext->GetCairo();
cairo_matrix_t currentCTM;
cairo_get_matrix(cr, &currentCTM);
if (mCairoFont) {
// Need to validate that its CTM is OK
cairo_matrix_t fontCTM;
cairo_scaled_font_get_ctm(mCairoFont, &fontCTM);
if (fontCTM.xx != currentCTM.xx || fontCTM.yy != currentCTM.yy ||
fontCTM.xy != currentCTM.xy || fontCTM.yx != currentCTM.yx) {
// Just recreate it from scratch, simplest way
cairo_scaled_font_destroy(mCairoFont);
mCairoFont = nsnull;
}
}
if (!mCairoFont) {
//mCairoFont = CreateScaledFont(cr, &currentCTM, GetPangoFont());
}
if (cairo_scaled_font_status(mCairoFont) != CAIRO_STATUS_SUCCESS) {
// Don't cairo_set_scaled_font as that would propagate the error to
// the cairo_t, precluding any further drawing.
return PR_FALSE;
}
cairo_set_scaled_font(cr, mCairoFont);
return PR_TRUE;
} }