aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/common.gypi7
-rw-r--r--gyp/core.gyp1
-rw-r--r--gyp/gpu.gyp2
-rw-r--r--gyp/utils.gyp2
-rw-r--r--include/core/SkOSFile.h16
-rw-r--r--include/core/SkString.h24
-rw-r--r--include/core/SkTDArray.h4
-rw-r--r--include/utils/SkRTConf.h135
-rw-r--r--src/core/SkGraphics.cpp9
-rw-r--r--src/core/SkStream.cpp4
-rw-r--r--src/gpu/gl/GrGLProgram.cpp29
-rw-r--r--src/ports/SkOSFile_stdio.cpp17
-rw-r--r--src/utils/SkRTConf.cpp325
13 files changed, 556 insertions, 19 deletions
diff --git a/gyp/common.gypi b/gyp/common.gypi
index 7dc27da143..810a0f81f5 100644
--- a/gyp/common.gypi
+++ b/gyp/common.gypi
@@ -82,6 +82,7 @@
'defines': [
'SK_DEBUG',
'GR_DEBUG=1',
+ 'SK_DEVELOPER=1',
],
},
'Release': {
@@ -90,6 +91,12 @@
'GR_RELEASE=1',
],
},
+ 'Release_Developer': {
+ 'inherit_from': ['Release'],
+ 'defines': [
+ 'SK_DEVELOPER=1',
+ ],
+ },
},
}, # end 'target_defaults'
}
diff --git a/gyp/core.gyp b/gyp/core.gyp
index eddb9400c7..7e7640c639 100644
--- a/gyp/core.gyp
+++ b/gyp/core.gyp
@@ -17,6 +17,7 @@
'../include/core',
'../include/pipe',
'../include/ports',
+ '../include/utils',
'../include/xml',
'../src/core',
'../src/image',
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp
index 7438babe59..6c599e162a 100644
--- a/gyp/gpu.gyp
+++ b/gyp/gpu.gyp
@@ -127,6 +127,7 @@
'include_dirs': [
'../include/config',
'../include/core',
+ '../include/utils',
'../src/core',
'../include/gpu',
'../src/gpu',
@@ -177,6 +178,7 @@
'include_dirs': [
'../include/core',
'../include/config',
+ '../include/utils',
'../include/gpu',
'../src/core', # SkRasterClip.h
'../src/gpu'
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
index cd44769fbe..d4942d781a 100644
--- a/gyp/utils.gyp
+++ b/gyp/utils.gyp
@@ -47,6 +47,7 @@
'../include/utils/SkParsePaint.h',
'../include/utils/SkParsePath.h',
'../include/utils/SkPictureUtils.h',
+ '../include/utils/SkRTConf.h',
'../include/utils/SkProxyCanvas.h',
'../include/utils/SkUnitMappers.h',
'../include/utils/SkWGL.h',
@@ -81,6 +82,7 @@
'../src/utils/SkParsePath.cpp',
'../src/utils/SkPictureUtils.cpp',
'../src/utils/SkProxyCanvas.cpp',
+ '../src/utils/SkRTConf.cpp',
'../src/utils/SkThreadUtils.h',
'../src/utils/SkThreadUtils_pthread.cpp',
'../src/utils/SkThreadUtils_pthread.h',
diff --git a/include/core/SkOSFile.h b/include/core/SkOSFile.h
index 79551ae206..685248cd00 100644
--- a/include/core/SkOSFile.h
+++ b/include/core/SkOSFile.h
@@ -18,6 +18,8 @@
#include <dirent.h>
#endif
+#include <stddef.h> // ptrdiff_t
+
struct SkFILE;
enum SkFILE_Flags {
@@ -43,8 +45,8 @@ size_t sk_fread(void* buffer, size_t byteCount, SkFILE*);
size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE*);
void sk_fflush(SkFILE*);
-int sk_fseek( SkFILE*, size_t, int );
-size_t sk_ftell( SkFILE* );
+int sk_fseek(SkFILE*, size_t, int);
+size_t sk_ftell(SkFILE*);
// Returns true if something (file, directory, ???) exists at this path.
bool sk_exists(const char *path);
@@ -52,6 +54,16 @@ bool sk_exists(const char *path);
// Returns true if a directory exists at this path.
bool sk_isdir(const char *path);
+// Get a single line of input from a file. Returns -1 on failure.
+// passing NULL for lineptr will allocate memory for the line with
+// sk_malloc; make sure to use sk_free to get rid of it when you're
+// done.
+ptrdiff_t sk_getline(char **lineptr, size_t *n, SkFILE *stream);
+
+// Have we reached the end of the file?
+int sk_feof(SkFILE *);
+
+
// Create a new directory at this path; returns true if successful.
// If the directory already existed, this will return true.
// Description of the error, if any, will be written to stderr.
diff --git a/include/core/SkString.h b/include/core/SkString.h
index 94dcf8b438..7ea3969082 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -30,16 +30,33 @@ bool SkStrEndsWith(const char string[], const char suffixChar);
int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
+static int SkStrFind(const char string[], const char substring[]) {
+ char *first = strstr(string, substring);
+ if (NULL == first) return -1;
+ return first - &(string[0]);
+}
+
static bool SkStrContains(const char string[], const char substring[]) {
SkASSERT(string);
SkASSERT(substring);
- return (NULL != strstr(string, substring));
+ return (-1 != SkStrFind(string, substring));
}
static bool SkStrContains(const char string[], const char subchar) {
SkASSERT(string);
- return (NULL != strchr(string, subchar));
+ char tmp[2];
+ tmp[0] = subchar;
+ tmp[1] = '\0';
+ return (-1 != SkStrFind(string, tmp));
+}
+
+static inline char *SkStrDup(const char string[]) {
+ char *ret = (char *) sk_malloc_throw(strlen(string)+1);
+ memcpy(ret,string,strlen(string));
+ return ret;
}
+
+
#define SkStrAppendS32_MaxSize 11
char* SkStrAppendS32(char buffer[], int32_t);
#define SkStrAppendS64_MaxSize 20
@@ -112,6 +129,9 @@ public:
bool contains(const char subchar) const {
return SkStrContains(fRec->data(), subchar);
}
+ int find(const char substring[]) const {
+ return SkStrFind(fRec->data(), substring);
+ }
friend bool operator==(const SkString& a, const SkString& b) {
return a.equals(b);
diff --git a/include/core/SkTDArray.h b/include/core/SkTDArray.h
index eaf25c67ae..6f7a60e9ba 100644
--- a/include/core/SkTDArray.h
+++ b/include/core/SkTDArray.h
@@ -108,6 +108,10 @@ public:
SkASSERT((unsigned)index < fCount);
return fArray[index];
}
+
+ T& getAt(int index) const {
+ return (*this)[index];
+ }
void reset() {
if (fArray) {
diff --git a/include/utils/SkRTConf.h b/include/utils/SkRTConf.h
new file mode 100644
index 0000000000..22d7e606ee
--- /dev/null
+++ b/include/utils/SkRTConf.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2013 Google, Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkRTConf_DEFINED
+#define SkRTConf_DEFINED
+
+#include "SkString.h"
+#include "SkStream.h"
+
+#include "SkTDict.h"
+#include "SkTArray.h"
+
+/** \class SkRTConfBase
+ Non-templated base class for the runtime configs
+*/
+
+class SkRTConfBase {
+public:
+ SkRTConfBase(const char *name) : fName(name) {}
+ virtual ~SkRTConfBase() {}
+ virtual const char *getName() const { return fName.c_str(); }
+ virtual bool isDefault() const = 0;
+ virtual void print(SkWStream *o) const = 0;
+ virtual bool equals(const SkRTConfBase *conf) const = 0;
+protected:
+ SkString fName;
+};
+
+/** \class SkRTConf
+ A class to provide runtime configurability.
+*/
+template<typename T> class SkRTConf: public SkRTConfBase {
+public:
+ SkRTConf(const char *name, const T &defaultValue, const char *description);
+ operator const T&() const { return fValue; }
+ void print(SkWStream *o) const;
+ bool equals(const SkRTConfBase *conf) const;
+ bool isDefault() const { return fDefault == fValue; }
+ void set(const T& value) { fValue = value; }
+protected:
+ void doPrint(char *s) const;
+
+ SkString fDescription;
+ T fDefault;
+ T fValue;
+};
+
+#ifdef SK_DEVELOPER
+#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static SkRTConf<confType> varName(confName, defaultValue, description)
+#define SK_CONF_SET(confname, value) skRTConfRegistry().set(confname, value)
+#else
+#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static const confType varName = defaultValue
+#define SK_CONF_SET(confname, value) (void) confname, (void) value
+#endif
+
+/** \class SkRTConfRegistry
+ A class that maintains a systemwide registry of all runtime configuration
+ parameters. Mainly used for printing them out and handling multiply-defined
+ knobs.
+*/
+
+class SkRTConfRegistry {
+public:
+ SkRTConfRegistry();
+ void printAll(const char *fname = NULL) const;
+ void printNonDefault(const char *fname = NULL) const;
+ const char *configFileLocation() const;
+ void possiblyDumpFile() const;
+ void validate() const;
+ template <typename T> void set(const char *confname, T value);
+private:
+ template<typename T> friend class SkRTConf;
+
+ void registerConf(SkRTConfBase *conf);
+ template <typename T> bool parse(const char *name, T* value);
+
+ SkTDArray<SkString *> fConfigFileKeys, fConfigFileValues;
+ typedef SkTDict< SkTDArray<SkRTConfBase *> * > ConfMap;
+ ConfMap fConfs;
+};
+
+// our singleton registry
+
+SkRTConfRegistry &skRTConfRegistry();
+
+template<typename T>
+SkRTConf<T>::SkRTConf(const char *name, const T &defaultValue, const char *description)
+ : SkRTConfBase(name)
+ , fValue(defaultValue)
+ , fDefault(defaultValue)
+ , fDescription(description) {
+
+ T value;
+ if (skRTConfRegistry().parse(fName.c_str(), &value)) {
+ fValue = value;
+ }
+ skRTConfRegistry().registerConf(this);
+}
+
+template<typename T>
+void SkRTConf<T>::print(SkWStream *o) const {
+ char outline[200]; // should be ok because we specify a max. width for everything here.
+
+ sprintf(outline, "%-30.30s", getName());
+ doPrint(&(outline[30]));
+ sprintf(&(outline[60]), " %.128s", fDescription.c_str());
+ if (' ' == outline[strlen(outline)-1]) {
+ for (int i = strlen(outline)-1 ; ' ' == outline[i] ; i--) {
+ outline[i] = '\0';
+ }
+ }
+ o->writeText(outline);
+}
+
+template<typename T>
+void SkRTConf<T>::doPrint(char *s) const {
+ sprintf(s, "%-30.30s", "How do I print myself??");
+}
+
+template<typename T>
+bool SkRTConf<T>::equals(const SkRTConfBase *conf) const {
+ const SkRTConf<T> *child_pointer = dynamic_cast<const SkRTConf<T> *>(conf);
+ return child_pointer &&
+ fName == child_pointer->fName &&
+ fDescription == child_pointer->fDescription &&
+ fValue == child_pointer->fValue &&
+ fDefault == child_pointer->fDefault;
+}
+
+#endif
diff --git a/src/core/SkGraphics.cpp b/src/core/SkGraphics.cpp
index 53d0318251..d0d64dece0 100644
--- a/src/core/SkGraphics.cpp
+++ b/src/core/SkGraphics.cpp
@@ -21,6 +21,7 @@
#include "SkPixelRef.h"
#include "SkRandom.h"
#include "SkRefCnt.h"
+#include "SkRTConf.h"
#include "SkScalerContext.h"
#include "SkShader.h"
#include "SkStream.h"
@@ -52,6 +53,13 @@ void SkGraphics::GetVersion(int32_t* major, int32_t* minor, int32_t* patch) {
#endif
void SkGraphics::Init() {
+#ifdef SK_DEVELOPER
+ skRTConfRegistry().possiblyDumpFile();
+ skRTConfRegistry().validate();
+ SkDebugf("Non-default runtime configuration options:\n");
+ skRTConfRegistry().printNonDefault( );
+#endif
+
SkFlattenable::InitializeFlattenables();
#ifdef BUILD_EMBOSS_TABLE
SkEmbossMask_BuildTable();
@@ -116,6 +124,7 @@ void SkGraphics::Init() {
GetFontCacheLimit() >> 10);
#endif
+
}
void SkGraphics::Term() {
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
index 59b5da3304..fb343ea76a 100644
--- a/src/core/SkStream.cpp
+++ b/src/core/SkStream.cpp
@@ -773,14 +773,14 @@ void SkDynamicMemoryWStream::invalidateCopy() {
void SkDebugWStream::newline()
{
-#ifdef SK_DEBUG
+#if defined(SK_DEBUG) || defined(SK_DEVELOPER)
SkDebugf("\n");
#endif
}
bool SkDebugWStream::write(const void* buffer, size_t size)
{
-#ifdef SK_DEBUG
+#if defined(SK_DEBUG) || defined(SK_DEVELOPER)
char* s = new char[size+1];
memcpy(s, buffer, size);
s[size] = 0;
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 63e991f654..1b472020c1 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -16,12 +16,14 @@
#include "SkTrace.h"
#include "SkXfermode.h"
+#include "SkRTConf.h"
+
SK_DEFINE_INST_COUNT(GrGLProgram)
#define GL_CALL(X) GR_GL_CALL(fContextInfo.interface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fContextInfo.interface(), R, X)
-#define PRINT_SHADERS 0
+SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, "Print the source code for all shaders generated.");
#define COL_ATTR_NAME "aColor"
#define COV_ATTR_NAME "aCoverage"
@@ -457,20 +459,21 @@ bool GrGLProgram::compileShaders(const GrGLShaderBuilder& builder) {
SkString shader;
builder.getShader(GrGLShaderBuilder::kVertex_ShaderType, &shader);
-#if PRINT_SHADERS
- GrPrintf(shader.c_str());
- GrPrintf("\n");
-#endif
+ if (c_PrintShaders) {
+ GrPrintf(shader.c_str());
+ GrPrintf("\n");
+ }
+
if (!(fVShaderID = compile_shader(fContextInfo, GR_GL_VERTEX_SHADER, shader))) {
return false;
}
if (builder.fUsesGS) {
builder.getShader(GrGLShaderBuilder::kGeometry_ShaderType, &shader);
-#if PRINT_SHADERS
- GrPrintf(shader.c_str());
- GrPrintf("\n");
-#endif
+ if (c_PrintShaders) {
+ GrPrintf(shader.c_str());
+ GrPrintf("\n");
+ }
if (!(fGShaderID = compile_shader(fContextInfo, GR_GL_GEOMETRY_SHADER, shader))) {
return false;
}
@@ -479,10 +482,10 @@ bool GrGLProgram::compileShaders(const GrGLShaderBuilder& builder) {
}
builder.getShader(GrGLShaderBuilder::kFragment_ShaderType, &shader);
-#if PRINT_SHADERS
- GrPrintf(shader.c_str());
- GrPrintf("\n");
-#endif
+ if (c_PrintShaders) {
+ GrPrintf(shader.c_str());
+ GrPrintf("\n");
+ }
if (!(fFShaderID = compile_shader(fContextInfo, GR_GL_FRAGMENT_SHADER, shader))) {
return false;
}
diff --git a/src/ports/SkOSFile_stdio.cpp b/src/ports/SkOSFile_stdio.cpp
index 9100f6d122..e7f65cd499 100644
--- a/src/ports/SkOSFile_stdio.cpp
+++ b/src/ports/SkOSFile_stdio.cpp
@@ -41,6 +41,23 @@ SkFILE* sk_fopen(const char path[], SkFILE_Flags flags)
return f;
}
+ptrdiff_t sk_getline(char **lineptr, size_t *n, SkFILE *f) {
+ bool make_private_copy = (NULL == *lineptr);
+
+ ptrdiff_t ret = ::getline(lineptr, n, (FILE *) f);
+ if (make_private_copy) {
+ char *local_copy = (char *) sk_malloc_throw(strlen(*lineptr) + 1);
+ ::memcpy(local_copy, *lineptr, strlen(*lineptr));
+ ::free(*lineptr);
+ *lineptr = local_copy;
+ }
+ return ret;
+}
+
+int sk_feof(SkFILE *f) {
+ return ::feof((FILE *)f);
+}
+
size_t sk_fgetsize(SkFILE* f)
{
SkASSERT(f);
diff --git a/src/utils/SkRTConf.cpp b/src/utils/SkRTConf.cpp
new file mode 100644
index 0000000000..fcc51c33c3
--- /dev/null
+++ b/src/utils/SkRTConf.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRTConf.h"
+#include "SkOSFile.h"
+
+SkRTConfRegistry::SkRTConfRegistry(): fConfs(100) {
+
+ SkFILE *fp = sk_fopen(configFileLocation(), kRead_SkFILE_Flag);
+
+ if (!fp) {
+ return;
+ }
+
+ char *line = NULL;
+ size_t n = 0;
+
+ while (!sk_feof(fp)) {
+ if (line) {
+ sk_free(line);
+ }
+ line = NULL;
+
+ if (sk_getline(&line, &n, fp) == -1) break;
+
+ char *commentptr = strchr(line, '#');
+ if (commentptr == line) {
+ continue;
+ }
+ if (NULL != commentptr) {
+ char *tmp = (char *) sk_malloc_throw(commentptr-line+1);
+ strncpy(tmp, line, commentptr-line);
+ sk_free(line);
+ line = tmp;
+ }
+
+ char sep[] = " \t";
+
+ char *keyptr = strtok(line, sep);
+ if (!keyptr) {
+ continue;
+ }
+
+ char *valptr = strtok(NULL, sep);
+ if (!valptr) {
+ continue;
+ }
+
+ SkString* key = new SkString(keyptr);
+ SkString* val = new SkString(valptr);
+
+ fConfigFileKeys.append(1, &key);
+ fConfigFileValues.append(1, &val);
+ }
+ sk_fclose(fp);
+}
+
+const char *SkRTConfRegistry::configFileLocation() const {
+ return "skia.conf"; // for now -- should probably do something fancier like home directories or whatever.
+}
+
+// dump all known runtime config options to the file with their default values.
+// to trigger this, make a config file of zero size.
+void SkRTConfRegistry::possiblyDumpFile() const {
+ const char *path = configFileLocation();
+ SkFILE *fp = sk_fopen(path, kRead_SkFILE_Flag);
+ if (!fp) {
+ return;
+ }
+ size_t configFileSize = sk_fgetsize(fp);
+ if (configFileSize == 0) {
+ printAll(path);
+ }
+ sk_fclose(fp);
+}
+
+// Run through every provided configuration option and print a warning if the user hasn't
+// declared a correponding configuration object somewhere.
+void SkRTConfRegistry::validate() const {
+ for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
+ if (fConfs.find(fConfigFileKeys[i]->c_str()) == -1) {
+ SkDebugf("WARNING: You have config value %s in your configuration file, but I've never heard of that.\n", fConfigFileKeys[i]->c_str());
+ }
+ }
+}
+
+void SkRTConfRegistry::printAll(const char *fname) const {
+ SkWStream *o;
+
+ if (NULL != fname) {
+ o = new SkFILEWStream(fname);
+ } else {
+ o = new SkDebugWStream();
+ }
+
+ ConfMap::Iter iter(fConfs);
+ SkTDArray<SkRTConfBase *> *confArray;
+
+ while (iter.next(&confArray)) {
+ if (confArray->getAt(0)->isDefault()) {
+ o->writeText("# ");
+ }
+ confArray->getAt(0)->print(o);
+ o->newline();
+ }
+
+ delete o;
+}
+
+void SkRTConfRegistry::printNonDefault(const char *fname) const {
+ SkWStream *o;
+
+ if (NULL != fname) {
+ o = new SkFILEWStream(fname);
+ } else {
+ o = new SkDebugWStream();
+ }
+ ConfMap::Iter iter(fConfs);
+ SkTDArray<SkRTConfBase *> *confArray;
+
+ while (iter.next(&confArray)) {
+ if (!confArray->getAt(0)->isDefault()) {
+ confArray->getAt(0)->print(o);
+ o->newline();
+ }
+ }
+
+ delete o;
+}
+
+// register a configuration variable after its value has been set by the parser.
+// we maintain a vector of these things instead of just a single one because the
+// user might set the value after initialization time and we need to have
+// all the pointers lying around, not just one.
+void SkRTConfRegistry::registerConf(SkRTConfBase *conf) {
+ SkTDArray<SkRTConfBase *> *confArray;
+ if (fConfs.find(conf->getName(), &confArray)) {
+ if (!conf->equals(confArray->getAt(0))) {
+ SkDebugf("WARNING: Skia config \"%s\" was registered more than once in incompatible ways.\n", conf->getName());
+ } else {
+ confArray->append(1, &conf);
+ }
+ } else {
+ confArray = new SkTDArray<SkRTConfBase *>;
+ confArray->append(1, &conf);
+ fConfs.set(conf->getName(),confArray);
+ }
+}
+
+template <typename T> T doParse(const char *s, bool *success ) {
+ SkDebugf("WARNING: Invoked non-specialized doParse function...\n");
+ if (success) {
+ *success = false;
+ }
+ return (T) 0;
+}
+
+template<> bool doParse<bool>(const char *s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ if (!strcmp(s,"1") || !strcmp(s,"true")) {
+ return true;
+ }
+ if (!strcmp(s,"0") || !strcmp(s,"false")) {
+ return false;
+ }
+ if (success) {
+ *success = false;
+ }
+ return false;
+}
+
+template<> const char * doParse<const char *>(const char * s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ return s;
+}
+
+template<> int doParse<int>(const char * s, bool *success) {
+ return atoi(s);
+}
+
+template<> unsigned int doParse<unsigned int>(const char * s, bool *success) {
+ return (unsigned int) atoi(s);
+}
+
+template<> float doParse<float>(const char * s, bool *success) {
+ return (float) atof(s);
+}
+
+template<> double doParse<double>(const char * s, bool *success) {
+ return atof(s);
+}
+
+static inline void str_replace(char *s, char search, char replace) {
+ for (char *ptr = s ; *ptr ; ptr++) {
+ if (*ptr == search) {
+ *ptr = replace;
+ }
+ }
+}
+
+template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) {
+ SkString *str = NULL;
+
+ for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
+ if (fConfigFileKeys[i]->equals(name)) {
+ str = fConfigFileValues[i];
+ }
+ }
+
+ SkString environment_variable("skia.");
+ environment_variable.append(name);
+
+ const char *environment_value = getenv(environment_variable.c_str());
+ if (environment_value) {
+ str->set(environment_value);
+ } else {
+ // apparently my shell doesn't let me have environment variables that
+ // have periods in them, so also let the user substitute underscores.
+ SkString underscore_environment_variable("skia_");
+ char *underscore_name = SkStrDup(name);
+ str_replace(underscore_name,'.','_');
+ underscore_environment_variable.append(underscore_name);
+ sk_free(underscore_name);
+ environment_value = getenv(underscore_environment_variable.c_str());
+ if (environment_value) {
+ str->set(environment_value);
+ }
+ }
+
+ if (!str) {
+ return false;
+ }
+
+ bool success;
+ T new_value = doParse<T>(str->c_str(),&success);
+ if (success) {
+ *value = new_value;
+ } else {
+ SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n", str->c_str(), name);
+ }
+ return success;
+}
+
+// need to explicitly instantiate the parsing function for every config type we might have...
+
+template bool SkRTConfRegistry::parse(const char *name, bool *value);
+template bool SkRTConfRegistry::parse(const char *name, int *value);
+template bool SkRTConfRegistry::parse(const char *name, unsigned int *value);
+template bool SkRTConfRegistry::parse(const char *name, float *value);
+template bool SkRTConfRegistry::parse(const char *name, double *value);
+template bool SkRTConfRegistry::parse(const char *name, const char **value);
+
+template <typename T> void SkRTConfRegistry::set(const char *name, T value) {
+
+ SkTDArray<SkRTConfBase *> *confArray;
+ if (!fConfs.find(name, &confArray)) {
+ SkDebugf("WARNING: Attempting to set configuration value \"%s\", but I've never heard of that.\n", name);
+ return;
+ }
+
+ for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) {
+
+ SkRTConf<bool> *concrete = dynamic_cast<SkRTConf<bool> *>(*confBase);
+
+ if (concrete) {
+ concrete->set(value);
+ }
+ }
+}
+
+template void SkRTConfRegistry::set(const char *name, bool value);
+template void SkRTConfRegistry::set(const char *name, int value);
+template void SkRTConfRegistry::set(const char *name, unsigned int value);
+template void SkRTConfRegistry::set(const char *name, float value);
+template void SkRTConfRegistry::set(const char *name, double value);
+template void SkRTConfRegistry::set(const char *name, char * value);
+
+template<> void SkRTConf<bool>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false");
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> void SkRTConf<int>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%d # [%d]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> void SkRTConf<unsigned int>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%u # [%u]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> void SkRTConf<float>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> void SkRTConf<double>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> void SkRTConf<const char *>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%s # [%s]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+SkRTConfRegistry &skRTConfRegistry() {
+ static SkRTConfRegistry r;
+ return r;
+}