aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/core/SkFontHost.h9
-rw-r--r--include/core/SkPaint.h20
-rw-r--r--include/core/SkScalerContext.h4
-rw-r--r--include/ports/SkTypeface_android.h45
-rw-r--r--src/core/SkPaint.cpp16
-rw-r--r--src/core/SkScalerContext.cpp8
-rw-r--r--src/ports/FontHostConfiguration_android.cpp53
-rw-r--r--src/ports/FontHostConfiguration_android.h17
-rw-r--r--src/ports/SkFontHost_android.cpp266
9 files changed, 269 insertions, 169 deletions
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index 25c9ecb..ace08d8 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -154,6 +154,15 @@ public:
*/
static SkFontID NextLogicalFont(SkFontID currFontID, SkFontID origFontID);
+#ifdef SK_BUILD_FOR_ANDROID
+ /*
+ * This Android-only version of NextLogicalFont allows us to pass in an
+ * entire Rec structure so that a caller can change fallback behavior
+ */
+ static SkFontID NextLogicalFont(const SkScalerContext::Rec& rec);
+#endif
+
+
///////////////////////////////////////////////////////////////////////////
/** Given a filled-out rec, the fonthost may decide to modify it to reflect
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 30ff663..1715013 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -665,6 +665,25 @@ public:
@param locale set the paint's locale value for drawing text.
*/
void setTextLocale(const SkString& locale);
+
+
+ enum FontVariant {
+ kDefault_Variant, // Currently setting yourself to Default gives you Compact Variant
+ kCompact_Variant,
+ kElegant_Variant,
+ kLast_Variant = kElegant_Variant,
+ };
+
+ /** Return the font variant
+ @return the font variant used by this paint object
+ */
+ FontVariant getFontVariant() const { return fFontVariant; }
+
+
+ /** Set the font variant
+ @param fontVariant set the paint's font variant for choosing fonts
+ */
+ void setFontVariant(FontVariant fontVariant);
#endif
/** Return the paint's text size.
@@ -906,6 +925,7 @@ private:
unsigned fHinting : 2;
#ifdef SK_BUILD_FOR_ANDROID
SkString fTextLocale;
+ FontVariant fFontVariant;
#endif
SkDrawCacheProc getDrawCacheProc() const;
diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h
index 9bcf601..33c3c3d 100644
--- a/include/core/SkScalerContext.h
+++ b/include/core/SkScalerContext.h
@@ -210,6 +210,9 @@ public:
#ifdef SK_USE_COLOR_LUMINANCE
uint32_t fLumBits;
#endif
+#ifdef SK_BUILD_FOR_ANDROID
+ SkPaint::FontVariant fFontVariant;
+#endif
uint8_t fMaskFormat;
uint8_t fStrokeJoin;
uint16_t fFlags;
@@ -234,7 +237,6 @@ public:
SkMask::Format getFormat() const {
return static_cast<SkMask::Format>(fMaskFormat);
}
-
#ifdef SK_USE_COLOR_LUMINANCE
SkColor getLuminanceColor() const {
return fLumBits;
diff --git a/include/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h
index 3471a94..c3eb3d1 100644
--- a/include/ports/SkTypeface_android.h
+++ b/include/ports/SkTypeface_android.h
@@ -10,47 +10,20 @@
#define SkTypeface_android_DEFINED
#include "SkTypeface.h"
+#include "SkPaint.h"
-enum FallbackScripts {
- kArabic_FallbackScript,
- kArmenian_FallbackScript,
- kBengali_FallbackScript,
- kDevanagari_FallbackScript,
- kEthiopic_FallbackScript,
- kGeorgian_FallbackScript,
- kHebrewRegular_FallbackScript,
- kHebrewBold_FallbackScript,
- kKannada_FallbackScript,
- kMalayalam_FallbackScript,
- kTamilRegular_FallbackScript,
- kTamilBold_FallbackScript,
- kThai_FallbackScript,
- kTelugu_FallbackScript,
- kFallbackScriptNumber
-};
-
-#define SkTypeface_ValidScript(s) (s >= 0 && s < kFallbackScriptNumber)
+#include "../harfbuzz/src/harfbuzz-shaper.h"
/**
* Return a new typeface for a fallback script. If the script is
* not valid, or can not map to a font, returns null.
- * @param script The script id.
- * @return reference to the matching typeface. Caller must call
- * unref() when they are done.
- */
-SK_API SkTypeface* SkCreateTypefaceForScript(FallbackScripts script);
-
-/**
- * Return the string representation for the fallback script on Android.
- * If the script is not valid, returns null.
- */
-SK_API const char* SkGetFallbackScriptID(FallbackScripts script);
-
-/**
- * Return the fallback script enum for the ID on Android.
- * If the ID is not valid, or can not map to a fallback
- * script, returns kFallbackScriptNumber.
+ * @param script The harfbuzz script id.
+ * @param style The font style, for example bold
+ * @param elegant true if we want the web friendly elegant version of the font
+ * @return reference to the matching typeface. Caller must call
+ * unref() when they are done.
*/
-SK_API FallbackScripts SkGetFallbackScriptFromID(const char* id);
+SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
+ SkPaint::FontVariant fontVariant = SkPaint::kDefault_Variant);
#endif
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index e1932a7..412ab2b 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -72,6 +72,7 @@ SkPaint::SkPaint() {
fHinting = SkPaintDefaults_Hinting;
#ifdef SK_BUILD_FOR_ANDROID
new(&fTextLocale) SkString();
+ fFontVariant = kDefault_Variant;
fGenerationID = 0;
#endif
}
@@ -372,6 +373,18 @@ void SkPaint::setTextLocale(const SkString& locale) {
GEN_ID_INC;
}
}
+
+void SkPaint::setFontVariant(FontVariant fontVariant) {
+ if ((unsigned)fontVariant <= kLast_Variant) {
+ GEN_ID_INC_EVAL((unsigned)fontVariant != fFontVariant);
+ fFontVariant = fontVariant;
+ } else {
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setFontVariant(%d) out of range\n", fontVariant);
+#endif
+ }
+}
+
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -1561,6 +1574,9 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
#else
rec->setLuminanceBits(computeLuminance(paint));
#endif
+#ifdef SK_BUILD_FOR_ANDROID
+ rec->fFontVariant = paint.getFontVariant();
+#endif //SK_BUILD_FOR_ANDROID
/* Allow the fonthost to modify our rec before we use it as a key into the
cache. This way if we're asking for something that they will ignore,
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 2921b1e..e33ad7a 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -118,7 +118,13 @@ static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) {
// fonthost will determine the next possible font to search, based
// on the current font in fRec. It will return NULL if ctx is our
// last font that can be searched (i.e. ultimate fallback font)
- uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
+#ifdef SK_BUILD_FOR_ANDROID
+ // On Android, pass entire rec structure so that clients can change fallback behavior
+ uint32_t newFontID = SkFontHost::NextLogicalFont(rec);
+#else
+ uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
+#endif
+
if (0 == newFontID) {
return NULL;
}
diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/FontHostConfiguration_android.cpp
index d1164c8..9296769 100644
--- a/src/ports/FontHostConfiguration_android.cpp
+++ b/src/ports/FontHostConfiguration_android.cpp
@@ -18,6 +18,7 @@
#include "FontHostConfiguration_android.h"
#include "SkString.h"
#include "SkTDArray.h"
+#include "SkTypeface.h"
#include <expat.h>
#if !defined(SK_BUILD_FOR_ANDROID_NDK)
#include <cutils/properties.h>
@@ -46,12 +47,13 @@ struct FamilyData {
XML_Parser *parser; // The expat parser doing the work
SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed
FontFamily *currentFamily; // The current family being created
+ FontFileInfo *currentFontInfo; // The current fontInfo being created
int currentTag; // A flag to indicate whether we're in nameset/fileset tags
};
/**
* Handler for arbitrary text. This is used to parse the text inside each name
- * or file tag. The resulting strings are put into the fNames or fFileNames arrays.
+ * or file tag. The resulting strings are put into the fNames or FontFileInfo arrays.
*/
void textHandler(void *data, const char *s, int len) {
FamilyData *familyData = (FamilyData*) data;
@@ -68,7 +70,9 @@ void textHandler(void *data, const char *s, int len) {
*(familyData->currentFamily->fNames.append()) = buff;
break;
case FILESET_TAG:
- *(familyData->currentFamily->fFileNames.append()) = buff;
+ if (familyData->currentFontInfo) {
+ familyData->currentFontInfo->fFileName = buff;
+ }
break;
default:
// Noop - don't care about any text that's not in the Fonts or Names list
@@ -78,6 +82,39 @@ void textHandler(void *data, const char *s, int len) {
}
/**
+ * Handler for font files. This processes the attributes for language and variants
+ * then lets textHandler handle the actual file name
+ */
+void fontFileElementHandler(FamilyData *familyData, const char **attributes) {
+ FontFileInfo* newFileInfo = new FontFileInfo();
+ if (attributes) {
+ int currentAttributeIndex = 0;
+ while (attributes[currentAttributeIndex]) {
+ const char* attributeName = attributes[currentAttributeIndex];
+ const char* attributeValue = attributes[currentAttributeIndex+1];
+ int nameLength = strlen(attributeName);
+ int valueLength = strlen(attributeValue);
+ if (strncmp(attributeName, "variant", nameLength) == 0) {
+ if (strncmp(attributeValue, "elegant", valueLength) == 0) {
+ newFileInfo->fVariant = SkPaint::kElegant_Variant;
+ } else if (strncmp(attributeValue, "compact", valueLength) == 0) {
+ newFileInfo->fVariant = SkPaint::kCompact_Variant;
+ }
+ } else if (strncmp(attributeName, "language", nameLength) == 0) {
+ if (strncmp(attributeValue, "ja", valueLength) == 0) {
+ newFileInfo->fLanguage = "ja";
+ } //else if (other languages)
+ }
+ //each element is a pair of attributeName/attributeValue string pairs
+ currentAttributeIndex += 2;
+ }
+ }
+ *(familyData->currentFamily->fFontFileArray.append()) = newFileInfo;
+ familyData->currentFontInfo = newFileInfo;
+ XML_SetCharacterDataHandler(*familyData->parser, textHandler);
+}
+
+/**
* Handler for the start of a tag. The only tags we expect are family, nameset,
* fileset, name, and file.
*/
@@ -98,14 +135,16 @@ void startElementHandler(void *data, const char *tag, const char **atts) {
familyData->currentFamily->order = value;
}
}
- } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
+ } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
familyData->currentTag = NAMESET_TAG;
} else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
familyData->currentTag = FILESET_TAG;
- } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
- (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
+ } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) {
// If it's a Name, parse the text inside
XML_SetCharacterDataHandler(*familyData->parser, textHandler);
+ } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG) {
+ // If it's a file, parse the attributes, then parse the text inside
+ fontFileElementHandler(familyData, atts);
}
}
@@ -120,9 +159,9 @@ void endElementHandler(void *data, const char *tag) {
// Done parsing a Family - store the created currentFamily in the families array
*familyData->families.append() = familyData->currentFamily;
familyData->currentFamily = NULL;
- } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
+ } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
familyData->currentTag = NO_TAG;
- } else if (len == 7 && strncmp(tag, "fileset", len)== 0) {
+ } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
familyData->currentTag = NO_TAG;
} else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
(strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
diff --git a/src/ports/FontHostConfiguration_android.h b/src/ports/FontHostConfiguration_android.h
index 2441f0e..c8a70e3 100644
--- a/src/ports/FontHostConfiguration_android.h
+++ b/src/ports/FontHostConfiguration_android.h
@@ -18,18 +18,27 @@
#define FONTHOSTCONFIGURATION_ANDROID_H_
#include "SkTDArray.h"
+#include "SkPaint.h"
+
+struct FontFileInfo {
+ FontFileInfo() : fVariant(SkPaint::kDefault_Variant), fLanguage(NULL), fFileName(NULL) {}
+ const char* fFileName;
+ SkPaint::FontVariant fVariant;
+ const char* fLanguage; // We may eventually use a enum for this
+};
+
/**
* The FontFamily data structure is created during parsing and handed back to
* Skia to fold into its representation of font families. fNames is the list of
- * font names that alias to a font family. fFileNames is the list of font
- * filenames for the family. Order is the priority order for the font. This is
+ * font names that alias to a font family. fontFileArray is the list of information
+ * about each file. Order is the priority order for the font. This is
* used internally to determine the order in which to place fallback fonts as
* they are read from the configuration files.
*/
struct FontFamily {
- SkTDArray<const char*> fNames;
- SkTDArray<const char*> fFileNames;
+ SkTDArray<const char*> fNames;
+ SkTDArray<FontFileInfo*> fFontFileArray;
int order;
};
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index afd0ebe..0a9cced 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -29,7 +29,7 @@
#include <string.h>
#include "SkGlyphCache.h"
#include "SkTypeface_android.h"
-
+#include "SkTSearch.h"
//#define SkDEBUGF(args ) SkDebugf args
@@ -76,7 +76,7 @@ static SkTypeface* createTypefaceLocked(const SkTypeface* familyFace,
SkTypeface::Style style);
static SkStream* openStreamLocked(uint32_t fontID);
static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int32_t* index);
-static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID);
+static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec);
static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream);
///////////////////////////////////////////////////////////////////////////////
@@ -150,6 +150,12 @@ static SkTypeface* findBestFaceLocked(const FamilyRec* family,
return NULL;
}
+static SkTypeface* FindBestFace(const FamilyRec* family,
+ SkTypeface::Style style) {
+ SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
+ return findBestFaceLocked(family, style);
+}
+
static FamilyRec* findFamilyLocked(const SkTypeface* member) {
FamilyRec* curr = gFamilyHead;
while (curr != NULL) {
@@ -180,6 +186,14 @@ static SkTypeface* findFromUniqueIDLocked(uint32_t uniqueID) {
return NULL;
}
+/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
+ is not modified.
+ */
+static SkTypeface* FindFromUniqueID(uint32_t uniqueID) {
+ SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
+ return findFromUniqueIDLocked(uniqueID);
+}
+
/* Remove reference to this face from its family. If the resulting family
is empty (has no faces), return that family, otherwise return NULL
*/
@@ -397,8 +411,15 @@ private:
// used to record our notion of the pre-existing fonts
struct FontInitRec {
- const char* fFileName;
- const char* const* fNames; // null-terminated list
+ const char* fFileName;
+ const char* const* fNames; // null-terminated list
+ SkPaint::FontVariant fVariant;
+};
+
+//used to record information about the fallback fonts
+struct FallbackFontRec {
+ SkFontID fFontID;
+ SkPaint::FontVariant fVariant;
};
// deliberately empty, but we use the address to identify fallback fonts
@@ -410,7 +431,7 @@ static const char* gFBNames[] = { NULL };
null for the list. The names list must be NULL-terminated.
*/
static SkTDArray<FontInitRec> gSystemFonts;
-static SkTDArray<SkFontID> gFallbackFonts;
+static SkTDArray<FallbackFontRec> gFallbackFonts;
// these globals are assigned (once) by loadSystemFontsLocked()
static FamilyRec* gDefaultFamily = NULL;
@@ -493,8 +514,8 @@ static void loadFontInfoLocked() {
for (int i = 0; i < fontFamilies.count(); ++i) {
FontFamily *family = fontFamilies[i];
- for (int j = 0; j < family->fFileNames.count(); ++j) {
- const char* filename = family->fFileNames[j];
+ for (int j = 0; j < family->fFontFileArray.count(); ++j) {
+ const char* filename = family->fFontFileArray[j]->fFileName;
if (haveSystemFont(filename)) {
SkDebugf("---- system font and fallback font files specify a duplicate "
"font %s, skipping the second occurrence", filename);
@@ -503,6 +524,7 @@ static void loadFontInfoLocked() {
FontInitRec fontInfoRecord;
fontInfoRecord.fFileName = filename;
+ fontInfoRecord.fVariant = family->fFontFileArray[j]->fVariant;
if (j == 0) {
if (family->fNames.count() == 0) {
// Fallback font
@@ -595,7 +617,10 @@ static void initSystemFontsLocked() {
if (names == gFBNames) {
SkDEBUGF(("---- adding %s as fallback[%d] fontID %d\n",
gSystemFonts[i].fFileName, gFallbackFonts.count(), tf->uniqueID()));
- *gFallbackFonts.append() = tf->uniqueID();
+ FallbackFontRec newFallbackRec;
+ newFallbackRec.fFontID = tf->uniqueID();
+ newFallbackRec.fVariant = gSystemFonts[i].fVariant;
+ *gFallbackFonts.append() = newFallbackRec;
}
firstInFamily = tf;
@@ -634,7 +659,7 @@ static SkFontID findUniqueIDLocked(const char* filename) {
static int findFallbackFontIndex(SkFontID fontId) {
for (int i = 0; i < gFallbackFonts.count(); i++) {
- if (gFallbackFonts[i] == fontId) {
+ if (gFallbackFonts[i].fFontID == fontId) {
return i;
}
}
@@ -652,8 +677,8 @@ static void reloadFallbackFontsLocked() {
for (int i = 0; i < fallbackFamilies.count(); ++i) {
FontFamily *family = fallbackFamilies[i];
- for (int j = 0; j < family->fFileNames.count(); ++j) {
- const char* filename = family->fFileNames[j];
+ for (int j = 0; j < family->fFontFileArray.count(); ++j) {
+ const char* filename = family->fFontFileArray[j]->fFileName;
if (filename) {
if (!haveSystemFont(filename)) {
SkDebugf("---- skipping fallback font %s because it was not "
@@ -680,8 +705,10 @@ static void reloadFallbackFontsLocked() {
SkDEBUGF(("---- reload %s as fallback[%d] fontID %d\n",
filename, gFallbackFonts.count(), uniqueID));
-
- *gFallbackFonts.append() = uniqueID;
+ FallbackFontRec newFallbackFont;
+ newFallbackFont.fFontID = uniqueID;
+ newFallbackFont.fVariant = family->fFontFileArray[j]->fVariant;
+ *gFallbackFonts.append() = newFallbackFont;
break; // The fallback set contains only the first font of each family
}
}
@@ -886,16 +913,16 @@ static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int
}
}
-SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
+SkFontID SkFontHost::NextLogicalFont(const SkScalerContext::Rec& rec) {
SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
- return nextLogicalFontLocked(currFontID, origFontID);
+ return nextLogicalFontLocked(rec);
}
-static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID) {
+static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec) {
loadSystemFontsLocked();
- const SkTypeface* origTypeface = findFromUniqueIDLocked(origFontID);
- const SkTypeface* currTypeface = findFromUniqueIDLocked(currFontID);
+ const SkTypeface* origTypeface = findFromUniqueIDLocked(rec.fOrigFontID);
+ const SkTypeface* currTypeface = findFromUniqueIDLocked(rec.fFontID);
SkASSERT(origTypeface != 0);
SkASSERT(currTypeface != 0);
@@ -911,17 +938,30 @@ static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID)
*/
int plainFallbackFontIndex = findFallbackFontIndex(plainFontID);
int nextFallbackFontIndex = plainFallbackFontIndex + 1;
- SkFontID nextFontID;
- if (nextFallbackFontIndex == gFallbackFonts.count()) {
- nextFontID = 0; // no more fallbacks
- } else {
- const SkTypeface* nextTypeface = findFromUniqueIDLocked(gFallbackFonts[nextFallbackFontIndex]);
- nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID();
+
+ // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
+ // In this case, we set the value to "kCompact_Variant"
+ SkPaint::FontVariant recPreference = rec.fFontVariant;
+ if (recPreference == SkPaint::kDefault_Variant) {
+ recPreference = SkPaint::kCompact_Variant;
+ }
+ SkFontID nextFontID = 0;
+ while (nextFallbackFontIndex < gFallbackFonts.count()) {
+ bool normalFont =
+ (gFallbackFonts[nextFallbackFontIndex].fVariant == SkPaint::kDefault_Variant);
+ bool fontChosen = (gFallbackFonts[nextFallbackFontIndex].fVariant == recPreference);
+ if (normalFont || fontChosen) {
+ const SkTypeface* nextTypeface =
+ findFromUniqueIDLocked(gFallbackFonts[nextFallbackFontIndex].fFontID);
+ nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID();
+ break;
+ }
+ nextFallbackFontIndex++;
}
SkDEBUGF(("---- nextLogicalFont: currFontID=%d, origFontID=%d, plainFontID=%d, "
"plainFallbackFontIndex=%d, nextFallbackFontIndex=%d "
- "=> nextFontID=%d", currFontID, origFontID, plainFontID,
+ "=> nextFontID=%d", rec.fFontID, rec.fOrigFontID, plainFontID,
plainFallbackFontIndex, nextFallbackFontIndex, nextFontID));
return nextFontID;
}
@@ -966,46 +1006,9 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
// Function from SkTypeface_android.h
///////////////////////////////////////////////////////////////////////////////
-struct FBScriptInfo {
- const FallbackScripts fScript;
- const char* fScriptID;
- const SkTypeface::Style fStyle;
- const SkUnichar fChar; // representative character for that script type
- SkFontID fFontID;
-};
-
-#define SK_DEFINE_SCRIPT_ENTRY(script, style, unichar) \
- { script, #script, style, unichar, 0 }
-
-static FBScriptInfo gFBScriptInfo[] = {
- SK_DEFINE_SCRIPT_ENTRY(kArabic_FallbackScript, SkTypeface::kNormal, 0x0600),
- SK_DEFINE_SCRIPT_ENTRY(kArmenian_FallbackScript, SkTypeface::kNormal, 0x0531),
- SK_DEFINE_SCRIPT_ENTRY(kBengali_FallbackScript, SkTypeface::kNormal, 0x0981),
- SK_DEFINE_SCRIPT_ENTRY(kDevanagari_FallbackScript, SkTypeface::kNormal, 0x0901),
- SK_DEFINE_SCRIPT_ENTRY(kEthiopic_FallbackScript, SkTypeface::kNormal, 0x1200),
- SK_DEFINE_SCRIPT_ENTRY(kGeorgian_FallbackScript, SkTypeface::kNormal, 0x10A0),
- SK_DEFINE_SCRIPT_ENTRY(kHebrewRegular_FallbackScript, SkTypeface::kNormal, 0x0591),
- SK_DEFINE_SCRIPT_ENTRY(kHebrewBold_FallbackScript, SkTypeface::kBold, 0x0591),
- SK_DEFINE_SCRIPT_ENTRY(kKannada_FallbackScript, SkTypeface::kNormal, 0x0C90),
- SK_DEFINE_SCRIPT_ENTRY(kMalayalam_FallbackScript, SkTypeface::kNormal, 0x0D10),
- SK_DEFINE_SCRIPT_ENTRY(kTamilRegular_FallbackScript, SkTypeface::kNormal, 0x0B82),
- SK_DEFINE_SCRIPT_ENTRY(kTamilBold_FallbackScript, SkTypeface::kBold, 0x0B82),
- SK_DEFINE_SCRIPT_ENTRY(kThai_FallbackScript, SkTypeface::kNormal, 0x0E01),
- SK_DEFINE_SCRIPT_ENTRY(kTelugu_FallbackScript, SkTypeface::kNormal, 0x0C10),
-};
-
-static bool gFBScriptInitialized = false;
-static const int gFBScriptInfoCount = sizeof(gFBScriptInfo) / sizeof(FBScriptInfo);
-
-// ensure that if any value is added to the public enum it is also added here
-SK_COMPILE_ASSERT(gFBScriptInfoCount == kFallbackScriptNumber, FBScript_count_mismatch);
-
-
-// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
-static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) {
- gFamilyHeadAndNameListMutex.acquire();
- SkTypeface* face = findBestFaceLocked(gDefaultFamily, style);
- gFamilyHeadAndNameListMutex.release();
+static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style,
+ SkPaint::FontVariant fontVariant) {
+ SkTypeface* face = FindBestFace(gDefaultFamily, style);
if (!face) {
return 0;
}
@@ -1013,6 +1016,7 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) {
SkPaint paint;
paint.setTypeface(face);
paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ paint.setFontVariant(fontVariant);
SkAutoGlyphCache autoCache(paint, NULL);
SkGlyphCache* cache = autoCache.getCache();
@@ -1025,71 +1029,93 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) {
return 0;
}
-// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
-static void initFBScriptInfo() {
- if (gFBScriptInitialized) {
- return;
- }
+struct HB_UnicodeMapping {
+ HB_Script script;
+ const SkUnichar unicode;
+};
- // ensure the system fonts are loaded
- gFamilyHeadAndNameListMutex.acquire();
- loadSystemFontsLocked();
- gFamilyHeadAndNameListMutex.release();
-
- for (int i = 0; i < gFBScriptInfoCount; i++) {
- FBScriptInfo& scriptInfo = gFBScriptInfo[i];
- // selects the best available style for the desired font. However, if
- // bold is requested and no bold font exists for the typeface containing
- // the character the next best style is chosen (e.g. normal).
- scriptInfo.fFontID = findFontIDForChar(scriptInfo.fChar, scriptInfo.fStyle);
- SkDEBUGF(("gFBScriptInfo[%s] --> %d", scriptInfo.fScriptID, scriptInfo.fFontID));
- }
- // mark the value as initialized so we don't repeat our work unnecessarily
- gFBScriptInitialized = true;
-}
+static HB_UnicodeMapping HB_UnicodeMappingArray[] {
+ {HB_Script_Arabic, 0x0600},
+ {HB_Script_Armenian, 0x0531},
+ {HB_Script_Bengali, 0x0981},
+ {HB_Script_Devanagari, 0x0901},
+ // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge
+ //{HB_Script_Ethiopic, 0x1200},
+ {HB_Script_Georgian, 0x10A0},
+ {HB_Script_Hebrew, 0x0591},
+ {HB_Script_Kannada, 0x0C90},
+ {HB_Script_Malayalam, 0x0D10},
+ {HB_Script_Tamil, 0x0B82},
+ {HB_Script_Thai, 0x0E01},
+ {HB_Script_Telugu, 0x0C10},
+};
-SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) {
- if (!SkTypeface_ValidScript(script)) {
- return NULL;
+// returns 0 for "Not Found"
+static SkUnichar getUnicodeFromHBScript(HB_Script script) {
+ SkUnichar unichar = 0;
+ int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
+ for (int i = 0; i < numSupportedFonts; i++) {
+ if (script == HB_UnicodeMappingArray[i].script) {
+ unichar = HB_UnicodeMappingArray[i].unicode;
+ break;
+ }
}
+ return unichar;
+}
- // ensure that our table is populated
- initFBScriptInfo();
-
- FBScriptInfo& scriptInfo = gFBScriptInfo[script];
+struct TypefaceLookupStruct {
+ HB_Script script;
+ SkTypeface::Style style;
+ SkPaint::FontVariant fontVariant;
+ SkTypeface* typeface;
+};
- // ensure the element with that index actually maps to the correct script
- SkASSERT(scriptInfo.fScript == script);
+SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable
+static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex
- // if a suitable script could not be found then return NULL
- if (scriptInfo.fFontID == 0) {
- return NULL;
+static int typefaceLookupCompare(const TypefaceLookupStruct& first,
+ const TypefaceLookupStruct& second) {
+ if (first.script != second.script) {
+ return (first.script > second.script) ? 1 : -1;
}
-
- SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
-
- // retrieve the typeface the corresponds to this fontID
- SkTypeface* tf = findFromUniqueIDLocked(scriptInfo.fFontID);
- // we ref(), since the semantic is to return a new instance
- tf->ref();
- return tf;
-}
-
-const char* SkGetFallbackScriptID(FallbackScripts script) {
- for (int i = 0; i < gFBScriptInfoCount; i++) {
- if (gFBScriptInfo[i].fScript == script) {
- return gFBScriptInfo[i].fScriptID;
- }
+ if (first.style != second.style) {
+ return (first.style > second.style) ? 1 : -1;
}
- return NULL;
+ if (first.fontVariant != second.fontVariant) {
+ return (first.fontVariant > second.fontVariant) ? 1 : -1;
+ }
+ return 0;
}
-FallbackScripts SkGetFallbackScriptFromID(const char* id) {
- for (int i = 0; i < gFBScriptInfoCount; i++) {
- if (strcmp(gFBScriptInfo[i].fScriptID, id) == 0) {
- return gFBScriptInfo[i].fScript;
+SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
+ SkPaint::FontVariant fontVariant) {
+ SkTypeface* retTypeface = NULL;
+
+ SkAutoMutexAcquire ac(gTypefaceTableMutex); // Note: NOT gFamilyHeadAndNameListMutex
+ TypefaceLookupStruct key;
+ key.script = script;
+ key.style = style;
+ key.fontVariant = fontVariant;
+ int index = SkTSearch<TypefaceLookupStruct>(
+ (const TypefaceLookupStruct*) gTypefaceTable.begin(),
+ gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
+ &typefaceLookupCompare);
+ if (index >= 0) {
+ retTypeface = gTypefaceTable[index].typeface;
+ }
+ else {
+ SkUnichar unichar = getUnicodeFromHBScript(script);
+ if (!unichar) {
+ return NULL;
}
+ SkFontID newFontID = findFontIDForChar(unichar, style, fontVariant);
+ // retrieve the typeface that corresponds to this fontID
+ retTypeface = FindFromUniqueID(newFontID);
+ // we ref(), since the semantic is to return a new instance
+ retTypeface->ref();
+ key.typeface = retTypeface;
+ index = ~index;
+ *gTypefaceTable.insert(index) = key;
}
- return kFallbackScriptNumber; // Use kFallbackScriptNumber as an invalid value.
+ return retTypeface;
}
-