зеркало из https://github.com/mozilla/pjs.git
Bug 705594. Use DirectWrite custom text renderer for fallback on Windows Vista/7. r=bas
This commit is contained in:
Родитель
f395d7b96f
Коммит
d28b9deaa3
|
@ -1194,3 +1194,182 @@ gfxDWriteFontList::ResolveFontName(const nsAString& aFontName,
|
||||||
|
|
||||||
return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
|
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;
|
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 {
|
class gfxDWriteFontList : public gfxPlatformFontList {
|
||||||
public:
|
public:
|
||||||
|
@ -248,6 +387,14 @@ private:
|
||||||
|
|
||||||
void GetDirectWriteSubstitutes();
|
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
|
* Fonts listed in the registry as substitutes but for which no actual
|
||||||
* font family is found.
|
* font family is found.
|
||||||
|
@ -270,6 +417,9 @@ private:
|
||||||
// whether to use GDI font table access routines
|
// whether to use GDI font table access routines
|
||||||
bool mGDIFontTableAccess;
|
bool mGDIFontTableAccess;
|
||||||
nsRefPtr<IDWriteGdiInterop> mGDIInterop;
|
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 kFontMongolianBaiti[] = "Mongolian Baiti";
|
||||||
static const char kFontNyala[] = "Nyala";
|
static const char kFontNyala[] = "Nyala";
|
||||||
static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
|
static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
|
||||||
|
static const char kFontSegoeUI[] = "Segoe UI";
|
||||||
static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
|
static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
|
||||||
static const char kFontSylfaen[] = "Sylfaen";
|
static const char kFontSylfaen[] = "Sylfaen";
|
||||||
static const char kFontTraditionalArabic[] = "Traditional Arabic";
|
static const char kFontTraditionalArabic[] = "Traditional Arabic";
|
||||||
|
@ -861,6 +862,9 @@ gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
|
||||||
PRInt32 aRunScript,
|
PRInt32 aRunScript,
|
||||||
nsTArray<const char*>& aFontList)
|
nsTArray<const char*>& aFontList)
|
||||||
{
|
{
|
||||||
|
// Arial is used as the default fallback for system fallback
|
||||||
|
aFontList.AppendElement(kFontArial);
|
||||||
|
|
||||||
if (!IS_IN_BMP(aCh)) {
|
if (!IS_IN_BMP(aCh)) {
|
||||||
PRUint32 p = aCh >> 16;
|
PRUint32 p = aCh >> 16;
|
||||||
if (p == 1) { // SMP plane
|
if (p == 1) { // SMP plane
|
||||||
|
@ -922,8 +926,9 @@ gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
|
||||||
case 0x2a:
|
case 0x2a:
|
||||||
case 0x2b:
|
case 0x2b:
|
||||||
case 0x2c:
|
case 0x2c:
|
||||||
aFontList.AppendElement(kFontCambria);
|
aFontList.AppendElement(kFontSegoeUI);
|
||||||
aFontList.AppendElement(kFontSegoeUISymbol);
|
aFontList.AppendElement(kFontSegoeUISymbol);
|
||||||
|
aFontList.AppendElement(kFontCambria);
|
||||||
aFontList.AppendElement(kFontCambriaMath);
|
aFontList.AppendElement(kFontCambriaMath);
|
||||||
aFontList.AppendElement(kFontMeiryo);
|
aFontList.AppendElement(kFontMeiryo);
|
||||||
aFontList.AppendElement(kFontArial);
|
aFontList.AppendElement(kFontArial);
|
||||||
|
@ -972,8 +977,8 @@ gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
|
||||||
break;
|
break;
|
||||||
case 0xfc:
|
case 0xfc:
|
||||||
case 0xfd:
|
case 0xfd:
|
||||||
aFontList.AppendElement(kFontArabicTypesetting);
|
|
||||||
aFontList.AppendElement(kFontTraditionalArabic);
|
aFontList.AppendElement(kFontTraditionalArabic);
|
||||||
|
aFontList.AppendElement(kFontArabicTypesetting);
|
||||||
break;
|
break;
|
||||||
case 0xfe:
|
case 0xfe:
|
||||||
aFontList.AppendElement(kFontTraditionalArabic);
|
aFontList.AppendElement(kFontTraditionalArabic);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче