Changeset 262070 in webkit


Ignore:
Timestamp:
May 22, 2020 1:16:20 PM (4 years ago)
Author:
weinig@apple.com
Message:

Extended Color Cleanup: Make alpha premultiplication code more consistent and clear regarding what works with extended colors
https://bugs.webkit.org/show_bug.cgi?id=212265

Reviewed by Simon Fraser.

  • Adds premultiplied(const FloatComponents&) to do premutiplication directly on FloatComponents rather than doing it on the ints and losing precision.
  • Makes non-FloatComponent alpha premultiplication all take place only for SimpleColors as that is what callers need. The existing premulitplication for ExtendedColors in blend() was incorrect as it never did a conversion to sRGB.
  • Adds new toSRGBASimpleColorLossy() (to complement toSRGBAComponentsLossy()). Will make it easy to find all the conversions in the future.
  • Broke non-premultiplying blend() out of blend() (removing parameter) and made a new blendWithoutPremultiply() function for it (no callers needed to make this decision dynamically).
  • css/CSSGradientValue.cpp:

(WebCore::CSSGradientValue::computeStops):
Use blendWithoutPremultiply() explicitly.

  • platform/graphics/Color.h:
  • platform/graphics/Color.cpp:

(WebCore::makePremultipliedRGBA): Renamed from premultipliedARGBFromColor and now only operates on SimpleColors.
(WebCore::makeUnPremultipliedRGBA): Renamed from colorFromPremultipliedARGB and now only operates on SimpleColors.
(WebCore::colorFromPremultipliedARGB): Deleted.
(WebCore::premultipliedARGBFromColor): Deleted.

(WebCore::Color::toSRGBASimpleColorLossy const):
Added. Useful for finding all non-colorspace preserving users of the color channels.

(WebCore::blend):
(WebCore::blendWithoutPremultiply):
Split these out from each other. Made blend() use toSRGBASimpleColorLossy() and do all
operations on SimpleColors directly. The old code that preported to work with extended
colors was nonsense as it didn't actually take the colorspaces into account, just grabbed
the channels regardless of space.

  • platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.cpp:

(WebCore::ImageBufferCairoImageSurfaceBackend::platformTransformColorSpace):
Adopt update premulitiplication names and stay in SimpleColor for entire conversion.

  • platform/graphics/cairo/NativeImageCairo.cpp:

(WebCore::nativeImageSinglePixelSolidColor):
Adopt update premulitiplication names.

  • platform/graphics/ColorUtilities.cpp:

(WebCore::premultiplied):

  • platform/graphics/ColorUtilities.h:
  • platform/graphics/texmap/TextureMapperGL.cpp:

(WebCore::TextureMapperGL::drawBorder):
(WebCore::prepareFilterProgram):
(WebCore::TextureMapperGL::drawSolidColor):
Add and adopt premultiplied(const FloatComponents&).

