1 /*
   2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.scenario.effect;
  27 
  28 import com.sun.javafx.geom.Point2D;
  29 import com.sun.javafx.geom.Rectangle;
  30 import com.sun.javafx.geom.transform.BaseTransform;
  31 import com.sun.scenario.effect.impl.state.RenderState;
  32 
  33 /**
  34  * An effect that blends the two inputs together using one of the
  35  * pre-defined {@code Mode}s.
  36  */
  37 public class Blend extends CoreEffect {
  38 
  39     /**
  40      * A blending mode that defines the manner in which the inputs
  41      * are composited together.
  42      * Each {@code Mode} describes a mathematical equation that
  43      * combines premultiplied inputs to produce some premultiplied result.
  44      */
  45     public enum Mode {
  46         /**
  47          * The top input is blended over the bottom input.
  48          * (Equivalent to the Porter-Duff "source over destination" rule.)
  49          * <p>
  50          * Thus:
  51          * <pre>
  52          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
  53          *      <em>C<sub>r</sub></em> = <em>C<sub>top</sub></em> + <em>C<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
  54          * </pre>
  55          */
  56         SRC_OVER,
  57 
  58         /**
  59          * The part of the top input lying inside of the bottom input
  60          * is kept in the resulting image.
  61          * (Equivalent to the Porter-Duff "source in destination" rule.)
  62          * <p>
  63          * Thus:
  64          * <pre>
  65          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em>*<em>A<sub>bot</sub></em>
  66          *      <em>C<sub>r</sub></em> = <em>C<sub>top</sub></em>*<em>A<sub>bot</sub></em>
  67          * </pre>
  68          */
  69         SRC_IN,
  70 
  71         /**
  72          * The part of the top input lying outside of the bottom input
  73          * is kept in the resulting image.
  74          * (Equivalent to the Porter-Duff "source held out by destination"
  75          * rule.)
  76          * <p>
  77          * Thus:
  78          * <pre>
  79          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em>*(1-<em>A<sub>bot</sub></em>)
  80          *      <em>C<sub>r</sub></em> = <em>C<sub>top</sub></em>*(1-<em>A<sub>bot</sub></em>)
  81          * </pre>
  82          */
  83         SRC_OUT,
  84 
  85         /**
  86          * The part of the top input lying inside of the bottom input
  87          * is blended with the bottom input.
  88          * (Equivalent to the Porter-Duff "source atop destination" rule.)
  89          * <p>
  90          * Thus:
  91          * <pre>
  92          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em>*<em>A<sub>bot</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>) = <em>A<sub>bot</sub></em>
  93          *      <em>C<sub>r</sub></em> = <em>C<sub>top</sub></em>*<em>A<sub>bot</sub></em> + <em>C<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
  94          * </pre>
  95          */
  96         SRC_ATOP,
  97 
  98         /**
  99          * The color and alpha components from the top input are
 100          * added to those from the bottom input.
 101          * The result is clamped to 1.0 if it exceeds the logical
 102          * maximum of 1.0.
 103          * <p>
 104          * Thus:
 105          * <pre>
 106          *      <em>A<sub>r</sub></em> = min(1, <em>A<sub>top</sub></em>+<em>A<sub>bot</sub></em>)
 107          *      <em>C<sub>r</sub></em> = min(1, <em>C<sub>top</sub></em>+<em>C<sub>bot</sub></em>)
 108          * </pre>
 109          * <p>
 110          * Notes:
 111          * <ul>
 112          * <li>This mode is commutative (ordering of inputs
 113          * does not matter).
 114          * <li>This mode is sometimes referred to as "linear dodge" in
 115          * imaging software packages.
 116          * </ul>
 117          */
 118         ADD,
 119 
 120         /**
 121          * The color components from the first input are multiplied with those
 122          * from the second input.
 123          * The alpha components are blended according to
 124          * the {@link #SRC_OVER} equation.
 125          * <p>
 126          * Thus:
 127          * <pre>
 128          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 129          *      <em>C<sub>r</sub></em> = <em>C<sub>top</sub></em> * <em>C<sub>bot</sub></em>
 130          * </pre>
 131          * <p>
 132          * Notes:
 133          * <ul>
 134          * <li>This mode is commutative (ordering of inputs
 135          * does not matter).
 136          * <li>This mode is the mathematical opposite of
 137          * the {@link #SCREEN} mode.
 138          * <li>The resulting color is always at least as dark as either
 139          * of the input colors.
 140          * <li>Rendering with a completely black top input produces black;
 141          * rendering with a completely white top input produces a result
 142          * equivalent to the bottom input.
 143          * </ul>
 144          */
 145         MULTIPLY,
 146 
 147         /**
 148          * The color components from both of the inputs are
 149          * inverted, multiplied with each other, and that result
 150          * is again inverted to produce the resulting color.
 151          * The alpha components are blended according
 152          * to the {@link #SRC_OVER} equation.
 153          * <p>
 154          * Thus:
 155          * <pre>
 156          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 157          *      <em>C<sub>r</sub></em> = 1 - ((1-<em>C<sub>top</sub></em>) * (1-<em>C<sub>bot</sub></em>))
 158          * </pre>
 159          * <p>
 160          * Notes:
 161          * <ul>
 162          * <li>This mode is commutative (ordering of inputs
 163          * does not matter).
 164          * <li>This mode is the mathematical opposite of
 165          * the {@link #MULTIPLY} mode.
 166          * <li>The resulting color is always at least as light as either
 167          * of the input colors.
 168          * <li>Rendering with a completely white top input produces white;
 169          * rendering with a completely black top input produces a result
 170          * equivalent to the bottom input.
 171          * </ul>
 172          */
 173         SCREEN,
 174 
 175         /**
 176          * The input color components are either multiplied or screened,
 177          * depending on the bottom input color.
 178          * The alpha components are blended according
 179          * to the {@link #SRC_OVER} equation.
 180          * <p>
 181          * Thus:
 182          * <pre>
 183          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 184          *      REMIND: not sure how to express this succinctly yet...
 185          * </pre>
 186          * <p>
 187          * Notes:
 188          * <ul>
 189          * <li>This mode is a combination of {@link #SCREEN} and
 190          * {@link #MULTIPLY}, depending on the bottom input color.
 191          * <li>This mode is the mathematical opposite of
 192          * the {@link #HARD_LIGHT} mode.
 193          * <li>In this mode, the top input colors "overlay" the bottom input
 194          * while preserving highlights and shadows of the latter.
 195          * </ul>
 196          */
 197         OVERLAY,
 198 
 199         /**
 200          * REMIND: cross check this formula with OpenVG spec...
 201          *
 202          * The darker of the color components from the two inputs are
 203          * selected to produce the resulting color.
 204          * The alpha components are blended according
 205          * to the {@link #SRC_OVER} equation.
 206          * <p>
 207          * Thus:
 208          * <pre>
 209          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 210          *      <em>C<sub>r</sub></em> = min(<em>C<sub>top</sub></em>, <em>C<sub>bot</sub></em>)
 211          * </pre>
 212          * <p>
 213          * Notes:
 214          * <ul>
 215          * <li>This mode is commutative (ordering of inputs
 216          * does not matter).
 217          * <li>This mode is the mathematical opposite of
 218          * the {@link #LIGHTEN} mode.
 219          * </ul>
 220          */
 221         DARKEN,
 222 
 223         /**
 224          * REMIND: cross check this formula with OpenVG spec...
 225          *
 226          * The lighter of the color components from the two inputs are
 227          * selected to produce the resulting color.
 228          * The alpha components are blended according
 229          * to the {@link #SRC_OVER} equation.
 230          * <p>
 231          * Thus:
 232          * <pre>
 233          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 234          *      <em>C<sub>r</sub></em> = max(<em>C<sub>top</sub></em>, <em>C<sub>bot</sub></em>)
 235          * </pre>
 236          * <p>
 237          * Notes:
 238          * <ul>
 239          * <li>This mode is commutative (ordering of inputs
 240          * does not matter).
 241          * <li>This mode is the mathematical opposite of
 242          * the {@link #DARKEN} mode.
 243          * </ul>
 244          */
 245         LIGHTEN,
 246 
 247         /**
 248          * The bottom input color components are divided by the inverse
 249          * of the top input color components to produce the resulting color.
 250          * The alpha components are blended according
 251          * to the {@link #SRC_OVER} equation.
 252          * <p>
 253          * Thus:
 254          * <pre>
 255          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 256          *      <em>C<sub>r</sub></em> = <em>C<sub>bot</sub></em> / (1-<em>C<sub>top</sub></em>)
 257          * </pre>
 258          */
 259         COLOR_DODGE,
 260 
 261         /**
 262          * The inverse of the bottom input color components are divided by
 263          * the top input color components, all of which is then inverted
 264          * to produce the resulting color.
 265          * The alpha components are blended according
 266          * to the {@link #SRC_OVER} equation.
 267          * <p>
 268          * Thus:
 269          * <pre>
 270          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 271          *      <em>C<sub>r</sub></em> = 1-((1-<em>C<sub>bot</sub></em>) / <em>C<sub>top</sub></em>)
 272          * </pre>
 273          */
 274         COLOR_BURN,
 275 
 276         /**
 277          * The input color components are either multiplied or screened,
 278          * depending on the top input color.
 279          * The alpha components are blended according
 280          * to the {@link #SRC_OVER} equation.
 281          * <p>
 282          * Thus:
 283          * <pre>
 284          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 285          *      REMIND: not sure how to express this succinctly yet...
 286          * </pre>
 287          * <p>
 288          * Notes:
 289          * <ul>
 290          * <li>This mode is a combination of {@link #SCREEN} and
 291          * {@link #MULTIPLY}, depending on the top input color.
 292          * <li>This mode is the mathematical opposite of
 293          * the {@link #OVERLAY} mode.
 294          * </ul>
 295          */
 296         HARD_LIGHT,
 297 
 298         /**
 299          * REMIND: this is a complicated formula, TBD...
 300          */
 301         SOFT_LIGHT,
 302 
 303         /**
 304          * The darker of the color components from the two inputs are
 305          * subtracted from the lighter ones to produce the resulting color.
 306          * The alpha components are blended according
 307          * to the {@link #SRC_OVER} equation.
 308          * <p>
 309          * Thus:
 310          * <pre>
 311          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 312          *      <em>C<sub>r</sub></em> = abs(<em>C<sub>top</sub></em>-<em>C<sub>bot</sub></em>)
 313          * </pre>
 314          * <p>
 315          * Notes:
 316          * <ul>
 317          * <li>This mode is commutative (ordering of inputs
 318          * does not matter).
 319          * <li>This mode can be used to invert parts of the bottom input
 320          * image, or to quickly compare two images (equal pixels will result
 321          * in black).
 322          * <li>Rendering with a completely white top input inverts the
 323          * bottom input; rendering with a completely black top input produces
 324          * a result equivalent to the bottom input.
 325          * </ul>
 326          */
 327         DIFFERENCE,
 328 
 329         /**
 330          * The color components from the two inputs are multiplied and
 331          * doubled, and then subtracted from the sum of the bottom input
 332          * color components, to produce the resulting color.
 333          * The alpha components are blended according
 334          * to the {@link #SRC_OVER} equation.
 335          * <p>
 336          * Thus:
 337          * <pre>
 338          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 339          *      <em>C<sub>r</sub></em> = <em>C<sub>top</sub></em> + <em>C<sub>bot</sub></em> - (2*<em>C<sub>top</sub></em>*<em>C<sub>bot</sub></em>)
 340          * </pre>
 341          * <p>
 342          * Notes:
 343          * <ul>
 344          * <li>This mode is commutative (ordering of inputs
 345          * does not matter).
 346          * <li>This mode can be used to invert parts of the bottom input.
 347          * <li>This mode produces results that are similar to those of
 348          * {@link #DIFFERENCE}, except with lower contrast.
 349          * <li>Rendering with a completely white top input inverts the
 350          * bottom input; rendering with a completely black top input produces
 351          * a result equivalent to the bottom input.
 352          * </ul>
 353          */
 354         EXCLUSION,
 355 
 356         /**
 357          * The red component of the bottom input is replaced with the
 358          * red component of the top input; the other color components
 359          * are unaffected.
 360          * The alpha components are blended according
 361          * to the {@link #SRC_OVER} equation.
 362          * <p>
 363          * Thus:
 364          * <pre>
 365          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 366          *      <em>R<sub>r</sub></em> = <em>R<sub>top</sub></em>
 367          *      <em>G<sub>r</sub></em> = <em>G<sub>bot</sub></em>
 368          *      <em>B<sub>r</sub></em> = <em>B<sub>bot</sub></em>
 369          * </pre>
 370          */
 371         RED,
 372 
 373         /**
 374          * The green component of the bottom input is replaced with the
 375          * green component of the top input; the other color components
 376          * are unaffected.
 377          * The alpha components are blended according
 378          * to the {@link #SRC_OVER} equation.
 379          * <p>
 380          * Thus:
 381          * <pre>
 382          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 383          *      <em>R<sub>r</sub></em> = <em>R<sub>bot</sub></em>
 384          *      <em>G<sub>r</sub></em> = <em>G<sub>top</sub></em>
 385          *      <em>B<sub>r</sub></em> = <em>B<sub>bot</sub></em>
 386          * </pre>
 387          */
 388         GREEN,
 389 
 390         /**
 391          * The blue component of the bottom input is replaced with the
 392          * blue component of the top input; the other color components
 393          * are unaffected.
 394          * The alpha components are blended according
 395          * to the {@link #SRC_OVER} equation.
 396          * <p>
 397          * Thus:
 398          * <pre>
 399          *      <em>A<sub>r</sub></em> = <em>A<sub>top</sub></em> + <em>A<sub>bot</sub></em>*(1-<em>A<sub>top</sub></em>)
 400          *      <em>R<sub>r</sub></em> = <em>R<sub>bot</sub></em>
 401          *      <em>G<sub>r</sub></em> = <em>G<sub>bot</sub></em>
 402          *      <em>B<sub>r</sub></em> = <em>B<sub>top</sub></em>
 403          * </pre>
 404          */
 405         BLUE,
 406     }
 407 
 408     private Mode mode;
 409     private float opacity;
 410 
 411     /**
 412      * Constructs a new {@code Blend} effect with the given mode and the
 413      * default opacity (1.0).
 414      * Either or both inputs may be {@code null} to indicate that the default
 415      * input should be used.
 416      *
 417      * @param mode the blending mode
 418      * @param bottomInput the bottom input
 419      * @param topInput the top input
 420      * @throws IllegalArgumentException if {@code mode} is null
 421      */
 422     public Blend(Mode mode, Effect bottomInput, Effect topInput) {
 423         super(bottomInput, topInput);
 424         setMode(mode);
 425         setOpacity(1f);
 426     }
 427 
 428     /**
 429      * Returns the bottom input for this {@code Effect}.
 430      *
 431      * @return the bottom input for this {@code Effect}
 432      */
 433     public final Effect getBottomInput() {
 434         return getInputs().get(0);
 435     }
 436 
 437     /**
 438      * Sets the bottom input for this {@code Effect} to a specific
 439      * {@code Effect} or to the default input if {@code input} is
 440      * {@code null}.
 441      *
 442      * @param bottomInput the bottom input for this {@code Effect}
 443      */
 444     public void setBottomInput(Effect bottomInput) {
 445         setInput(0, bottomInput);
 446     }
 447 
 448     /**
 449      * Returns the top input for this {@code Effect}.
 450      *
 451      * @return the top input for this {@code Effect}
 452      */
 453     public final Effect getTopInput() {
 454         return getInputs().get(1);
 455     }
 456 
 457     /**
 458      * Sets the top input for this {@code Effect} to a specific
 459      * {@code Effect} or to the default input if {@code input} is
 460      * {@code null}.
 461      *
 462      * @param topInput the top input for this {@code Effect}
 463      */
 464     public void setTopInput(Effect topInput) {
 465         setInput(1, topInput);
 466     }
 467 
 468     /**
 469      * Returns the {@code Mode} used to blend the two inputs together.
 470      *
 471      * @return the {@code Mode} used to blend the two inputs together.
 472      */
 473     public Mode getMode() {
 474         return mode;
 475     }
 476 
 477     /**
 478      * Sets the {@code Mode} used to blend the two inputs together.
 479      * <pre>
 480      *       Min: n/a
 481      *       Max: n/a
 482      *   Default: Mode.SRC_OVER
 483      *  Identity: n/a
 484      * </pre>
 485      *
 486      * @param mode the blending mode
 487      * @throws IllegalArgumentException if {@code mode} is null
 488      */
 489     public void setMode(Mode mode) {
 490         if (mode == null) {
 491             throw new IllegalArgumentException("Mode must be non-null");
 492         }
 493         Blend.Mode old = this.mode;
 494         this.mode = mode;
 495         updatePeerKey("Blend_" + mode.name());
 496     }
 497 
 498     /**
 499      * Returns the opacity value, which is modulated with the top input
 500      * prior to blending.
 501      *
 502      * @return the opacity value
 503      */
 504     public float getOpacity() {
 505         return opacity;
 506     }
 507 
 508     /**
 509      * Sets the opacity value, which is modulated with the top input prior
 510      * to blending.
 511      * <pre>
 512      *       Min: 0.0
 513      *       Max: 1.0
 514      *   Default: 1.0
 515      *  Identity: 1.0
 516      * </pre>
 517      *
 518      * @param opacity the opacity value
 519      * @throws IllegalArgumentException if {@code opacity} is outside the
 520      * allowable range
 521      */
 522     public void setOpacity(float opacity) {
 523         if (opacity < 0f || opacity > 1f) {
 524             throw new IllegalArgumentException("Opacity must be in the range [0,1]");
 525         }
 526         float old = this.opacity;
 527         this.opacity = opacity;
 528     }
 529 
 530     /**
 531      * Transform the specified point {@code p} from the coordinate space
 532      * of the primary content input to the coordinate space of the effect
 533      * output.
 534      * In essence, this method asks the question "Which output coordinate
 535      * is most affected by the data at the specified coordinate in the
 536      * primary source input?"
 537      * <p>
 538      * The {@code Blend} effect delegates this operation to its {@code top}
 539      * input, or the {@code defaultInput} if the {@code top} input is
 540      * {@code null}.
 541      *
 542      * @param p the point in the coordinate space of the primary content
 543      *          input to be transformed
 544      * @param defaultInput the default input {@code Effect} to be used in
 545      *                     all cases where a filter has a null input
 546      * @return the transformed point in the coordinate space of the result
 547      */
 548     @Override
 549     public Point2D transform(Point2D p, Effect defaultInput) {
 550         return getDefaultedInput(1, defaultInput).transform(p, defaultInput);
 551     }
 552 
 553     /**
 554      * Transform the specified point {@code p} from the coordinate space
 555      * of the output of the effect into the coordinate space of the
 556      * primary content input.
 557      * In essence, this method asks the question "Which source coordinate
 558      * contributes most to the definition of the output at the specified
 559      * coordinate?"
 560      * <p>
 561      * The {@code Blend} effect delegates this operation to its {@code top}
 562      * input, or the {@code defaultInput} if the {@code top} input is
 563      * {@code null}.
 564      *
 565      * @param p the point in the coordinate space of the result output
 566      *          to be transformed
 567      * @param defaultInput the default input {@code Effect} to be used in
 568      *                     all cases where a filter has a null input
 569      * @return the untransformed point in the coordinate space of the
 570      *         primary content input
 571      */
 572     @Override
 573     public Point2D untransform(Point2D p, Effect defaultInput) {
 574         return getDefaultedInput(1, defaultInput).untransform(p, defaultInput);
 575     }
 576 
 577     @Override
 578     public RenderState getRenderState(FilterContext fctx,
 579                                       BaseTransform transform,
 580                                       Rectangle outputClip,
 581                                       Object renderHelper,
 582                                       Effect defaultInput)
 583     {
 584         // A blend operation operates on its inputs pixel-by-pixel
 585         // with no expansion or contraction.
 586         // RT-27563
 587         // TODO: The RenderSpaceRenderState object uses the output clip unchanged
 588         // for its inputs, but we could further restrict the amount we ask for
 589         // each input to the intersection of the two input bounds, but for now we
 590         // will simply let it pass along the output clip as the input clip.
 591         return RenderState.RenderSpaceRenderState;
 592     }
 593 
 594     @Override
 595     public boolean reducesOpaquePixels() {
 596         final Effect bottomInput = getBottomInput();
 597         final Effect topInput = getTopInput();
 598         switch (getMode()) {
 599             case SRC_IN:
 600             case SRC_OUT:
 601                 return true;
 602             case SRC_ATOP:
 603                 return bottomInput != null && bottomInput.reducesOpaquePixels();
 604             case SRC_OVER:
 605             case ADD:
 606             case MULTIPLY:
 607             case SCREEN:
 608             case OVERLAY:
 609             case DARKEN:
 610             case LIGHTEN:
 611             case COLOR_DODGE:
 612             case COLOR_BURN:
 613             case HARD_LIGHT:
 614             case SOFT_LIGHT:
 615             case DIFFERENCE:
 616             case EXCLUSION:
 617             case RED:
 618             case GREEN:
 619             case BLUE:
 620                 return topInput != null && topInput.reducesOpaquePixels() && bottomInput != null && bottomInput.reducesOpaquePixels();
 621         }
 622         return true;
 623     }
 624 }