Support for COLR foreground color in CoreText.

COLR fonts can use a magic palette index value 0xFFFF to indicate the
foreground color of the drawing context. Modify the CoreText port to
properly indicate when the foreground color is needed and use it.

Bug: skia:12576
Change-Id: I14818b34fbe40ee508ed720510be53bc289c748a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/509178
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
Ben Wagner 2022-02-15 11:43:03 -05:00 committed by SkCQ
parent 85e7f31e6d
commit c9ca00910a
4 changed files with 60 additions and 20 deletions

View File

@ -118,6 +118,7 @@ SkScalerContext_Mac::SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface,
const SkScalerContextEffects& effects,
const SkDescriptor* desc)
: INHERITED(std::move(typeface), effects, desc)
, fOffscreen(fRec.fForegroundColor)
, fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
{
@ -150,17 +151,36 @@ static int RoundSize(int dimension) {
return SkNextPow2(dimension);
}
static CGColorRef CGColorForSkColor(CGColorSpaceRef rgbcs, SkColor bgra) {
CGFloat components[4];
components[0] = (CGFloat)SkColorGetR(bgra) * (1/255.0f);
components[1] = (CGFloat)SkColorGetG(bgra) * (1/255.0f);
components[2] = (CGFloat)SkColorGetB(bgra) * (1/255.0f);
// CoreText applies the CGContext fill color as the COLR foreground color.
// However, the alpha is applied to the whole glyph drawing (and Skia will do that as well).
// For now, cannot really support COLR foreground color alpha.
components[3] = 1.0f;
return CGColorCreate(rgbcs, components);
}
SkScalerContext_Mac::Offscreen::Offscreen(SkColor foregroundColor)
// It doesn't appear to matter what color space is specified.
// Regular blends and antialiased text are always (s*a + d*(1-a))
// and subpixel antialiased text is always g=2.0.
// However, we need to specify one anyway.
: fRGBSpace(CGColorSpaceCreateDeviceRGB())
, fCG(nullptr)
, fForegroundColor(CGColorForSkColor(fRGBSpace.get(), foregroundColor))
, fDoAA(false)
, fDoLCD(false)
{
fSize.set(0, 0);
}
CGRGBPixel* SkScalerContext_Mac::Offscreen::getCG(const SkScalerContext_Mac& context,
const SkGlyph& glyph, CGGlyph glyphID,
size_t* rowBytesPtr,
bool generateA8FromLCD) {
if (!fRGBSpace) {
//It doesn't appear to matter what color space is specified.
//Regular blends and antialiased text are always (s*a + d*(1-a))
//and subpixel antialiased text is always g=2.0.
fRGBSpace.reset(CGColorSpaceCreateDeviceRGB());
}
// default to kBW_Format
bool doAA = false;
bool doLCD = false;
@ -214,8 +234,12 @@ CGRGBPixel* SkScalerContext_Mac::Offscreen::getCG(const SkScalerContext_Mac& con
CGContextSetTextDrawingMode(fCG.get(), kCGTextFill);
// Draw black on white to create mask. (Special path exists to speed this up in CG.)
CGContextSetGrayFillColor(fCG.get(), 0.0f, 1.0f);
if (SkMask::kARGB32_Format != glyph.maskFormat()) {
// Draw black on white to create mask. (Special path exists to speed this up in CG.)
CGContextSetGrayFillColor(fCG.get(), 0.0f, 1.0f);
} else {
CGContextSetFillColorWithColor(fCG.get(), fForegroundColor.get());
}
// force our checks below to happen
fDoAA = !doAA;

View File

@ -53,14 +53,7 @@ protected:
private:
class Offscreen {
public:
Offscreen()
: fRGBSpace(nullptr)
, fCG(nullptr)
, fDoAA(false)
, fDoLCD(false)
{
fSize.set(0, 0);
}
Offscreen(SkColor foregroundColor);
CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
CGGlyph glyphID, size_t* rowBytesPtr, bool generateA8FromLCD);
@ -74,6 +67,7 @@ private:
// cached state
SkUniqueCFRef<CGContextRef> fCG;
SkUniqueCFRef<CGColorRef> fForegroundColor;
SkISize fSize;
bool fDoAA;
bool fDoLCD;

View File

@ -780,6 +780,28 @@ std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenExistingStream(int* ttcInde
return fStream ? fStream->duplicate() : nullptr;
}
static bool has_table(CTFontRef ctFont, SkFontTableTag tableTag) {
SkUniqueCFRef<CFArrayRef> cfArray(
CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions));
if (!cfArray) {
return 0;
}
CFIndex count = CFArrayGetCount(cfArray.get());
for (CFIndex i = 0; i < count; ++i) {
uintptr_t fontTag = reinterpret_cast<uintptr_t>(
CFArrayGetValueAtIndex(cfArray.get(), i));
if (tableTag == static_cast<SkFontTableTag>(fontTag)) {
return true;
}
}
return false;
}
bool SkTypeface_Mac::onGlyphMaskNeedsCurrentColor() const {
constexpr SkFontTableTag cpalTag = SkSetFourByteTag('C', 'P', 'A', 'L');
// CoreText only provides the size of a table with a copy, so do not use this->getTableSize().
return has_table(fFontRef.get(), cpalTag);
}
int SkTypeface_Mac::onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
{
@ -865,9 +887,9 @@ int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
if (!cfArray) {
return 0;
}
int count = SkToInt(CFArrayGetCount(cfArray.get()));
CFIndex count = CFArrayGetCount(cfArray.get());
if (tags) {
for (int i = 0; i < count; ++i) {
for (CFIndex i = 0; i < count; ++i) {
uintptr_t fontTag = reinterpret_cast<uintptr_t>(
CFArrayGetValueAtIndex(cfArray.get(), i));
tags[i] = static_cast<SkFontTableTag>(fontTag);

View File

@ -95,7 +95,7 @@ protected:
int onGetUPEM() const override;
std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override;
std::unique_ptr<SkStreamAsset> onOpenExistingStream(int* ttcIndex) const override;
bool onGlyphMaskNeedsCurrentColor() const override { return false; }
bool onGlyphMaskNeedsCurrentColor() const override;
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const override;
void onGetFamilyName(SkString* familyName) const override;