Bug 1321031 pt 6 - Include variation settings in moz2d recording stream when using the native Mac font backend. r=bas,jrmuizel

This commit is contained in:
Jonathan Kew 2017-01-06 16:35:12 +00:00
parent 67b65a3027
commit 7199a26387
11 changed files with 257 additions and 19 deletions

View File

@ -679,7 +679,14 @@ public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
virtual ~ScaledFont() {}
typedef void (*FontFileDataOutput)(const uint8_t* aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void* aBaton);
typedef struct {
uint32_t mTag;
Float mValue;
} VariationSetting;
typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize,
uint32_t aVariationCount, const VariationSetting* aVariations,
void *aBaton);
typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton);
typedef void (*FontDescriptorOutput)(const uint8_t* aData, uint32_t aLength, Float aFontSize, void* aBaton);
@ -1398,11 +1405,16 @@ public:
*
* @param aData Pointer to the data
* @param aSize Size of the TrueType data
* @param aVariationCount Number of VariationSetting records provided.
* @param aVariations Pointer to VariationSetting records.
* @param aType Type of NativeFontResource that should be created.
* @return a NativeFontResource of nullptr if failed.
*/
static already_AddRefed<NativeFontResource>
CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType);
CreateNativeFontResource(uint8_t *aData, uint32_t aSize,
uint32_t aVariationCount,
const ScaledFont::VariationSetting* aVariations,
FontType aType);
/**
* This creates a scaled font of the given type based on font descriptor

View File

@ -502,6 +502,8 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz
already_AddRefed<NativeFontResource>
Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize,
uint32_t aVariationCount,
const ScaledFont::VariationSetting* aVariations,
FontType aType)
{
switch (aType) {
@ -526,7 +528,8 @@ Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize,
/* aNeedsCairo = */ true);
}
#elif defined(XP_DARWIN)
return NativeFontResourceMac::Create(aData, aSize);
return NativeFontResourceMac::Create(aData, aSize,
aVariationCount, aVariations);
#elif defined(MOZ_WIDGET_GTK)
return NativeFontResourceFontconfig::Create(aData, aSize);
#else

View File

