Bug 507970, part 2: implement support for downloadable WOFF fonts, r=jdaggett

--HG--
extra : rebase_source : e68c49d2dbea815e453f9ab52ba89bd9127d3f51
This commit is contained in:
Jonathan Kew 2009-08-30 14:55:24 +01:00
parent 251df10046
commit 37bbb8bf3d
25 changed files with 1816 additions and 100 deletions

View File

@ -86,12 +86,14 @@ public:
}
static FontEntry*
CreateFontEntry(const gfxProxyFontEntry &aProxyEntry, nsISupports *aLoader,
CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength);
static FontEntry*
CreateFontEntryFromFace(FT_Face aFace);
CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData = nsnull);
// aFontData is NS_Malloc'ed data that aFace depends on, to be freed
// after the face is destroyed; null if there is no such buffer
cairo_font_face_t *CairoFontFace();
nsresult ReadCMAP();

View File

@ -359,6 +359,13 @@ struct FontDataOverlay {
PRUint32 overlayDest; // dest offset from start of font data
};
enum gfxUserFontType {
GFX_USERFONT_UNKNOWN = 0,
GFX_USERFONT_OPENTYPE = 1,
GFX_USERFONT_SVG = 2,
GFX_USERFONT_WOFF = 3
};
class THEBES_API gfxFontUtils {
public:
@ -484,13 +491,22 @@ public:
static nsresult
MakeEOTHeader(const PRUint8 *aFontData, PRUint32 aFontDataLength,
nsTArray<PRUint8> *aHeader, FontDataOverlay *aOverlay);
// determine whether a font (which has already passed ValidateSFNTHeaders)
// is CFF format rather than TrueType
static PRBool
IsCffFont(const PRUint8* aFontData);
#endif
// determine the format of font data
static gfxUserFontType
DetermineFontDataType(const PRUint8 *aFontData, PRUint32 aFontDataLength);
// checks for valid SFNT table structure, returns true if valid
// does *not* guarantee that all font data is valid
static PRBool
ValidateSFNTHeaders(const PRUint8 *aFontData, PRUint32 aFontDataLength,
PRBool *aIsCFF = nsnull);
ValidateSFNTHeaders(const PRUint8 *aFontData, PRUint32 aFontDataLength);
// create a new name table and build a new font with that name table
// appended on the end, returns true on success

View File

@ -88,7 +88,6 @@ public:
const nsAString &aFullname);
// Used for @font-face { src: url(); }
static gfxFontEntry *NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData,
PRUint32 aLength);

View File

@ -211,15 +211,15 @@ public:
/**
* Activate a platform font. (Needed to support @font-face src url().)
* aFontData must persist as long as a reference is held to aLoader.
* aFontData is a NS_Malloc'ed block that must be freed by this function
* (or responsibility passed on) when it is no longer needed; the caller
* will NOT free it.
* Ownership of the returned gfxFontEntry is passed to the caller,
* who must either AddRef() or delete.
*/
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData,
PRUint32 aLength)
{ return nsnull; }
PRUint32 aLength);
/**
* Whether to allow downloadable fonts via @font-face rules

View File

@ -102,7 +102,6 @@ public:
*
*/
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData,
PRUint32 aLength);

View File

@ -78,7 +78,6 @@ public:
virtual gfxPlatformFontList* CreatePlatformFontList();
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData,
PRUint32 aLength);

View File

@ -197,7 +197,9 @@ public:
// aDownloadStatus == NS_OK ==> download succeeded, error otherwise
// returns true if platform font creation sucessful (or local()
// reference was next in line)
PRBool OnLoadComplete(gfxFontEntry *aFontToLoad, nsISupports *aLoader,
// Ownership of aFontData is passed in here; the font set must
// ensure that it is eventually deleted with NS_Free().
PRBool OnLoadComplete(gfxFontEntry *aFontToLoad,
const PRUint8 *aFontData, PRUint32 aLength,
nsresult aDownloadStatus);

View File

@ -140,7 +140,6 @@ public:
// create a font entry from downloaded font data
static FontEntry* LoadFont(const gfxProxyFontEntry &aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData,
PRUint32 aLength);

View File

@ -126,7 +126,6 @@ public:
* Activate a platform font (needed to support @font-face src url() )
*/
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData,
PRUint32 aLength);

