зеркало из 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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче