Change sRGB and XYZD50 profiles to functions

By only exporting functions, shared-library building on Windows is
significantly simpler (no need to dllimport).

See also: https://skia-review.googlesource.com/c/skia/+/124983

Change-Id: I916b77b8cb4f54d2e087e3e8c78ad4459c7ee927
Reviewed-on: https://skia-review.googlesource.com/124982
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/skcms.h b/skcms.h
index 94dfe03..2053fe6 100644
--- a/skcms.h
+++ b/skcms.h
@@ -113,9 +113,9 @@
 } skcms_ICCProfile;
 
 // The sRGB color profile is so commonly used that we offer a canonical skcms_ICCProfile for it.
-SKCMS_API extern const skcms_ICCProfile skcms_sRGB_profile;
+SKCMS_API const skcms_ICCProfile* skcms_sRGB_profile(void);
 // Ditto for XYZD50, the most common profile connection space.
-SKCMS_API extern const skcms_ICCProfile skcms_XYZD50_profile;
+SKCMS_API const skcms_ICCProfile* skcms_XYZD50_profile(void);
 
 // Practical equality test for two skcms_ICCProfiles.
 // The implementation is subject to change, but it will always try to answer
diff --git a/src/ICCProfile.c b/src/ICCProfile.c
index 90ce6fc..322e097 100644
--- a/src/ICCProfile.c
+++ b/src/ICCProfile.c
@@ -781,63 +781,71 @@
     return usable_as_src(profile);
 }
 