View File

@ -154,9 +154,11 @@ CMMSRCS = gfxMacPlatformFontList.mm
EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL -framework QuickTime
endif
CSRCS += woff.c
EXTRA_DSO_LDOPTS += $(TK_LIBS)
DEFINES += -DIMPL_THEBES
DEFINES += -DIMPL_THEBES -DWOFF_MOZILLA_CLIENT
include $(topsrcdir)/config/rules.mk

View File

@ -117,33 +117,56 @@ FontEntry::~FontEntry()
/* static */
FontEntry*
FontEntry::CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
nsISupports *aLoader, const PRUint8 *aFontData,
PRUint32 aLength) {
if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength))
return nsnull;
const PRUint8 *aFontData,
PRUint32 aLength)
{
// Ownership of aFontData is passed in here; the fontEntry must
// retain it as long as the FT_Face needs it, and ensure it is
// eventually deleted.
FT_Face face;
FT_Error error =
FT_New_Memory_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(),
aFontData, aLength, 0, &face);
if (error != FT_Err_Ok)
if (error != FT_Err_Ok) {
NS_Free((void*)aFontData);
return nsnull;
FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
}
FontEntry* fe = FontEntry::CreateFontEntryFromFace(face, aFontData);
fe->mItalic = aProxyEntry.mItalic;
fe->mWeight = aProxyEntry.mWeight;
fe->mStretch = aProxyEntry.mStretch;
return fe;
}
class FTUserFontData {
public:
FTUserFontData(FT_Face aFace, const PRUint8* aData)
: mFace(aFace), mFontData(aData)
{
}
~FTUserFontData()
{
FT_Done_Face(mFace);
if (mFontData) {
NS_Free((void*)mFontData);
}
}
private:
FT_Face mFace;
const PRUint8 *mFontData;
};
static void
FTFontDestroyFunc(void *data)
{
FT_Face face = (FT_Face)data;
FT_Done_Face(face);
FTUserFontData *userFontData = static_cast<FTUserFontData*>(data);
delete userFontData;
}
/* static */ FontEntry*
FontEntry::CreateFontEntryFromFace(FT_Face aFace) {
FontEntry::CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData) {
static cairo_user_data_key_t key;
if (!aFace->family_name) {
@ -161,10 +184,12 @@ FontEntry::CreateFontEntryFromFace(FT_Face aFace) {
fe->mItalic = aFace->style_flags & FT_STYLE_FLAG_ITALIC;
fe->mFTFace = aFace;
fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, 0);
cairo_font_face_set_user_data(fe->mFontFace, &key,
aFace, FTFontDestroyFunc);
TT_OS2 *os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(aFace, ft_sfnt_os2));
FTUserFontData *userFontData = new FTUserFontData(aFace, aFontData);
cairo_font_face_set_user_data(fe->mFontFace, &key,
userFontData, FTFontDestroyFunc);
TT_OS2 *os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(aFace, ft_sfnt_os2));
PRUint16 os2weight = 0;
if (os2 && os2->version != 0xffff) {
// Technically, only 100 to 900 are valid, but some fonts
@ -205,7 +230,9 @@ FontEntry::CairoFontFace()
FT_New_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(), mFilename.get(), mFTFontIndex, &face);
mFTFace = face;
mFontFace = cairo_ft_font_face_create_for_ft_face(face, 0);
cairo_font_face_set_user_data(mFontFace, &key, face, FTFontDestroyFunc);
FTUserFontData *userFontData = new FTUserFontData(face, nsnull);
cairo_font_face_set_user_data(mFontFace, &key,
userFontData, FTFontDestroyFunc);
}
return mFontFace;
}

View File

