factor out hexadecimal constants.

Now we don't have to rely on the linker to de-duplicate
so many gHex[] constants.

Change-Id: Ia86d3a92648415afdb8d29499b4faded5ed05c7d
Reviewed-on: https://skia-review.googlesource.com/20180
Commit-Queue: Hal Canary <halcanary@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
diff --git a/src/core/SkICC.cpp b/src/core/SkICC.cpp
index c26f6d8..7eaf667 100644
--- a/src/core/SkICC.cpp
+++ b/src/core/SkICC.cpp
@@ -15,6 +15,7 @@
 #include "SkICC.h"
 #include "SkICCPriv.h"
 #include "SkMD5.h"
+#include "SkUtils.h"
 
 SkICC::SkICC(sk_sp<SkColorSpace> colorSpace)
     : fColorSpace(std::move(colorSpace))
@@ -332,11 +333,10 @@
         SkMD5::Digest digest;
         md5.finish(digest);
         for (unsigned i = 0; i < sizeof(SkMD5::Digest); ++i) {
-            static const char gHex[] = "0123456789ABCDEF";
             *ptr++ = 0;
-            *ptr++ = gHex[digest.data[i] >> 4];
+            *ptr++ = SkHexadecimalDigits::gUpper[digest.data[i] >> 4];
             *ptr++ = 0;
-            *ptr++ = gHex[digest.data[i] & 0xF];
+            *ptr++ = SkHexadecimalDigits::gUpper[digest.data[i] & 0xF];
         }
         SkASSERT(ptr == ptrCheck + kDescriptionTagBodySize + sizeof(kDescriptionTagHeader));
     }
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index 528c602..8eee127 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -539,13 +539,11 @@
 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
     minDigits = SkTPin(minDigits, 0, 8);
 
-    static const char gHex[] = "0123456789ABCDEF";
-
     char    buffer[8];
     char*   p = buffer + sizeof(buffer);
 
     do {
-        *--p = gHex[hex & 0xF];
+        *--p = SkHexadecimalDigits::gUpper[hex & 0xF];
         hex >>= 4;
         minDigits -= 1;
     } while (hex != 0);
diff --git a/src/core/SkUtils.cpp b/src/core/SkUtils.cpp
index 85ebb3e..1eb2a7d 100644
--- a/src/core/SkUtils.cpp
+++ b/src/core/SkUtils.cpp
@@ -355,3 +355,9 @@
     }
     return size;
 }
+
+const char SkHexadecimalDigits::gUpper[16] =
+           { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+const char SkHexadecimalDigits::gLower[16] =
+           { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
diff --git a/src/core/SkUtils.h b/src/core/SkUtils.h
index 2ae6f87..832bdbd 100644
--- a/src/core/SkUtils.h
+++ b/src/core/SkUtils.h
@@ -107,4 +107,10 @@
     }
     return true;
 }
+
+namespace SkHexadecimalDigits {
+    extern const char gUpper[16];  // 0-9A-F
+    extern const char gLower[16];  // 0-9a-f
+}
+
 #endif
diff --git a/src/pdf/SkPDFMetadata.cpp b/src/pdf/SkPDFMetadata.cpp
index ee5c19b..edef851 100644
--- a/src/pdf/SkPDFMetadata.cpp
+++ b/src/pdf/SkPDFMetadata.cpp
@@ -9,6 +9,8 @@
 #include "SkMilestone.h"
 #include "SkPDFMetadata.h"
 #include "SkPDFTypes.h"
+#include "SkUtils.h"
+
 #include <utility>
 
 #define SKPDF_STRING(X) SKPDF_STRING_IMPL(X)
@@ -120,35 +122,36 @@
     return array;
 }
 
-#define HEXIFY(INPUT_PTR, OUTPUT_PTR, HEX_STRING, BYTE_COUNT) \
-    do {                                                      \
-        for (int i = 0; i < (BYTE_COUNT); ++i) {              \
-            uint8_t value = *(INPUT_PTR)++;                   \
-            *(OUTPUT_PTR)++ = (HEX_STRING)[value >> 4];       \
-            *(OUTPUT_PTR)++ = (HEX_STRING)[value & 0xF];      \
-        }                                                     \
-    } while (false)
+// Convert a block of memory to hexadecimal.  Input and output pointers will be
+// moved to end of the range.
+static void hexify(const uint8_t** inputPtr, char** outputPtr, int count) {
+    SkASSERT(inputPtr && *inputPtr);
+    SkASSERT(outputPtr && *outputPtr);
+    while (count-- > 0) {
+        uint8_t value = *(*inputPtr)++;
+        *(*outputPtr)++ = SkHexadecimalDigits::gLower[value >> 4];
+        *(*outputPtr)++ = SkHexadecimalDigits::gLower[value & 0xF];
+    }
+}
+
 static SkString uuid_to_string(const SkPDFMetadata::UUID& uuid) {
     //  8-4-4-4-12
     char buffer[36];  // [32 + 4]
-    static const char gHex[] = "0123456789abcdef";
-    SkASSERT(strlen(gHex) == 16);
     char* ptr = buffer;
     const uint8_t* data = uuid.fData;
-    HEXIFY(data, ptr, gHex, 4);
+    hexify(&data, &ptr, 4);
     *ptr++ = '-';
-    HEXIFY(data, ptr, gHex, 2);
+    hexify(&data, &ptr, 2);
     *ptr++ = '-';
-    HEXIFY(data, ptr, gHex, 2);
+    hexify(&data, &ptr, 2);
     *ptr++ = '-';
-    HEXIFY(data, ptr, gHex, 2);
+    hexify(&data, &ptr, 2);
     *ptr++ = '-';
-    HEXIFY(data, ptr, gHex, 6);
+    hexify(&data, &ptr, 6);
     SkASSERT(ptr == buffer + 36);
     SkASSERT(data == uuid.fData + 16);
     return SkString(buffer, 36);
 }