@ -13,12 +13,146 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
// Simple helper class to automatically release a CFObject when it goes out
// of scope.
template<class T>
class AutoRelease
{
public:
explicit AutoRelease(T aObject)
: mObject(aObject)
{
}
~AutoRelease()
{
if (mObject) {
CFRelease(mObject);
}
}
operator T()
{
return mObject;
}
T forget()
{
T obj = mObject;
mObject = nullptr;
return obj;
}
private:
T mObject;
};
// This is essentially identical to the similarly-named helper function
// in gfx/thebes/gfxMacFont.cpp. Maybe we should put it somewhere that
// can be shared by both Moz2d and Thebes callers?
static CFDictionaryRef
CreateVariationDictionaryOrNull(CGFontRef aCGFont, uint32_t aVariationCount,
const mozilla::gfx::ScaledFont::VariationSetting* aVariations)
{
AutoRelease<CTFontRef>
ctFont(CTFontCreateWithGraphicsFont(aCGFont, 0, nullptr, nullptr));
AutoRelease<CFArrayRef> axes(CTFontCopyVariationAxes(ctFont));
if (!axes) {
return nullptr;
}
CFIndex axisCount = CFArrayGetCount(axes);
AutoRelease<CFMutableDictionaryRef>
dict(CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
// Number of variation settings passed in the aVariations parameter.
// This will typically be a very low value, so we just linear-search them.
bool allDefaultValues = true;
for (CFIndex i = 0; i < axisCount; ++i) {
// We sanity-check the axis info found in the CTFont, and bail out
// (returning null) if it doesn't have the expected types.
CFTypeRef axisInfo = CFArrayGetValueAtIndex(axes, i);
if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
return nullptr;
}
CFDictionaryRef axis = static_cast<CFDictionaryRef>(axisInfo);
CFTypeRef axisTag =
CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey);
if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
return nullptr;
}
int64_t tagLong;
if (!CFNumberGetValue(static_cast<CFNumberRef>(axisTag),
kCFNumberSInt64Type, &tagLong)) {
return nullptr;
}
CFTypeRef axisName =
CFDictionaryGetValue(axis, kCTFontVariationAxisNameKey);
if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
return nullptr;
}
// Clamp axis values to the supported range.
CFTypeRef min = CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey);
CFTypeRef max = CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey);
CFTypeRef def = CFDictionaryGetValue(axis, kCTFontVariationAxisDefaultValueKey);
if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
!max || CFGetTypeID(max) != CFNumberGetTypeID() ||
!def || CFGetTypeID(def) != CFNumberGetTypeID()) {
return nullptr;
}
double minDouble;
double maxDouble;
double defDouble;
if (!CFNumberGetValue(static_cast<CFNumberRef>(min), kCFNumberDoubleType,
&minDouble) ||
!CFNumberGetValue(static_cast<CFNumberRef>(max), kCFNumberDoubleType,
&maxDouble) ||
!CFNumberGetValue(static_cast<CFNumberRef>(def), kCFNumberDoubleType,
&defDouble)) {
return nullptr;
}
double value = defDouble;
for (uint32_t j = 0; j < aVariationCount; ++j) {
if (aVariations[j].mTag == tagLong) {
value = std::min(std::max<double>(aVariations[j].mValue,
minDouble),
maxDouble);
if (value != defDouble) {
allDefaultValues = false;
}
break;
}
}
AutoRelease<CFNumberRef> valueNumber(CFNumberCreate(kCFAllocatorDefault,
kCFNumberDoubleType,
&value));
CFDictionaryAddValue(dict, axisName, valueNumber);
}
if (allDefaultValues) {
// We didn't actually set any non-default values, so throw away the
// variations dictionary and just use the default rendering.
return nullptr;
}
return dict.forget();
}
namespace mozilla {
namespace gfx {
/* static */
already_AddRefed<NativeFontResourceMac>
NativeFontResourceMac::Create(uint8_t *aFontData, uint32_t aDataLength)
NativeFontResourceMac::Create(uint8_t *aFontData, uint32_t aDataLength,
uint32_t aVariationCount,
const ScaledFont::VariationSetting* aVariations)
{
// copy font data
CFDataRef data = CFDataCreate(kCFAllocatorDefault, aFontData, aDataLength);
@ -42,6 +176,20 @@ NativeFontResourceMac::Create(uint8_t *aFontData, uint32_t aDataLength)
return nullptr;
}
if (aVariationCount > 0) {
MOZ_ASSERT(aVariations);
AutoRelease<CFDictionaryRef>
varDict(CreateVariationDictionaryOrNull(fontRef, aVariationCount,
aVariations));
if (varDict) {
CGFontRef varFont = CGFontCreateCopyWithVariations(fontRef, varDict);
if (varFont) {
CFRelease(fontRef);
fontRef = varFont;
}
}
}
// passes ownership of fontRef to the NativeFontResourceMac instance
RefPtr<NativeFontResourceMac> fontResource =
new NativeFontResourceMac(fontRef);

View File

@ -20,7 +20,9 @@ public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceMac)
static already_AddRefed<NativeFontResourceMac>
Create(uint8_t *aFontData, uint32_t aDataLength);
Create(uint8_t *aFontData, uint32_t aDataLength,
uint32_t aVariationCount,
const ScaledFont::VariationSetting* aVariations);
already_AddRefed<ScaledFont>
CreateScaledFont(uint32_t aIndex, Float aGlyphSize,

View File

@ -1513,6 +1513,7 @@ RecordedSnapshot::OutputSimpleEventInfo(stringstream &aStringStream) const
RecordedFontData::~RecordedFontData()
{
delete[] mData;
delete[] mVariations;
}
bool
@ -1520,6 +1521,7 @@ RecordedFontData::PlayEvent(Translator *aTranslator) const
{
RefPtr<NativeFontResource> fontResource =
Factory::CreateNativeFontResource(mData, mFontDetails.size,
mFontDetails.variationCount, mVariations,
aTranslator->GetDesiredFontType());
if (!fontResource) {
return false;
@ -1537,6 +1539,8 @@ RecordedFontData::RecordToStream(std::ostream &aStream) const
WriteElement(aStream, mFontDetails.fontDataKey);
WriteElement(aStream, mFontDetails.size);
aStream.write((const char*)mData, mFontDetails.size);
WriteElement(aStream, mFontDetails.variationCount);
aStream.write((const char*)mVariations, mFontDetails.variationCount * sizeof(ScaledFont::VariationSetting));
}
void
@ -1546,14 +1550,23 @@ RecordedFontData::OutputSimpleEventInfo(stringstream &aStringStream) const
}
void
RecordedFontData::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize)
RecordedFontData::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex,
Float aGlyphSize, uint32_t aVariationCount,
const ScaledFont::VariationSetting* aVariations)
{
mData = new uint8_t[aSize];
memcpy(mData, aData, aSize);
mFontDetails.fontDataKey = SFNTData::GetUniqueKey(aData, aSize);
uint32_t varDataSize = aVariationCount * sizeof(ScaledFont::VariationSetting);
mFontDetails.fontDataKey =
SFNTData::GetUniqueKey(aData, aSize, varDataSize, aVariations);
mFontDetails.size = aSize;
mFontDetails.index = aIndex;
mFontDetails.glyphSize = aGlyphSize;
mFontDetails.variationCount = aVariationCount;
if (aVariationCount > 0) {
mVariations = new ScaledFont::VariationSetting[aVariationCount];
memcpy(mVariations, aVariations, varDataSize);
}
}
bool
@ -1567,16 +1580,26 @@ RecordedFontData::GetFontDetails(RecordedFontDetails& fontDetails)
fontDetails.size = mFontDetails.size;
fontDetails.glyphSize = mFontDetails.glyphSize;
fontDetails.index = mFontDetails.index;
fontDetails.variationCount = mFontDetails.variationCount;
return true;
}
RecordedFontData::RecordedFontData(istream &aStream)
: RecordedEvent(FONTDATA)
, mData(nullptr)
, mVariations(nullptr)
{
ReadElement(aStream, mFontDetails.fontDataKey);
ReadElement(aStream, mFontDetails.size);
mData = new uint8_t[mFontDetails.size];
aStream.read((char*)mData, mFontDetails.size);
ReadElement(aStream, mFontDetails.variationCount);
if (mFontDetails.variationCount > 0) {
mVariations = new ScaledFont::VariationSetting[mFontDetails.variationCount];
aStream.read((char*)mVariations, mFontDetails.variationCount * sizeof(ScaledFont::VariationSetting));
} else {
mVariations = nullptr;
}
}
RecordedFontDescriptor::~RecordedFontDescriptor()