@ -52,6 +52,8 @@
#include "plbase64.h"
#include "woff.h"
#ifdef XP_MACOSX
#include <CoreFoundation/CoreFoundation.h>
#endif
@ -694,12 +696,38 @@ ValidateKernTable(const PRUint8 *aKernTable, PRUint32 aKernLength)
return PR_FALSE;
}
gfxUserFontType
gfxFontUtils::DetermineFontDataType(const PRUint8 *aFontData, PRUint32 aFontDataLength)
{
// test for OpenType font data
// problem: EOT-Lite with 0x10000 length will look like TrueType!
if (aFontDataLength >= sizeof(SFNTHeader)) {
const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
PRUint32 sfntVersion = sfntHeader->sfntVersion;
if (IsValidSFNTVersion(sfntVersion)) {
return GFX_USERFONT_OPENTYPE;
}
}
// test for WOFF
if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) {
const AutoSwap_PRUint32 *version =
reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
if (PRUint32(*version) == TRUETYPE_TAG('w','O','F','F')) {
return GFX_USERFONT_WOFF;
}
}
// tests for other formats here
return GFX_USERFONT_UNKNOWN;
}
PRBool
gfxFontUtils::ValidateSFNTHeaders(const PRUint8 *aFontData,
PRUint32 aFontDataLength,
PRBool *aIsCFF)
PRUint32 aFontDataLength)
{
NS_ASSERTION(aFontData && aFontDataLength != 0, "null font data");
NS_ASSERTION(aFontData, "null font data");
PRUint64 dataLength(aFontDataLength);
@ -716,9 +744,6 @@ gfxFontUtils::ValidateSFNTHeaders(const PRUint8 *aFontData,
return PR_FALSE;
}
if (aIsCFF)
*aIsCFF = (sfntVersion == TRUETYPE_TAG('O','T','T','O'));
// iterate through the table headers to find the head, name and OS/2 tables
PRBool foundHead = PR_FALSE, foundOS2 = PR_FALSE, foundName = PR_FALSE;
PRBool foundGlyphs = PR_FALSE, foundCFF = PR_FALSE, foundKern = PR_FALSE;
@ -1733,4 +1758,14 @@ gfxFontUtils::MakeEOTHeader(const PRUint8 *aFontData, PRUint32 aFontDataLength,
return NS_OK;
}
/* static */
PRBool
gfxFontUtils::IsCffFont(const PRUint8* aFontData)
{
// this is only called after aFontData has passed basic validation,
// so we know there is enough data present to allow us to read the version!
const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
}
#endif

View File

@ -690,27 +690,13 @@ public:
};
gfxFontEntry*
gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength)
gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength)
{
OSStatus err;
NS_ASSERTION(aFontData && aLength != 0,
"MakePlatformFont called with null data ptr");
// do simple validation check on font data before
// attempting to activate it
if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength)) {
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font error, invalid font data for (%s)",
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
return nsnull;
}
NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
ATSFontRef fontRef;
ATSFontContainerRef containerRef;
@ -720,7 +706,7 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
const PRUint32 kMaxRetries = 3;
PRUint32 retryCount = 0;
while (retryCount++ < kMaxRetries) {
err = ::ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
err = ::ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
kPrivateATSFontContextPrivate,
kATSFontFormatUnspecified,
NULL,

View File

@ -300,10 +300,10 @@ public:
class gfxDownloadedFcFontEntry : public gfxFcFontEntry {
public:
// This takes ownership of the face.
// This takes ownership of the face and its underlying data
gfxDownloadedFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
nsISupports *aLoader, FT_Face aFace)
: gfxFcFontEntry(aProxyEntry), mLoader(aLoader), mFace(aFace)
const PRUint8 *aData, FT_Face aFace)
: gfxFcFontEntry(aProxyEntry), mFontData(aData), mFace(aFace)
{
NS_PRECONDITION(aFace != NULL, "aFace is NULL!");
InitPattern();
@ -319,9 +319,13 @@ public:
protected:
virtual void InitPattern();
// mLoader holds a reference to memory used by mFace.
nsCOMPtr<nsISupports> mLoader;
// mFontData holds the data used to instantiate the FT_Face;
// this has to persist until we are finished with the face,
// then be released with NS_Free().
const PRUint8* mFontData;
FT_Face mFace;
// mPangoCoverage is the charset property of the pattern translated to a
// format that Pango understands. A reference is kept here so that it can
// be shared by multiple PangoFonts (of different sizes).
@ -371,6 +375,7 @@ gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry()
FcPatternDel(mPatterns[0], FC_FT_FACE);
}
FT_Done_Face(mFace);
NS_Free((void*)mFontData);
}
typedef FcPattern* (*QueryFaceFunction)(const FT_Face face,
@ -2218,18 +2223,22 @@ GetFTLibrary()
/* static */ gfxFontEntry *
gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData, PRUint32 aLength)
{
// Ownership of aFontData is passed in here, and transferred to the
// new fontEntry, which will release it when no longer needed.
// Using face_index = 0 for the first face in the font, as we have no
// other information. FT_New_Memory_Face checks for a NULL FT_Library.
FT_Face face;
FT_Error error =
FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face);
if (error != 0)
if (error != 0) {
NS_Free((void*)aFontData);
return nsnull;
}
return new gfxDownloadedFcFontEntry(aProxyEntry, aLoader, face);
return new gfxDownloadedFcFontEntry(aProxyEntry, aFontData, face);
}

