Bug 705594. Use DirectWrite custom text renderer for fallback on Windows Vista/7. r=bas

This commit is contained in:
John Daggett 2012-03-09 11:05:55 +09:00
Родитель f395d7b96f
Коммит d28b9deaa3
3 изменённых файлов: 336 добавлений и 2 удалений

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

@ -1194,3 +1194,182 @@ gfxDWriteFontList::ResolveFontName(const nsAString& aFontName,
return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
}
static nsresult GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
{
HRESULT hr;
nsRefPtr<IDWriteFontFamily> family;
// clean out previous value
aFamilyName.Truncate();
hr = aFont->GetFontFamily(getter_AddRefs(family));
if (FAILED(hr)) {
return hr;
}
nsRefPtr<IDWriteLocalizedStrings> familyNames;
hr = family->GetFamilyNames(getter_AddRefs(familyNames));
if (FAILED(hr)) {
return hr;
}
UINT32 index = 0;
BOOL exists = false;
hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
if (FAILED(hr)) {
return hr;
}
// If the specified locale doesn't exist, select the first on the list.
if (!exists) {
index = 0;
}
nsAutoTArray<WCHAR, 32> name;
UINT32 length;
hr = familyNames->GetStringLength(index, &length);
if (FAILED(hr)) {
return hr;
}
if (!name.SetLength(length + 1)) {
return NS_ERROR_FAILURE;
}
hr = familyNames->GetString(index, name.Elements(), length + 1);
if (FAILED(hr)) {
return hr;
}
aFamilyName.Assign(name.Elements());
return NS_OK;
}
// bug 705594 - the method below doesn't actually do any "drawing", it's only
// used to invoke the DirectWrite layout engine to determine the fallback font
// for a given character.
IFACEMETHODIMP FontFallbackRenderer::DrawGlyphRun(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
__maybenull IUnknown* clientDrawingEffect
)
{
if (!mSystemFonts) {
return E_FAIL;
}
HRESULT hr = S_OK;
nsRefPtr<IDWriteFont> font;
hr = mSystemFonts->GetFontFromFontFace(glyphRun->fontFace,
getter_AddRefs(font));
if (FAILED(hr)) {
return hr;
}
// copy the family name
hr = GetFamilyName(font, mFamilyName);
if (FAILED(hr)) {
return hr;
}
// Arial is used as the default fallback font
// so if it matches ==> no font found
if (mFamilyName.EqualsLiteral("Arial")) {
mFamilyName.Truncate();
return E_FAIL;
}
return hr;
}
gfxFontEntry*
gfxDWriteFontList::GlobalFontFallback(const PRUint32 aCh,
PRInt32 aRunScript,
const gfxFontStyle* aMatchStyle,
PRUint32& aCmapCount)
{
bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
if (useCmaps) {
return gfxPlatformFontList::GlobalFontFallback(aCh,
aRunScript,
aMatchStyle,
aCmapCount);
}
HRESULT hr;
nsRefPtr<IDWriteFactory> dwFactory =
gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
if (!dwFactory) {
return nsnull;
}
// initialize fallback renderer
if (!mFallbackRenderer) {
mFallbackRenderer = new FontFallbackRenderer(dwFactory);
}
// initialize text format
if (!mFallbackFormat) {
hr = dwFactory->CreateTextFormat(L"Arial", NULL,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
72.0f, L"en-us",
getter_AddRefs(mFallbackFormat));
if (FAILED(hr)) {
return nsnull;
}
}
// set up string with fallback character
wchar_t str[16];
PRUint32 strLen;
if (IS_IN_BMP(aCh)) {
str[0] = static_cast<wchar_t> (aCh);
str[1] = 0;
strLen = 1;
} else {
str[0] = static_cast<wchar_t> (H_SURROGATE(aCh));
str[1] = static_cast<wchar_t> (L_SURROGATE(aCh));
str[2] = 0;
strLen = 2;
}
// set up layout
nsRefPtr<IDWriteTextLayout> fallbackLayout;
hr = dwFactory->CreateTextLayout(str, strLen, mFallbackFormat,
200.0f, 200.0f,
getter_AddRefs(fallbackLayout));
if (FAILED(hr)) {
return nsnull;
}
// call the draw method to invoke the DirectWrite layout functions
// which determine the fallback font
hr = fallbackLayout->Draw(NULL, mFallbackRenderer, 50.0f, 50.0f);
if (FAILED(hr)) {
return nsnull;
}
gfxFontEntry *fontEntry = nsnull;
bool needsBold; // ignored in the system fallback case
fontEntry = FindFontForFamily(mFallbackRenderer->FallbackFamilyName(),
aMatchStyle, needsBold);
if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
fontEntry = nsnull;
Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
}
return fontEntry;
}

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

