aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLucas Crowthers <lucasc@codeaurora.org>2013-11-06 14:38:45 -0500
committerLinux Build Service Account <lnxbuild@localhost>2014-11-04 08:54:53 -0700
commitaaf3a59a0001c6e1f3f2a92864dbcac1198967b1 (patch)
tree0940b18c942c1e4da28f59a97b0993569d4e0dae
parent1da4b5f475730e7ca469e4c00c2979e6151a5fae (diff)
downloadandroid_external_skia-aaf3a59a0001c6e1f3f2a92864dbcac1198967b1.tar.gz
android_external_skia-aaf3a59a0001c6e1f3f2a92864dbcac1198967b1.tar.bz2
android_external_skia-aaf3a59a0001c6e1f3f2a92864dbcac1198967b1.zip
SkLanguage and SkPaintOptionsAndroid optimization
(1) Global linked list to manage SkLanguage and SkPaintOptionsAndroid objects (2) All copy constructor overheads associated with above classes are changed to simple pointer assignment (3) All string related operations in SkLanguage class are replaced with simple pointer manipulation. Also saving on string allocations. (4) SkLangList and SkPaintOptionsAndroidList are 2 new classes created to manage the global linked list (5) SkLanguages and SkPaintOptionsAndroids are 2 new singleton classes created to work with the global linked list class (See 4) Change-Id: Ib17381be6bae046e2c6e1f1c6a1d1c4707c20c32
-rw-r--r--include/core/SkPaint.h55
-rw-r--r--include/core/SkPaintOptionsAndroid.h88
-rw-r--r--include/core/SkTypes.h5
-rw-r--r--src/core/SkPaint.cpp141
-rw-r--r--src/core/SkPaintOptionsAndroid.cpp190
5 files changed, 473 insertions, 6 deletions
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index f766ca1c7f..95697d7ec7 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -17,8 +17,21 @@
#include "SkXfermode.h"
#ifdef SK_BUILD_FOR_ANDROID
#include "SkPaintOptionsAndroid.h"
+
+#define SKPAINTOPTIONS_OPT
+#ifdef SKPAINTOPTIONS_OPT
+//For testing this optimization ensure you rebuild and push libandroid_runtime.so and libhwui.so
+//everytime you build and push libskia.so
+#undef SKPAINT_OPT_DEBUG
+#ifdef SKPAINT_OPT_DEBUG
+#define SkPaintOptDebugf(...) SkDebugf(__VA_ARGS__)
+#else
+#define SkPaintOptDebugf(...)
+#endif
+#endif
#endif
+
class SkAnnotation;
class SkAutoGlyphCache;
class SkColorFilter;
@@ -45,6 +58,38 @@ typedef const SkGlyph& (*SkMeasureCacheProc)(SkGlyphCache*, const char**);
#define kBicubicFilterBitmap_Flag kHighQualityFilterBitmap_Flag
+/**************************************************************************************/
+#ifdef SK_BUILD_FOR_ANDROID
+#ifdef SKPAINTOPTIONS_OPT
+class SkPaintOptionsAndroidList {
+ public:
+ SkPaintOptionsAndroidList(const SkPaintOptionsAndroid& options);
+ SkPaintOptionsAndroid s;
+ SkPaintOptionsAndroidList *next;
+};
+
+
+class SkPaintOptionsAndroids {
+public:
+ static SkPaintOptionsAndroids* getInstance();
+ SkPaintOptionsAndroidList* setPaintOptionsAndroid( const SkPaintOptionsAndroid& options);
+
+private:
+ SkPaintOptionsAndroids();
+ ~SkPaintOptionsAndroids() {}
+
+ //Disallow copy and assigning by declaring the (copy) constructors
+ SkPaintOptionsAndroids(const SkPaintOptionsAndroids&);
+ SkPaintOptionsAndroids& operator=(const SkPaintOptionsAndroids&);
+
+ static SkPaintOptionsAndroids* m_pInstance;
+ SkPaintOptionsAndroidList * LocaleArray;
+ pthread_mutex_t update_mutex;
+};
+#endif
+#endif
+/**************************************************************************************/
+
/** \class SkPaint
The SkPaint class holds the style and color information about how to draw
@@ -942,11 +987,17 @@ public:
*/
unsigned getBaseGlyphCount(SkUnichar text) const;
+
+#ifdef SKPAINTOPTIONS_OPT
+ const SkPaintOptionsAndroid& getPaintOptionsAndroid() const;
+ void setPaintOptionsAndroid(const SkPaintOptionsAndroid& options);
+#else
const SkPaintOptionsAndroid& getPaintOptionsAndroid() const {
return fPaintOptionsAndroid;
}
void setPaintOptionsAndroid(const SkPaintOptionsAndroid& options);
#endif
+#endif
// returns true if the paint's settings (e.g. xfermode + alpha) resolve to
// mean that we need not draw at all (e.g. SrcOver + 0-alpha)
@@ -1143,7 +1194,11 @@ private:
friend class SkCanonicalizePaint;
#ifdef SK_BUILD_FOR_ANDROID
+#ifdef SKPAINTOPTIONS_OPT
+ SkPaintOptionsAndroidList* fpPaintOptionsAndroid;
+#else
SkPaintOptionsAndroid fPaintOptionsAndroid;
+#endif
// In order for the == operator to work properly this must be the last field
// in the struct so that we can do a memcmp to this field's offset.
diff --git a/include/core/SkPaintOptionsAndroid.h b/include/core/SkPaintOptionsAndroid.h
index ab84ec050e..fb3b8e726d 100644
--- a/include/core/SkPaintOptionsAndroid.h
+++ b/include/core/SkPaintOptionsAndroid.h
@@ -13,6 +13,19 @@
#include "SkTypes.h"
#include "SkString.h"
+#define SKLANG_OPT
+#ifdef SKLANG_OPT
+//For testing this optimization ensure you rebuild and push libandroid_runtime.so
+//everytime you build and push libskia.so
+#include <pthread.h>
+#endif
+#undef SKLANG_OPT_DEBUG
+#ifdef SKLANG_OPT_DEBUG
+#define SkLangOptDebugf(...) SkDebugf(__VA_ARGS__)
+#else
+#define SkLangOptDebugf(...)
+#endif
+
class SkReadBuffer;
class SkWriteBuffer;
@@ -56,15 +69,54 @@ private:
SkString fTag;
};
+/**************************************************************************************/
+#ifdef SKLANG_OPT
+class SkLangList {
+public:
+ SkLangList(const SkLanguage& lang);
+ SkLanguage s;
+ SkLangList *next;
+};
+
+class SkLanguages {
+public:
+ static SkLanguages* getInstance();
+ SkLangList* setLanguage( const SkLanguage& lang );
+ SkLangList* setLanguage( const char* langTag );
+
+private:
+ SkLanguages();
+ ~SkLanguages() {}
+
+ //Disallow copy and assigning by declaring the (copy) constructors
+ SkLanguages(const SkLanguages&);
+ SkLanguages& operator=(const SkLanguages&);
+
+ static SkLanguages* m_pInstance;
+ SkLangList * LocaleArray;
+ pthread_mutex_t update_mutex;
+};
+#endif
+/**************************************************************************************/
+
class SkPaintOptionsAndroid {
public:
SkPaintOptionsAndroid() {
+ SkLangOptDebugf("SKLANG_OPT SkPaintOptionsAndroid constr");
+#ifdef SKLANG_OPT
+ fpLanguage = NULL;
+#endif
fFontVariant = kDefault_Variant;
fUseFontFallbacks = false;
}
SkPaintOptionsAndroid& operator=(const SkPaintOptionsAndroid& b) {
+ SkLangOptDebugf("SKLANG_OPT SkPaintOptionsAndroid overload= this=%p", this);
+#ifdef SKLANG_OPT
+ fpLanguage = b.fpLanguage;
+#else
fLanguage = b.fLanguage;
+#endif
fFontVariant = b.fFontVariant;
fUseFontFallbacks = b.fUseFontFallbacks;
return *this;
@@ -75,7 +127,13 @@ public:
}
bool operator!=(const SkPaintOptionsAndroid& b) const {
- return fLanguage != b.fLanguage ||
+ SkLangOptDebugf("SKLANG_OPT SkPaintOptionsAndroid overload!= this=%p", this);
+ return
+#ifdef SKLANG_OPT
+ fpLanguage != b.fpLanguage ||
+#else
+ fLanguage != b.fLanguage ||
+#endif
fFontVariant != b.fFontVariant ||
fUseFontFallbacks != b.fUseFontFallbacks;
}
@@ -86,14 +144,29 @@ public:
/** Return the paint's language value used for drawing text.
@return the paint's language value used for drawing text.
*/
- const SkLanguage& getLanguage() const { return fLanguage; }
+#ifdef SKLANG_OPT
+ const SkLanguage& getLanguage() const;
+#else
+ const SkLanguage& getLanguage() const {
+ return fLanguage;
+ }
+#endif
/** Set the paint's language value used for drawing text.
@param language set the paint's language value for drawing text.
*/
- void setLanguage(const SkLanguage& language) { fLanguage = language; }
- void setLanguage(const char* languageTag) { fLanguage = SkLanguage(languageTag); }
+#ifdef SKLANG_OPT
+ void setLanguage(const SkLanguage& language);
+ void setLanguage(const char* languageTag);
+#else
+ void setLanguage(const SkLanguage& language) {
+ fLanguage = language;
+ }
+ void setLanguage(const char* languageTag) {
+ fLanguage = SkLanguage(languageTag);
+ }
+#endif
enum FontVariant {
kDefault_Variant = 0x01,
@@ -122,7 +195,12 @@ public:
}
private:
- SkLanguage fLanguage;
+#ifdef SKLANG_OPT
+ //Convert all string manipulations to pointer manipulations
+ SkLangList* fpLanguage;
+#else
+ SkLanguage fLanguage;
+#endif
FontVariant fFontVariant;
bool fUseFontFallbacks;
};
diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h
index 5ff57f8078..fefe2f7760 100644
--- a/include/core/SkTypes.h
+++ b/include/core/SkTypes.h
@@ -22,6 +22,11 @@
#define SKIA_VERSION_MINOR 0
#define SKIA_VERSION_PATCH 0
+/**Brnach prediction hint to compiler
+*/
+#define SkLikely(x) __builtin_expect ((x), 1)
+#define SkUnlikely(x) __builtin_expect ((x), 0)
+
/*
memory wrappers to be implemented by the porting layer (platform)
*/
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index ad2635cb52..a9b14e942a 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -64,6 +64,94 @@ enum {
#ifdef SK_BUILD_FOR_ANDROID
#define GEN_ID_INC fGenerationID++
#define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; }
+
+#ifdef SKPAINTOPTIONS_OPT
+#define SKPAINT_ENABLE_MUTEX
+SkPaintOptionsAndroidList::SkPaintOptionsAndroidList(const SkPaintOptionsAndroid& options){
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroidList::SkPaintOptionsAndroidList this=%p", this);
+ s = SkPaintOptionsAndroid(options);
+ next = NULL;
+}
+
+//Global static pointer user to ensure a single instance of the class
+SkPaintOptionsAndroids* SkPaintOptionsAndroids::m_pInstance = NULL;
+
+SkPaintOptionsAndroids* SkPaintOptionsAndroids::getInstance(){
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroids::getInstance");
+ if(SkUnlikely(!m_pInstance))
+ m_pInstance = new SkPaintOptionsAndroids();
+
+ return m_pInstance;
+}
+
+SkPaintOptionsAndroids::SkPaintOptionsAndroids(){
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroids::SkPaintOptionsAndroids this=%p", this);
+ LocaleArray = NULL;
+#ifdef SKPAINT_ENABLE_MUTEX
+ pthread_mutex_init(&update_mutex, NULL);
+#endif
+}
+
+SkPaintOptionsAndroidList* SkPaintOptionsAndroids::setPaintOptionsAndroid( const SkPaintOptionsAndroid& options ){
+start:
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroids::setPaintOptionsAndroid this=%p", this);
+ if( SkUnlikely(!LocaleArray) ){
+#ifdef SKPAINT_ENABLE_MUTEX
+ pthread_mutex_lock( &update_mutex );
+#endif
+ if( SkUnlikely(!LocaleArray) ){
+ LocaleArray = new SkPaintOptionsAndroidList(options);
+#ifdef SKPAINT_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroids::setPaintOptionsAndroid Create LocaleArray=%p", LocaleArray);
+ return LocaleArray;
+ } else {
+#ifdef SKPAINT_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ goto start;
+ }
+ }
+
+ SkPaintOptionsAndroidList* l = LocaleArray;
+ SkPaintOptionsAndroidList* prev = LocaleArray;
+ while( l ){
+ if( l->s == options ){
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroids::setPaintOptionsAndroid Found a match returning");
+ return l;
+ }
+ prev = l;
+ l = l->next;
+ }
+
+#ifdef SKPAINT_ENABLE_MUTEX
+ pthread_mutex_lock( &update_mutex );
+
+ //Within mutex, restart from beginning
+ l = LocaleArray;
+ prev = LocaleArray;
+ while( l ){
+ if( l->s == options ){
+ pthread_mutex_unlock( &update_mutex );
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroids::setPaintOptionsAndroid Found a match returning inside LOCK");
+ return l;
+ }
+ prev = l;
+ l = l->next;
+ }
+#endif
+
+ SkPaintOptDebugf("SKPAINT_OPT SkPaintOptionsAndroids::setPaintOptionsAndroid Create a new SkPaintOptionsAndroidList and add and ret");
+ l = new SkPaintOptionsAndroidList(options);
+ prev->next = l;
+
+#ifdef SKPAINT_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ return l;
+}
+#endif //SKPAINTOPTIONS_OPT
#else
#define GEN_ID_INC
#define GEN_ID_INC_EVAL(expression)
@@ -100,8 +188,13 @@ SkPaint::SkPaint() {
fDirtyBits = 0;
#ifdef SK_BUILD_FOR_ANDROID
+#ifndef SKPAINTOPTIONS_OPT
new (&fPaintOptionsAndroid) SkPaintOptionsAndroid;
fGenerationID = 0;
+#else
+ fpPaintOptionsAndroid = NULL;
+ fGenerationID = 0;
+#endif
#endif
}
@@ -130,7 +223,11 @@ SkPaint::SkPaint(const SkPaint& src) {
COPY(fDirtyBits);
#ifdef SK_BUILD_FOR_ANDROID
+#ifndef SKPAINTOPTIONS_OPT
new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid);
+#else
+ fpPaintOptionsAndroid = src.fpPaintOptionsAndroid;
+#endif //End of SKPAINTOPTIONS_OPT
COPY(fGenerationID);
#endif
@@ -182,8 +279,12 @@ SkPaint& SkPaint::operator=(const SkPaint& src) {
COPY(fDirtyBits);
#ifdef SK_BUILD_FOR_ANDROID
+#ifndef SKPAINTOPTIONS_OPT
fPaintOptionsAndroid.~SkPaintOptionsAndroid();
new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid);
+#else
+ fpPaintOptionsAndroid = src.fpPaintOptionsAndroid;
+#endif //End of SKPAINTOPTIONS_OPT
++fGenerationID;
#endif
@@ -214,7 +315,11 @@ bool operator==(const SkPaint& a, const SkPaint& b) {
&& EQUAL(fMiterLimit)
&& EQUAL(fBitfields)
#ifdef SK_BUILD_FOR_ANDROID
+#ifndef SKPAINTOPTIONS_OPT
&& EQUAL(fPaintOptionsAndroid)
+#else
+ && EQUAL(fpPaintOptionsAndroid)
+#endif
#endif
;
#undef EQUAL
@@ -247,6 +352,35 @@ unsigned SkPaint::getBaseGlyphCount(SkUnichar text) const {
return cache->getBaseGlyphCount(text);
}
+#ifdef SKPAINTOPTIONS_OPT
+const SkPaintOptionsAndroid& SkPaint::getPaintOptionsAndroid() const{
+ if( SkUnlikely (fpPaintOptionsAndroid == NULL)){
+ SkPaintOptDebugf("SKPAINT_OPT g1 this=%p", this);
+ //Add the default empty SkPaintOptionsAndroid
+ //We shouldn't go through this path anyway
+ SkPaintOptionsAndroid emptyPaintOptions;
+ //We can NOT assign the return pointer to fpPaintOptionsAndroid as the API is
+ //defined on the READ-ONLY object.
+ SkPaintOptionsAndroidList* fpl;
+ fpl = SkPaintOptionsAndroids::getInstance()->setPaintOptionsAndroid(emptyPaintOptions);
+ //This is persistent object in the global array,
+ //So there is no memory leak
+ return (fpl->s);
+ } else {
+ SkPaintOptDebugf("SKPAINT_OPT g2 this=%p", this);
+ return fpPaintOptionsAndroid->s;
+ }
+}
+
+void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options){
+ SkPaintOptDebugf("SKPAINT_OPT s1 this=%p", this);
+ SkPaintOptionsAndroidList* oldOptions = fpPaintOptionsAndroid;
+ fpPaintOptionsAndroid = SkPaintOptionsAndroids::getInstance()->setPaintOptionsAndroid(options);
+ if(oldOptions != fpPaintOptionsAndroid){
+ GEN_ID_INC;
+ }
+}
+#else
void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options) {
if (options != fPaintOptionsAndroid) {
fPaintOptionsAndroid = options;
@@ -254,7 +388,8 @@ void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options) {
fDirtyBits |= kPaintOptionsAndroid_DirtyBit;
}
}
-#endif
+#endif //End of SKPAINTOPTIONS_OPT
+#endif //End of SK_BUILD_FOR_ANDROID
void SkPaint::setFilterLevel(FilterLevel level) {
GEN_ID_INC_EVAL((unsigned) level != fFilterLevel);
@@ -1875,7 +2010,11 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties,
#ifdef SK_BUILD_FOR_ANDROID
SkWriteBuffer androidBuffer;
+#ifdef SKPAINTOPTIONS_OPT
+ getPaintOptionsAndroid().flatten(androidBuffer);
+#else
fPaintOptionsAndroid.flatten(androidBuffer);
+#endif
descSize += androidBuffer.bytesWritten();
entryCount += 1;
#endif
diff --git a/src/core/SkPaintOptionsAndroid.cpp b/src/core/SkPaintOptionsAndroid.cpp
index 56f1bd1654..5119e555e1 100644
--- a/src/core/SkPaintOptionsAndroid.cpp
+++ b/src/core/SkPaintOptionsAndroid.cpp
@@ -13,6 +13,157 @@
#include "SkThread.h"
#include <cstring>
+#define SKLANG_ENABLE_MUTEX
+#ifdef SKLANG_OPT
+SkLangList::SkLangList(const SkLanguage& lang){
+ SkLangOptDebugf("SKLANG_OPT SkLangList::SkLangList this=%p", this);
+ s = SkLanguage(lang);
+ next = NULL;
+}
+
+//Global static pointer user to ensure a single instance of the class
+SkLanguages* SkLanguages::m_pInstance = NULL;
+
+SkLanguages* SkLanguages::getInstance(){
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::getInstance");
+ if(SkUnlikely(!m_pInstance))
+ m_pInstance = new SkLanguages();
+
+ return m_pInstance;
+}
+
+SkLanguages::SkLanguages(){
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::SkLanguages this=%p", this);
+ LocaleArray = NULL;
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_init(&update_mutex, NULL);
+#endif
+}
+
+SkLangList* SkLanguages::setLanguage( const SkLanguage& lang ){
+startlang:
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage this=%p", this);
+ if( SkUnlikely(!LocaleArray) ){
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_lock( &update_mutex );
+#endif
+ if( SkUnlikely(!LocaleArray) ){
+ LocaleArray = new SkLangList(lang);
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage Create LocaleArray=%p", LocaleArray);
+ return LocaleArray;
+ } else {
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ goto startlang;
+ }
+ }
+
+ SkLangList* l = LocaleArray;
+ SkLangList* prev = LocaleArray;
+ while( l ){
+ if( l->s == lang ){
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage Found a match returning");
+ return l;
+ }
+ prev = l;
+ l = l->next;
+ }
+
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_lock( &update_mutex );
+
+ //SkLangOptDebugf("SKLANG_OPT new locale %s", lang.getTag().c_str());
+ //Within mutex, restart from beginning
+ l = LocaleArray;
+ prev = LocaleArray;
+ while( l ){
+ if( l->s == lang ){
+ pthread_mutex_unlock( &update_mutex );
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage Found a match returning inside LOCK");
+ return l;
+ }
+ prev = l;
+ l = l->next;
+ }
+#endif
+
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage Create a new SkLanglist and add and ret");
+ l = new SkLangList(lang);
+ prev->next = l;
+
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ return l;
+}
+
+SkLangList* SkLanguages::setLanguage( const char* langTag ){
+startlangtag:
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage with Tag this=%p", this);
+ if( SkUnlikely(!LocaleArray) ){
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_lock( &update_mutex );
+#endif
+ if( SkUnlikely(!LocaleArray) ){
+ SkLanguage newLang = SkLanguage(langTag); //Create a new SkLanguage
+ LocaleArray = new SkLangList(newLang);
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage with Tag Create LocaleArray=%p", LocaleArray);
+ return LocaleArray;
+ } else {
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ goto startlangtag;
+ }
+ }
+
+ SkLangList* l = LocaleArray;
+ SkLangList* prev = LocaleArray;
+ while( l ){
+ if( l->s.getTag().equals(langTag) ){
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage with Tag Found a match returning");
+ return l;
+ }
+ prev = l;
+ l = l->next;
+ }
+
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_lock( &update_mutex );
+
+ //Within mutex, restart from beginning
+ l = LocaleArray;
+ prev = LocaleArray;
+ while( l ){
+ if( l->s.getTag().equals(langTag) ){
+ pthread_mutex_unlock( &update_mutex );
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage with Tag Found a match returning inside LOCK");
+ return l;
+ }
+ prev = l;
+ l = l->next;
+ }
+#endif
+
+ SkLangOptDebugf("SKLANG_OPT SkLanguages::setLanguage with Tag Create a new SkLanglist and add and ret");
+ SkLanguage newLang = SkLanguage(langTag); //Create a new SkLanguage
+ l = new SkLangList(newLang);
+ prev->next = l;
+
+#ifdef SKLANG_ENABLE_MUTEX
+ pthread_mutex_unlock( &update_mutex );
+#endif
+ return l;
+}
+#endif
+
SkLanguage SkLanguage::getParent() const {
SkASSERT(!fTag.isEmpty());
const char* tag = fTag.c_str();
@@ -28,7 +179,11 @@ SkLanguage SkLanguage::getParent() const {
void SkPaintOptionsAndroid::flatten(SkWriteBuffer& buffer) const {
buffer.writeUInt(fFontVariant);
+#ifdef SKLANG_OPT
+ buffer.writeString(getLanguage().getTag().c_str());
+#else
buffer.writeString(fLanguage.getTag().c_str());
+#endif
buffer.writeBool(fUseFontFallbacks);
}
@@ -36,6 +191,41 @@ void SkPaintOptionsAndroid::unflatten(SkReadBuffer& buffer) {
fFontVariant = (FontVariant)buffer.readUInt();
SkString tag;
buffer.readString(&tag);
+#ifdef SKLANG_OPT
+ setLanguage(tag);
+#else
fLanguage = SkLanguage(tag);
+#endif
fUseFontFallbacks = buffer.readBool();
}
+
+#ifdef SKLANG_OPT
+void SkPaintOptionsAndroid::setLanguage(const SkLanguage& language) {
+ SkLangOptDebugf("SKLANG_OPT s1 this=%p", this);
+ fpLanguage = SkLanguages::getInstance()->setLanguage(language);
+}
+
+void SkPaintOptionsAndroid::setLanguage(const char* languageTag) {
+ SkLangOptDebugf("SKLANG_OPT s2 this=%p", this);
+ fpLanguage = SkLanguages::getInstance()->setLanguage(languageTag);
+}
+
+const SkLanguage& SkPaintOptionsAndroid::getLanguage() const {
+ if( SkUnlikely (fpLanguage == NULL)){
+ SkLangOptDebugf("SKLANG_OPT g1 this=%p", this);
+ //Add the default empty language
+ //We shouldn't go through this path anyway
+ SkLanguage emptyLang = SkLanguage("");
+ //We can NOT assign the return pointer to fpLanguage as the API is
+ //defined on the READ-ONLY object.
+ SkLangList* fpl;
+ fpl = SkLanguages::getInstance()->setLanguage(emptyLang);
+ //This is persistent object in the global array,
+ //So there is no memory leak
+ return fpl->s;
+ } else {
+ SkLangOptDebugf("SKLANG_OPT g2 this=%p", this);
+ return fpLanguage->s;
+ }
+}
+#endif