View File

@ -24,7 +24,7 @@ const uint32_t kMagicInt = 0xc001feed;
// loss of backwards compatibility. Old streams will not work in a player
// using a newer major revision. And new streams will not work in a player
// using an older major revision.
const uint16_t kMajorRevision = 6;
const uint16_t kMajorRevision = 7;
// A change in minor revision means additions of new events. New streams will
// not play in older players.
const uint16_t kMinorRevision = 0;
@ -67,6 +67,7 @@ struct RecordedFontDetails
uint64_t fontDataKey;
uint32_t size;
uint32_t index;
uint32_t variationCount;
Float glyphSize;
};
@ -1014,14 +1015,18 @@ class RecordedFontData : public RecordedEvent {
public:
static void FontDataProc(const uint8_t *aData, uint32_t aSize,
uint32_t aIndex, Float aGlyphSize, void* aBaton)
uint32_t aIndex, Float aGlyphSize,
uint32_t aVariationCount,
const ScaledFont::VariationSetting* aVariations,
void* aBaton)
{
auto recordedFontData = static_cast<RecordedFontData*>(aBaton);
recordedFontData->SetFontData(aData, aSize, aIndex, aGlyphSize);
recordedFontData->SetFontData(aData, aSize, aIndex, aGlyphSize,
aVariationCount, aVariations);
}
explicit RecordedFontData(ScaledFont *aScaledFont)
: RecordedEvent(FONTDATA), mData(nullptr)
: RecordedEvent(FONTDATA), mData(nullptr), mVariations(nullptr)
{
mGetFontFileDataSucceeded = aScaledFont->GetFontFileData(&FontDataProc, this);
}
@ -1037,14 +1042,16 @@ public:
virtual ReferencePtr GetObjectRef() const { return nullptr; };
void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex,
Float aGlyphSize);
Float aGlyphSize, uint32_t aVariationCount,
const ScaledFont::VariationSetting* aVariations);
bool GetFontDetails(RecordedFontDetails& fontDetails);
private:
friend class RecordedEvent;
uint8_t *mData;
uint8_t* mData;
ScaledFont::VariationSetting* mVariations;
RecordedFontDetails mFontDetails;
bool mGetFontFileDataSucceeded;