@ -204,6 +204,145 @@ protected:
bool mForceGDIClassic;
};
// custom text renderer used to determine the fallback font for a given char
class FontFallbackRenderer : public IDWriteTextRenderer
{
public:
FontFallbackRenderer(IDWriteFactory *aFactory)
: mRefCount(0)
{
HRESULT hr = S_OK;
hr = aFactory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
}
~FontFallbackRenderer()
{}
// IDWriteTextRenderer methods
IFACEMETHOD(DrawGlyphRun)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
__maybenull IUnknown* clientDrawingEffect
);
IFACEMETHOD(DrawUnderline)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_UNDERLINE const* underline,
__maybenull IUnknown* clientDrawingEffect
)
{
return E_NOTIMPL;
}
IFACEMETHOD(DrawStrikethrough)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_STRIKETHROUGH const* strikethrough,
__maybenull IUnknown* clientDrawingEffect
)
{
return E_NOTIMPL;
}
IFACEMETHOD(DrawInlineObject)(
__maybenull void* clientDrawingContext,
FLOAT originX,
FLOAT originY,
IDWriteInlineObject* inlineObject,
BOOL isSideways,
BOOL isRightToLeft,
__maybenull IUnknown* clientDrawingEffect
)
{
return E_NOTIMPL;
}
// IDWritePixelSnapping methods
IFACEMETHOD(IsPixelSnappingDisabled)(
__maybenull void* clientDrawingContext,
__out BOOL* isDisabled
)
{
*isDisabled = FALSE;
return S_OK;
}
IFACEMETHOD(GetCurrentTransform)(
__maybenull void* clientDrawingContext,
__out DWRITE_MATRIX* transform
)
{
const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
*transform = ident;
return S_OK;
}
IFACEMETHOD(GetPixelsPerDip)(
__maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip
)
{
*pixelsPerDip = 1.0f;
return S_OK;
}
// IUnknown methods
IFACEMETHOD_(unsigned long, AddRef) ()
{
return InterlockedIncrement(&mRefCount);
}
IFACEMETHOD_(unsigned long, Release) ()
{
unsigned long newCount = InterlockedDecrement(&mRefCount);
if (newCount == 0)
{
delete this;
return 0;
}
return newCount;
}
IFACEMETHOD(QueryInterface) (IID const& riid, void** ppvObject)
{
if (__uuidof(IDWriteTextRenderer) == riid) {
*ppvObject = this;
} else if (__uuidof(IDWritePixelSnapping) == riid) {
*ppvObject = this;
} else if (__uuidof(IUnknown) == riid) {
*ppvObject = this;
} else {
*ppvObject = NULL;
return E_FAIL;
}
this->AddRef();
return S_OK;
}
const nsString& FallbackFamilyName() { return mFamilyName; }
protected:
unsigned long mRefCount;
nsRefPtr<IDWriteFontCollection> mSystemFonts;
nsString mFamilyName;
};
class gfxDWriteFontList : public gfxPlatformFontList {
public:
@ -248,6 +387,14 @@ private:
void GetDirectWriteSubstitutes();
// search fonts system-wide for a given character, null otherwise
virtual gfxFontEntry* GlobalFontFallback(const PRUint32 aCh,
PRInt32 aRunScript,
const gfxFontStyle* aMatchStyle,
PRUint32& aCmapCount);
virtual bool UsesSystemFallback() { return true; }
/**
* Fonts listed in the registry as substitutes but for which no actual
* font family is found.
@ -270,6 +417,9 @@ private:
// whether to use GDI font table access routines
bool mGDIFontTableAccess;
nsRefPtr<IDWriteGdiInterop> mGDIInterop;
nsRefPtr<FontFallbackRenderer> mFallbackRenderer;
nsRefPtr<IDWriteTextFormat> mFallbackFormat;
};

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

@ -852,6 +852,7 @@ static const char kFontMeiryo[] = "Meiryo";
static const char kFontMongolianBaiti[] = "Mongolian Baiti";
static const char kFontNyala[] = "Nyala";
static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
static const char kFontSegoeUI[] = "Segoe UI";
static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
static const char kFontSylfaen[] = "Sylfaen";
static const char kFontTraditionalArabic[] = "Traditional Arabic";
@ -861,6 +862,9 @@ gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
PRInt32 aRunScript,
nsTArray<const char*>& aFontList)
{
// Arial is used as the default fallback for system fallback
aFontList.AppendElement(kFontArial);
if (!IS_IN_BMP(aCh)) {
PRUint32 p = aCh >> 16;
if (p == 1) { // SMP plane
@ -922,8 +926,9 @@ gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
case 0x2a:
case 0x2b:
case 0x2c:
aFontList.AppendElement(kFontCambria);
aFontList.AppendElement(kFontSegoeUI);
aFontList.AppendElement(kFontSegoeUISymbol);
aFontList.AppendElement(kFontCambria);
aFontList.AppendElement(kFontCambriaMath);
aFontList.AppendElement(kFontMeiryo);
aFontList.AppendElement(kFontArial);
@ -972,8 +977,8 @@ gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
break;
case 0xfc:
case 0xfd:
aFontList.AppendElement(kFontArabicTypesetting);
aFontList.AppendElement(kFontTraditionalArabic);
aFontList.AppendElement(kFontArabicTypesetting);
break;
case 0xfe:
aFontList.AppendElement(kFontTraditionalArabic);