зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1398802 - Support the AAT 'trak' table when shaping macOS fonts via Core Text. r=jrmuizel
This commit is contained in:
Родитель
cb611a9aff
Коммит
e592a806a6
|
@ -163,7 +163,8 @@ gfxMacFont::ShapeText(DrawTarget *aDrawTarget,
|
|||
|
||||
// Currently, we don't support vertical shaping via CoreText,
|
||||
// so we ignore RequiresAATLayout if vertical is requested.
|
||||
if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout() &&
|
||||
auto macFontEntry = static_cast<MacOSFontEntry*>(GetFontEntry());
|
||||
if (macFontEntry->RequiresAATLayout() &&
|
||||
!aVertical) {
|
||||
if (!mCoreTextShaper) {
|
||||
mCoreTextShaper = MakeUnique<gfxCoreTextShaper>(this);
|
||||
|
@ -173,6 +174,24 @@ gfxMacFont::ShapeText(DrawTarget *aDrawTarget,
|
|||
aShapedText)) {
|
||||
PostShapingFixup(aDrawTarget, aText, aOffset,
|
||||
aLength, aVertical, aShapedText);
|
||||
|
||||
if (macFontEntry->HasTrackingTable()) {
|
||||
// Convert font size from device pixels back to CSS px
|
||||
// to use in selecting tracking value
|
||||
float trackSize = GetAdjustedSize() *
|
||||
aShapedText->GetAppUnitsPerDevUnit() /
|
||||
AppUnitsPerCSSPixel();
|
||||
float tracking =
|
||||
macFontEntry->TrackingForCSSPx(trackSize) *
|
||||
mFUnitsConvFactor;
|
||||
// Applying tracking is a lot like the adjustment we do for
|
||||
// synthetic bold: we want to apply between clusters, not to
|
||||
// non-spacing glyphs within a cluster. So we can reuse that
|
||||
// helper here.
|
||||
aShapedText->AdjustAdvancesForSyntheticBold(tracking,
|
||||
aOffset, aLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ public:
|
|||
bool aIsDataUserFont, bool aIsLocal);
|
||||
|
||||
virtual ~MacOSFontEntry() {
|
||||
if (mTrakTable) {
|
||||
hb_blob_destroy(mTrakTable);
|
||||
}
|
||||
::CGFontRelease(mFontRef);
|
||||
}
|
||||
|
||||
|
@ -61,12 +64,26 @@ public:
|
|||
bool HasVariations();
|
||||
bool IsCFF();
|
||||
|
||||
// Return true if the font has a 'trak' table (and we can successfully
|
||||
// interpret it), otherwise false. This will load and cache the table
|
||||
// the first time it is called.
|
||||
bool HasTrackingTable();
|
||||
|
||||
// Return the tracking (in font units) to be applied for the given size.
|
||||
// (This is a floating-point number because of possible interpolation.)
|
||||
float TrackingForCSSPx(float aPointSize) const;
|
||||
|
||||
protected:
|
||||
gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle,
|
||||
bool aNeedsBold) override;
|
||||
|
||||
bool HasFontTable(uint32_t aTableTag) override;
|
||||
|
||||
// Helper for HasTrackingTable; check/parse the table and cache pointers
|
||||
// to the subtables we need. Returns false on failure, in which case the
|
||||
// table is unusable.
|
||||
bool ParseTrakTable();
|
||||
|
||||
static void DestroyBlobFunc(void* aUserData);
|
||||
|
||||
CGFontRef mFontRef; // owning reference to the CGFont, released on destruction
|
||||
|
@ -79,9 +96,18 @@ protected:
|
|||
bool mIsCFFInitialized;
|
||||
bool mHasVariations;
|
||||
bool mHasVariationsInitialized;
|
||||
bool mCheckedForTracking;
|
||||
nsTHashtable<nsUint32HashKey> mAvailableTables;
|
||||
|
||||
mozilla::WeakPtr<mozilla::gfx::UnscaledFont> mUnscaledFont;
|
||||
|
||||
// For AAT font being shaped by Core Text, a strong reference to the 'trak'
|
||||
// table (if present).
|
||||
hb_blob_t* mTrakTable;
|
||||
// Cached pointers to tables within 'trak', initialized by ParseTrakTable.
|
||||
const mozilla::AutoSwap_PRInt16* mTrakValues;
|
||||
const mozilla::AutoSwap_PRInt32* mTrakSizeTable;
|
||||
uint16_t mNumTrakSizes;
|
||||
};
|
||||
|
||||
class gfxMacPlatformFontList : public gfxPlatformFontList {
|
||||
|
|
|
@ -312,7 +312,11 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
|
|||
mIsCFF(false),
|
||||
mIsCFFInitialized(false),
|
||||
mHasVariations(false),
|
||||
mHasVariationsInitialized(false)
|
||||
mHasVariationsInitialized(false),
|
||||
mCheckedForTracking(false),
|
||||
mTrakTable(nullptr),
|
||||
mTrakValues(nullptr),
|
||||
mTrakSizeTable(nullptr)
|
||||
{
|
||||
mWeight = aWeight;
|
||||
}
|
||||
|
@ -331,7 +335,11 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
|
|||
mIsCFF(false),
|
||||
mIsCFFInitialized(false),
|
||||
mHasVariations(false),
|
||||
mHasVariationsInitialized(false)
|
||||
mHasVariationsInitialized(false),
|
||||
mCheckedForTracking(false),
|
||||
mTrakTable(nullptr),
|
||||
mTrakValues(nullptr),
|
||||
mTrakSizeTable(nullptr)
|
||||
{
|
||||
mFontRef = aFontRef;
|
||||
mFontRefInitialized = true;
|
||||
|
@ -464,6 +472,142 @@ MacOSFontEntry::HasFontTable(uint32_t aTableTag)
|
|||
return mAvailableTables.GetEntry(aTableTag);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
AutoSwap_PRUint32 version;
|
||||
AutoSwap_PRUint16 format;
|
||||
AutoSwap_PRUint16 horizOffset;
|
||||
AutoSwap_PRUint16 vertOffset;
|
||||
AutoSwap_PRUint16 reserved;
|
||||
// TrackData horizData;
|
||||
// TrackData vertData;
|
||||
} TrakHeader;
|
||||
|
||||
typedef struct {
|
||||
AutoSwap_PRUint16 nTracks;
|
||||
AutoSwap_PRUint16 nSizes;
|
||||
AutoSwap_PRUint32 sizeTableOffset;
|
||||
// trackTableEntry trackTable[];
|
||||
// fixed32 sizeTable[];
|
||||
} TrackData;
|
||||
|
||||
typedef struct {
|
||||
AutoSwap_PRUint32 track;
|
||||
AutoSwap_PRUint16 nameIndex;
|
||||
AutoSwap_PRUint16 offset;
|
||||
} TrackTableEntry;
|
||||
|
||||
bool
|
||||
MacOSFontEntry::HasTrackingTable()
|
||||
{
|
||||
if (!mCheckedForTracking) {
|
||||
mCheckedForTracking = true;
|
||||
mTrakTable = GetFontTable(TRUETYPE_TAG('t','r','a','k'));
|
||||
if (mTrakTable) {
|
||||
if (!ParseTrakTable()) {
|
||||
hb_blob_destroy(mTrakTable);
|
||||
mTrakTable = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mTrakTable != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
MacOSFontEntry::ParseTrakTable()
|
||||
{
|
||||
// Check table validity and set up the subtable pointers we need;
|
||||
// if 'trak' table is invalid, or doesn't contain a 'normal' track,
|
||||
// return false to tell the caller not to try using it.
|
||||
unsigned int len;
|
||||
const char* data = hb_blob_get_data(mTrakTable, &len);
|
||||
if (len < sizeof(TrakHeader)) {
|
||||
return false;
|
||||
}
|
||||
auto trak = reinterpret_cast<const TrakHeader*>(data);
|
||||
uint16_t horizOffset = trak->horizOffset;
|
||||
if (trak->version != 0x00010000 ||
|
||||
uint16_t(trak->format) != 0 ||
|
||||
horizOffset == 0 ||
|
||||
uint16_t(trak->reserved) != 0) {
|
||||
return false;
|
||||
}
|
||||
// Find the horizontal trackData, and check it doesn't overrun the buffer.
|
||||
if (horizOffset > len - sizeof(TrackData)) {
|
||||
return false;
|
||||
}
|
||||
auto trackData = reinterpret_cast<const TrackData*>(data + horizOffset);
|
||||
uint16_t nTracks = trackData->nTracks;
|
||||
mNumTrakSizes = trackData->nSizes;
|
||||
if (nTracks == 0 || mNumTrakSizes < 2) {
|
||||
return false;
|
||||
}
|
||||
uint32_t sizeTableOffset = trackData->sizeTableOffset;
|
||||
// Find the trackTable, and check it doesn't overrun the buffer.
|
||||
if (horizOffset >
|
||||
len - (sizeof(TrackData) + nTracks * sizeof(TrackTableEntry))) {
|
||||
return false;
|
||||
}
|
||||
auto trackTable = reinterpret_cast<const TrackTableEntry*>
|
||||
(data + horizOffset + sizeof(TrackData));
|
||||
// Look for 'normal' tracking, bail out if no such track is present.
|
||||
unsigned trackIndex;
|
||||
for (trackIndex = 0; trackIndex < nTracks; ++trackIndex) {
|
||||
if (trackTable[trackIndex].track == 0x00000000) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trackIndex == nTracks) {
|
||||
return false;
|
||||
}
|
||||
// Find list of tracking values, and check they won't overrun.
|
||||
uint16_t offset = trackTable[trackIndex].offset;
|
||||
if (offset > len - mNumTrakSizes * sizeof(uint16_t)) {
|
||||
return false;
|
||||
}
|
||||
mTrakValues = reinterpret_cast<const AutoSwap_PRInt16*>(data + offset);
|
||||
// Find the size subtable, and check it doesn't overrun the buffer.
|
||||
mTrakSizeTable =
|
||||
reinterpret_cast<const AutoSwap_PRInt32*>(data + sizeTableOffset);
|
||||
if (mTrakSizeTable + mNumTrakSizes >
|
||||
reinterpret_cast<const AutoSwap_PRInt32*>(data + len)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float
|
||||
MacOSFontEntry::TrackingForCSSPx(float aSize) const
|
||||
{
|
||||
MOZ_ASSERT(mTrakTable && mTrakValues && mTrakSizeTable);
|
||||
|
||||
// Find index of first sizeTable entry that is >= the requested size.
|
||||
Fixed fixedSize = X2Fix(aSize);
|
||||
unsigned sizeIndex;
|
||||
for (sizeIndex = 0; sizeIndex < mNumTrakSizes; ++sizeIndex) {
|
||||
if (mTrakSizeTable[sizeIndex] >= fixedSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Return the tracking value for the requested size, or an interpolated
|
||||
// value if the exact size isn't found.
|
||||
if (sizeIndex == mNumTrakSizes) {
|
||||
// Request is larger than last entry in the table, so just use that.
|
||||
// (We don't attempt to extrapolate more extreme tracking values than
|
||||
// the largest or smallest present in the table.)
|
||||
return int16_t(mTrakValues[mNumTrakSizes - 1]);
|
||||
}
|
||||
if (sizeIndex == 0 || mTrakSizeTable[sizeIndex] == fixedSize) {
|
||||
// Found an exact match, or size was smaller than the first entry.
|
||||
return int16_t(mTrakValues[sizeIndex]);
|
||||
}
|
||||
// Requested size falls between two entries: interpolate value.
|
||||
double s0 = Fix2X(mTrakSizeTable[sizeIndex - 1]);
|
||||
double s1 = Fix2X(mTrakSizeTable[sizeIndex]);
|
||||
double t = (aSize - s0) / (s1 - s0);
|
||||
return (1.0 - t) * int16_t(mTrakValues[sizeIndex - 1]) +
|
||||
t * int16_t(mTrakValues[sizeIndex]);
|
||||
}
|
||||
|
||||
void
|
||||
MacOSFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const
|
||||
|
|
Загрузка…
Ссылка в новой задаче