color blindness enhancement

This is an attempt at improving the experience of
users with color vision impairement.

At this time this feature can only be enabled for
debugging:

  adb shell service call SurfaceFlinger 1014 i32 PARAM

  with PARAM:
   0 : disabled
   1 : protanomaly/protanopia simulation
   2 : deuteranomaly/deuteranopia simulation
   3 : tritanopia/tritanomaly simulation
  11, 12, 13: same as above w/ attempted correction/enhancement

The enhancement algorithm tries to spread the "error"
such that tones that would otherwise appear similar can be
distinguished.

Bug: 9465644

Change-Id: I860f7eed0cb81f54ef9cf24ad78155b6395ade48
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0323cb7..fa1ea09 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -68,7 +68,10 @@
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/VirtualDisplaySurface.h"
 
+#include "Effects/Daltonizer.h"
+
 #include "RenderEngine/RenderEngine.h"
+#include <cutils/compiler.h>
 
 #define DISPLAY_COUNT       1
 
@@ -110,7 +113,8 @@
         mLastSwapBufferTime(0),
         mDebugInTransaction(0),
         mLastTransactionTime(0),
-        mBootFinished(false)
+        mBootFinished(false),
+        mDaltonize(false)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -865,7 +869,7 @@
                         for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
                             const sp<Layer>& layer(currentLayers[i]);
                             layer->setGeometry(hw, *cur);
-                            if (mDebugDisableHWC || mDebugRegion) {
+                            if (mDebugDisableHWC || mDebugRegion || mDaltonize) {
                                 cur->setSkip(true);
                             }
                         }
@@ -1479,7 +1483,14 @@
         }
     }
 
-    doComposeSurfaces(hw, dirtyRegion);
+    if (CC_LIKELY(!mDaltonize)) {
+        doComposeSurfaces(hw, dirtyRegion);
+    } else {
+        RenderEngine& engine(getRenderEngine());
+        engine.beginGroup(mDaltonizer());
+        doComposeSurfaces(hw, dirtyRegion);
+        engine.endGroup();
+    }
 
     // update the swap region and clear the dirty region
     hw->swapRegion.orSelf(dirtyRegion);
@@ -2360,7 +2371,7 @@
     colorizer.reset(result);
     result.appendFormat("  h/w composer %s and %s\n",
             hwc.initCheck()==NO_ERROR ? "present" : "not present",
-                    (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
+                    (mDebugDisableHWC || mDebugRegion || mDaltonize) ? "disabled" : "enabled");
     hwc.dump(result);
 
     /*
@@ -2505,6 +2516,24 @@
                 Mutex::Autolock _l(mStateLock);
                 sp<const DisplayDevice> hw(getDefaultDisplayDevice());
                 reply->writeInt32(hw->getPageFlipCount());
+                return NO_ERROR;
+            }
+            case 1014: {
+                // daltonize
+                n = data.readInt32();
+                switch (n % 10) {
+                    case 1: mDaltonizer.setType(Daltonizer::protanomaly);   break;
+                    case 2: mDaltonizer.setType(Daltonizer::deuteranomaly); break;
+                    case 3: mDaltonizer.setType(Daltonizer::tritanomaly);   break;
+                }
+                if (n >= 10) {
+                    mDaltonizer.setMode(Daltonizer::correction);
+                } else {
+                    mDaltonizer.setMode(Daltonizer::simulation);
+                }
+                mDaltonize = n > 0;
+                invalidateHwcGeometry();
+                repaintEverything();
             }
             return NO_ERROR;
         }