View File

@ -152,7 +152,8 @@ SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
/* static */
uint64_t
SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength)
SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength,
uint32_t aVarDataSize, const void* aVarData)
{
uint64_t hash;
UniquePtr<SFNTData> sfntData = SFNTData::Create(aFontData, aDataLength);
@ -164,6 +165,10 @@ SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength)
hash = HashString(aFontData, aDataLength);
}
if (aVarDataSize) {
hash = AddToHash(hash, HashBytes(aVarData, aVarDataSize));
}
return hash << 32 | aDataLength;;
}

View File

@ -31,13 +31,14 @@ public:
uint32_t aDataLength);
/**
* Creates a unique key for the given font data.
* Creates a unique key for the given font data and variation settings.
*
* @param aFontData the SFNT data
* @param aDataLength length
* @return unique key to be used for caching
*/
static uint64_t GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength);
static uint64_t GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength,
uint32_t aVarDataSize, const void* aVarData);
~SFNTData();

View File

@ -257,7 +257,8 @@ ScaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton
void *context;
stream->ReadFileFragment(&fragmentStart, 0, fileSize, &context);
aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(), mSize, aBaton);
aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(), mSize,
0, nullptr, aBaton);
stream->ReleaseFileFragment(context);

View File

@ -186,6 +186,24 @@ struct writeBuf
int offset;
};
static void CollectVariationSetting(const void *key, const void *value, void *context)
{
auto keyPtr = static_cast<const CFTypeRef>(key);
auto valuePtr = static_cast<const CFTypeRef>(value);
auto vpp = static_cast<ScaledFont::VariationSetting**>(context);
if (CFGetTypeID(keyPtr) == CFNumberGetTypeID() &&
CFGetTypeID(valuePtr) == CFNumberGetTypeID()) {
uint64_t t;
double v;
if (CFNumberGetValue(static_cast<CFNumberRef>(keyPtr), kCFNumberSInt64Type, &t) &&
CFNumberGetValue(static_cast<CFNumberRef>(valuePtr), kCFNumberDoubleType, &v)) {
(*vpp)->mTag = t;
(*vpp)->mValue = v;
(*vpp)++;
}
}
}
bool
ScaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
{
@ -254,8 +272,26 @@ ScaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
// set checkSumAdjust to the computed checksum
memcpy(&buf.data[checkSumAdjustmentOffset], &fontChecksum, sizeof(fontChecksum));
// Collect any variation settings that were incorporated into the CTFont.
uint32_t variationCount = 0;
VariationSetting* variations = nullptr;
if (mCTFont) {
CFDictionaryRef dict = CTFontCopyVariation(mCTFont);
if (dict) {
CFIndex count = CFDictionaryGetCount(dict);
if (count > 0) {
variations = new VariationSetting[count];
VariationSetting* vPtr = variations;
CFDictionaryApplyFunction(dict, CollectVariationSetting, &vPtr);
variationCount = vPtr - variations;
}
CFRelease(dict);
}
}
// we always use an index of 0
aDataCallback(buf.data, buf.offset, 0, mSize, aBaton);
aDataCallback(buf.data, buf.offset, 0, mSize, variationCount, variations, aBaton);
delete[] variations;
return true;

View File

@ -77,7 +77,7 @@ ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
}
}
aDataCallback(fontData.get(), tableSize, index, mSize, aBaton);
aDataCallback(fontData.get(), tableSize, index, mSize, 0, nullptr, aBaton);
return true;
}