Apply palette request to DirectWrite fonts

Bug: skia:12984
Change-Id: Ic0c3774c38c19efb224bf4462ce1397c21c95b78
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/512576
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
Ben Wagner 2022-02-23 19:51:29 -05:00 committed by SkCQ
parent 1380d2c02c
commit e5d89539fb
5 changed files with 153 additions and 49 deletions

View File

@ -206,24 +206,32 @@ void SkFontDescriptor::serialize(SkWStream* stream) const {
write_scalar(stream, fStyle.slant() == SkFontStyle::kUpright_Slant ? 0 : 14, kSlant);
write_scalar(stream, fStyle.slant() == SkFontStyle::kItalic_Slant ? 1 : 0, kItalic);
if (fCollectionIndex) {
if (fCollectionIndex > 0) {
write_uint(stream, fCollectionIndex, kFontIndex);
}
if (fPaletteIndex) {
if (fPaletteIndex > 0) {
write_uint(stream, fPaletteIndex, kPaletteIndex);
}
if (fCoordinateCount) {
if (fCoordinateCount > 0) {
write_uint(stream, fCoordinateCount, kFontVariation);
for (int i = 0; i < fCoordinateCount; ++i) {
stream->write32(fVariation[i].axis);
stream->writeScalar(fVariation[i].value);
}
}
if (fPaletteEntryOverrideCount) {
write_uint(stream, fPaletteEntryOverrideCount, kPaletteEntryOverrides);
if (fPaletteEntryOverrideCount > 0) {
int nonNegativePaletteOverrideIndexes = 0;
for (int i = 0; i < fPaletteEntryOverrideCount; ++i) {
stream->writePackedUInt(fPaletteEntryOverrides[i].index);
stream->write32(fPaletteEntryOverrides[i].color);
if (0 <= fPaletteEntryOverrides[i].index) {
++nonNegativePaletteOverrideIndexes;
}
}
write_uint(stream, nonNegativePaletteOverrideIndexes, kPaletteEntryOverrides);
for (int i = 0; i < fPaletteEntryOverrideCount; ++i) {
if (0 <= fPaletteEntryOverrides[i].index) {
stream->writePackedUInt(fPaletteEntryOverrides[i].index);
stream->write32(fPaletteEntryOverrides[i].color);
}
}
}

View File

@ -531,7 +531,8 @@ sk_sp<SkTypeface> SkFontMgr_DirectWrite::makeTypefaceFromDWriteFont(
ProtoDWriteTypeface spec = { fontFace, font, fontFamily };
sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec);
if (nullptr == face) {
face = DWriteFontTypeface::Make(fFactory.get(), fontFace, font, fontFamily, nullptr);
face = DWriteFontTypeface::Make(fFactory.get(), fontFace, font, fontFamily, nullptr,
SkFontArguments::Palette{0, nullptr, 0});
if (face) {
fTFCache.add(face);
}
@ -1113,7 +1114,8 @@ sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamArgs(std::unique_ptr<Sk
sk_make_sp<DWriteFontTypeface::Loaders>(
fFactory.get(),
autoUnregisterFontFileLoader.detatch(),
autoUnregisterFontCollectionLoader.detatch()));
autoUnregisterFontCollectionLoader.detatch()),
args.getPalette());
}
}

View File

@ -1067,21 +1067,22 @@ void SkScalerContext_DW::drawColorGlyphImage(const SkGlyph& glyph, SkCanvas& can
}
canvas.concat(fSkXform);
DWriteFontTypeface* typeface = this->getDWriteTypeface();
size_t paletteEntryCount = typeface->fPaletteEntryCount;
SkColor* palette = typeface->fPalette.get();
BOOL hasNextRun = FALSE;
while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
SkColor color;
if (colorGlyph->paletteIndex != 0xffff) {
color = SkColorSetARGB(sk_float_round2int(colorGlyph->runColor.a * 255),
sk_float_round2int(colorGlyph->runColor.r * 255),
sk_float_round2int(colorGlyph->runColor.g * 255),
sk_float_round2int(colorGlyph->runColor.b * 255));
} else {
// If all components of runColor are 0 or (equivalently) paletteIndex is 0xFFFF then
// the 'foreground color' is used.
if (colorGlyph->paletteIndex == 0xffff) {
color = fRec.fForegroundColor;
} else if (colorGlyph->paletteIndex < paletteEntryCount) {
color = palette[colorGlyph->paletteIndex];
} else {
SK_TRACEHR(DWRITE_E_NOCOLOR, "Invalid palette index.");
color = SK_ColorBLACK;
}
paint.setColor(color);

View File

@ -33,6 +33,96 @@
#include "src/utils/win/SkDWrite.h"
#include "src/utils/win/SkDWriteFontFileStream.h"
HRESULT DWriteFontTypeface::initializePalette() {
if (!fIsColorFont) {
return S_OK;
}
if (!SkTFitsIn<UINT32>(fRequestedPalette.index)) {
HRM(DWRITE_E_NOCOLOR, "Requested palette index out of UINT32 range.");
}
UINT32 dwPaletteCount = fDWriteFontFace2->GetColorPaletteCount();
UINT32 requestedPaletteIndex = fRequestedPalette.index;
if (!(requestedPaletteIndex < dwPaletteCount)) {
HRM(DWRITE_E_NOCOLOR, "Requested palette index out of range.");
}
UINT32 dwPaletteEntryCount = fDWriteFontFace2->GetPaletteEntryCount();
SkAutoSTMalloc<8, DWRITE_COLOR_F> dwPaletteEntry(dwPaletteEntryCount);
HRM(fDWriteFontFace2->GetPaletteEntries(requestedPaletteIndex,
0, dwPaletteEntryCount,
dwPaletteEntry),
"Could not retrieve palette entries.");
fPalette.reset(new SkColor[dwPaletteEntryCount]);
for (UINT32 i = 0; i < dwPaletteEntryCount; ++i) {
fPalette[i] = SkColorSetARGB(sk_float_round2int(dwPaletteEntry[i].a * 255),
sk_float_round2int(dwPaletteEntry[i].r * 255),
sk_float_round2int(dwPaletteEntry[i].g * 255),
sk_float_round2int(dwPaletteEntry[i].b * 255));
}
for (int i = 0; i < fRequestedPalette.overrideCount; ++i) {
const SkFontArguments::Palette::Override& paletteOverride = fRequestedPalette.overrides[i];
if (!SkTFitsIn<UINT32>(paletteOverride.index) ||
!((UINT32)paletteOverride.index < dwPaletteEntryCount))
{
continue;
}
fPalette[paletteOverride.index] = paletteOverride.color;
}
fPaletteEntryCount = dwPaletteEntryCount;
return S_OK;
}
DWriteFontTypeface::DWriteFontTypeface(const SkFontStyle& style,
IDWriteFactory* factory,
IDWriteFontFace* fontFace,
IDWriteFont* font,
IDWriteFontFamily* fontFamily,
sk_sp<Loaders> loaders,
const SkFontArguments::Palette& palette)
: SkTypeface(style, false)
, fFactory(SkRefComPtr(factory))
, fDWriteFontFamily(SkRefComPtr(fontFamily))
, fDWriteFont(SkRefComPtr(font))
, fDWriteFontFace(SkRefComPtr(fontFace))
, fRequestedPaletteEntryOverrides(palette.overrideCount
? (SkFontArguments::Palette::Override*)memcpy(
new SkFontArguments::Palette::Override[palette.overrideCount],
palette.overrides,
palette.overrideCount * sizeof(palette.overrides[0]))
: nullptr)
, fRequestedPalette{palette.index,
fRequestedPaletteEntryOverrides.get(), palette.overrideCount }
, fPaletteEntryCount(0)
, fLoaders(std::move(loaders))
{
if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace1))) {
// IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
// http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
SkASSERT_RELEASE(nullptr == fDWriteFontFace1.get());
}
if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace2))) {
SkASSERT_RELEASE(nullptr == fDWriteFontFace2.get());
}
if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace4))) {
SkASSERT_RELEASE(nullptr == fDWriteFontFace4.get());
}
if (!SUCCEEDED(fFactory->QueryInterface(&fFactory2))) {
SkASSERT_RELEASE(nullptr == fFactory2.get());
}
if (fDWriteFontFace1 && fDWriteFontFace1->IsMonospacedFont()) {
this->setIsFixedPitch(true);
}
fIsColorFont = fFactory2 && fDWriteFontFace2 && fDWriteFontFace2->IsColorFont();
this->initializePalette();
}
DWriteFontTypeface::Loaders::~Loaders() {
// Don't return if any fail, just keep going to free up as much as possible.
HRESULT hr;
@ -85,6 +175,12 @@ void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
desc->setFamilyName(utf8FamilyName.c_str());
desc->setStyle(this->fontStyle());
desc->setPaleteIndex(fRequestedPalette.index);
sk_careful_memcpy(desc->setPaletteEntryOverrides(fRequestedPalette.overrideCount),
fRequestedPalette.overrides,
fRequestedPalette.overrideCount * sizeof(fRequestedPalette.overrides[0]));
*isLocalStream = SkToBool(fLoaders);
}
@ -357,11 +453,26 @@ sk_sp<SkTypeface> DWriteFontTypeface::onMakeClone(const SkFontArguments& args) c
newFontFace.get(),
fDWriteFont.get(),
fDWriteFontFamily.get(),
fLoaders);
fLoaders,
args.getPalette());
}
#endif
// If the palette args have changed, a new font will need to be created.
if (args.getPalette().index != fRequestedPalette.index ||
args.getPalette().overrideCount != fRequestedPalette.overrideCount ||
memcmp(args.getPalette().overrides, fRequestedPalette.overrides,
fRequestedPalette.overrideCount * sizeof(fRequestedPalette.overrides[0])))
{
return DWriteFontTypeface::Make(fFactory.get(),
fDWriteFontFace.get(),
fDWriteFont.get(),
fDWriteFontFamily.get(),
fLoaders,
args.getPalette());
}
return sk_ref_sp(this);
}

