Bug 1299741 part 6 - Add NS_LinearBlendColors function for linear blending two colors. r?jrmuizel draft
authorXidorn Quan <me@upsuper.org>
Thu, 01 Sep 2016 23:53:34 +1000
changeset 408667 e9fbf7cb21a79b64558f5d31d2b61aedf5b11e57
parent 408666 0e0e6dde057aaa7a0780221e5da9e65f75cbab0e
child 408668 d2718e2b5445523907ec226807cfca5529bd153e
child 408674 8fea359a52f0304839c2d7d262928f52e682ff81
push id28268
push userxquan@mozilla.com
push dateThu, 01 Sep 2016 14:08:08 +0000
reviewersjrmuizel
bugs1299741
milestone51.0a1
Bug 1299741 part 6 - Add NS_LinearBlendColors function for linear blending two colors. r?jrmuizel MozReview-Commit-ID: KVzV2DxXRqu
gfx/src/nsColor.cpp
gfx/src/nsColor.h
--- a/gfx/src/nsColor.cpp
+++ b/gfx/src/nsColor.cpp
@@ -251,16 +251,59 @@ NS_ComposeColors(nscolor aBG, nscolor aF
     blendAlpha = (fgAlpha*255)/a;
   }
   auto r = BlendColorComponent(NS_GET_R(aBG), NS_GET_R(aFG), blendAlpha);
   auto g = BlendColorComponent(NS_GET_G(aBG), NS_GET_G(aFG), blendAlpha);
   auto b = BlendColorComponent(NS_GET_B(aBG), NS_GET_B(aFG), blendAlpha);
   return NS_RGBA(r, g, b, a);
 }
 
+nscolor
+NS_LinearBlendColors(nscolor aBg, nscolor aFg, uint_fast8_t aFgRatio)
+{
+  // Common case that either pure background or pure foreground
+  if (aFgRatio == 0) {
+    return aBg;
+  }
+  if (aFgRatio == 255) {
+    return aFg;
+  }
+  // Common case that alpha channel is equal (usually both are opaque)
+  if (NS_GET_A(aBg) == NS_GET_A(aFg)) {
+    auto r = BlendColorComponent(NS_GET_R(aBg), NS_GET_R(aFg), aFgRatio);
+    auto g = BlendColorComponent(NS_GET_G(aBg), NS_GET_G(aFg), aFgRatio);
+    auto b = BlendColorComponent(NS_GET_B(aBg), NS_GET_B(aFg), aFgRatio);
+    return NS_RGBA(r, g, b, NS_GET_A(aFg));
+  }
+
+  constexpr float kFactor = 1.0f / 255.0f;
+
+  float p1 = kFactor * (255 - aFgRatio);
+  float a1 = kFactor * NS_GET_A(aBg);
+  float r1 = a1 * NS_GET_R(aBg);
+  float g1 = a1 * NS_GET_G(aBg);
+  float b1 = a1 * NS_GET_B(aBg);
+
+  float p2 = 1.0f - p1;
+  float a2 = kFactor * NS_GET_A(aFg);
+  float r2 = a2 * NS_GET_R(aFg);
+  float g2 = a2 * NS_GET_G(aFg);
+  float b2 = a2 * NS_GET_B(aFg);
+
+  float a = p1 * a1 + p2 * a2;
+  if (a == 0.0) {
+    return NS_RGBA(0, 0, 0, 0);
+  }
+
+  auto r = NS_ClampColor((p1 * r1 + p2 * r2) / a);
+  auto g = NS_ClampColor((p1 * g1 + p2 * g2) / a);
+  auto b = NS_ClampColor((p1 * b1 + p2 * b2) / a);
+  return NS_RGBA(r, g, b, NSToIntRound(a * 255));
+}
+
 // Functions to convert from HSL color space to RGB color space.
 // This is the algorithm described in the CSS3 specification
 
 // helper
 static float
 HSL_HueToRGB(float m1, float m2, float h)
 {
   if (h < 0.0f)
--- a/gfx/src/nsColor.h
+++ b/gfx/src/nsColor.h
@@ -55,16 +55,20 @@ enum class nsHexColorType : uint8_t {
 // This accepts the number of digits specified by aType.
 bool
 NS_HexToRGBA(const nsAString& aBuf, nsHexColorType aType, nscolor* aResult);
 
 // Compose one NS_RGB color onto another. The result is what
 // you get if you draw aFG on top of aBG with operator OVER.
 nscolor NS_ComposeColors(nscolor aBG, nscolor aFG);
 
+// Blend one RGBA color with another based on a given ratio.
+// It is a linear interpolation on each channel with alpha premultipled.
+nscolor NS_LinearBlendColors(nscolor aBg, nscolor aFg, uint_fast8_t aFgRatio);
+
 // Translate a hex string to a color. Return true if it parses ok,
 // otherwise return false.
 // This version accepts 1 to 9 digits (missing digits are 0)
 bool NS_LooseHexToRGB(const nsString& aBuf, nscolor* aResult);
 
 // There is no function to translate a color to a hex string, because
 // the hex-string syntax does not support transparency.