text: /**************************************************************************\
  * 
  * Copyright (c) 1999-2000  Microsoft Corporation
  *
  * Module name:
  *
  *   The "AlphaMultiply" and "AlphaDivide" scan operations.
  *
  * Abstract:
  *
  *   See Gdiplus\Specs\ScanOperation.doc for an overview.
  *
  *   These scan operations multiply/divide the color components by the alpha
  *   component. API-level input colors are (usually) specified in 
  *   'non-premultiplied'. Given a non-premultiplied
  *   color (R, G, B, A), its 'premultiplied' form is (RA, GA, BA, A).
  *
  * Notes:
  *
  *   Since "AlphaMultiply" loses information, "AlphaDivide" is not a true
  *   inverse operation. (But it is an inverse if all pixels have an alpha of 1.)
  *
  *   If the alpha is 0, "AlphaDivide" won't cause a divide-by-zero exception or
  *   do anything drastic. But it may do something random. Currently, the pixel 
  *   value is unchanged. It could, instead, set the pixel to 0.
  *
  * Revision History:
  *
  *   12/14/1999 agodfrey
  *       Created it.
  *
  \**************************************************************************/
  
  #include "precomp.hpp"
  
  /**************************************************************************\
  *
  * Operation Description:
  *
  *   AlphaMultiply/AlphaDivide: Convert between premultiplied and
  *       non-premultiplied alpha.
  *
  * Arguments:
  *
  *   dst         - The destination scan
  *   src         - The source scan
  *   count       - The length of the scan, in pixels
  *   otherParams - Additional data. (Ignored.)
  *
  * Return Value:
  *
  *   None
  *
  * Notes:
  *
  *   !!![agodfrey] Currently we use 'Unpremultiply' from imgutils.cpp. 
  *   While we may keep the tables and lookup in imgutils.cpp, 
  *   it needs better naming, and we want the alpha=0 and alpha=255 cases in
  *   here, not out-of-line in imgutils.cpp.
  *
  * History:
  *
  *   12/14/1999 agodfrey
  *       Created it.
  *
  \**************************************************************************/
  
  ARGB Unpremultiply(ARGB argb);
  
  // AlphaDivide from 32bpp PARGB
  
  VOID FASTCALL
  ScanOperation::AlphaDivide_sRGB(
      VOID *dst,
      const VOID *src,
      INT count,
      const OtherParams *otherParams
      )
  {
      DEFINE_POINTERS(ARGB, ARGB)
  
      while (count--)
      {
          sRGB::sRGBColor c;
          c.argb = *s;
          if (sRGB::isTranslucent(c.argb))
          {
              c.argb = Unpremultiply(c.argb);
          }
          *d = c.argb;
          d++;
          s++;
      }
  }
  
  // !!![agodfrey] This should be sorted out. It should be out-of-line, and kept
  //     with its mates in imgutils.cpp (which should maybe move), but it 
  //     shouldn't have a translucency check (we want to do that in
  //     AlphaMultiply_sRGB).
  
  ARGB MyPremultiply(ARGB argb)
  {
      ARGB a = (argb >> ALPHA_SHIFT);
  
      ARGB _000000gg = (argb >> 8) & 0x000000ff;
      ARGB _00rr00bb = (argb & 0x00ff00ff);
  
      ARGB _0000gggg = _000000gg * a + 0x00000080;
      _0000gggg += (_0000gggg >> 8);
  
      ARGB _rrrrbbbb = _00rr00bb * a + 0x00800080;
      _rrrrbbbb += ((_rrrrbbbb >> 8) & 0x00ff00ff);
  
      return (a << ALPHA_SHIFT) |
             (_0000gggg & 0x0000ff00) |
             ((_rrrrbbbb >> 8) & 0x00ff00ff);
  }
  
  // AlphaMultiply from 32bpp ARGB
  
  VOID FASTCALL
  ScanOperation::AlphaMultiply_sRGB(
      VOID *dst,
      const VOID *src,
      INT count,
      const OtherParams *otherParams
      )
  {
      DEFINE_POINTERS(ARGB, ARGB)
  
      while (count--)
      {
          sRGB::sRGBColor c;
          c.argb = *s;
          ARGB alpha = c.argb & 0xff000000;
          
          if (alpha != 0xff000000)
          {
              if (alpha != 0x00000000)
              {
                  c.argb = MyPremultiply(c.argb);
              }
              else
              {
                  c.argb = 0;
              }
          }
          *d = c.argb;
          d++;
          s++;
      }
  }
  
  // !!![agodfrey] We may want to round off, in both AlphaDivide_sRGB64 and
  //     AlphaMultiply_sRGB64.
  
  // AlphaDivide from 64bpp PARGB
  
  VOID FASTCALL
  ScanOperation::AlphaDivide_sRGB64(
      VOID *dst,
      const VOID *src,
      INT count,
      const OtherParams *otherParams
      )
  {
      DEFINE_POINTERS(ARGB64, ARGB64)
  
      while (count--)
      {
          using namespace sRGB;
          
          sRGB64Color c;
          c.argb = *s;
          if (isTranslucent64(c.a))
          {
              c.r = ((INT) c.r << SRGB_FRACTIONBITS) / c.a;
              c.g = ((INT) c.g << SRGB_FRACTIONBITS) / c.a;
              c.b = ((INT) c.b << SRGB_FRACTIONBITS) / c.a;
          }
          *d = c.argb;
          d++;
          s++;
      }
  }
  
  // AlphaMultiply from 64bpp ARGB
  
  VOID FASTCALL
  ScanOperation::AlphaMultiply_sRGB64(
      VOID *dst,
      const VOID *src,
      INT count,
      const OtherParams *otherParams
      )
  {
      DEFINE_POINTERS(ARGB64, ARGB64)
  
      while (count--)
      {
          using namespace sRGB;
          
          sRGB64Color c;
          c.argb = *s;
          if (c.a != SRGB_ONE)
          {
              if (c.a != 0)
              {
                  c.r = ((INT) c.r * c.a) >> SRGB_FRACTIONBITS;
                  c.g = ((INT) c.g * c.a) >> SRGB_FRACTIONBITS;
                  c.b = ((INT) c.b * c.a) >> SRGB_FRACTIONBITS;
              }
              else
              {
                  c.argb = 0;
              }
          }
          *d = c.argb;
          d++;
          s++;
      }
  }
  
  