Location:
trunk/Source/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r262069 r262070  
     12020-05-22  Sam Weinig  <weinig@apple.com>
     2
     3        Extended Color Cleanup: Make alpha premultiplication code more consistent and clear regarding what works with extended colors
     4        https://bugs.webkit.org/show_bug.cgi?id=212265
     5
     6        Reviewed by Simon Fraser.
     7
     8        - Adds premultiplied(const FloatComponents&) to do premutiplication directly on FloatComponents
     9          rather than doing it on the ints and losing precision.
     10        - Makes non-FloatComponent alpha premultiplication all take place only for SimpleColors as that
     11          is what callers need. The existing premulitplication for ExtendedColors in blend() was incorrect
     12          as it never did a conversion to sRGB.
     13        - Adds new toSRGBASimpleColorLossy() (to complement toSRGBAComponentsLossy()). Will make it easy
     14          to find all the conversions in the future.
     15        - Broke non-premultiplying blend() out of blend() (removing parameter) and made a new blendWithoutPremultiply()
     16          function for it (no callers needed to make this decision dynamically).
     17
     18        * css/CSSGradientValue.cpp:
     19        (WebCore::CSSGradientValue::computeStops):
     20        Use blendWithoutPremultiply() explicitly.
     21
     22        * platform/graphics/Color.h:
     23        * platform/graphics/Color.cpp:
     24        (WebCore::makePremultipliedRGBA): Renamed from premultipliedARGBFromColor and now only operates on SimpleColors.
     25        (WebCore::makeUnPremultipliedRGBA): Renamed from colorFromPremultipliedARGB and now only operates on SimpleColors.
     26        (WebCore::colorFromPremultipliedARGB): Deleted.
     27        (WebCore::premultipliedARGBFromColor): Deleted.
     28
     29        (WebCore::Color::toSRGBASimpleColorLossy const):
     30        Added. Useful for finding all non-colorspace preserving users of the color channels.
     31
     32        (WebCore::blend):
     33        (WebCore::blendWithoutPremultiply):
     34        Split these out from each other. Made blend() use toSRGBASimpleColorLossy() and do all
     35        operations on SimpleColors directly. The old code that preported to work with extended
     36        colors was nonsense as it didn't actually take the colorspaces into account, just grabbed
     37        the channels regardless of space. 
     38       
     39        * platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.cpp:
     40        (WebCore::ImageBufferCairoImageSurfaceBackend::platformTransformColorSpace):
     41        Adopt update premulitiplication names and stay in SimpleColor for entire conversion.
     42
     43        * platform/graphics/cairo/NativeImageCairo.cpp:
     44        (WebCore::nativeImageSinglePixelSolidColor):
     45        Adopt update premulitiplication names.
     46
     47        * platform/graphics/ColorUtilities.cpp:
     48        (WebCore::premultiplied):
     49        * platform/graphics/ColorUtilities.h:
     50        * platform/graphics/texmap/TextureMapperGL.cpp:
     51        (WebCore::TextureMapperGL::drawBorder):
     52        (WebCore::prepareFilterProgram):
     53        (WebCore::TextureMapperGL::drawSolidColor):
     54        Add and adopt premultiplied(const FloatComponents&).
     55
    1562020-05-22  Andy Estes  <aestes@apple.com>
    257
  • trunk/Source/WebCore/css/CSSGradientValue.cpp

    r259703 r262070  
    484484            float multiplier = std::pow(relativeOffset, std::log(.5f) / std::log(midpoint));
    485485            // FIXME: Why not premultiply here?
    486             newStops[y].color = blend(color1, color2, multiplier, false /* do not premultiply */);
     486            newStops[y].color = blendWithoutPremultiply(color1, color2, multiplier);
    487487        }
    488488
  • trunk/Source/WebCore/platform/graphics/Color.cpp

    r262035 r262070  
    5656}
    5757
     58RGBA32 makePremultipliedRGBA(RGBA32 pixelColor)
     59{
     60    if (pixelColor.isOpaque())
     61        return pixelColor;
     62    return makePremultipliedRGBA(pixelColor.redComponent(), pixelColor.greenComponent(), pixelColor.blueComponent(), pixelColor.alphaComponent());
     63}
     64
    5865RGBA32 makeUnPremultipliedRGBA(int r, int g, int b, int a)
    5966{
    6067    return makeRGBA(unpremultipliedChannel(r, a), unpremultipliedChannel(g, a), unpremultipliedChannel(b, a), a);
     68}
     69
     70RGBA32 makeUnPremultipliedRGBA(RGBA32 pixelColor)
     71{
     72    if (pixelColor.isVisible() && !pixelColor.isOpaque())
     73        return makeUnPremultipliedRGBA(pixelColor.redComponent(), pixelColor.greenComponent(), pixelColor.blueComponent(), pixelColor.alphaComponent());
     74    return pixelColor;
    6175}
    6276
     
    497511}
    498512
     513SimpleColor Color::toSRGBASimpleColorLossy() const
     514{
     515    if (!isExtended())
     516        return rgb();
     517
     518    auto [r, g, b, a] = toSRGBAComponentsLossy();
     519    return makeRGBA32FromFloats(r, g, b, a);
     520}
     521
    499522FloatComponents Color::toSRGBAComponentsLossy() const
    500523{
     
    512535}
    513536
    514 Color colorFromPremultipliedARGB(RGBA32 pixelColor)
    515 {
    516     if (pixelColor.isVisible() && !pixelColor.isOpaque())
    517         return makeUnPremultipliedRGBA(pixelColor.redComponent(), pixelColor.greenComponent(), pixelColor.blueComponent(), pixelColor.alphaComponent());
    518     return pixelColor;
    519 }
    520 
    521 RGBA32 premultipliedARGBFromColor(const Color& color)
    522 {
    523     if (color.isOpaque()) {
    524         if (color.isExtended())
    525             return makeRGB(color.asExtended().red() * 255, color.asExtended().green() * 255, color.asExtended().blue() * 255);
    526         return color.rgb();
    527     }
    528 
    529     if (color.isExtended())
    530         return makePremultipliedRGBA(color.asExtended().red() * 255, color.asExtended().green() * 255, color.asExtended().blue() * 255, color.asExtended().alpha() * 255);
    531 
    532     return makePremultipliedRGBA(color.red(), color.green(), color.blue(), color.alpha());
    533 }
    534 
    535537bool extendedColorsEqual(const Color& a, const Color& b)
    536538{
     
    542544}
    543545
    544 Color blend(const Color& from, const Color& to, double progress, bool blendPremultiplied)
     546Color blend(const Color& from, const Color& to, double progress)
    545547{
    546548    // FIXME: ExtendedColor - needs to handle color spaces.
     
    549551        return Color();
    550552
    551     if (blendPremultiplied) {
    552         // Since premultipliedARGBFromColor() bails on zero alpha, special-case that.
    553         Color premultFrom = from.alpha() ? premultipliedARGBFromColor(from) : Color::transparent;
    554         Color premultTo = to.alpha() ? premultipliedARGBFromColor(to) : Color::transparent;
    555 
    556         Color premultBlended(blend(premultFrom.red(), premultTo.red(), progress),
    557             blend(premultFrom.green(), premultTo.green(), progress),
    558             blend(premultFrom.blue(), premultTo.blue(), progress),
    559             blend(premultFrom.alpha(), premultTo.alpha(), progress));
    560 
    561         return Color(colorFromPremultipliedARGB(premultBlended.rgb()));
    562     }
    563 
    564     return Color(blend(from.red(), to.red(), progress),
    565         blend(from.green(), to.green(), progress),
    566         blend(from.blue(), to.blue(), progress),
    567         blend(from.alpha(), to.alpha(), progress));
     553    // Since makePremultipliedRGBA() bails on zero alpha, special-case that.
     554    auto premultFrom = from.alpha() ? makePremultipliedRGBA(from.toSRGBASimpleColorLossy()) : Color::transparent;
     555    auto premultTo = to.alpha() ? makePremultipliedRGBA(to.toSRGBASimpleColorLossy()) : Color::transparent;
     556
     557    RGBA32 premultBlended = makeRGBA(
     558        WebCore::blend(premultFrom.redComponent(), premultTo.redComponent(), progress),
     559        WebCore::blend(premultFrom.greenComponent(), premultTo.greenComponent(), progress),
     560        WebCore::blend(premultFrom.blueComponent(), premultTo.blueComponent(), progress),
     561        WebCore::blend(premultFrom.alphaComponent(), premultTo.alphaComponent(), progress)
     562    );
     563
     564    return makeUnPremultipliedRGBA(premultBlended);
     565}
     566
     567Color blendWithoutPremultiply(const Color& from, const Color& to, double progress)
     568{
     569    // FIXME: ExtendedColor - needs to handle color spaces.
     570    // We need to preserve the state of the valid flag at the end of the animation
     571    if (progress == 1 && !to.isValid())
     572        return { };
     573
     574    auto fromSRGB = from.toSRGBASimpleColorLossy();
     575    auto toSRGB = from.toSRGBASimpleColorLossy();
     576
     577    return {
     578        WebCore::blend(fromSRGB.redComponent(), toSRGB.redComponent(), progress),
     579        WebCore::blend(fromSRGB.greenComponent(), toSRGB.greenComponent(), progress),
     580        WebCore::blend(fromSRGB.blueComponent(), toSRGB.blueComponent(), progress),
     581        WebCore::blend(fromSRGB.alphaComponent(), toSRGB.alphaComponent(), progress)
     582    };
    568583}
    569584
  • trunk/Source/WebCore/platform/graphics/Color.h

    r262045 r262070  
    9191
    9292RGBA32 makePremultipliedRGBA(int r, int g, int b, int a, bool ceiling = true);
     93RGBA32 makePremultipliedRGBA(RGBA32);
    9394RGBA32 makeUnPremultipliedRGBA(int r, int g, int b, int a);
     95RGBA32 makeUnPremultipliedRGBA(RGBA32);
    9496
    9597WEBCORE_EXPORT RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a);
     
    206208
    207209    WEBCORE_EXPORT std::pair<ColorSpace, FloatComponents> colorSpaceAndComponents() const;
     210
     211    // This will convert non-sRGB colorspace colors into sRGB.
     212    WEBCORE_EXPORT SimpleColor toSRGBASimpleColorLossy() const;
    208213
    209214    // This will convert non-sRGB colorspace colors into sRGB.
     
    318323bool operator!=(const Color&, const Color&);
    319324
    320 Color colorFromPremultipliedARGB(RGBA32);
    321 RGBA32 premultipliedARGBFromColor(const Color&);
    322325// One or both must be extended colors.
    323326WEBCORE_EXPORT bool extendedColorsEqual(const Color&, const Color&);
    324327
    325 Color blend(const Color& from, const Color& to, double progress, bool blendPremultiplied = true);
     328Color blend(const Color& from, const Color& to, double progress);
     329Color blendWithoutPremultiply(const Color& from, const Color& to, double progress);
    326330
    327331int differenceSquared(const Color&, const Color&);
  • trunk/Source/WebCore/platform/graphics/ColorUtilities.cpp

    r261967 r262070  
    284284}
    285285
     286FloatComponents premultiplied(const FloatComponents& sRGBComponents)
     287{
     288    auto [r, g, b, a] = sRGBComponents;
     289    return {
     290        r * a,
     291        g * a,
     292        b * a,
     293        a
     294    };
     295}
     296
    286297ColorMatrix::ColorMatrix()
    287298{
  • trunk/Source/WebCore/platform/graphics/ColorUtilities.h

    r261967 r262070  
    192192float contrastRatio(const FloatComponents&, const FloatComponents&);
    193193
     194FloatComponents premultiplied(const FloatComponents& sRGBCompontents);
     195
    194196class ColorMatrix {
    195197public:
  • trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.cpp

    r256892 r262070  
    8181        for (int x = 0; x < m_logicalSize.width(); x++) {
    8282            unsigned* pixel = row + x;
    83             Color pixelColor = colorFromPremultipliedARGB(*pixel);
    84             pixelColor = Color(lookUpTable[pixelColor.red()], lookUpTable[pixelColor.green()], lookUpTable[pixelColor.blue()], pixelColor.alpha());
    85             *pixel = premultipliedARGBFromColor(pixelColor).value();
     83            auto pixelColor = makeUnPremultipliedRGBA(*pixel);
     84            pixelColor = makeRGBA(lookUpTable[pixelColor.redComponent()], lookUpTable[pixelColor.greenComponent()], lookUpTable[pixelColor.blueComponent()], pixelColor.alphaComponent());
     85            *pixel = makePremultipliedRGBA(pixelColor).value();
    8686        }
    8787    }
  • trunk/Source/WebCore/platform/graphics/cairo/NativeImageCairo.cpp

    r249217 r262070  
    5555
    5656    RGBA32* pixel = reinterpret_cast_ptr<RGBA32*>(cairo_image_surface_get_data(image.get()));
    57     return colorFromPremultipliedARGB(*pixel);
     57    return makeUnPremultipliedRGBA(*pixel);
    5858}
    5959
  • trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp

    r261901 r262070  
    254254    glUseProgram(program->programID());
    255255
    256     // FIXME: Do the premultiply on FloatComponents directly.
    257     auto [r, g, b, a] = Color(premultipliedARGBFromColor(color)).toSRGBAComponentsLossy();
     256    auto [r, g, b, a] = premultiplied(color.toSRGBAComponentsLossy());
    258257    glUniform4f(program->colorLocation(), r, g, b, a);
    259258    glLineWidth(width);
     
    416415        case 1:
    417416            // Second pass: we need the shadow color and the content texture for compositing.
    418             // FIXME: Do the premultiply on FloatComponents directly.
    419             auto [r, g, b, a] = Color(premultipliedARGBFromColor(shadow.color())).toSRGBAComponentsLossy();
     417            auto [r, g, b, a] = premultiplied(shadow.color().toSRGBAComponentsLossy());
    420418            glUniform4f(program.colorLocation(), r, g, b, a);
    421419            glUniform2f(program.blurRadiusLocation(), 0, shadow.stdDeviation() / float(size.height()));
     
    679677    glUseProgram(program->programID());
    680678
    681     // FIXME: Do the premultiply on FloatComponents directly.
    682     auto [r, g, b, a] = Color(premultipliedARGBFromColor(color)).toSRGBAComponentsLossy();
     679    auto [r, g, b, a] = premultiplied(color.toSRGBAComponentsLossy());
    683680    glUniform4f(program->colorLocation(), r, g, b, a);
    684681    if (a < 1 && isBlendingAllowed)
Note: See TracChangeset for help on using the changeset viewer.