View Javadoc
1   /*
2    * Copyright (c) 2007, 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 sun.java2d.pipe;
27  
28  import java.awt.AlphaComposite;
29  import java.awt.Composite;
30  import sun.java2d.SunGraphics2D;
31  import sun.java2d.SurfaceData;
32  import sun.java2d.loops.CompositeType;
33  import sun.java2d.loops.MaskFill;
34  import sun.java2d.loops.SurfaceType;
35  import static sun.java2d.pipe.BufferedOpCodes.*;
36  
37  /**
38   * The MaskFill operation is expressed as:
39   *   dst = ((src <MODE> dst) * pathA) + (dst * (1 - pathA))
40   *
41   * The OGL/D3D implementation of the MaskFill operation differs from the above
42   * equation because it is not possible to perform such a complex operation in
43   * OpenGL/Direct3D (without the use of advanced techniques like fragment
44   * shaders and multitexturing).  Therefore, the BufferedMaskFill operation
45   * is expressed as:
46   *   dst = (src * pathA) <SrcOver> dst
47   *
48   * This simplified formula is only equivalent to the "true" MaskFill equation
49   * in the following situations:
50   *   - <MODE> is SrcOver
51   *   - <MODE> is Src, extra alpha == 1.0, and the source paint is opaque
52   *
53   * Therefore, we register BufferedMaskFill primitives for only the SurfaceType
54   * and CompositeType restrictions mentioned above.  In addition, for the
55   * SrcNoEa case we must override the incoming composite with a SrcOver (no
56   * extra alpha) instance, so that we set up the OpenGL/Direct3D blending
57   * mode to match the BufferedMaskFill equation.
58   */
59  public abstract class BufferedMaskFill extends MaskFill {
60  
61      protected final RenderQueue rq;
62  
63      protected BufferedMaskFill(RenderQueue rq,
64                                 SurfaceType srcType,
65                                 CompositeType compType,
66                                 SurfaceType dstType)
67      {
68          super(srcType, compType, dstType);
69          this.rq = rq;
70      }
71  
72      @Override
73      public void MaskFill(SunGraphics2D sg2d, SurfaceData sData,
74                           Composite comp,
75                           final int x, final int y, final int w, final int h,
76                           final byte[] mask,
77                           final int maskoff, final int maskscan)
78      {
79          AlphaComposite acomp = (AlphaComposite)comp;
80          if (acomp.getRule() != AlphaComposite.SRC_OVER) {
81              comp = AlphaComposite.SrcOver;
82          }
83  
84          rq.lock();
85          try {
86              validateContext(sg2d, comp, BufferedContext.USE_MASK);
87  
88              // we adjust the mask length so that the mask ends on a
89              // 4-byte boundary
90              int maskBytesRequired;
91              if (mask != null) {
92                  // we adjust the mask length so that the mask ends on a
93                  // 4-byte boundary
94                  maskBytesRequired = (mask.length + 3) & (~3);
95              } else {
96                  // mask not needed
97                  maskBytesRequired = 0;
98              }
99              int totalBytesRequired = 32 + maskBytesRequired;
100 
101             RenderBuffer buf = rq.getBuffer();
102             if (totalBytesRequired <= buf.capacity()) {
103                 if (totalBytesRequired > buf.remaining()) {
104                     // process the queue first and then enqueue the mask
105                     rq.flushNow();
106                 }
107 
108                 buf.putInt(MASK_FILL);
109                 // enqueue parameters
110                 buf.putInt(x).putInt(y).putInt(w).putInt(h);
111                 buf.putInt(maskoff);
112                 buf.putInt(maskscan);
113                 buf.putInt(maskBytesRequired);
114                 if (mask != null) {
115                     // enqueue the mask
116                     int padding = maskBytesRequired - mask.length;
117                     buf.put(mask);
118                     if (padding != 0) {
119                         buf.position(buf.position() + padding);
120                     }
121                 }
122             } else {
123                 // queue is too small to accommodate entire mask; perform
124                 // the operation directly on the queue flushing thread
125                 rq.flushAndInvokeNow(new Runnable() {
126                     public void run() {
127                         maskFill(x, y, w, h,
128                                  maskoff, maskscan, mask.length, mask);
129                     }
130                 });
131             }
132         } finally {
133             rq.unlock();
134         }
135     }
136 
137     /**
138      * Called as a separate Runnable when the operation is too large to fit
139      * on the RenderQueue.  The OGL/D3D pipelines each have their own (small)
140      * native implementation of this method.
141      */
142     protected abstract void maskFill(int x, int y, int w, int h,
143                                      int maskoff, int maskscan, int masklen,
144                                      byte[] mask);
145 
146     /**
147      * Validates the state in the provided SunGraphics2D object and sets up
148      * any special resources for this operation (e.g. enabling gradient
149      * shading).
150      */
151     protected abstract void validateContext(SunGraphics2D sg2d,
152                                             Composite comp, int ctxflags);
153 }