-#undef HEXIFY
 
 namespace {
 class PDFXMLObject final : public SkPDFObject {
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index 2559f93..b9e9060 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -100,12 +100,12 @@
 // leading slash).
 static void write_name_escaped(SkWStream* o, const char* name) {
     static const char kToEscape[] = "#/%()<>[]{}";
-    static const char kHex[] = "0123456789ABCDEF";
     for (const uint8_t* n = reinterpret_cast<const uint8_t*>(name); *n; ++n) {
-        if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) {
-            char buffer[3] = {'#', '\0', '\0'};
-            buffer[1] = kHex[(*n >> 4) & 0xF];
-            buffer[2] = kHex[*n & 0xF];
+        uint8_t v = *n;
+        if (v < '!' || v > '~' || strchr(kToEscape, v)) {
+            char buffer[3] = {'#',
+                              SkHexadecimalDigits::gUpper[v >> 4],
+                              SkHexadecimalDigits::gUpper[v & 0xF]};
             o->write(buffer, sizeof(buffer));
         } else {
             o->write(n, 1);
diff --git a/src/pdf/SkPDFUtils.cpp b/src/pdf/SkPDFUtils.cpp
index 2487043..3cbf038 100644
--- a/src/pdf/SkPDFUtils.cpp
+++ b/src/pdf/SkPDFUtils.cpp
@@ -479,10 +479,8 @@
         wStream->writeText("<");
         for (size_t i = 0; i < len; i++) {
             uint8_t c = static_cast<uint8_t>(cin[i]);
-            static const char gHex[] = "0123456789ABCDEF";
-            char hexValue[2];
-            hexValue[0] = gHex[(c >> 4) & 0xF];
-            hexValue[1] = gHex[ c       & 0xF];
+            char hexValue[2] = { SkHexadecimalDigits::gUpper[c >> 4],
+                                 SkHexadecimalDigits::gUpper[c & 0xF] };
             wStream->write(hexValue, 2);
         }
         wStream->writeText(">");
diff --git a/src/pdf/SkPDFUtils.h b/src/pdf/SkPDFUtils.h
index c1d9a72..58453ae 100644
--- a/src/pdf/SkPDFUtils.h
+++ b/src/pdf/SkPDFUtils.h
@@ -79,21 +79,20 @@
 void WriteString(SkWStream* wStream, const char* input, size_t len);
 
 inline void WriteUInt16BE(SkDynamicMemoryWStream* wStream, uint16_t value) {
-    static const char gHex[] = "0123456789ABCDEF";
     char result[4];
-    result[0] = gHex[       value >> 12 ];
-    result[1] = gHex[0xF & (value >> 8 )];
-    result[2] = gHex[0xF & (value >> 4 )];
-    result[3] = gHex[0xF & (value      )];
+    result[0] = SkHexadecimalDigits::gUpper[       value >> 12 ];
+    result[1] = SkHexadecimalDigits::gUpper[0xF & (value >> 8 )];
+    result[2] = SkHexadecimalDigits::gUpper[0xF & (value >> 4 )];
+    result[3] = SkHexadecimalDigits::gUpper[0xF & (value      )];
     wStream->write(result, 4);
 }
+
 inline void WriteUInt8(SkDynamicMemoryWStream* wStream, uint8_t value) {
-    static const char gHex[] = "0123456789ABCDEF";
-    char result[2];
-    result[0] = gHex[value >> 4 ];
-    result[1] = gHex[0xF & value];
+    char result[2] = { SkHexadecimalDigits::gUpper[value >> 4],
+                       SkHexadecimalDigits::gUpper[value & 0xF] };
     wStream->write(result, 2);
 }
+
 inline void WriteUTF16beHex(SkDynamicMemoryWStream* wStream, SkUnichar utf32) {
     uint16_t utf16[2] = {0, 0};
     size_t len = SkUTF16_FromUnichar(utf32, utf16);