Bug 215956 - CoreImage Implementation of CSS Filters invert(), opacity(), brightness(), contrast()
Summary: CoreImage Implementation of CSS Filters invert(), opacity(), brightness(), co...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: Other
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: frankhome61
URL:
Keywords: InRadar
Depends on: 213673
Blocks:
  Show dependency treegraph
 
Reported: 2020-08-28 16:28 PDT by frankhome61
Modified: 2020-09-08 12:25 PDT (History)
7 users (show)

See Also:


Attachments
Patch (16.49 KB, patch)
2020-08-31 13:52 PDT, frankhome61
no flags Details | Formatted Diff | Diff
Patch (16.50 KB, patch)
2020-08-31 14:11 PDT, frankhome61
no flags Details | Formatted Diff | Diff
Patch (8.04 KB, patch)
2020-09-03 15:23 PDT, frankhome61
no flags Details | Formatted Diff | Diff
Patch (15.69 KB, patch)
2020-09-03 16:08 PDT, frankhome61
no flags Details | Formatted Diff | Diff
Patch (14.96 KB, patch)
2020-09-04 11:37 PDT, frankhome61
darin: review+
Details | Formatted Diff | Diff
Ready for commit (14.90 KB, patch)
2020-09-04 13:39 PDT, frankhome61
no flags Details | Formatted Diff | Diff
Ready for commit (14.92 KB, patch)
2020-09-04 14:16 PDT, frankhome61
no flags Details | Formatted Diff | Diff
Patch (missing reviewer name) (14.93 KB, patch)
2020-09-04 14:48 PDT, frankhome61
no flags Details | Formatted Diff | Diff
Ready for Commit (14.92 KB, patch)
2020-09-08 11:46 PDT, frankhome61
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description frankhome61 2020-08-28 16:28:35 PDT
Implementing invert(), opacity(), brightness(), contrast(), which are based on FEComponentTransfer using CoreImage
Comment 1 Radar WebKit Bug Importer 2020-08-28 16:29:01 PDT
<rdar://problem/67968206>
Comment 2 frankhome61 2020-08-31 13:52:52 PDT
Created attachment 407622 [details]
Patch
Comment 3 frankhome61 2020-08-31 13:55:11 PDT
This patch depends on path 213673, so it will temporarily contain changes already introduced in 213673. Once 213673 is landed, the only changes in this patch should only be the two additional functions, 
  - feComponentTransferLinearFunctionImage
  - componentTransferLinearFunctionOnly
Comment 4 frankhome61 2020-08-31 14:11:34 PDT
Created attachment 407625 [details]
Patch
Comment 5 frankhome61 2020-09-03 15:23:08 PDT
Created attachment 407920 [details]
Patch
Comment 6 Darin Adler 2020-09-03 16:03:16 PDT
Comment on attachment 407920 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=407920&action=review

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:31
> +#import "FEComponentTransfer.h"

Could forward declare this instead of including it in the header. Nothing in the header requires the full definition.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:62
> +    static bool isNullOrLinearComponentTransferFunction(const FEComponentTransfer&);