-const skcms_ICCProfile skcms_sRGB_profile = {
-    // These fields are moot when not a skcms_Parse()'d profile.
-    .buffer    = NULL,
-    .size      =    0,
-    .tag_count =    0,
 
-    // We choose to represent sRGB with its canonical transfer function,
-    // and with its canonical XYZD50 gamut matrix.
-    .data_color_space = make_signature('R', 'G', 'B', ' '),
-    .pcs              = make_signature('X', 'Y', 'Z', ' '),
-    .has_trc      = true,
-    .has_toXYZD50 = true,
-    .has_A2B      = false,
+const skcms_ICCProfile* skcms_sRGB_profile() {
+    static const skcms_ICCProfile sRGB_profile = {
+        // These fields are moot when not a skcms_Parse()'d profile.
+        .buffer    = NULL,
+        .size      =    0,
+        .tag_count =    0,
 
-    .trc = {
-        {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
-        {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
-        {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
-    },
+        // We choose to represent sRGB with its canonical transfer function,
+        // and with its canonical XYZD50 gamut matrix.
+        .data_color_space = make_signature('R', 'G', 'B', ' '),
+        .pcs              = make_signature('X', 'Y', 'Z', ' '),
+        .has_trc      = true,
+        .has_toXYZD50 = true,
+        .has_A2B      = false,
 
-    .toXYZD50 = {{
-        { 0.436065674f, 0.385147095f, 0.143066406f },
-        { 0.222488403f, 0.716873169f, 0.060607910f },
-        { 0.013916016f, 0.097076416f, 0.714096069f },
-    }},
+        .trc = {
+            {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
+            {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
+            {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0 }}},
+        },
 
-    .has_poly_tf = { true, true, true },
-    .poly_tf = {
-       {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
-       {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
-       {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
-    },
-};
+        .toXYZD50 = {{
+            { 0.436065674f, 0.385147095f, 0.143066406f },
+            { 0.222488403f, 0.716873169f, 0.060607910f },
+            { 0.013916016f, 0.097076416f, 0.714096069f },
+        }},
 
-const skcms_ICCProfile skcms_XYZD50_profile = {
-    .buffer           = NULL,
-    .size             = 0,
-    .tag_count        = 0,
+        .has_poly_tf = { true, true, true },
+        .poly_tf = {
+        {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
+        {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
+        {0.293833881617f, 0.704207003117f, (float)(1/12.92), 0.04045f},
+        },
+    };
+    return &sRGB_profile;
+}
 
-    .data_color_space = make_signature('R', 'G', 'B', ' '),
-    .pcs              = make_signature('X', 'Y', 'Z', ' '),
-    .has_trc          = true,
-    .has_toXYZD50     = true,
-    .has_A2B          = false,
+const skcms_ICCProfile* skcms_XYZD50_profile() {
+    static const skcms_ICCProfile XYZD50_profile = {
+        .buffer           = NULL,
+        .size             = 0,
+        .tag_count        = 0,
 
-    .trc = {
-        {{0, {1,1,0,0,0,0,0}}},
-        {{0, {1,1,0,0,0,0,0}}},
-        {{0, {1,1,0,0,0,0,0}}},
-    },
+        .data_color_space = make_signature('R', 'G', 'B', ' '),
+        .pcs              = make_signature('X', 'Y', 'Z', ' '),
+        .has_trc          = true,
+        .has_toXYZD50     = true,
+        .has_A2B          = false,
 
-    .toXYZD50 = {{
-        {1,0,0},
-        {0,1,0},
-        {0,0,1},
-    }},
-};
+        .trc = {
+            {{0, {1,1,0,0,0,0,0}}},
+            {{0, {1,1,0,0,0,0,0}}},
+            {{0, {1,1,0,0,0,0,0}}},
+        },
+
+        .toXYZD50 = {{
+            {1,0,0},
+            {0,1,0},
+            {0,0,1},
+        }},
+    };
+
+    return &XYZD50_profile;
+}
 
 const uint8_t skcms_252_random_bytes[] = {
     8, 179, 128, 204, 253, 38, 134, 184, 68, 102, 32, 138, 99, 39, 169, 215,
@@ -885,13 +893,13 @@
             dstB[252];
     if (!skcms_Transform(
                 skcms_252_random_bytes,     fmt, skcms_AlphaFormat_Unpremul, A,
-                dstA, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+                dstA, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
                 npixels)) {
         return false;
     }
     if (!skcms_Transform(
                 skcms_252_random_bytes,     fmt, skcms_AlphaFormat_Unpremul, B,
-                dstB, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+                dstB, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
                 npixels)) {
         return false;
     }
diff --git a/test_only.c b/test_only.c
index 2acb466..7a37dd3 100644
--- a/test_only.c
+++ b/test_only.c
@@ -32,7 +32,7 @@
 
     if (!skcms_Transform(
                 skcms_252_random_bytes,    fmt, skcms_AlphaFormat_Unpremul, profile,
-                dst, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+                dst, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
                 npixels)) {
         fprintf(fp, "We can parse this profile, but not transform it XYZD50!\n");
         return;
@@ -61,7 +61,7 @@
     uint8_t opt[252];
     if (!skcms_Transform(
                 skcms_252_random_bytes,    fmt, skcms_AlphaFormat_Unpremul, optimized,
-                opt, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, &skcms_XYZD50_profile,
+                opt, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(),
                 npixels)) {
         fprintf(fp, "We cannot transform the optimized profile!  THIS IS REALLY BAD.\n");
         return;
@@ -184,7 +184,7 @@
     }
 
     skcms_ICCProfile best_single_curve = *profile;
-    skcms_EnsureUsableAsDestinationWithSingleCurve(&best_single_curve, &skcms_sRGB_profile);
+    skcms_EnsureUsableAsDestinationWithSingleCurve(&best_single_curve, skcms_sRGB_profile());
     dump_transfer_function(fp, "Best", &best_single_curve.trc[0].parametric, 0.0f);
 
     if (profile->has_toXYZD50) {
@@ -251,7 +251,7 @@
         }
     }
 
-    if (skcms_ApproximatelyEqualProfiles(profile, &skcms_sRGB_profile)) {
+    if (skcms_ApproximatelyEqualProfiles(profile, skcms_sRGB_profile())) {
         fprintf(fp, "This profile ≈ sRGB.\n");
     }
 }
diff --git a/tests.c b/tests.c
index 3f6f961..9d88f33 100644
--- a/tests.c
+++ b/tests.c
@@ -1006,16 +1006,16 @@
 
     // We can't transform to table-based profiles (yet?).
     expect(!skcms_Transform(
-                &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &skcms_sRGB_profile,
+                &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, skcms_sRGB_profile(),
                 &dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &profile,
                 1));
 
     // We take care to use a fallback profile that is not sRGB. :)
-    skcms_EnsureUsableAsDestination(&profile, &skcms_XYZD50_profile);
+    skcms_EnsureUsableAsDestination(&profile, skcms_XYZD50_profile());
 
     // Now the transform should work.
     expect(skcms_Transform(
-               &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &skcms_sRGB_profile,
+               &src, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, skcms_sRGB_profile(),
                &dst, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &profile,
                1));
 
@@ -1034,7 +1034,7 @@
     expect(skcms_Parse(ptr, len, &profile));
 
     skcms_ICCProfile usable_as_dst = profile;
-    skcms_EnsureUsableAsDestination(&usable_as_dst, &skcms_sRGB_profile);
+    skcms_EnsureUsableAsDestination(&usable_as_dst, skcms_sRGB_profile());
 
     // These profiles should behave nearly (or exactly) identical.
     // If we let any part of sRGB (eg PolyTF) leak into usable_as_dst, this will fail.
@@ -1042,7 +1042,7 @@
 
     // Same sequence as above, using the more aggressive SingleCurve version.
     skcms_ICCProfile single_curve = profile;
-    skcms_EnsureUsableAsDestinationWithSingleCurve(&single_curve, &skcms_sRGB_profile);
+    skcms_EnsureUsableAsDestinationWithSingleCurve(&single_curve, skcms_sRGB_profile());
     expect(skcms_ApproximatelyEqualProfiles(&profile, &single_curve));
 
     free(ptr);
@@ -1050,7 +1050,7 @@
 
 static void test_sRGB_profile_has_poly_tf() {
     // If we can find an skcms_PolyTF for anything, it'd better be sRGB.
-    skcms_ICCProfile srgb = skcms_sRGB_profile;
+    skcms_ICCProfile srgb = *skcms_sRGB_profile();
 
     // First, test skcms_OptimizeForSpeed() is a no-op if the has_poly_tf bits are already set.
     for (int i = 0; i < 3; i++) {
@@ -1080,7 +1080,7 @@
     }
 
     // Mostly a reminder to update skcms_sRGB_profile when skcms_OptimizeForSpeed() changes.
-    expect(0 == memcmp(&srgb, &skcms_sRGB_profile, sizeof(srgb)));
+    expect(0 == memcmp(&srgb, skcms_sRGB_profile(), sizeof(srgb)));
 }
 
 static void test_AlmostLinear2() {
@@ -1089,7 +1089,7 @@
     // This table will fit with a b+e offset that's non-zero, and cannot be fit with a PolyTF.
     uint8_t table_16[] = { 0x50, 0x50, 0x50, 0x63 };
 
-    skcms_ICCProfile p = skcms_sRGB_profile;
+    skcms_ICCProfile p = *skcms_sRGB_profile();
     p.trc[0].table_entries = 2;
     p.trc[0].table_8       = NULL;
     p.trc[0].table_16      = table_16;
@@ -1103,7 +1103,7 @@
 static void test_AlmostLinear3() {
     uint8_t table_8[] = { 0x00, 0x50, 0xff };
 
-    skcms_ICCProfile p = skcms_sRGB_profile;
+    skcms_ICCProfile p = *skcms_sRGB_profile();
     p.trc[0].table_entries = 3;
     p.trc[0].table_8       = table_8;
     p.trc[0].table_16      = NULL;