View File

@ -327,6 +327,21 @@ gfxPlatform::DownloadableFontsEnabled()
return allowDownloadableFonts;
}
gfxFontEntry*
gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength)
{
// Default implementation does not handle activating downloaded fonts;
// just free the data and return.
// Platforms that support @font-face must override this,
// using the data to instantiate the font, and taking responsibility
// for freeing it when no longer required.
if (aFontData) {
NS_Free((void*)aFontData);
}
return nsnull;
}
static void
AppendGenericFontFromPref(nsString& aFonts, const char *aLangGroup, const char *aGenericName)

View File

@ -108,6 +108,7 @@ public:
const nsAString& aFontName) = 0;
// create a new platform font from downloaded data (@font-face)
// this method is responsible to ensure aFontData is NS_Free()'d
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength) = 0;

View File

@ -308,15 +308,10 @@ gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
gfxFontEntry*
gfxPlatformGtk::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData, PRUint32 aLength)
{
// Just being consistent with other platforms.
// This will mean that only fonts in SFNT formats will be accepted.
if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength))
return nsnull;
return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aLoader,
// passing ownership of the font data to the new font entry
return gfxPangoFontGroup::NewFontEntry(*aProxyEntry,
aFontData, aLength);
}

View File

@ -187,10 +187,16 @@ gfxPlatformMac::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
gfxFontEntry*
gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData, PRUint32 aLength)
{
return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, aFontData, aLength);
// Ownership of aFontData is passed in here.
// After activating the font via ATS, we can discard the data.
gfxFontEntry *fe =
gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
aFontData,
aLength);
NS_Free((void*)aFontData);
return fe;
}
PRBool

View File

