Bug 1477366 - Handle color space conversion for drop shadow filters with WebRender. r=mstange
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 21 Jan 2019 20:01:02 +0000
changeset 454753 719acee85b9a35d20def0570776748668f1a9648
parent 454752 4e1eb0b0b422a44b882bef43b86a756d8f25eb8a
child 454754 f218594acb923ca13bf5398b2ab74387075946fc
push id111331
push usercsabou@mozilla.com
push dateTue, 22 Jan 2019 04:06:14 +0000
treeherdermozilla-inbound@44be6c1eb581 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1477366
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1477366 - Handle color space conversion for drop shadow filters with WebRender. r=mstange Differential Revision: https://phabricator.services.mozilla.com/D17089
gfx/src/FilterSupport.cpp
gfx/src/FilterSupport.h
layout/svg/nsFilterInstance.cpp
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -49,17 +49,17 @@ static const float glinearRGBTosRGBMap[2
     0.930f, 0.931f, 0.933f, 0.935f, 0.937f, 0.939f, 0.941f, 0.943f, 0.945f,
     0.946f, 0.948f, 0.950f, 0.952f, 0.954f, 0.956f, 0.957f, 0.959f, 0.961f,
     0.963f, 0.965f, 0.967f, 0.968f, 0.970f, 0.972f, 0.974f, 0.975f, 0.977f,
     0.979f, 0.981f, 0.983f, 0.984f, 0.986f, 0.988f, 0.990f, 0.991f, 0.993f,
     0.995f, 0.997f, 0.998f, 1.000f};
 
 // c = n / 255
 // c <= 0.04045f ? c / 12.92f : powf((c + 0.055f) / 1.055f, 2.4f)
-static const float gsRGBToLinearRGBMap[256] = {
+extern const float gsRGBToLinearRGBMap[256] = {
     0.000f, 0.000f, 0.001f, 0.001f, 0.001f, 0.002f, 0.002f, 0.002f, 0.002f,
     0.003f, 0.003f, 0.003f, 0.004f, 0.004f, 0.004f, 0.005f, 0.005f, 0.006f,
     0.006f, 0.007f, 0.007f, 0.007f, 0.008f, 0.009f, 0.009f, 0.010f, 0.010f,
     0.011f, 0.012f, 0.012f, 0.013f, 0.014f, 0.014f, 0.015f, 0.016f, 0.017f,
     0.018f, 0.019f, 0.019f, 0.020f, 0.021f, 0.022f, 0.023f, 0.024f, 0.025f,
     0.026f, 0.027f, 0.028f, 0.030f, 0.031f, 0.032f, 0.033f, 0.034f, 0.036f,
     0.037f, 0.038f, 0.040f, 0.041f, 0.042f, 0.044f, 0.045f, 0.047f, 0.048f,
     0.050f, 0.051f, 0.053f, 0.054f, 0.056f, 0.058f, 0.060f, 0.061f, 0.063f,
--- a/gfx/src/FilterSupport.h
+++ b/gfx/src/FilterSupport.h
@@ -19,16 +19,18 @@
 namespace mozilla {
 namespace gfx {
 class FilterPrimitiveDescription;
 }  // namespace gfx
 }  // namespace mozilla
 
 DECLARE_USE_COPY_CONSTRUCTORS(mozilla::gfx::FilterPrimitiveDescription)
 
+extern const float gsRGBToLinearRGBMap[256];
+
 namespace mozilla {
 namespace gfx {
 
 // Morphology Operators
 const unsigned short SVG_OPERATOR_UNKNOWN = 0;
 const unsigned short SVG_OPERATOR_ERODE = 1;
 const unsigned short SVG_OPERATOR_DILATE = 2;
 
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -145,24 +145,24 @@ bool nsFilterInstance::BuildWebRenderFil
       if (primitive.InputPrimitiveIndex(0) !=
           FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic) {
         return false;
       }
     } else if (primitive.InputPrimitiveIndex(0) != int32_t(i - 1)) {
       return false;
     }
 
-    bool primIsSrgb = primitive.OutputColorSpace() == gfx::ColorSpace::SRGB;
-    if (srgb && !primIsSrgb) {
+    bool previousSrgb = srgb;
+    bool primNeedsSrgb = primitive.InputColorSpace(0) == gfx::ColorSpace::SRGB;
+    if (srgb && !primNeedsSrgb) {
       aWrFilters.AppendElement(wr::FilterOp::SrgbToLinear());
-      srgb = false;
-    } else if (!srgb && primIsSrgb) {
+    } else if (!srgb && primNeedsSrgb) {
       aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb());
-      srgb = true;
     }
+    srgb = primitive.OutputColorSpace() == gfx::ColorSpace::SRGB;
 
     const PrimitiveAttributes& attr = primitive.Attributes();
 
     bool filterIsNoop = false;
 
     if (attr.is<OpacityAttributes>()) {
       float opacity = attr.as<OpacityAttributes>().mOpacity;
       aWrFilters.AppendElement(wr::FilterOp::Opacity(
@@ -232,18 +232,24 @@ bool nsFilterInstance::BuildWebRenderFil
       const Size& stdDev = shadow.mStdDeviation;
       if (stdDev.width != stdDev.height) {
         return false;
       }
 
       wr::LayoutVector2D offset = {(float)shadow.mOffset.x,
                                    (float)shadow.mOffset.y};
       float radius = stdDev.width;
-      wr::FilterOp filterOp =
-          wr::FilterOp::DropShadow(offset, radius, wr::ToColorF(shadow.mColor));
+      Color color = shadow.mColor;
+      if (!primNeedsSrgb) {
+        color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
+                      gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
+                      gsRGBToLinearRGBMap[uint8_t(color.b * 255)], color.a);
+      }
+      wr::FilterOp filterOp = wr::FilterOp::DropShadow(
+          offset, radius, wr::ToColorF(ToDeviceColor(color)));
 
       aWrFilters.AppendElement(filterOp);
     } else {
       return false;
     }
 
     if (filterIsNoop && aWrFilters.Length() > 0 &&
         (aWrFilters.LastElement().tag == wr::FilterOp::Tag::SrgbToLinear ||
@@ -251,17 +257,17 @@ bool nsFilterInstance::BuildWebRenderFil
       // We pushed a color space conversion filter in prevision of applying
       // another filter which turned out to be a no-op, so the conversion is
       // unnecessary. Remove it from the filter list.
       // This is both an optimization and a way to pass the wptest
       // css/filter-effects/filter-scale-001.html for which the needless
       // sRGB->linear->no-op->sRGB roundtrip introduces a slight error and we
       // cannot add fuzziness to the test.
       Unused << aWrFilters.PopLastElement();
-      srgb = !srgb;
+      srgb = previousSrgb;
     }
 
     if (!filterIsNoop) {
       if (finalClip.isNothing()) {
         finalClip = Some(primitive.PrimitiveSubregion());
       } else {
         finalClip =
             Some(primitive.PrimitiveSubregion().Intersect(finalClip.value()));