зеркало из https://github.com/mozilla/gecko-dev.git
bug 449292 - part 6 - font table cache and accessors to support harfbuzz. r=jdaggett sr=roc
This commit is contained in:
Родитель
37f3b9fe59
Коммит
673bdd945e
|
@ -44,6 +44,9 @@
|
|||
#include "gfxUserFontSet.h"
|
||||
#include "cairo-win32.h"
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
/**
|
||||
* \brief Class representing a font face for a font entry.
|
||||
*/
|
||||
|
@ -72,6 +75,10 @@ public:
|
|||
|
||||
IDWriteFontFace *GetFontFace() { return mFontFace.get(); }
|
||||
|
||||
// override gfxFont table access function to bypass gfxFontEntry cache,
|
||||
// use DWrite API to get direct access to system font data
|
||||
virtual hb_blob_t *GetFontTable(PRUint32 aTag);
|
||||
|
||||
protected:
|
||||
void ComputeMetrics();
|
||||
|
||||
|
@ -79,6 +86,8 @@ protected:
|
|||
|
||||
cairo_scaled_font_t *CairoScaledFont();
|
||||
|
||||
static void DestroyBlobFunc(void* userArg);
|
||||
|
||||
nsRefPtr<IDWriteFontFace> mFontFace;
|
||||
cairo_font_face_t *mCairoFontFace;
|
||||
cairo_scaled_font_t *mCairoScaledFont;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "gfxFontUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "gfxSkipChars.h"
|
||||
#include "gfxRect.h"
|
||||
|
@ -71,6 +72,8 @@ class gfxUserFontData;
|
|||
|
||||
class nsILanguageAtomService;
|
||||
|
||||
typedef struct _hb_blob_t hb_blob_t;
|
||||
|
||||
// We should eliminate these synonyms when it won't cause many merge conflicts.
|
||||
#define FONT_STYLE_NORMAL NS_FONT_STYLE_NORMAL
|
||||
#define FONT_STYLE_ITALIC NS_FONT_STYLE_ITALIC
|
||||
|
@ -217,7 +220,15 @@ public:
|
|||
|
||||
const nsString& FamilyName();
|
||||
|
||||
already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle, PRBool aNeedsBold);
|
||||
already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
|
||||
PRBool aNeedsBold);
|
||||
|
||||
// Subclasses should override this if they can do something more efficient
|
||||
// than getting tables with GetFontTable() and caching them in the entry.
|
||||
//
|
||||
// Note that some gfxFont implementations may not call this at all,
|
||||
// if it is more efficient to get the table from the OS at that level.
|
||||
virtual hb_blob_t *GetFontTable(PRUint32 aTag);
|
||||
|
||||
nsString mName;
|
||||
|
||||
|
@ -273,6 +284,61 @@ protected:
|
|||
|
||||
gfxFontFamily *mFamily;
|
||||
|
||||
/*
|
||||
* Font table cache, to support GetFontTable for harfbuzz.
|
||||
*
|
||||
* The harfbuzz shaper (and potentially other clients) needs access to raw
|
||||
* font table data. This needs to be cached so that it can be used
|
||||
* repeatedly (each time we construct a text run; in some cases, for
|
||||
* each character/glyph within the run) without re-fetching large tables
|
||||
* every time.
|
||||
*
|
||||
* Because we may instantiate many gfxFonts for the same physical font
|
||||
* file (at different sizes), we should ensure that they can share a
|
||||
* single cached copy of the font tables. To do this, we implement table
|
||||
* access and caching on the fontEntry rather than the font itself.
|
||||
*
|
||||
* The default implementation uses GetFontTable() to read font table
|
||||
* data into byte arrays, and caches these in a hashtable along with
|
||||
* hb_blob_t wrappers. The entry can then return blobs to harfbuzz.
|
||||
*
|
||||
* Harfbuzz will "destroy" the blobs when it is finished with them;
|
||||
* they are created with a destroy callback that removes them from
|
||||
* the hashtable when all references are released.
|
||||
*/
|
||||
class FontTableCacheEntry {
|
||||
public:
|
||||
// create a cache entry by adopting the content of an existing buffer
|
||||
FontTableCacheEntry(nsTArray<PRUint8>& aBuffer,
|
||||
PRUint32 aTag,
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry>& aCache);
|
||||
|
||||
~FontTableCacheEntry() {
|
||||
MOZ_COUNT_DTOR(FontTableCacheEntry);
|
||||
}
|
||||
|
||||
hb_blob_t *GetBlob() const { return mBlob; }
|
||||
|
||||
protected:
|
||||
// the data block, owned (via adoption) by the entry
|
||||
nsTArray<PRUint8> mData;
|
||||
// a harfbuzz blob wrapper that we can return to clients
|
||||
hb_blob_t *mBlob;
|
||||
// the blob destroy function needs to know the table tag
|
||||
// and the owning hashtable, so that it can remove the entry
|
||||
PRUint32 mTag;
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry>&
|
||||
mCache;
|
||||
|
||||
private:
|
||||
// not implemented
|
||||
FontTableCacheEntry(const FontTableCacheEntry&);
|
||||
|
||||
static void Destroy(void *aUserData);
|
||||
};
|
||||
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry> mFontTableCache;
|
||||
|
||||
private:
|
||||
gfxFontEntry(const gfxFontEntry&);
|
||||
gfxFontEntry& operator=(const gfxFontEntry&);
|
||||
|
@ -779,6 +845,20 @@ public:
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
// Access to raw font table data (needed for Harfbuzz):
|
||||
// returns a pointer to data owned by the fontEntry or the OS,
|
||||
// which will remain valid until released.
|
||||
//
|
||||
// Default implementations forward to the font entry, which
|
||||
// maintains a shared table cache; however, subclasses may
|
||||
// override if they can provide more efficient table access.
|
||||
|
||||
// Get pointer to a specific font table, or an empty blob if
|
||||
// the table doesn't exist in the font
|
||||
virtual hb_blob_t *GetFontTable(PRUint32 aTag) {
|
||||
return mFontEntry->GetFontTable(aTag);
|
||||
}
|
||||
|
||||
// Font metrics
|
||||
struct Metrics {
|
||||
gfxFloat xHeight;
|
||||
|
|
|
@ -505,35 +505,39 @@ public:
|
|||
}
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength,
|
||||
ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxSparseBitSet& aCharacterMap);
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength,
|
||||
ReadCMAPTableFormat4(const PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxSparseBitSet& aCharacterMap);
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat14(PRUint8 *aBuf, PRUint32 aLength,
|
||||
ReadCMAPTableFormat14(const PRUint8 *aBuf, PRUint32 aLength,
|
||||
PRUint8*& aTable);
|
||||
|
||||
static PRUint32
|
||||
FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
|
||||
FindPreferredSubtable(const PRUint8 *aBuf, PRUint32 aBufLength,
|
||||
PRUint32 *aTableOffset, PRUint32 *aUVSTableOffset,
|
||||
PRBool *aSymbolEncoding);
|
||||
|
||||
static nsresult
|
||||
ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
|
||||
ReadCMAP(const PRUint8 *aBuf, PRUint32 aBufLength,
|
||||
gfxSparseBitSet& aCharacterMap,
|
||||
PRUint32& aUVSOffset,
|
||||
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
|
||||
|
||||
static PRUint32
|
||||
MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh);
|
||||
|
||||
static PRUint32
|
||||
MapCharToGlyphFormat12(const PRUint8 *aBuf, PRUint32 aCh);
|
||||
|
||||
static PRUint16
|
||||
MapUVSToGlyphFormat14(const PRUint8 *aBuf, PRUint32 aCh, PRUint32 aVS);
|
||||
|
||||
static PRUint32
|
||||
MapCharToGlyph(PRUint8 *aBuf, PRUint32 aBufLength, PRUnichar aCh);
|
||||
MapCharToGlyph(const PRUint8 *aBuf, PRUint32 aBufLength, PRUnichar aCh);
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ EXTRA_DSO_LDOPTS += \
|
|||
$(NSPR_LIBS) \
|
||||
$(ZLIB_LIBS) \
|
||||
$(QCMS_LIBS) \
|
||||
$(MOZ_HARFBUZZ_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
|
||||
#include "gfxDWriteTextAnalysis.h"
|
||||
|
||||
#include "harfbuzz/hb-blob.h"
|
||||
|
||||
// Chosen this as to resemble DWrite's own oblique face style.
|
||||
#define OBLIQUE_SKEW_FACTOR 0.3
|
||||
|
||||
|
@ -318,3 +320,48 @@ gfxDWriteFont::CairoScaledFont()
|
|||
|
||||
return mCairoScaledFont;
|
||||
}
|
||||
|
||||
// Access to font tables packaged in hb_blob_t form
|
||||
|
||||
// object attached to the Harfbuzz blob, used to release
|
||||
// the table when the blob is destroyed
|
||||
class FontTableRec {
|
||||
public:
|
||||
FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
|
||||
: mFontFace(aFontFace), mContext(aContext)
|
||||
{ }
|
||||
|
||||
~FontTableRec() {
|
||||
mFontFace->ReleaseFontTable(mContext);
|
||||
}
|
||||
|
||||
private:
|
||||
IDWriteFontFace *mFontFace;
|
||||
void *mContext;
|
||||
};
|
||||
|
||||
/*static*/ void
|
||||
gfxDWriteFont::DestroyBlobFunc(void* aUserData)
|
||||
{
|
||||
FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
|
||||
delete ftr;
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxDWriteFont::GetFontTable(PRUint32 aTag)
|
||||
{
|
||||
const void *data;
|
||||
UINT32 size;
|
||||
void *context;
|
||||
BOOL exists;
|
||||
HRESULT hr = mFontFace->TryGetFontTable(NS_SWAP32(aTag),
|
||||
&data, &size, &context, &exists);
|
||||
if (SUCCEEDED(hr) && exists) {
|
||||
FontTableRec *ftr = new FontTableRec(mFontFace, context);
|
||||
return hb_blob_create(static_cast<const char*>(data), size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
DestroyBlobFunc, ftr);
|
||||
}
|
||||
|
||||
return hb_blob_create_empty();
|
||||
}
|
||||
|
|
|
@ -63,6 +63,8 @@
|
|||
#include "cairo.h"
|
||||
#include "gfxFontTest.h"
|
||||
|
||||
#include "harfbuzz/hb-blob.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
gfxFontCache *gfxFontCache::gGlobalCache = nsnull;
|
||||
|
@ -87,11 +89,11 @@ static PRUint32 gGlyphExtentsSetupFallBackToTight = 0;
|
|||
|
||||
gfxFontEntry::~gfxFontEntry()
|
||||
{
|
||||
if (mUserFontData)
|
||||
if (mUserFontData) {
|
||||
delete mUserFontData;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PRBool gfxFontEntry::TestCharacterMap(PRUint32 aCh)
|
||||
{
|
||||
if (!mCmapInitialized) {
|
||||
|
@ -100,7 +102,6 @@ PRBool gfxFontEntry::TestCharacterMap(PRUint32 aCh)
|
|||
return mCharacterMap.test(aCh);
|
||||
}
|
||||
|
||||
|
||||
nsresult gfxFontEntry::InitializeUVSMap()
|
||||
{
|
||||
// mUVSOffset will not be initialized
|
||||
|
@ -137,7 +138,6 @@ nsresult gfxFontEntry::InitializeUVSMap()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRUint16 gfxFontEntry::GetUVSGlyph(PRUint32 aCh, PRUint32 aVS)
|
||||
{
|
||||
InitializeUVSMap();
|
||||
|
@ -149,14 +149,12 @@ PRUint16 gfxFontEntry::GetUVSGlyph(PRUint32 aCh, PRUint32 aVS)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
nsresult gfxFontEntry::ReadCMAP()
|
||||
{
|
||||
mCmapInitialized = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
const nsString& gfxFontEntry::FamilyName()
|
||||
{
|
||||
NS_ASSERTION(mFamily, "gfxFontEntry is not a member of a family");
|
||||
|
@ -185,6 +183,66 @@ gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle, PRBool aNeedsBold)
|
|||
return f;
|
||||
}
|
||||
|
||||
gfxFontEntry::FontTableCacheEntry::FontTableCacheEntry
|
||||
(nsTArray<PRUint8>& aBuffer,
|
||||
PRUint32 aTag,
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry>& aCache)
|
||||
: mTag(aTag), mCache(aCache)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FontTableCacheEntry);
|
||||
mData.SwapElements(aBuffer);
|
||||
mBlob = hb_blob_create((const char*)mData.Elements(), mData.Length(),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
gfxFontEntry::FontTableCacheEntry::Destroy,
|
||||
this);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
gfxFontEntry::FontTableCacheEntry::Destroy(void *aUserData)
|
||||
{
|
||||
gfxFontEntry::FontTableCacheEntry *ftce =
|
||||
static_cast<gfxFontEntry::FontTableCacheEntry*>(aUserData);
|
||||
ftce->mCache.Remove(ftce->mTag);
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxFontEntry::GetFontTable(PRUint32 aTag)
|
||||
{
|
||||
if (!mFontTableCache.IsInitialized()) {
|
||||
// we do this here rather than on fontEntry construction
|
||||
// because not all shapers will access the table cache at all
|
||||
mFontTableCache.Init(10);
|
||||
}
|
||||
|
||||
FontTableCacheEntry *entry = nsnull;
|
||||
if (!mFontTableCache.Get(aTag, &entry)) {
|
||||
nsTArray<PRUint8> buffer;
|
||||
if (NS_SUCCEEDED(GetFontTable(aTag, buffer))) {
|
||||
entry = new FontTableCacheEntry(buffer, // adopts buffer elements
|
||||
aTag, mFontTableCache);
|
||||
if (mFontTableCache.Put(aTag, entry)) {
|
||||
return entry->GetBlob();
|
||||
}
|
||||
hb_blob_destroy(entry->GetBlob());
|
||||
delete entry; // we failed to cache it!
|
||||
return hb_blob_create_empty();
|
||||
}
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
return hb_blob_reference(entry->GetBlob());
|
||||
}
|
||||
|
||||
return hb_blob_create_empty();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// class gfxFontFamily
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// we consider faces with mStandardFace == PR_TRUE to be "greater than" those with PR_FALSE,
|
||||
// because during style matching, later entries will replace earlier ones
|
||||
class FontEntryStandardFaceComparator {
|
||||
|
|
|
@ -60,6 +60,10 @@
|
|||
|
||||
#define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
|
||||
|
||||
#define UNICODE_BMP_LIMIT 0x10000
|
||||
|
||||
using namespace mozilla; // for the AutoSwap_* types
|
||||
|
||||
/* Unicode subrange table
|
||||
* from: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
|
||||
*
|
||||
|
@ -230,45 +234,62 @@ static const struct UnicodeRangeTableEntry gUnicodeRanges[] = {
|
|||
{ 111, 0x1D360, 0x1D37F, "Counting Rod Numerals" }
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct {
|
||||
AutoSwap_PRUint16 format;
|
||||
AutoSwap_PRUint16 reserved;
|
||||
AutoSwap_PRUint32 length;
|
||||
AutoSwap_PRUint32 language;
|
||||
AutoSwap_PRUint32 numGroups;
|
||||
} Format12CmapHeader;
|
||||
|
||||
typedef struct {
|
||||
AutoSwap_PRUint32 startCharCode;
|
||||
AutoSwap_PRUint32 endCharCode;
|
||||
AutoSwap_PRUint32 startGlyphId;
|
||||
} Format12Group;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBitSet& aCharacterMap)
|
||||
gfxFontUtils::ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxSparseBitSet& aCharacterMap)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
OffsetReserved = 2,
|
||||
OffsetTableLength = 4,
|
||||
OffsetLanguage = 8,
|
||||
OffsetNumberGroups = 12,
|
||||
OffsetGroups = 16,
|
||||
// Ensure table is large enough that we can safely read the header
|
||||
NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
SizeOfGroup = 12,
|
||||
|
||||
GroupOffsetStartCode = 0,
|
||||
GroupOffsetEndCode = 4
|
||||
};
|
||||
NS_ENSURE_TRUE(aLength >= 16, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 12,
|
||||
// Sanity-check header fields
|
||||
const Format12CmapHeader *cmap12 =
|
||||
reinterpret_cast<const Format12CmapHeader*>(aBuf);
|
||||
NS_ENSURE_TRUE(PRUint16(cmap12->format) == 12,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetReserved) == 0,
|
||||
NS_ENSURE_TRUE(PRUint16(cmap12->reserved) == 0,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
PRUint32 tablelen = ReadLongAt(aBuf, OffsetTableLength);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
NS_ENSURE_TRUE(tablelen >= 16, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
PRUint32 tablelen = cmap12->length;
|
||||
NS_ENSURE_TRUE(tablelen >= sizeof(Format12CmapHeader) &&
|
||||
tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
NS_ENSURE_TRUE(ReadLongAt(aBuf, OffsetLanguage) == 0,
|
||||
NS_ENSURE_TRUE(cmap12->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
// Check that the table is large enough for the group array
|
||||
const PRUint32 numGroups = cmap12->numGroups;
|
||||
NS_ENSURE_TRUE((tablelen - sizeof(Format12CmapHeader)) /
|
||||
sizeof(Format12Group) >= numGroups,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
const PRUint32 numGroups = ReadLongAt(aBuf, OffsetNumberGroups);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (12 * numGroups),
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
// The array of groups immediately follows the subtable header.
|
||||
const Format12Group *group =
|
||||
reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
|
||||
|
||||
const PRUint8 *groups = aBuf + OffsetGroups;
|
||||
// Check that groups are in correct order and do not overlap,
|
||||
// and record character coverage in aCharacterMap.
|
||||
PRUint32 prevEndCharCode = 0;
|
||||
for (PRUint32 i = 0; i < numGroups; i++, groups += SizeOfGroup) {
|
||||
const PRUint32 startCharCode = ReadLongAt(groups, GroupOffsetStartCode);
|
||||
const PRUint32 endCharCode = ReadLongAt(groups, GroupOffsetEndCode);
|
||||
for (PRUint32 i = 0; i < numGroups; i++, group++) {
|
||||
const PRUint32 startCharCode = group->startCharCode;
|
||||
const PRUint32 endCharCode = group->endCharCode;
|
||||
NS_ENSURE_TRUE((prevEndCharCode < startCharCode || i == 0) &&
|
||||
startCharCode <= endCharCode &&
|
||||
endCharCode <= CMAP_MAX_CODEPOINT,
|
||||
|
@ -283,7 +304,8 @@ gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBi
|
|||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBitSet& aCharacterMap)
|
||||
gfxFontUtils::ReadCMAPTableFormat4(const PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxSparseBitSet& aCharacterMap)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
|
@ -360,7 +382,7 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBit
|
|||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat14(PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxFontUtils::ReadCMAPTableFormat14(const PRUint8 *aBuf, PRUint32 aLength,
|
||||
PRUint8*& aTable)
|
||||
{
|
||||
enum {
|
||||
|
@ -473,8 +495,9 @@ gfxFontUtils::ReadCMAPTableFormat14(PRUint8 *aBuf, PRUint32 aLength,
|
|||
#define isUVSEncoding(p, e) ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform)
|
||||
|
||||
PRUint32
|
||||
gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
|
||||
PRUint32 *aTableOffset, PRUint32 *aUVSTableOffset,
|
||||
gfxFontUtils::FindPreferredSubtable(const PRUint8 *aBuf, PRUint32 aBufLength,
|
||||
PRUint32 *aTableOffset,
|
||||
PRUint32 *aUVSTableOffset,
|
||||
PRBool *aSymbolEncoding)
|
||||
{
|
||||
enum {
|
||||
|
@ -508,7 +531,7 @@ gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
|
|||
// save the format we want here
|
||||
PRUint32 keepFormat = 0;
|
||||
|
||||
PRUint8 *table = aBuf + SizeOfHeader;
|
||||
const PRUint8 *table = aBuf + SizeOfHeader;
|
||||
for (PRUint16 i = 0; i < numTables; ++i, table += SizeOfTable) {
|
||||
const PRUint16 platformID = ReadShortAt(table, TableOffsetPlatformID);
|
||||
if (!acceptablePlatform(platformID))
|
||||
|
@ -551,13 +574,15 @@ gfxFontUtils::FindPreferredSubtable(PRUint8 *aBuf, PRUint32 aBufLength,
|
|||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
|
||||
gfxFontUtils::ReadCMAP(const PRUint8 *aBuf, PRUint32 aBufLength,
|
||||
gfxSparseBitSet& aCharacterMap,
|
||||
PRUint32& aUVSOffset,
|
||||
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont)
|
||||
{
|
||||
PRUint32 offset;
|
||||
PRBool symbol;
|
||||
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, &aUVSOffset, &symbol);
|
||||
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength,
|
||||
&offset, &aUVSOffset, &symbol);
|
||||
|
||||
if (format == 4) {
|
||||
if (symbol) {
|
||||
|
@ -567,20 +592,20 @@ gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCha
|
|||
aUnicodeFont = PR_TRUE;
|
||||
aSymbolFont = PR_FALSE;
|
||||
}
|
||||
return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset, aCharacterMap);
|
||||
return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset,
|
||||
aCharacterMap);
|
||||
}
|
||||
|
||||
if (format == 12) {
|
||||
aUnicodeFont = PR_TRUE;
|
||||
aSymbolFont = PR_FALSE;
|
||||
return ReadCMAPTableFormat12(aBuf + offset, aBufLength - offset, aCharacterMap);
|
||||
return ReadCMAPTableFormat12(aBuf + offset, aBufLength - offset,
|
||||
aCharacterMap);
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
using namespace mozilla; // for the AutoSwap_* types
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct {
|
||||
|
@ -635,11 +660,6 @@ gfxFontUtils::MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh)
|
|||
PRUint16 rangeShiftOver2;
|
||||
PRUint16 index;
|
||||
|
||||
// not needed because PRUnichar cannot exceed 0xFFFF
|
||||
// if (aCh >= 0x10000) {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
segCount = (PRUint16)(cmap4->segCountX2) / 2;
|
||||
|
||||
endCodes = &cmap4->arrays[0];
|
||||
|
@ -683,6 +703,54 @@ gfxFontUtils::MapCharToGlyphFormat4(const PRUint8 *aBuf, PRUnichar aCh)
|
|||
return 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
gfxFontUtils::MapCharToGlyphFormat12(const PRUint8 *aBuf, PRUint32 aCh)
|
||||
{
|
||||
const Format12CmapHeader *cmap12 =
|
||||
reinterpret_cast<const Format12CmapHeader*>(aBuf);
|
||||
|
||||
// We know that numGroups is within range for the subtable size
|
||||
// because it was checked by ReadCMAPTableFormat12.
|
||||
PRUint32 numGroups = cmap12->numGroups;
|
||||
|
||||
// The array of groups immediately follows the subtable header.
|
||||
const Format12Group *groups =
|
||||
reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
|
||||
|
||||
// For most efficient binary search, we want to work on a range that
|
||||
// is a power of 2 so that we can always halve it by shifting.
|
||||
// So we find the largest power of 2 that is <= numGroups.
|
||||
// We will offset this range by rangeOffset so as to reach the end
|
||||
// of the table, provided that doesn't put us beyond the target
|
||||
// value from the outset.
|
||||
PRUint32 powerOf2 = mozilla::FindHighestBit(numGroups);
|
||||
PRUint32 rangeOffset = numGroups - powerOf2;
|
||||
PRUint32 range = 0;
|
||||
PRUint32 startCharCode;
|
||||
|
||||
if (groups[rangeOffset].startCharCode <= aCh) {
|
||||
range = rangeOffset;
|
||||
}
|
||||
|
||||
// Repeatedly halve the size of the range until we find the target group
|
||||
while (powerOf2 > 1) {
|
||||
powerOf2 >>= 1;
|
||||
if (groups[range + powerOf2].startCharCode <= aCh) {
|
||||
range += powerOf2;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the character is actually present in the range and return
|
||||
// the corresponding glyph ID
|
||||
startCharCode = groups[range].startCharCode;
|
||||
if (startCharCode <= aCh && groups[range].endCharCode >= aCh) {
|
||||
return groups[range].startGlyphId + aCh - startCharCode;
|
||||
}
|
||||
|
||||
// Else it's not present, so return the .notdef glyph
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRUint16
|
||||
gfxFontUtils::MapUVSToGlyphFormat14(const PRUint8 *aBuf, PRUint32 aCh, PRUint32 aVS)
|
||||
{
|
||||
|
@ -732,19 +800,23 @@ gfxFontUtils::MapUVSToGlyphFormat14(const PRUint8 *aBuf, PRUint32 aCh, PRUint32
|
|||
}
|
||||
|
||||
PRUint32
|
||||
gfxFontUtils::MapCharToGlyph(PRUint8 *aBuf, PRUint32 aBufLength, PRUnichar aCh)
|
||||
gfxFontUtils::MapCharToGlyph(const PRUint8 *aBuf, PRUint32 aBufLength,
|
||||
PRUnichar aCh)
|
||||
{
|
||||
PRUint32 offset;
|
||||
PRBool symbol;
|
||||
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset, nsnull, &symbol);
|
||||
PRUint32 format = FindPreferredSubtable(aBuf, aBufLength, &offset,
|
||||
nsnull, &symbol);
|
||||
|
||||
if (format == 4)
|
||||
return MapCharToGlyphFormat4(aBuf + offset, aCh);
|
||||
|
||||
// other formats not currently supported; this is used only for the
|
||||
// Mac OS X 10.6 LiGothic font hack (bug 532346)
|
||||
|
||||
return 0;
|
||||
switch (format) {
|
||||
case 4:
|
||||
return aCh < UNICODE_BMP_LIMIT ?
|
||||
MapCharToGlyphFormat4(aBuf + offset, aCh) : 0;
|
||||
case 12:
|
||||
return MapCharToGlyphFormat12(aBuf + offset, aCh);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint8 gfxFontUtils::CharRangeBit(PRUint32 ch) {
|
||||
|
|
|
@ -246,13 +246,19 @@ GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, PRBool aNeedsBo
|
|||
nsresult
|
||||
GDIFontEntry::GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer)
|
||||
{
|
||||
if (!IsTrueType()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
AutoDC dc;
|
||||
AutoSelectFont font(dc.GetDC(), &mLogFont);
|
||||
if (font.IsValid()) {
|
||||
PRInt32 tableSize = ::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, NULL, NULL);
|
||||
PRInt32 tableSize =
|
||||
::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, NULL, NULL);
|
||||
if (tableSize != GDI_ERROR) {
|
||||
if (aBuffer.SetLength(tableSize)) {
|
||||
::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, aBuffer.Elements(), tableSize);
|
||||
::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0,
|
||||
aBuffer.Elements(), tableSize);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
|
|
@ -49,6 +49,7 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl
|
|||
PRBool aNeedsBold)
|
||||
: gfxFont(aFontEntry, aFontStyle),
|
||||
mATSFont(aFontEntry->GetFontRef()),
|
||||
mCGFont(nsnull),
|
||||
mFontFace(nsnull),
|
||||
mScaledFont(nsnull),
|
||||
mAdjustedSize(0.0)
|
||||
|
@ -57,14 +58,19 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl
|
|||
mSyntheticBoldOffset = 1; // devunit offset when double-striking text to fake boldness
|
||||
}
|
||||
|
||||
mCGFont = ::CGFontCreateWithPlatformFont(&mATSFont);
|
||||
if (!mCGFont) {
|
||||
mIsValid = PR_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
// InitMetrics will handle the sizeAdjust factor and set mAdjustedSize
|
||||
InitMetrics();
|
||||
if (!mIsValid)
|
||||
if (!mIsValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGFontRef cgFont = ::CGFontCreateWithPlatformFont(&mATSFont);
|
||||
mFontFace = cairo_quartz_font_face_create_for_cgfont(cgFont);
|
||||
::CGFontRelease(cgFont);
|
||||
mFontFace = cairo_quartz_font_face_create_for_cgfont(mCGFont);
|
||||
|
||||
cairo_status_t cairoerr = cairo_font_face_status(mFontFace);
|
||||
if (cairoerr != CAIRO_STATUS_SUCCESS) {
|
||||
|
@ -133,6 +139,9 @@ gfxMacFont::~gfxMacFont()
|
|||
if (mFontFace) {
|
||||
cairo_font_face_destroy(mFontFace);
|
||||
}
|
||||
|
||||
// this is documented to be safe if mCGFont is null
|
||||
::CGFontRelease(mCGFont);
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -158,6 +167,17 @@ gfxMacFont::InitMetrics()
|
|||
{
|
||||
gfxFloat size =
|
||||
PR_MAX(((mAdjustedSize != 0.0f) ? mAdjustedSize : mStyle.size), 1.0f);
|
||||
PRUint32 upem = ::CGFontGetUnitsPerEm(mCGFont);
|
||||
if (!upem) {
|
||||
mIsValid = PR_FALSE;
|
||||
#ifdef DEBUG
|
||||
char warnBuf[1024];
|
||||
sprintf(warnBuf, "Bad font metrics for: %s (no unitsPerEm value)",
|
||||
NS_ConvertUTF16toUTF8(mFontEntry->Name()).get());
|
||||
NS_WARNING(warnBuf);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
ATSFontMetrics atsMetrics;
|
||||
OSStatus err;
|
||||
|
@ -176,16 +196,10 @@ gfxMacFont::InitMetrics()
|
|||
return;
|
||||
}
|
||||
|
||||
// create a temporary local CTFont for glyph measurement
|
||||
CTFontRef aCTFont =
|
||||
::CTFontCreateWithPlatformFont(mATSFont, size, NULL, NULL);
|
||||
|
||||
// prefer to get xHeight from ATS metrics (unhinted) rather than Core Text (hinted),
|
||||
// see bug 429605.
|
||||
if (atsMetrics.xHeight > 0)
|
||||
mMetrics.xHeight = atsMetrics.xHeight * size;
|
||||
else
|
||||
mMetrics.xHeight = GetCharHeight(aCTFont, 'x');
|
||||
mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * size / upem;
|
||||
|
||||
if (mAdjustedSize == 0.0f) {
|
||||
if (mMetrics.xHeight != 0.0f && mStyle.sizeAdjust != 0.0f) {
|
||||
|
@ -195,9 +209,6 @@ gfxMacFont::InitMetrics()
|
|||
// the recursive call to InitMetrics will see the adjusted size,
|
||||
// and set up the rest of the metrics fields accordingly
|
||||
InitMetrics();
|
||||
|
||||
// release our temporary CTFont
|
||||
::CFRelease(aCTFont);
|
||||
return;
|
||||
}
|
||||
mAdjustedSize = size;
|
||||
|
@ -228,8 +239,11 @@ gfxMacFont::InitMetrics()
|
|||
mMetrics.emAscent = mMetrics.maxAscent * mMetrics.emHeight / mMetrics.maxHeight;
|
||||
mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent;
|
||||
|
||||
CFDataRef cmap =
|
||||
::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('c','m','a','p'));
|
||||
|
||||
PRUint32 glyphID;
|
||||
float xWidth = GetCharWidth(aCTFont, 'x', &glyphID);
|
||||
gfxFloat xWidth = GetCharWidth(cmap, upem, size, 'x', &glyphID);
|
||||
if (atsMetrics.avgAdvanceWidth != 0.0)
|
||||
mMetrics.aveCharWidth = PR_MIN(atsMetrics.avgAdvanceWidth * size, xWidth);
|
||||
else if (glyphID != 0)
|
||||
|
@ -245,14 +259,16 @@ gfxMacFont::InitMetrics()
|
|||
mMetrics.maxAdvance = mMetrics.aveCharWidth;
|
||||
}
|
||||
|
||||
mMetrics.spaceWidth = GetCharWidth(aCTFont, ' ', &glyphID);
|
||||
mMetrics.spaceWidth = GetCharWidth(cmap, upem, size, ' ', &glyphID);
|
||||
mSpaceGlyph = glyphID;
|
||||
|
||||
mMetrics.zeroOrAveCharWidth = GetCharWidth(aCTFont, '0', &glyphID);
|
||||
mMetrics.zeroOrAveCharWidth = GetCharWidth(cmap, upem, size, '0', &glyphID);
|
||||
if (glyphID == 0)
|
||||
mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
|
||||
|
||||
::CFRelease(aCTFont);
|
||||
if (cmap) {
|
||||
::CFRelease(cmap);
|
||||
}
|
||||
|
||||
SanitizeMetrics(&mMetrics, mFontEntry->mIsBadUnderlineFont);
|
||||
|
||||
|
@ -270,44 +286,48 @@ gfxMacFont::InitMetrics()
|
|||
#endif
|
||||
}
|
||||
|
||||
float
|
||||
gfxMacFont::GetCharWidth(CTFontRef aCTFont, PRUnichar aUniChar,
|
||||
PRUint32 *aGlyphID)
|
||||
gfxFloat
|
||||
gfxMacFont::GetCharWidth(CFDataRef aCmap, PRUint32 aUpem, gfxFloat aSize,
|
||||
PRUnichar aUniChar, PRUint32 *aGlyphID)
|
||||
{
|
||||
UniChar c = aUniChar;
|
||||
CGGlyph glyph;
|
||||
if (::CTFontGetGlyphsForCharacters(aCTFont, &c, &glyph, 1)) {
|
||||
CGSize advance;
|
||||
::CTFontGetAdvancesForGlyphs(aCTFont,
|
||||
kCTFontHorizontalOrientation,
|
||||
&glyph,
|
||||
&advance,
|
||||
1);
|
||||
if (aGlyphID != nsnull)
|
||||
*aGlyphID = glyph;
|
||||
return advance.width;
|
||||
CGGlyph glyph = 0;
|
||||
|
||||
if (aCmap) {
|
||||
glyph = gfxFontUtils::MapCharToGlyph(::CFDataGetBytePtr(aCmap),
|
||||
::CFDataGetLength(aCmap),
|
||||
aUniChar);
|
||||
}
|
||||
|
||||
// couldn't get glyph for the char
|
||||
if (aGlyphID != nsnull)
|
||||
*aGlyphID = 0;
|
||||
return 0;
|
||||
}
|
||||
if (aGlyphID) {
|
||||
*aGlyphID = glyph;
|
||||
}
|
||||
|
||||
float
|
||||
gfxMacFont::GetCharHeight(CTFontRef aCTFont, PRUnichar aUniChar)
|
||||
{
|
||||
UniChar c = aUniChar;
|
||||
CGGlyph glyph;
|
||||
if (::CTFontGetGlyphsForCharacters(aCTFont, &c, &glyph, 1)) {
|
||||
CGRect boundingRect;
|
||||
::CTFontGetBoundingRectsForGlyphs(aCTFont,
|
||||
kCTFontHorizontalOrientation,
|
||||
&glyph,
|
||||
&boundingRect,
|
||||
1);
|
||||
return boundingRect.size.height;
|
||||
if (glyph) {
|
||||
int advance;
|
||||
if (::CGFontGetGlyphAdvances(mCGFont, &glyph, 1, &advance)) {
|
||||
return advance * aSize / aUpem;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
gfxMacFont::DestroyBlobFunc(void* aUserData)
|
||||
{
|
||||
::CFRelease((CFDataRef)aUserData);
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxMacFont::GetFontTable(PRUint32 aTag)
|
||||
{
|
||||
CFDataRef dataRef = ::CGFontCopyTableForTag(mCGFont, aTag);
|
||||
if (dataRef) {
|
||||
return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
|
||||
::CFDataGetLength(dataRef),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
DestroyBlobFunc, (void*)dataRef);
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
virtual ~gfxMacFont();
|
||||
|
||||
ATSFontRef GetATSFontRef() const { return mATSFont; }
|
||||
CGFontRef GetCGFontRef() const { return mCGFont; }
|
||||
|
||||
// TODO: probably should move this up to gfxFont
|
||||
// and ensure it is handled uniformly across all platforms
|
||||
|
@ -71,14 +72,20 @@ public:
|
|||
|
||||
virtual PRBool SetupCairoFont(gfxContext *aContext);
|
||||
|
||||
// override gfxFont table access function to bypass gfxFontEntry cache,
|
||||
// use CGFontRef API to get direct access to system font data
|
||||
virtual hb_blob_t *GetFontTable(PRUint32 aTag);
|
||||
|
||||
protected:
|
||||
void InitMetrics();
|
||||
|
||||
float GetCharWidth(CTFontRef aCTFont, PRUnichar aUniChar,
|
||||
PRUint32 *aGlyphID);
|
||||
float GetCharHeight(CTFontRef aCTFont, PRUnichar aUniChar);
|
||||
gfxFloat GetCharWidth(CFDataRef aCmap, PRUint32 aUpem, gfxFloat aSize,
|
||||
PRUnichar aUniChar, PRUint32 *aGlyphID);
|
||||
|
||||
static void DestroyBlobFunc(void* aUserData);
|
||||
|
||||
ATSFontRef mATSFont;
|
||||
CGFontRef mCGFont;
|
||||
|
||||
cairo_font_face_t *mFontFace;
|
||||
cairo_scaled_font_t *mScaledFont;
|
||||
|
|
|
@ -292,15 +292,19 @@ MacOSFontEntry::GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer)
|
|||
nsAutoreleasePool localPool;
|
||||
|
||||
ATSFontRef fontRef = GetFontRef();
|
||||
if (fontRef == (ATSFontRef)kATSUInvalidFontID)
|
||||
if (fontRef == (ATSFontRef)kATSUInvalidFontID) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ByteCount dataLength;
|
||||
OSStatus status = ::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &dataLength);
|
||||
NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
|
||||
if (status != noErr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!aBuffer.AppendElements(dataLength))
|
||||
if (!aBuffer.AppendElements(dataLength)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
PRUint8 *dataPtr = aBuffer.Elements();
|
||||
|
||||
status = ::ATSFontGetTable(fontRef, aTableTag, 0, dataLength, dataPtr, &dataLength);
|
||||
|
|
Загрузка…
Ссылка в новой задаче