@ -15,11 +15,12 @@
* The Original Code is thebes gfx code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* Portions created by the Initial Developer are Copyright (C) 2008-2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -46,6 +47,8 @@
#include "nsUnicharUtils.h"
#include "prlong.h"
#include "woff.h"
#ifdef PR_LOGGING
static PRLogModuleInfo *gUserFontsLog = PR_NewLogModule("userfonts");
#endif /* PR_LOGGING */
@ -87,7 +90,6 @@ gfxUserFontSet::gfxUserFontSet()
gfxUserFontSet::~gfxUserFontSet()
{
}
void
@ -169,25 +171,99 @@ gfxUserFontSet::FindFontEntry(const nsAString& aName,
return nsnull;
}
// Given a buffer of downloaded font data, do any necessary preparation
// to make it into usable OpenType.
// May return the original pointer unchanged, or a newly-allocated
// block (in which case the passed-in block is NS_Free'd).
// aLength is updated if necessary to the new length of the data.
// Returns NULL and NS_Free's the incoming data in case of errors.
const PRUint8*
PrepareOpenTypeData(const PRUint8* aData, PRUint32* aLength)
{
switch(gfxFontUtils::DetermineFontDataType(aData, *aLength)) {
case GFX_USERFONT_OPENTYPE:
// nothing to do
return aData;
case GFX_USERFONT_WOFF: {
PRUint32 status = eWOFF_ok;
PRUint32 bufferSize = woffGetDecodedSize(aData, *aLength, &status);
if (WOFF_FAILURE(status)) {
break;
}
PRUint8* decodedData = static_cast<PRUint8*>(NS_Alloc(bufferSize));
if (!decodedData) {
break;
}
woffDecodeToBuffer(aData, *aLength,
decodedData, bufferSize,
aLength, &status);
// replace original data with the decoded version
NS_Free((void*)aData);
aData = decodedData;
if (WOFF_FAILURE(status)) {
// something went wrong, discard the data and return NULL
break;
}
// success, return the decoded data
return aData;
}
// xxx - add support for other wrappers here
default:
NS_WARNING("unknown font format");
break;
}
// discard downloaded data that couldn't be used
NS_Free((void*)aData);
return nsnull;
}
// This is called when a font download finishes.
// Ownership of aFontData passes in here, and the font set must
// ensure that it is eventually deleted via NS_Free().
PRBool
gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
nsISupports *aLoader,
const PRUint8 *aFontData, PRUint32 aLength,
nsresult aDownloadStatus)
{
NS_ASSERTION(aFontToLoad->mIsProxy, "trying to load font data for wrong font entry type");
if (!aFontToLoad->mIsProxy)
if (!aFontToLoad->mIsProxy) {
NS_Free((void*)aFontData);
return PR_FALSE;
}
gfxProxyFontEntry *pe = static_cast<gfxProxyFontEntry*> (aFontToLoad);
// download successful, make platform font using font data
if (NS_SUCCEEDED(aDownloadStatus)) {
gfxFontEntry *fe =
gfxPlatform::GetPlatform()->MakePlatformFont(pe, aLoader,
aFontData, aLength);
gfxFontEntry *fe = nsnull;
// Unwrap/decompress or otherwise munge the downloaded data
// to make a usable sfnt structure.
// This may cause aFontData to point to a new buffer, or be NULL.
aFontData = PrepareOpenTypeData(aFontData, &aLength);
if (aFontData &&
gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength)) {
// Here ownership of aFontData is passed to the platform,
// which will delete it when no longer required
fe = gfxPlatform::GetPlatform()->MakePlatformFont(pe,
aFontData,
aLength);
aFontData = nsnull; // the platform may have freed the data now!
} else {
// the data was unusable, so just discard it
// (error will be reported below, if logging is enabled)
if (aFontData) {
NS_Free((void*)aFontData);
}
}
if (fe) {
static_cast<gfxMixedFontFamily*>(pe->mFamily)->ReplaceFontEntry(pe, fe);
IncrementGeneration();
@ -195,10 +271,9 @@ gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
if (LOG_ENABLED()) {
nsCAutoString fontURI;
pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
this, pe->mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(),
LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
this, pe->mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(),
PRUint32(mGeneration)));
}
#endif
@ -208,21 +283,24 @@ gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
if (LOG_ENABLED()) {
nsCAutoString fontURI;
pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error making platform font\n",
this, pe->mSrcIndex, fontURI.get(),
LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error making platform font\n",
this, pe->mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get()));
}
#endif
}
} else {
// download failed
if (aFontData) {
NS_Free((void*)aFontData);
}
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
nsCAutoString fontURI;
pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error %8.8x downloading font data\n",
this, pe->mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(),
LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error %8.8x downloading font data\n",
this, pe->mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(),
aDownloadStatus));
}
#endif

View File

@ -515,15 +515,14 @@ public:
/* static */
FontEntry*
FontEntry::LoadFont(const gfxProxyFontEntry &aProxyEntry,
nsISupports *aLoader,const PRUint8 *aFontData,
PRUint32 aLength) {
const PRUint8 *aFontData,
PRUint32 aLength)
{
// if calls aren't available, bail
if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
return nsnull;
PRBool isCFF;
if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength, &isCFF))
return nsnull;
PRBool isCFF = gfxFontUtils::IsCffFont(aFontData);
nsresult rv;
HANDLE fontRef = nsnull;

View File

