mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
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:
parent
67b65a3027
commit
7199a26387
16
gfx/2d/2D.h
16
gfx/2d/2D.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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,7 +1042,8 @@ 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);
|
||||
|
||||
@ -1045,6 +1051,7 @@ private:
|
||||
friend class RecordedEvent;
|
||||
|
||||
uint8_t* mData;
|
||||
ScaledFont::VariationSetting* mVariations;
|
||||
RecordedFontDetails mFontDetails;
|
||||
|
||||
bool mGetFontFileDataSucceeded;
|
||||
|
@ -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;;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user