Could just make this a free function in the .cpp file instead of a static member function.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:72
> +    if (effect.redFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> +        && effect.redFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        return false;
> +    if (effect.greenFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> +        && effect.greenFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        return false;
> +    if (effect.blueFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> +        && effect.blueFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        return false;
> +    if (effect.alphaFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> +        && effect.alphaFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        return false;
> +    return true;

This very wordy thing could be cut down to size with a lambda:

    auto isNullOrLinear = [] (const ComponentTransferFunction& function) {
        return function.type == FECOMPONENTTRANSFER_TYPE_UNKNOWN || function.type == FECOMPONENTTRANSFER_TYPE_LINEAR;
    };
    return isNullOrLinear(effect.redFunction()) && isNullOrLinear(effect.greenFunction())
        && isNullOrLinear(effect.blueFunction()) && isNullOrLinear(effect.alphaFunction());

I think the && is also easier to read than the backwards logic and early returns.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:243
> +    if (!isNullOrLinearComponentTransferFunction(effect))
> +        return nullptr;

Seems like this should be an assertion instead of a "return null" thing.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:245
> +    
> +

Extra blank line here.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:247
> +    CIFilter* componentTransferFilter = [CIFilter filterWithName:@"CIColorPolynomial"];

auto

Also how about using a shorter local variable name, like "filter"? The function is a narrow enough scope that the meaning of the name is clear enough, I think.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:252
> +    ComponentTransferFunction redFunction = effect.redFunction();
> +    ComponentTransferFunction greenFunction = effect.greenFunction();
> +    ComponentTransferFunction blueFunction = effect.blueFunction();
> +    ComponentTransferFunction alphaFunction = effect.alphaFunction();

auto&

There is no need to copy these functions out of the effect object.

Could also consider shorter names. I think we could call the locals just red, green, blue, alpha given the scope of a short function like this. No real ambiguity about what they mean.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:263
> +    if (redFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        [componentTransferFilter setValue:[CIVector vectorWithX:redFunction.intercept   Y:redFunction.slope    Z:0  W:0] forKey:@"inputRedCoefficients"];
> +    if (greenFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        [componentTransferFilter setValue:[CIVector vectorWithX:greenFunction.intercept Y:greenFunction.slope  Z:0  W:0] forKey:@"inputGreenCoefficients"];
> +    if (blueFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        [componentTransferFilter setValue:[CIVector vectorWithX:blueFunction.intercept  Y:blueFunction.slope   Z:0  W:0] forKey:@"inputBlueCoefficients"];
> +    if (alphaFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> +        [componentTransferFilter setValue:[CIVector vectorWithX:alphaFunction.intercept Y:alphaFunction.slope  Z:0  W:0] forKey:@"inputAlphaCoefficients"];

Code can be simplified with a lambda:

    auto setCoefficients = [&] (NSString *key, const ComponentFunction& function) {
        if (function.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
            [componentTransferFilter setValue:[CIVector vectorWithX:function.intercept Y:function.slope Z:0 W:0] forKey:key];
    };
    setCoefficients(@"inputRedCoefficients", effect.redFunction());
    setCoefficients(@"inputGreenCoefficients", effect.greenFunction());
    setCoefficients(@"inputBlueCoefficients", effect.blueFunction());
    setCoefficients(@"inputAlphaCoefficients", effect.alphaFunction());

This replaces 12 lines of more hard-to-read code.
Comment 7 frankhome61 2020-09-03 16:08:18 PDT
Created attachment 407926 [details]
Patch
Comment 8 Darin Adler 2020-09-03 16:10:29 PDT
Comment on attachment 407926 [details]
Patch

Please check out my comments on the earlier version of the patch.
Comment 9 frankhome61 2020-09-03 16:11:57 PDT
(In reply to Darin Adler from comment #8)
> Comment on attachment 407926 [details]
> Patch
> 
> Please check out my comments on the earlier version of the patch.

Oh whoops just saw the comments, I immediately obsoleted the one you commented on because I forgot to include the test files. Working on it right now.
Comment 10 frankhome61 2020-09-04 10:24:28 PDT
(In reply to Darin Adler from comment #6)
> Comment on attachment 407920 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=407920&action=review
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:31
> > +#import "FEComponentTransfer.h"
> 
> Could forward declare this instead of including it in the header. Nothing in
> the header requires the full definition.
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:62
> > +    static bool isNullOrLinearComponentTransferFunction(const FEComponentTransfer&);
> 
> Could just make this a free function in the .cpp file instead of a static
> member function.
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:72
> > +    if (effect.redFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> > +        && effect.redFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        return false;
> > +    if (effect.greenFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> > +        && effect.greenFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        return false;
> > +    if (effect.blueFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> > +        && effect.blueFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        return false;
> > +    if (effect.alphaFunction().type != FECOMPONENTTRANSFER_TYPE_UNKNOWN
> > +        && effect.alphaFunction().type != FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        return false;
> > +    return true;
> 
> This very wordy thing could be cut down to size with a lambda:
> 
>     auto isNullOrLinear = [] (const ComponentTransferFunction& function) {
>         return function.type == FECOMPONENTTRANSFER_TYPE_UNKNOWN ||
> function.type == FECOMPONENTTRANSFER_TYPE_LINEAR;
>     };
>     return isNullOrLinear(effect.redFunction()) &&
> isNullOrLinear(effect.greenFunction())
>         && isNullOrLinear(effect.blueFunction()) &&
> isNullOrLinear(effect.alphaFunction());
> 
> I think the && is also easier to read than the backwards logic and early
> returns.
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:243
> > +    if (!isNullOrLinearComponentTransferFunction(effect))
> > +        return nullptr;
> 
> Seems like this should be an assertion instead of a "return null" thing.
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:245
> > +    
> > +
> 
> Extra blank line here.
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:247
> > +    CIFilter* componentTransferFilter = [CIFilter filterWithName:@"CIColorPolynomial"];
> 
> auto
> 
> Also how about using a shorter local variable name, like "filter"? The
> function is a narrow enough scope that the meaning of the name is clear
> enough, I think.
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:252
> > +    ComponentTransferFunction redFunction = effect.redFunction();
> > +    ComponentTransferFunction greenFunction = effect.greenFunction();
> > +    ComponentTransferFunction blueFunction = effect.blueFunction();
> > +    ComponentTransferFunction alphaFunction = effect.alphaFunction();
> 
> auto&
since redFunction(), and those function are all marked const, we need "const auto&"
> 
> There is no need to copy these functions out of the effect object.
> 
> Could also consider shorter names. I think we could call the locals just
> red, green, blue, alpha given the scope of a short function like this. No
> real ambiguity about what they mean.
> 
> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:263
> > +    if (redFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        [componentTransferFilter setValue:[CIVector vectorWithX:redFunction.intercept   Y:redFunction.slope    Z:0  W:0] forKey:@"inputRedCoefficients"];
> > +    if (greenFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        [componentTransferFilter setValue:[CIVector vectorWithX:greenFunction.intercept Y:greenFunction.slope  Z:0  W:0] forKey:@"inputGreenCoefficients"];
> > +    if (blueFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        [componentTransferFilter setValue:[CIVector vectorWithX:blueFunction.intercept  Y:blueFunction.slope   Z:0  W:0] forKey:@"inputBlueCoefficients"];
> > +    if (alphaFunction.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
> > +        [componentTransferFilter setValue:[CIVector vectorWithX:alphaFunction.intercept Y:alphaFunction.slope  Z:0  W:0] forKey:@"inputAlphaCoefficients"];
> 
> Code can be simplified with a lambda:
> 
>     auto setCoefficients = [&] (NSString *key, const ComponentFunction&
> function) {
>         if (function.type == FECOMPONENTTRANSFER_TYPE_LINEAR)
>             [componentTransferFilter setValue:[CIVector
> vectorWithX:function.intercept Y:function.slope Z:0 W:0] forKey:key];
>     };
>     setCoefficients(@"inputRedCoefficients", effect.redFunction());
>     setCoefficients(@"inputGreenCoefficients", effect.greenFunction());
>     setCoefficients(@"inputBlueCoefficients", effect.blueFunction());
>     setCoefficients(@"inputAlphaCoefficients", effect.alphaFunction());
> 
> This replaces 12 lines of more hard-to-read code.
Comment 11 frankhome61 2020-09-04 11:37:03 PDT
Created attachment 408006 [details]
Patch
Comment 12 Darin Adler 2020-09-04 12:14:43 PDT
Comment on attachment 408006 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=408006&action=review

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:68
> +        return isNullOrLinear(effect.redFunction()) && isNullOrLinear(effect.greenFunction())
> +            && isNullOrLinear(effect.blueFunction()) && isNullOrLinear(effect.alphaFunction());

This is indented too much.

> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:241
> +    CIFilter* filter = [CIFilter filterWithName:@"CIColorPolynomial"];

I suggest auto here.
Comment 13 frankhome61 2020-09-04 13:39:47 PDT
Created attachment 408019 [details]
Ready for commit
Comment 14 frankhome61 2020-09-04 14:16:20 PDT
Created attachment 408024 [details]
Ready for commit
Comment 15 frankhome61 2020-09-04 14:48:57 PDT
Created attachment 408026 [details]
Patch (missing reviewer name)
Comment 16 frankhome61 2020-09-08 11:46:02 PDT
Created attachment 408247 [details]
Ready for Commit
Comment 17 EWS 2020-09-08 12:25:18 PDT
Committed r266740: <https://trac.webkit.org/changeset/266740>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 408247 [details].