Add limited/full testing and full CICP specifying to avifyuv's drift mode (#473)

Add another loop to test both LIMITED and FULL range. (Fix #471.)
Tighten MAX_DRIFT limit to 5.
Replace matrixCoeffsList with cicpList.  Some MCs need to incorporate with CP and  TC to perform RGB<->YUV conversion:

- `*_CHROMA_DERIVED_*`: need CP
- `*_CL`, `AVIF_MATRIX_COEFFICIENTS_ICTCP`: need TC

Set up test logic first.
diff --git a/tests/avifyuv.c b/tests/avifyuv.c
index 34b26cb..6883704 100644
--- a/tests/avifyuv.c
+++ b/tests/avifyuv.c
@@ -9,7 +9,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define MAX_DRIFT 10
+#define MAX_DRIFT 5
 
 #define NEXTARG()                                                     \
     if (((argIndex + 1) == argc) || (argv[argIndex + 1][0] == '-')) { \
@@ -43,6 +43,13 @@
     return "Unknown";
 }
 
+typedef struct avifCICP
+{
+    avifColorPrimaries cp;
+    avifTransferCharacteristics tc;
+    avifMatrixCoefficients mc;
+} avifCICP;
+
 int main(int argc, char * argv[])
 {
     (void)argc;
@@ -81,6 +88,7 @@
     const int yuvDepthsCount = (int)(sizeof(yuvDepths) / sizeof(yuvDepths[0]));
     const uint32_t rgbDepths[] = { 8, 10, 12 };
     const int rgbDepthsCount = (int)(sizeof(rgbDepths) / sizeof(rgbDepths[0]));
+    const avifRange ranges[2] = { AVIF_RANGE_FULL, AVIF_RANGE_LIMITED };
 
     if (mode == 0) {
         // Limited to full conversion roundtripping test
@@ -97,7 +105,16 @@
             printf("%s %d -> %d -> %d\n", prefix, i, li, fi);
         }
     } else if (mode == 1) {
-        // Calculate maximum codepoint drift on different combinations of depth and matrixCoefficients
+        // Calculate maximum codepoint drift on different combinations of depth and CICPs
+        const avifCICP cicpList[] = {
+            { AVIF_COLOR_PRIMARIES_BT709, AVIF_TRANSFER_CHARACTERISTICS_SRGB, AVIF_MATRIX_COEFFICIENTS_BT709 },
+            { AVIF_COLOR_PRIMARIES_BT709, AVIF_TRANSFER_CHARACTERISTICS_SRGB, AVIF_MATRIX_COEFFICIENTS_BT601 },
+            { AVIF_COLOR_PRIMARIES_BT709, AVIF_TRANSFER_CHARACTERISTICS_SRGB, AVIF_MATRIX_COEFFICIENTS_BT2020_NCL },
+            { AVIF_COLOR_PRIMARIES_BT709, AVIF_TRANSFER_CHARACTERISTICS_SRGB, AVIF_MATRIX_COEFFICIENTS_IDENTITY },
+            { AVIF_COLOR_PRIMARIES_BT709, AVIF_TRANSFER_CHARACTERISTICS_SRGB, AVIF_MATRIX_COEFFICIENTS_YCGCO },
+            { AVIF_COLOR_PRIMARIES_SMPTE432, AVIF_TRANSFER_CHARACTERISTICS_SRGB, AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL },
+        };
+        const int cicpCount = (int)(sizeof(cicpList) / sizeof(cicpList[0]));
 
         for (int rgbDepthIndex = 0; rgbDepthIndex < rgbDepthsCount; ++rgbDepthIndex) {
             uint32_t rgbDepth = rgbDepths[rgbDepthIndex];
@@ -108,140 +125,163 @@
                     continue;
                 }
 
-                const avifMatrixCoefficients matrixCoeffsList[] = { AVIF_MATRIX_COEFFICIENTS_BT709,
-                                                                    AVIF_MATRIX_COEFFICIENTS_BT601,
-                                                                    AVIF_MATRIX_COEFFICIENTS_BT2020_NCL,
-                                                                    AVIF_MATRIX_COEFFICIENTS_IDENTITY,
-                                                                    AVIF_MATRIX_COEFFICIENTS_YCGCO };
-                const int matrixCoeffsCount = (int)(sizeof(matrixCoeffsList) / sizeof(matrixCoeffsList[0]));
+                for (int cicpIndex = 0; cicpIndex < cicpCount; ++cicpIndex) {
+                    const avifCICP * cicp = &cicpList[cicpIndex];
+                    for (int rangeIndex = 0; rangeIndex < 2; ++rangeIndex) {
+                        avifRange range = ranges[rangeIndex];
 
-                for (int matrixCoeffsIndex = 0; matrixCoeffsIndex < matrixCoeffsCount; ++matrixCoeffsIndex) {
-                    avifMatrixCoefficients matrixCoeffs = matrixCoeffsList[matrixCoeffsIndex];
+                        // YCgCo with limited range is not implemented now
+                        if (range == AVIF_RANGE_LIMITED && cicp->mc == AVIF_MATRIX_COEFFICIENTS_YCGCO) {
+                            printf(" * RGB depth: %d, YUV depth: %d, colorPrimaries: %d, transferCharas: %d, matrixCoeffs: %d, range: Limited\n"
+                                   "   * Skipped: currently not supported.\n",
+                                   rgbDepth,
+                                   yuvDepth,
+                                   cicp->cp,
+                                   cicp->tc,
+                                   cicp->mc);
+                            continue;
+                        }
 
-                    int dim = 1 << rgbDepth;
-                    int maxDrift = 0;
+                        int dim = 1 << rgbDepth;
+                        int maxDrift = 0;
 
-                    avifImage * image = avifImageCreate(dim, dim, yuvDepth, AVIF_PIXEL_FORMAT_YUV444);
-                    image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
-                    image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
-                    image->matrixCoefficients = matrixCoeffs;
-                    image->yuvRange = AVIF_RANGE_FULL;
-                    avifImageAllocatePlanes(image, AVIF_PLANES_YUV);
+                        avifImage * image = avifImageCreate(dim, dim, yuvDepth, AVIF_PIXEL_FORMAT_YUV444);
+                        image->colorPrimaries = cicp->cp;
+                        image->transferCharacteristics = cicp->tc;
+                        image->matrixCoefficients = cicp->mc;
+                        image->yuvRange = range;
+                        avifImageAllocatePlanes(image, AVIF_PLANES_YUV);
 
-                    avifRGBImage srcRGB;
-                    avifRGBImageSetDefaults(&srcRGB, image);
-                    srcRGB.format = AVIF_RGB_FORMAT_RGB;
-                    srcRGB.depth = rgbDepth;
-                    avifRGBImageAllocatePixels(&srcRGB);
+                        avifRGBImage srcRGB;
+                        avifRGBImageSetDefaults(&srcRGB, image);
+                        srcRGB.format = AVIF_RGB_FORMAT_RGB;
+                        srcRGB.depth = rgbDepth;
+                        avifRGBImageAllocatePixels(&srcRGB);
 
-                    avifRGBImage dstRGB;
-                    avifRGBImageSetDefaults(&dstRGB, image);
-                    dstRGB.format = AVIF_RGB_FORMAT_RGB;
-                    dstRGB.depth = rgbDepth;
-                    avifRGBImageAllocatePixels(&dstRGB);
+                        avifRGBImage dstRGB;
+                        avifRGBImageSetDefaults(&dstRGB, image);
+                        dstRGB.format = AVIF_RGB_FORMAT_RGB;
+                        dstRGB.depth = rgbDepth;
+                        avifRGBImageAllocatePixels(&dstRGB);
 
-                    uint64_t driftPixelCounts[MAX_DRIFT];
-                    for (int i = 0; i < MAX_DRIFT; ++i) {
-                        driftPixelCounts[i] = 0;
-                    }
+                        uint64_t driftPixelCounts[MAX_DRIFT];
+                        for (int i = 0; i < MAX_DRIFT; ++i) {
+                            driftPixelCounts[i] = 0;
+                        }
 
-                    for (int r = 0; r < dim; ++r) {
+                        for (int r = 0; r < dim; ++r) {
+                            if (verbose) {
+                                printf("[%4d/%4d] RGB depth: %d, YUV depth: %d, colorPrimaries: %d, transferCharas: %d, matrixCoeffs: %d, range: %s\r",
+                                       r + 1,
+                                       dim,
+                                       rgbDepth,
+                                       yuvDepth,
+                                       cicp->cp,
+                                       cicp->tc,
+                                       cicp->mc,
+                                       range == AVIF_RANGE_FULL ? "Full" : "Limited");
+                            }
+
+                            for (int g = 0; g < dim; ++g) {
+                                uint8_t * row = &srcRGB.pixels[g * srcRGB.rowBytes];
+                                for (int b = 0; b < dim; ++b) {
+                                    if (rgbDepth == 8) {
+                                        uint8_t * pixel = &row[b * sizeof(uint8_t) * 3];
+                                        pixel[0] = (uint8_t)r;
+                                        pixel[1] = (uint8_t)g;
+                                        pixel[2] = (uint8_t)b;
+                                    } else {
+                                        uint16_t * pixel = (uint16_t *)&row[b * sizeof(uint16_t) * 3];
+                                        pixel[0] = (uint16_t)r;
+                                        pixel[1] = (uint16_t)g;
+                                        pixel[2] = (uint16_t)b;
+                                    }
+                                }
+                            }
+
+                            avifImageRGBToYUV(image, &srcRGB);
+                            avifImageYUVToRGB(image, &dstRGB);
+
+                            for (int y = 0; y < dim; ++y) {
+                                const uint8_t * srcRow = &srcRGB.pixels[y * srcRGB.rowBytes];
+                                const uint8_t * dstRow = &dstRGB.pixels[y * dstRGB.rowBytes];
+                                for (int x = 0; x < dim; ++x) {
+                                    int drift = 0;
+                                    if (rgbDepth == 8) {
+                                        const uint8_t * srcPixel = &srcRow[x * sizeof(uint8_t) * 3];
+                                        const uint8_t * dstPixel = &dstRow[x * sizeof(uint8_t) * 3];
+
+                                        const int driftR = abs((int)srcPixel[0] - (int)dstPixel[0]);
+                                        if (drift < driftR) {
+                                            drift = driftR;
+                                        }
+                                        const int driftG = abs((int)srcPixel[1] - (int)dstPixel[1]);
+                                        if (drift < driftG) {
+                                            drift = driftG;
+                                        }
+                                        const int driftB = abs((int)srcPixel[2] - (int)dstPixel[2]);
+                                        if (drift < driftB) {
+                                            drift = driftB;
+                                        }
+                                    } else {
+                                        const uint16_t * srcPixel = (const uint16_t *)&srcRow[x * sizeof(uint16_t) * 3];
+                                        const uint16_t * dstPixel = (const uint16_t *)&dstRow[x * sizeof(uint16_t) * 3];
+
+                                        const int driftR = abs((int)srcPixel[0] - (int)dstPixel[0]);
+                                        if (drift < driftR) {
+                                            drift = driftR;
+                                        }
+                                        const int driftG = abs((int)srcPixel[1] - (int)dstPixel[1]);
+                                        if (drift < driftG) {
+                                            drift = driftG;
+                                        }
+                                        const int driftB = abs((int)srcPixel[2] - (int)dstPixel[2]);
+                                        if (drift < driftB) {
+                                            drift = driftB;
+                                        }
+                                    }
+
+                                    if (drift < MAX_DRIFT) {
+                                        ++driftPixelCounts[drift];
+                                        if (maxDrift < drift) {
+                                            maxDrift = drift;
+                                        }
+                                    } else {
+                                        printf("ERROR: Encountered a drift greater than MAX_DRIFT(%d): %d\n", MAX_DRIFT, drift);
+                                        return 1;
+                                    }
+                                }
+                            }
+                        }
+
                         if (verbose) {
-                            printf("[%4d/%4d] RGB depth: %d, YUV depth: %d, matrixCoeffs: %d\r", r + 1, dim, rgbDepth, yuvDepth, matrixCoeffs);
+                            printf("\n");
                         }
 
-                        for (int g = 0; g < dim; ++g) {
-                            uint8_t * row = &srcRGB.pixels[g * srcRGB.rowBytes];
-                            for (int b = 0; b < dim; ++b) {
-                                if (rgbDepth == 8) {
-                                    uint8_t * pixel = &row[b * sizeof(uint8_t) * 3];
-                                    pixel[0] = (uint8_t)r;
-                                    pixel[1] = (uint8_t)g;
-                                    pixel[2] = (uint8_t)b;
-                                } else {
-                                    uint16_t * pixel = (uint16_t *)&row[b * sizeof(uint16_t) * 3];
-                                    pixel[0] = (uint16_t)r;
-                                    pixel[1] = (uint16_t)g;
-                                    pixel[2] = (uint16_t)b;
-                                }
+                        printf(" * RGB depth: %d, YUV depth: %d, colorPrimaries: %d, transferCharas: %d, matrixCoeffs: %d, range: %s, maxDrift: %2d\n",
+                               rgbDepth,
+                               yuvDepth,
+                               cicp->cp,
+                               cicp->tc,
+                               cicp->mc,
+                               range == AVIF_RANGE_FULL ? "Full" : "Limited",
+                               maxDrift);
+
+                        const uint64_t totalPixelCount = (uint64_t)dim * dim * dim;
+                        for (int i = 0; i < MAX_DRIFT; ++i) {
+                            if (verbose && (driftPixelCounts[i] > 0)) {
+                                printf("   * drift: %2d -> %12" PRIu64 " / %12" PRIu64 " pixels (%.2f %%)\n",
+                                       i,
+                                       driftPixelCounts[i],
+                                       totalPixelCount,
+                                       (double)driftPixelCounts[i] * 100.0 / (double)totalPixelCount);
                             }
                         }
 
-                        avifImageRGBToYUV(image, &srcRGB);
-                        avifImageYUVToRGB(image, &dstRGB);
-
-                        for (int y = 0; y < dim; ++y) {
-                            const uint8_t * srcRow = &srcRGB.pixels[y * srcRGB.rowBytes];
-                            const uint8_t * dstRow = &dstRGB.pixels[y * dstRGB.rowBytes];
-                            for (int x = 0; x < dim; ++x) {
-                                int drift = 0;
-                                if (rgbDepth == 8) {
-                                    const uint8_t * srcPixel = &srcRow[x * sizeof(uint8_t) * 3];
-                                    const uint8_t * dstPixel = &dstRow[x * sizeof(uint8_t) * 3];
-
-                                    const int driftR = abs((int)srcPixel[0] - (int)dstPixel[0]);
-                                    if (drift < driftR) {
-                                        drift = driftR;
-                                    }
-                                    const int driftG = abs((int)srcPixel[1] - (int)dstPixel[1]);
-                                    if (drift < driftG) {
-                                        drift = driftG;
-                                    }
-                                    const int driftB = abs((int)srcPixel[2] - (int)dstPixel[2]);
-                                    if (drift < driftB) {
-                                        drift = driftB;
-                                    }
-                                } else {
-                                    const uint16_t * srcPixel = (const uint16_t *)&srcRow[x * sizeof(uint16_t) * 3];
-                                    const uint16_t * dstPixel = (const uint16_t *)&dstRow[x * sizeof(uint16_t) * 3];
-
-                                    const int driftR = abs((int)srcPixel[0] - (int)dstPixel[0]);
-                                    if (drift < driftR) {
-                                        drift = driftR;
-                                    }
-                                    const int driftG = abs((int)srcPixel[1] - (int)dstPixel[1]);
-                                    if (drift < driftG) {
-                                        drift = driftG;
-                                    }
-                                    const int driftB = abs((int)srcPixel[2] - (int)dstPixel[2]);
-                                    if (drift < driftB) {
-                                        drift = driftB;
-                                    }
-                                }
-
-                                if (drift < MAX_DRIFT) {
-                                    ++driftPixelCounts[drift];
-                                    if (maxDrift < drift) {
-                                        maxDrift = drift;
-                                    }
-                                } else {
-                                    printf("ERROR: Encountered a drift greater than MAX_DRIFT(%d): %d\n", MAX_DRIFT, drift);
-                                    return 1;
-                                }
-                            }
-                        }
+                        avifRGBImageFreePixels(&srcRGB);
+                        avifRGBImageFreePixels(&dstRGB);
+                        avifImageDestroy(image);
                     }
-
-                    if (verbose) {
-                        printf("\n");
-                    }
-
-                    printf(" * RGB depth: %d, YUV depth: %d, matrixCoeffs: %d, maxDrift: %2d\n", rgbDepth, yuvDepth, matrixCoeffs, maxDrift);
-
-                    const uint64_t totalPixelCount = (uint64_t)dim * dim * dim;
-                    for (int i = 0; i < MAX_DRIFT; ++i) {
-                        if (verbose && (driftPixelCounts[i] > 0)) {
-                            printf("   * drift: %2d -> %12" PRIu64 " / %12" PRIu64 " pixels (%.2f %%)\n",
-                                   i,
-                                   driftPixelCounts[i],
-                                   totalPixelCount,
-                                   (double)driftPixelCounts[i] * 100.0 / (double)totalPixelCount);
-                        }
-                    }
-
-                    avifRGBImageFreePixels(&srcRGB);
-                    avifRGBImageFreePixels(&dstRGB);
-                    avifImageDestroy(image);
                 }
             }
         }
@@ -285,16 +325,13 @@
                 }
             }
 
-            uint32_t depths[4] = { 8, 10, 12, 16 };
+            const uint32_t depths[4] = { 8, 10, 12, 16 };
             for (int depthIndex = 0; depthIndex < 4; ++depthIndex) {
                 uint32_t rgbDepth = depths[depthIndex];
-
-                avifRange ranges[2] = { AVIF_RANGE_FULL, AVIF_RANGE_LIMITED };
                 for (int rangeIndex = 0; rangeIndex < 2; ++rangeIndex) {
                     avifRange yuvRange = ranges[rangeIndex];
-
-                    avifRGBFormat rgbFormats[6] = { AVIF_RGB_FORMAT_RGB, AVIF_RGB_FORMAT_RGBA, AVIF_RGB_FORMAT_ARGB,
-                                                    AVIF_RGB_FORMAT_BGR, AVIF_RGB_FORMAT_BGRA, AVIF_RGB_FORMAT_ABGR };
+                    const avifRGBFormat rgbFormats[6] = { AVIF_RGB_FORMAT_RGB, AVIF_RGB_FORMAT_RGBA, AVIF_RGB_FORMAT_ARGB,
+                                                          AVIF_RGB_FORMAT_BGR, AVIF_RGB_FORMAT_BGRA, AVIF_RGB_FORMAT_ABGR };
                     for (int rgbFormatIndex = 0; rgbFormatIndex < 6; ++rgbFormatIndex) {
                         avifRGBFormat rgbFormat = rgbFormats[rgbFormatIndex];
 
@@ -392,7 +429,7 @@
         avifImageDestroy(image);
     } else if (mode == 3) {
         // alpha premultiply roundtrip test
-        uint32_t depths[4] = { 8, 10, 12, 16 };
+        const uint32_t depths[4] = { 8, 10, 12, 16 };
         uint64_t driftPixelCounts[MAX_DRIFT];
         int maxDrift;
         for (int depthIndex = 0; depthIndex < 4; ++depthIndex) {