Path: blob/master/src/java.desktop/share/classes/sun/java2d/pipe/BufferedMaskFill.java
41159 views
/*1* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.pipe;2627import java.awt.AlphaComposite;28import java.awt.Composite;29import sun.java2d.SunGraphics2D;30import sun.java2d.SurfaceData;31import sun.java2d.loops.CompositeType;32import sun.java2d.loops.MaskFill;33import sun.java2d.loops.SurfaceType;34import static sun.java2d.pipe.BufferedOpCodes.*;3536/**37* The MaskFill operation is expressed as:38* dst = ((src <MODE> dst) * pathA) + (dst * (1 - pathA))39*40* The OGL/D3D implementation of the MaskFill operation differs from the above41* equation because it is not possible to perform such a complex operation in42* OpenGL/Direct3D (without the use of advanced techniques like fragment43* shaders and multitexturing). Therefore, the BufferedMaskFill operation44* is expressed as:45* dst = (src * pathA) <SrcOver> dst46*47* This simplified formula is only equivalent to the "true" MaskFill equation48* in the following situations:49* - <MODE> is SrcOver50* - <MODE> is Src, extra alpha == 1.0, and the source paint is opaque51*52* Therefore, we register BufferedMaskFill primitives for only the SurfaceType53* and CompositeType restrictions mentioned above. In addition, for the54* SrcNoEa case we must override the incoming composite with a SrcOver (no55* extra alpha) instance, so that we set up the OpenGL/Direct3D blending56* mode to match the BufferedMaskFill equation.57*/58public abstract class BufferedMaskFill extends MaskFill {5960protected final RenderQueue rq;6162protected BufferedMaskFill(RenderQueue rq,63SurfaceType srcType,64CompositeType compType,65SurfaceType dstType)66{67super(srcType, compType, dstType);68this.rq = rq;69}7071@Override72public void MaskFill(SunGraphics2D sg2d, SurfaceData sData,73Composite comp,74final int x, final int y, final int w, final int h,75final byte[] mask,76final int maskoff, final int maskscan)77{78AlphaComposite acomp = (AlphaComposite)comp;79if (acomp.getRule() != AlphaComposite.SRC_OVER) {80comp = AlphaComposite.SrcOver;81}8283rq.lock();84try {85validateContext(sg2d, comp, BufferedContext.USE_MASK);8687// we adjust the mask length so that the mask ends on a88// 4-byte boundary89int maskBytesRequired;90if (mask != null) {91// we adjust the mask length so that the mask ends on a92// 4-byte boundary93maskBytesRequired = (mask.length + 3) & (~3);94} else {95// mask not needed96maskBytesRequired = 0;97}98int totalBytesRequired = 32 + maskBytesRequired;99100RenderBuffer buf = rq.getBuffer();101if (totalBytesRequired <= buf.capacity()) {102if (totalBytesRequired > buf.remaining()) {103// process the queue first and then enqueue the mask104rq.flushNow();105}106107buf.putInt(MASK_FILL);108// enqueue parameters109buf.putInt(x).putInt(y).putInt(w).putInt(h);110buf.putInt(maskoff);111buf.putInt(maskscan);112buf.putInt(maskBytesRequired);113if (mask != null) {114// enqueue the mask115int padding = maskBytesRequired - mask.length;116buf.put(mask);117if (padding != 0) {118buf.position(buf.position() + padding);119}120}121} else {122// queue is too small to accommodate entire mask; perform123// the operation directly on the queue flushing thread124rq.flushAndInvokeNow(new Runnable() {125public void run() {126maskFill(x, y, w, h,127maskoff, maskscan, mask.length, mask);128}129});130}131} finally {132rq.unlock();133}134}135136/**137* Called as a separate Runnable when the operation is too large to fit138* on the RenderQueue. The OGL/D3D pipelines each have their own (small)139* native implementation of this method.140*/141protected abstract void maskFill(int x, int y, int w, int h,142int maskoff, int maskscan, int masklen,143byte[] mask);144145/**146* Validates the state in the provided SunGraphics2D object and sets up147* any special resources for this operation (e.g. enabling gradient148* shading).149*/150protected abstract void validateContext(SunGraphics2D sg2d,151Composite comp, int ctxflags);152}153154155