@ -841,13 +841,18 @@ gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
gfxFontEntry*
gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
nsISupports *aLoader,
const PRUint8 *aFontData, PRUint32 aLength)
{
#ifdef MOZ_FT2_FONTS
return FontEntry::CreateFontEntry(*aProxyEntry, aLoader, aFontData, aLength);
// The FT2 font needs the font data to persist, so we do NOT free it here
// but instead pass ownership to the font entry.
// Deallocation will happen later, when the font face is destroyed.
return FontEntry::CreateFontEntry(*aProxyEntry, aFontData, aLength);
#else
return FontEntry::LoadFont(*aProxyEntry, aLoader, aFontData, aLength);
// With GDI, we can free the downloaded data after activating the font
gfxFontEntry *fe = FontEntry::LoadFont(*aProxyEntry, aFontData, aLength);
NS_Free((void*)aFontData);
return fe;
#endif
}

View File

@ -0,0 +1,159 @@
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is WOFF font packaging code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef WOFF_PRIVATE_H_
#define WOFF_PRIVATE_H_
#include "woff.h"
/* private definitions used in the WOFF encoder/decoder functions */
/* create an OT tag from 4 characters */
#define TAG(a,b,c,d) ((a)<<24 | (b)<<16 | (c)<<8 | (d))
#define WOFF_SIGNATURE TAG('w','O','F','F')
#define SFNT_VERSION_CFF TAG('O','T','T','O')
#define SFNT_VERSION_TT 0x00010000
#define SFNT_VERSION_true TAG('t','r','u','e')
#define TABLE_TAG_DSIG TAG('D','S','I','G')
#define TABLE_TAG_head TAG('h','e','a','d')
#define TABLE_TAG_bhed TAG('b','h','e','d')
#define SFNT_CHECKSUM_CALC_CONST 0xB1B0AFBAU /* from the TT/OT spec */
#ifdef WOFF_MOZILLA_CLIENT/* Copies of the NS_SWAP16 and NS_SWAP32 macros; they are defined in
a C++ header in mozilla, so we cannot include that here */
# include "prtypes.h" /* defines IS_LITTLE_ENDIAN / IS_BIG_ENDIAN */
# if defined IS_LITTLE_ENDIAN
# define READ16BE(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
# define READ32BE(x) ((READ16BE((x) & 0xffff) << 16) | (READ16BE((x) >> 16)))
# elif defined IS_BIG_ENDIAN
# define READ16BE(x) (x)
# define READ32BE(x) (x)
# else
# error "Unknown byte order"
# endif
#else
/* These macros to read values as big-endian only work on "real" variables,
not general expressions, because of the use of &(x), but they are
designed to work on both BE and LE machines without the need for a
configure check. For production code, we might want to replace this
with something more efficient. */
/* read a 32-bit BigEndian value */
# define READ32BE(x) ( ( (uint32_t) ((uint8_t*)&(x))[0] << 24 ) + \
( (uint32_t) ((uint8_t*)&(x))[1] << 16 ) + \
( (uint32_t) ((uint8_t*)&(x))[2] << 8 ) + \
(uint32_t) ((uint8_t*)&(x))[3] )
/* read a 16-bit BigEndian value */
# define READ16BE(x) ( ( (uint16_t) ((uint8_t*)&(x))[0] << 8 ) + \
(uint16_t) ((uint8_t*)&(x))[1] )
#endif
#pragma pack(push,1)
typedef struct {
uint32_t version;
uint16_t numTables;
uint16_t searchRange;
uint16_t entrySelector;
uint16_t rangeShift;
} sfntHeader;
typedef struct {
uint32_t tag;
uint32_t checksum;
uint32_t offset;
uint32_t length;
} sfntDirEntry;
typedef struct {
uint32_t signature;
uint32_t flavor;
uint32_t length;
uint16_t numTables;
uint16_t reserved;
uint32_t totalSfntSize;
uint16_t majorVersion;
uint16_t minorVersion;
uint32_t metaOffset;
uint32_t metaCompLen;
uint32_t metaOrigLen;
uint32_t privOffset;
uint32_t privLen;
} woffHeader;
typedef struct {
uint32_t tag;
uint32_t offset;
uint32_t compLen;
uint32_t origLen;
uint32_t checksum;
} woffDirEntry;
typedef struct {
uint32_t version;
uint32_t fontRevision;
uint32_t checkSumAdjustment;
uint32_t magicNumber;
uint16_t flags;
uint16_t unitsPerEm;
uint32_t created[2];
uint32_t modified[2];
int16_t xMin;
int16_t yMin;
int16_t xMax;
int16_t yMax;
uint16_t macStyle;
uint16_t lowestRecPpem;
int16_t fontDirectionHint;
int16_t indexToLocFormat;
int16_t glyphDataFormat;
} sfntHeadTable;
#define HEAD_TABLE_SIZE 54 /* sizeof(sfntHeadTable) may report 56 because of alignment */
typedef struct {
uint32_t offset;
uint16_t oldIndex;
uint16_t newIndex;
} tableOrderRec;
#pragma pack(pop)
#endif

