blob: 74b94758385d5d220bee20495a65983652d7f3bd [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.java2d.pipe;
27
28import java.awt.AlphaComposite;
29import java.awt.Composite;
30import sun.java2d.SunGraphics2D;
31import sun.java2d.SurfaceData;
32import sun.java2d.loops.CompositeType;
33import sun.java2d.loops.MaskFill;
34import sun.java2d.loops.SurfaceType;
35import 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 */
59public 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 accomodate 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}