Repository: dankamongmen/notcurses (language: python)

Issue:
support blending with default colors
I don't think we currently support `NCALPHA_HIGHCONTRAST` when the background is the default color, but now that we ask the terminal for that value, we could. Do so. Probably need to update the documentation somewhere. See #2432.
support blending with default colors
I don't think we currently support `NCALPHA_HIGHCONTRAST` when the background is the default color, but now that we ask the terminal for that value, we could. Do so. Probably need to update the documentation somewhere. See #2432.
support blending with default colors
I don't think we currently support `NCALPHA_HIGHCONTRAST` when the background is the default color, but now that we ask the terminal for that value, we could. Do so. Probably need to update the documentation somewhere. See #2432.


Discussion / hints:
this already works, actually (just tested in `tfman`, see #2480). it's just blending that doesn't work with default backgrounds.

this is annoying to bring into `channels_blend()` because you need to use either the fg or the bg, but the two `inline` wrappers can solve that trivially enough...
this already works, actually (just tested in `tfman`, see #2480). it's just blending that doesn't work with default backgrounds.

this is annoying to bring into `channels_blend()` because you need to use either the fg or the bg, but the two `inline` wrappers can solve that trivially enough...
this already works, actually (just tested in `tfman`, see #2480). it's just blending that doesn't work with default backgrounds.

this is annoying to bring into `channels_blend()` because you need to use either the fg or the bg, but the two `inline` wrappers can solve that trivially enough...

Fix patch:
diff --git a/src/lib/internal.h b/src/lib/internal.h
index f6de1776cc..4a09252a55 100644
--- a/src/lib/internal.h
+++ b/src/lib/internal.h
@@ -1335,41 +1335,57 @@ cell_set_fchannel(nccell* cl, uint32_t channel){
 }
 
 // Returns the result of blending two channels. 'blends' indicates how heavily
-// 'c1' ought be weighed. If 'blends' is 0, 'c1' will be entirely replaced by
-// 'c2'. If 'c1' is otherwise the default color, 'c1' will not be touched,
-// since we can't blend default colors. Likewise, if 'c2' is a default color,
-// it will not be used (unless 'blends' is 0).
+// 'c1' ought be weighed. If 'blends' is 0 (indicating that 'c1' has not yet
+// been set), 'c1' will be entirely determined by 'c2'. Otherwise, the default
+// color is preserved if both are the default, palette color is preserved if
+// both are the same palette index, and the result is otherwise RGB.
 static inline unsigned
-channels_blend(notcurses* nc, unsigned c1, unsigned c2, unsigned* blends){
+channels_blend(notcurses* nc, unsigned c1, unsigned c2, unsigned* blends,
+               uint32_t defchan){
   if(ncchannel_alpha(c2) == NCALPHA_TRANSPARENT){
     return c1; // do *not* increment *blends
   }
-  bool c2default = ncchannel_default_p(c2);
-  bool c2palette = ncchannel_palindex_p(c2);
   if(*blends == 0){
     // don't just return c2, or you set wide status and all kinds of crap
-    if(c2default){
+    if(ncchannel_default_p(c2)){
       ncchannel_set_default(&c1);
-    }else if(c2palette){
+    }else if(ncchannel_palindex_p(c2)){
       ncchannel_set_palindex(&c1, ncchannel_palindex(c2));
     }else{
       ncchannel_set(&c1, ncchannel_rgb(c2));
     }
-    ncchannel_set_alpha(&c1, ncchannel_alpha(c2));
-  }else if(!c2default && !ncchannel_default_p(c1)){
-    unsigned rsum, gsum, bsum;
-    if(c2palette){
+  }else if(ncchannel_default_p(c1) && ncchannel_default_p(c2)){
+    // do nothing, leave as default
+  // intentional bitwise AND on the first condition, to eliminate the
+  // dependency due to C's short-circuit evaluation
+  }else if((ncchannel_palindex_p(c1) & ncchannel_palindex_p(c2)) &&
+           ncchannel_palindex(c1) == ncchannel_palindex(c2)){
+    // do nothing, leave as palette
+  }else{
+    unsigned r1, g1, b1;
+    unsigned r2, g2, b2;
+    if(ncchannel_default_p(c2)){
+      ncchannel_rgb8(defchan, &r2, &g2, &b2);
+    }else if(ncchannel_palindex_p(c2)){
       ncchannel_rgb8(nc->palette.chans[ncchannel_palindex(c2)],
-                     &rsum, &gsum, &bsum);
+                     &r2, &g2, &b2);
+    }else{
+      ncchannel_rgb8(c2, &r2, &g2, &b2);
+    }
+    if(ncchannel_default_p(c1)){
+      ncchannel_rgb8(defchan, &r1, &g1, &b1);
+    }else if(ncchannel_palindex_p(c1)){
+      ncchannel_rgb8(nc->palette.chans[ncchannel_palindex(c1)],
+                     &r1, &g1, &b1);
     }else{
-      ncchannel_rgb8(c2, &rsum, &gsum, &bsum);
+      ncchannel_rgb8(c1, &r1, &g1, &b1);
     }
-    rsum = (ncchannel_r(c1) * *blends + rsum) / (*blends + 1);
-    gsum = (ncchannel_g(c1) * *blends + gsum) / (*blends + 1);
-    bsum = (ncchannel_b(c1) * *blends + bsum) / (*blends + 1);
-    ncchannel_set_rgb8(&c1, rsum, gsum, bsum);
-    ncchannel_set_alpha(&c1, ncchannel_alpha(c2));
+    unsigned r = (r1 * *blends + r2) / (*blends + 1);
+    unsigned g = (g1 * *blends + g2) / (*blends + 1);
+    unsigned b = (b1 * *blends + b2) / (*blends + 1);
+    ncchannel_set_rgb8(&c1, r, g, b);
   }
+  ncchannel_set_alpha(&c1, ncchannel_alpha(c2));
   ++*blends;
   return c1;
 }
@@ -1377,12 +1393,14 @@ channels_blend(notcurses* nc, unsigned c1, unsigned c2, unsigned* blends){
 // do not pass palette-indexed channels!
 static inline uint64_t
 cell_blend_fchannel(notcurses* nc, nccell* cl, unsigned channel, unsigned* blends){
-  return cell_set_fchannel(cl, channels_blend(nc, cell_fchannel(cl), channel, blends));
+  return cell_set_fchannel(cl, channels_blend(nc, cell_fchannel(cl),
+                           channel, blends, nc->tcache.fg_default));
 }
 
 static inline uint64_t
 cell_blend_bchannel(notcurses* nc, nccell* cl, unsigned channel, unsigned* blends){
-  return cell_set_bchannel(cl, channels_blend(nc, cell_bchannel(cl), channel, blends));
+  return cell_set_bchannel(cl, channels_blend(nc, cell_bchannel(cl),
+                           channel, blends, nc->tcache.bg_collides_default));
 }
 
 // a sprixel occupies the entirety of its associated plane, usually an entirely
diff --git a/src/lib/render.c b/src/lib/render.c
index 094f78d563..d97fc8e2ff 100644
--- a/src/lib/render.c
+++ b/src/lib/render.c
@@ -428,10 +428,12 @@ lock_in_highcontrast(notcurses* nc, const tinfo* ti, nccell* targc, struct crend
       unsigned fgblends = 3;
       uint32_t fchan = cell_fchannel(targc);
       uint32_t bchan = cell_bchannel(targc);
-      uint32_t hchan = channels_blend(nc, highcontrast(ti, bchan), fchan, &fgblends);
+      uint32_t hchan = channels_blend(nc, highcontrast(ti, bchan), fchan,
+                                      &fgblends, nc->tcache.fg_default);
       cell_set_fchannel(targc, hchan);
       fgblends = crender->s.hcfgblends;
-      hchan = channels_blend(nc, hchan, crender->hcfg, &fgblends);
+      hchan = channels_blend(nc, hchan, crender->hcfg, &fgblends,
+                             nc->tcache.fg_default);
       cell_set_fchannel(targc, hchan);
     }else{
       nccell_set_fg_rgb(targc, highcontrast(ti, cell_bchannel(targc)));


Test patch:
diff --git a/src/tests/channel.cpp b/src/tests/channel.cpp
deleted file mode 100644
index 4852decde5..0000000000
--- a/src/tests/channel.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-#include "main.h"
-
-// These tests primarily check against expected constant values, which is
-// useful in terms of maintaining ABI, but annoying when they do change.
-
-TEST_CASE("ChannelGetRGB") {
-  const struct t {
-    uint32_t channel;
-    int r, g, b;
-  } test[] = {
-    { .channel = 0x000000, .r = 0x00, .g = 0x00, .b = 0x00, },
-    { .channel = 0x808080, .r = 0x80, .g = 0x80, .b = 0x80, },
-    { .channel = 0x080808, .r = 0x08, .g = 0x08, .b = 0x08, },
-    { .channel = 0xffffff, .r = 0xff, .g = 0xff, .b = 0xff, },
-  };
-  for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
-    unsigned r, g, b;
-    CHECK(test[i].channel == ncchannel_rgb8(test[i].channel, &r, &g, &b));
-    CHECK(test[i].r == r);
-    CHECK(test[i].g == g);
-    CHECK(test[i].b == b);
-  }
-}
-
-TEST_CASE("ChannelGetAlpha") {
-  const struct t {
-    uint32_t channel;
-    int a;
-  } test[] = {
-    { .channel = 0x00000000, .a = NCALPHA_OPAQUE, },
-    { .channel = 0x10808080, .a = NCALPHA_BLEND, },
-    { .channel = 0x20080808, .a = NCALPHA_TRANSPARENT, },
-    { .channel = 0xe0080808, .a = NCALPHA_TRANSPARENT, },
-    { .channel = 0x3fffffff, .a = NCALPHA_HIGHCONTRAST, },
-    { .channel = 0xffffffff, .a = NCALPHA_HIGHCONTRAST, },
-  };
-  for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
-    CHECK(test[i].a == ncchannel_alpha(test[i].channel));
-  }
-}
-
-TEST_CASE("ChannelGetDefault") {
-  const struct t {
-    uint32_t channel;
-    bool def;
-  } test[] = {
-    { .channel = 0x00000000, .def = true, },
-    { .channel = 0x0fffffff, .def = true, },
-    { .channel = 0xbfffffff, .def = true, },
-    { .channel = 0x40000000, .def = false, },
-    { .channel = 0x40080808, .def = false, },
-    { .channel = 0xffffffff, .def = false, },
-  };
-  for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
-    CHECK(test[i].def == ncchannel_default_p(test[i].channel));
-  }
-}
-
-TEST_CASE("ChannelSetDefault") {
-  const uint32_t channels[] = {
-    0x40000000, 0x4fffffff, 0xcfffffff,
-    0x40808080, 0x40080808, 0xffffffff,
-  };
-  for(auto i = 0u ; i < sizeof(channels) / sizeof(*channels) ; ++i){
-    uint32_t channel = channels[i];
-    CHECK(!ncchannel_default_p(channel));
-    ncchannel_set_default(&channel);
-    CHECK(ncchannel_default_p(channel));
-  }
-}
-
-// blend of 0 ought set c1 to c2
-TEST_CASE("ChannelBlend0") {
-  uint32_t c1 = 0;
-  uint32_t c2 = 0;
-  ncchannel_set_rgb8(&c1, 0x80, 0x40, 0x20);
-  ncchannel_set_rgb8(&c2, 0x88, 0x44, 0x22);
-  unsigned blends = 0;
-  uint32_t c = channels_blend(nullptr, c1, c2, &blends);
-  CHECK(!ncchannel_default_p(c));
-  unsigned r, g, b;
-  ncchannel_rgb8(c, &r, &g, &b);
-  CHECK(0x88 == r);
-  CHECK(0x44 == g);
-  CHECK(0x22 == b);
-  CHECK(1 == blends);
-}
-
-// blend of 1 ought perfectly average c1 and c2
-TEST_CASE("ChannelBlend1") {
-  uint32_t c1 = 0;
-  uint32_t c2 = 0;
-  ncchannel_set_rgb8(&c1, 0x80, 0x40, 0x20);
-  ncchannel_set_rgb8(&c2, 0x0, 0x0, 0x0);
-  unsigned blends = 1;
-  uint32_t c = channels_blend(nullptr, c1, c2, &blends);
-  CHECK(!ncchannel_default_p(c));
-  unsigned r, g, b;
-  ncchannel_rgb8(c, &r, &g, &b);
-  CHECK(0x40 == r);
-  CHECK(0x20 == g);
-  CHECK(0x10 == b);
-  CHECK(2 == blends);
-}
-
-// blend of 2 ought weigh c1 twice as much as c2
-TEST_CASE("ChannelBlend2") {
-  uint32_t c1 = 0;
-  uint32_t c2 = 0;
-  ncchannel_set_rgb8(&c1, 0x60, 0x30, 0x0f);
-  ncchannel_set_rgb8(&c2, 0x0, 0x0, 0x0);
-  unsigned blends = 2;
-  uint32_t c = channels_blend(nullptr, c1, c2, &blends);
-  CHECK(!ncchannel_default_p(c));
-  unsigned r, g, b;
-  ncchannel_rgb8(c, &r, &g, &b);
-  CHECK(0x40 == r);
-  CHECK(0x20 == g);
-  CHECK(0x0a == b);
-  CHECK(3 == blends);
-}
-
-// you can't blend into a default color at any positive number of blends
-TEST_CASE("ChannelBlendDefaultLeft") {
-  uint32_t c1 = 0;
-  uint32_t c2 = 0;
-  ncchannel_set_rgb8(&c2, 0x80, 0x40, 0x20);
-  unsigned blends = 0;
-  uint32_t c = channels_blend(nullptr, c1, c2, &blends); // will replace
-  CHECK(!ncchannel_default_p(c));
-  unsigned r, g, b;
-  ncchannel_rgb8(c, &r, &g, &b);
-  CHECK(0x80 == r);
-  CHECK(0x40 == g);
-  CHECK(0x20 == b);
-  CHECK(1 == blends);
-  c = channels_blend(nullptr, c1, c2, &blends); // will not replace
-  CHECK(ncchannel_default_p(c));
-  ncchannel_rgb8(c, &r, &g, &b);
-  CHECK(0 == r);
-  CHECK(0 == g);
-  CHECK(0 == b);
-  CHECK(2 == blends);
-  c = channels_blend(nullptr, c1, c2, &blends); // will not replace
-  CHECK(ncchannel_default_p(c));
-  ncchannel_rgb8(c, &r, &g, &b);
-  CHECK(0 == r);
-  CHECK(0 == g);
-  CHECK(0 == b);
-  CHECK(3 == blends);
-}
-
-// you can't blend from a default color, but blend 0 sets it
-TEST_CASE("ChannelBlendDefaultRight") {
-  uint32_t c1 = 0;
-  uint32_t c2 = 0;
-  ncchannel_set_rgb8(&c1, 0x80, 0x40, 0x20);
-  CHECK(!ncchannel_default_p(c1));
-  CHECK(ncchannel_default_p(c2));
-  unsigned blends = 0;
-  uint32_t c = channels_blend(nullptr, c1, c2, &blends);
-  CHECK(ncchannel_default_p(c));
-  CHECK(1 == blends);
-  c = channels_blend(nullptr, c1, c2, &blends);
-  CHECK(!ncchannel_default_p(c));
-  unsigned r, g, b;
-  ncchannel_rgb8(c, &r, &g, &b);
-  CHECK(0x80 == r);
-  CHECK(0x40 == g);
-  CHECK(0x20 == b);
-  CHECK(2 == blends);
-}
-
-// test that colors are inverted, but nothing else
-TEST_CASE("ChannelsReverse") {
-  uint64_t channels = 0;
-  uint64_t rev = ncchannels_reverse(channels);
-  CHECK(0 == rev);
-  ncchannels_set_fg_palindex(&channels, 8);
-  rev = ncchannels_reverse(channels);
-  CHECK(8 == ncchannels_bg_palindex(rev));
-  CHECK(0 == ncchannels_fg_palindex(rev));
-  ncchannels_set_fg_palindex(&rev, 63);
-  rev = ncchannels_reverse(rev);
-  CHECK(8 == ncchannels_fg_palindex(rev));
-  CHECK(63 == ncchannels_bg_palindex(rev));
-  ncchannels_set_fg_default(&rev);
-  ncchannels_set_bg_alpha(&rev, NCALPHA_TRANSPARENT);
-  rev = ncchannels_reverse(rev);
-  CHECK(63 == ncchannels_fg_palindex(rev));
-  CHECK(ncchannels_bg_default_p(rev));
-  CHECK(NCALPHA_OPAQUE == ncchannels_bg_alpha(rev));
-  ncchannels_set_fg_rgb(&rev, 0x2288cc);
-  rev = ncchannels_reverse(rev);
-  CHECK(0x2288cc == ncchannels_bg_rgb(rev));
-  CHECK(ncchannels_fg_default_p(rev));
-}
diff --git a/src/tests/channels.cpp b/src/tests/channels.cpp
new file mode 100644
index 0000000000..923801ac7e
--- /dev/null
+++ b/src/tests/channels.cpp
@@ -0,0 +1,177 @@
+#include "main.h"
+
+// These tests primarily check against expected constant values, which is
+// useful in terms of maintaining ABI, but annoying when they do change.
+TEST_CASE("Channels") {
+
+  SUBCASE("ChannelGetRGB") {
+    const struct t {
+      uint32_t channel;
+      int r, g, b;
+    } test[] = {
+      { .channel = 0x000000, .r = 0x00, .g = 0x00, .b = 0x00, },
+      { .channel = 0x808080, .r = 0x80, .g = 0x80, .b = 0x80, },
+      { .channel = 0x080808, .r = 0x08, .g = 0x08, .b = 0x08, },
+      { .channel = 0xffffff, .r = 0xff, .g = 0xff, .b = 0xff, },
+    };
+    for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
+      unsigned r, g, b;
+      CHECK(test[i].channel == ncchannel_rgb8(test[i].channel, &r, &g, &b));
+      CHECK(test[i].r == r);
+      CHECK(test[i].g == g);
+      CHECK(test[i].b == b);
+    }
+  }
+
+  SUBCASE("ChannelGetAlpha") {
+    const struct t {
+      uint32_t channel;
+      int a;
+    } test[] = {
+      { .channel = 0x00000000, .a = NCALPHA_OPAQUE, },
+      { .channel = 0x10808080, .a = NCALPHA_BLEND, },
+      { .channel = 0x20080808, .a = NCALPHA_TRANSPARENT, },
+      { .channel = 0xe0080808, .a = NCALPHA_TRANSPARENT, },
+      { .channel = 0x3fffffff, .a = NCALPHA_HIGHCONTRAST, },
+      { .channel = 0xffffffff, .a = NCALPHA_HIGHCONTRAST, },
+    };
+    for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
+      CHECK(test[i].a == ncchannel_alpha(test[i].channel));
+    }
+  }
+
+  SUBCASE("ChannelGetDefault") {
+    const struct t {
+      uint32_t channel;
+      bool def;
+    } test[] = {
+      { .channel = 0x00000000, .def = true, },
+      { .channel = 0x0fffffff, .def = true, },
+      { .channel = 0xbfffffff, .def = true, },
+      { .channel = 0x40000000, .def = false, },
+      { .channel = 0x40080808, .def = false, },
+      { .channel = 0xffffffff, .def = false, },
+    };
+    for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
+      CHECK(test[i].def == ncchannel_default_p(test[i].channel));
+    }
+  }
+
+  SUBCASE("ChannelSetDefault") {
+    const uint32_t channels[] = {
+      0x40000000, 0x4fffffff, 0xcfffffff,
+      0x40808080, 0x40080808, 0xffffffff,
+    };
+    for(auto i = 0u ; i < sizeof(channels) / sizeof(*channels) ; ++i){
+      uint32_t channel = channels[i];
+      CHECK(!ncchannel_default_p(channel));
+      ncchannel_set_default(&channel);
+      CHECK(ncchannel_default_p(channel));
+    }
+  }
+
+  // blend of 0 ought set c1 to c2
+  SUBCASE("ChannelBlend0") {
+    uint32_t c1 = 0;
+    uint32_t c2 = 0;
+    ncchannel_set_rgb8(&c1, 0x80, 0x40, 0x20);
+    ncchannel_set_rgb8(&c2, 0x88, 0x44, 0x22);
+    unsigned blends = 0;
+    uint32_t c = channels_blend(nullptr, c1, c2, &blends, 0);
+    CHECK(!ncchannel_default_p(c));
+    unsigned r, g, b;
+    ncchannel_rgb8(c, &r, &g, &b);
+    CHECK(0x88 == r);
+    CHECK(0x44 == g);
+    CHECK(0x22 == b);
+    CHECK(1 == blends);
+  }
+
+  // blend of 1 ought perfectly average c1 and c2
+  SUBCASE("ChannelBlend1") {
+    uint32_t c1 = 0;
+    uint32_t c2 = 0;
+    ncchannel_set_rgb8(&c1, 0x80, 0x40, 0x20);
+    ncchannel_set_rgb8(&c2, 0x0, 0x0, 0x0);
+    unsigned blends = 1;
+    uint32_t c = channels_blend(nullptr, c1, c2, &blends, 0);
+    CHECK(!ncchannel_default_p(c));
+    unsigned r, g, b;
+    ncchannel_rgb8(c, &r, &g, &b);
+    CHECK(0x40 == r);
+    CHECK(0x20 == g);
+    CHECK(0x10 == b);
+    CHECK(2 == blends);
+  }
+
+  // blend of 2 ought weigh c1 twice as much as c2
+  SUBCASE("ChannelBlend2") {
+    uint32_t c1 = 0;
+    uint32_t c2 = 0;
+    ncchannel_set_rgb8(&c1, 0x60, 0x30, 0x0f);
+    ncchannel_set_rgb8(&c2, 0x0, 0x0, 0x0);
+    unsigned blends = 2;
+    uint32_t c = channels_blend(nullptr, c1, c2, &blends, 0);
+    CHECK(!ncchannel_default_p(c));
+    unsigned r, g, b;
+    ncchannel_rgb8(c, &r, &g, &b);
+    CHECK(0x40 == r);
+    CHECK(0x20 == g);
+    CHECK(0x0a == b);
+    CHECK(3 == blends);
+  }
+
+  // blending the default color in ought use the provided default
+  SUBCASE("ChannelBlendDefaultLeft") {
+    uint32_t c1 = 0;
+    uint32_t c2 = 0;
+    ncchannel_set_rgb8(&c2, 0x80, 0x40, 0x20);
+    unsigned blends = 0;
+    uint32_t c = channels_blend(nullptr, c1, c2, &blends, 0); // will replace
+    CHECK(!ncchannel_default_p(c));
+    unsigned r, g, b;
+    ncchannel_rgb8(c, &r, &g, &b);
+    CHECK(0x80 == r);
+    CHECK(0x40 == g);
+    CHECK(0x20 == b);
+    CHECK(1 == blends);
+    c = channels_blend(nullptr, c, c1, &blends, 0x666666); // blends 0x666666 into 0x804020
+    ncchannel_rgb8(c, &r, &g, &b);
+    CHECK(0x73 == r);
+    CHECK(0x53 == g);
+    CHECK(0x43 == b);
+    CHECK(2 == blends);
+    c = channels_blend(nullptr, c1, c2, &blends, 0x666666); // blends 0x804020 into 0x666666x2
+    ncchannel_rgb8(c, &r, &g, &b);
+    CHECK(0x6e == r);
+    CHECK(0x59 == g);
+    CHECK(0x4e == b);
+    CHECK(3 == blends);
+  }
+
+  // test that colors are inverted, but nothing else
+  SUBCASE("ChannelsReverse") {
+    uint64_t channels = 0;
+    uint64_t rev = ncchannels_reverse(channels);
+    CHECK(0 == rev);
+    ncchannels_set_fg_palindex(&channels, 8);
+    rev = ncchannels_reverse(channels);
+    CHECK(8 == ncchannels_bg_palindex(rev));
+    CHECK(0 == ncchannels_fg_palindex(rev));
+    ncchannels_set_fg_palindex(&rev, 63);
+    rev = ncchannels_reverse(rev);
+    CHECK(8 == ncchannels_fg_palindex(rev));
+    CHECK(63 == ncchannels_bg_palindex(rev));
+    ncchannels_set_fg_default(&rev);
+    ncchannels_set_bg_alpha(&rev, NCALPHA_TRANSPARENT);
+    rev = ncchannels_reverse(rev);
+    CHECK(63 == ncchannels_fg_palindex(rev));
+    CHECK(ncchannels_bg_default_p(rev));
+    CHECK(NCALPHA_OPAQUE == ncchannels_bg_alpha(rev));
+    ncchannels_set_fg_rgb(&rev, 0x2288cc);
+    rev = ncchannels_reverse(rev);
+    CHECK(0x2288cc == ncchannels_bg_rgb(rev));
+    CHECK(ncchannels_fg_default_p(rev));
+  }
+
+}