1170
gfx/thebes/src/woff.c Normal file

File diff suppressed because it is too large Load Diff

211
gfx/thebes/src/woff.h Normal file
View File

@ -0,0 +1,211 @@
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is WOFF font packaging code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef WOFF_H_
#define WOFF_H_
/* API for the WOFF encoder and decoder */
#ifdef _MSC_VER /* MS VC lacks inttypes.h
but we can make do with a few definitons here */
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
#include <inttypes.h>
#endif
#include <stdio.h> /* only for FILE, needed for woffPrintStatus */
/* error codes returned in the status parameter of WOFF functions */
enum {
/* Success */
eWOFF_ok = 0,
/* Errors: no valid result returned */
eWOFF_out_of_memory = 1, /* malloc or realloc failed */
eWOFF_invalid = 2, /* invalid input file (e.g., bad offset) */
eWOFF_compression_failure = 3, /* error in zlib call */
eWOFF_bad_signature = 4, /* unrecognized file signature */
eWOFF_buffer_too_small = 5, /* the provided buffer is too small */
eWOFF_bad_parameter = 6, /* bad parameter (e.g., null source ptr) */
eWOFF_illegal_order = 7, /* improperly ordered chunks in WOFF font */
/* Warnings: call succeeded but something odd was noticed.
Multiple warnings may be OR'd together. */
eWOFF_warn_unknown_version = 0x0100, /* unrecognized version of sfnt,
not standard TrueType or CFF */
eWOFF_warn_checksum_mismatch = 0x0200, /* bad checksum, use with caution;
any DSIG will be invalid */
eWOFF_warn_misaligned_table = 0x0400, /* table not long-aligned; fixing,
but DSIG will be invalid */
eWOFF_warn_trailing_data = 0x0800, /* trailing junk discarded,
any DSIG may be invalid */
eWOFF_warn_unpadded_table = 0x1000, /* sfnt not correctly padded,
any DSIG may be invalid */
eWOFF_warn_removed_DSIG = 0x2000 /* removed digital signature
while fixing checksum errors */
};
/* Note: status parameters must be initialized to eWOFF_ok before calling
WOFF functions. If the status parameter contains an error code,
functions will return immediately. */
#define WOFF_SUCCESS(status) (((uint32_t)(status) & 0xff) == eWOFF_ok)
#define WOFF_FAILURE(status) (!WOFF_SUCCESS(status))
#define WOFF_WARNING(status) ((uint32_t)(status) & ~0xff)
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WOFF_DISABLE_ENCODING
/*****************************************************************************
* Returns a new malloc() block containing the encoded data, or NULL on error;
* caller should free() this when finished with it.
* Returns length of the encoded data in woffLen.
* The new WOFF has no metadata or private block;
* see the following functions to update these elements.
*/
const uint8_t * woffEncode(const uint8_t * sfntData, uint32_t sfntLen,
uint16_t majorVersion, uint16_t minorVersion,
uint32_t * woffLen, uint32_t * status);
/*****************************************************************************
* Add the given metadata block to the WOFF font, replacing any existing
* metadata block. The block will be zlib-compressed.
* Metadata is required to be valid XML (use of UTF-8 is recommended),
* though this function does not currently check this.
* The woffData pointer must be a malloc() block (typically from woffEncode);
* it will be freed by this function and a new malloc() block will be returned.
* Returns NULL if an error occurs, in which case the original WOFF is NOT freed.
*/
const uint8_t * woffSetMetadata(const uint8_t * woffData, uint32_t * woffLen,
const uint8_t * metaData, uint32_t metaLen,
uint32_t * status);
/*****************************************************************************
* Add the given private data block to the WOFF font, replacing any existing
* private block. The block will NOT be zlib-compressed.
* Private data may be any arbitrary block of bytes; it may be externally
* compressed by the client if desired.
* The woffData pointer must be a malloc() block (typically from woffEncode);
* it will be freed by this function and a new malloc() block will be returned.
* Returns NULL if an error occurs, in which case the original WOFF is NOT freed.
*/
const uint8_t * woffSetPrivateData(const uint8_t * woffData, uint32_t * woffLen,
const uint8_t * privData, uint32_t privLen,
uint32_t * status);
#endif /* WOFF_DISABLE_ENCODING */
/*****************************************************************************
* Returns the size of buffer needed to decode the font (or zero on error).
*/
uint32_t woffGetDecodedSize(const uint8_t * woffData, uint32_t woffLen,
uint32_t * pStatus);
/*****************************************************************************
* Decodes WOFF font to a caller-supplied buffer of size bufferLen.
* Returns the actual size of the decoded sfnt data in pActualSfntLen
* (must be <= bufferLen, otherwise an error will be returned).
*/
void woffDecodeToBuffer(const uint8_t * woffData, uint32_t woffLen,
uint8_t * sfntData, uint32_t bufferLen,
uint32_t * pActualSfntLen, uint32_t * pStatus);
/*****************************************************************************
* Returns a new malloc() block containing the decoded data, or NULL on error;
* caller should free() this when finished with it.
* Returns length of the decoded data in sfntLen.
*/
const uint8_t * woffDecode(const uint8_t * woffData, uint32_t woffLen,
uint32_t * sfntLen, uint32_t * status);
/*****************************************************************************
* Returns a new malloc() block containing the metadata from the WOFF font,
* or NULL if an error occurs or no metadata is present.
* Length of the metadata is returned in metaLen.
* The metadata is decompressed before returning.
*/
const uint8_t * woffGetMetadata(const uint8_t * woffData, uint32_t woffLen,
uint32_t * metaLen, uint32_t * status);
/*****************************************************************************
* Returns a new malloc() block containing the private data from the WOFF font,
* or NULL if an error occurs or no private data is present.
* Length of the private data is returned in privLen.
*/
const uint8_t * woffGetPrivateData(const uint8_t * woffData, uint32_t woffLen,
uint32_t * privLen, uint32_t * status);
/*****************************************************************************
* Returns the font version numbers from the WOFF font in the major and minor
* parameters.
* Check the status result to know if the function succeeded.
*/
void woffGetFontVersion(const uint8_t * woffData, uint32_t woffLen,
uint16_t * major, uint16_t * minor,
uint32_t * status);
/*****************************************************************************
* Utility to print warning and/or error status to the specified FILE*.
* The prefix string will be prepended to each line (ok to pass NULL if no
* prefix is wanted).
* (Provides terse English messages only, not intended for end-user display;
* user-friendly tools should map the status codes to their own messages.)
*/
void woffPrintStatus(FILE * f, uint32_t status, const char * prefix);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -130,8 +130,11 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
if (!userFontSet) {
return aStatus;
}
PRBool fontUpdate = userFontSet->OnLoadComplete(mFontEntry, aLoader,
// The userFontSet is responsible for freeing the downloaded data
// (aString) when finished with it; the pointer is no longer valid
// after OnLoadComplete returns.
PRBool fontUpdate = userFontSet->OnLoadComplete(mFontEntry,
aString, aStringLen,
aStatus);
@ -143,7 +146,7 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
LOG(("fontdownloader (%p) reflow\n", this));
}
return aStatus;
return NS_SUCCESS_ADOPTED_DATA;
}
void