View File

@ -8,6 +8,7 @@
#ifndef SkTypeface_win_dw_DEFINED
#define SkTypeface_win_dw_DEFINED
#include "include/core/SkFontArguments.h"
#include "include/core/SkTypeface.h"
#include "src/core/SkAdvancedTypefaceMetrics.h"
#include "src/core/SkLeanWindows.h"
@ -64,35 +65,9 @@ private:
IDWriteFontFace* fontFace,
IDWriteFont* font,
IDWriteFontFamily* fontFamily,
sk_sp<Loaders> loaders)
: SkTypeface(style, false)
, fFactory(SkRefComPtr(factory))
, fDWriteFontFamily(SkRefComPtr(fontFamily))
, fDWriteFont(SkRefComPtr(font))
, fDWriteFontFace(SkRefComPtr(fontFace))
, fLoaders(std::move(loaders))
{
if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace1))) {
// IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
// http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
SkASSERT_RELEASE(nullptr == fDWriteFontFace1.get());
}
if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace2))) {
SkASSERT_RELEASE(nullptr == fDWriteFontFace2.get());
}
if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace4))) {
SkASSERT_RELEASE(nullptr == fDWriteFontFace4.get());
}
if (!SUCCEEDED(fFactory->QueryInterface(&fFactory2))) {
SkASSERT_RELEASE(nullptr == fFactory2.get());
}
if (fDWriteFontFace1 && fDWriteFontFace1->IsMonospacedFont()) {
this->setIsFixedPitch(true);
}
fIsColorFont = fFactory2 && fDWriteFontFace2 && fDWriteFontFace2->IsColorFont();
}
sk_sp<Loaders> loaders,
const SkFontArguments::Palette&);
HRESULT initializePalette();
public:
SkTScopedComPtr<IDWriteFactory> fFactory;
@ -105,15 +80,22 @@ public:
SkTScopedComPtr<IDWriteFontFace4> fDWriteFontFace4;
bool fIsColorFont;
std::unique_ptr<SkFontArguments::Palette::Override> fRequestedPaletteEntryOverrides;
SkFontArguments::Palette fRequestedPalette;
size_t fPaletteEntryCount;
std::unique_ptr<SkColor[]> fPalette;
static sk_sp<DWriteFontTypeface> Make(
IDWriteFactory* factory,
IDWriteFontFace* fontFace,
IDWriteFont* font,
IDWriteFontFamily* fontFamily,
sk_sp<Loaders> loaders)
sk_sp<Loaders> loaders,
const SkFontArguments::Palette& palette)
{
return sk_sp<DWriteFontTypeface>(new DWriteFontTypeface(
get_style(font), factory, fontFace, font, fontFamily, std::move(loaders)));
get_style(font), factory, fontFace, font, fontFamily, std::move(loaders), palette));
}
protected: