diff options
Diffstat (limited to 'awt/org/apache/harmony/awt/gl/render/JavaBlitter.java')
-rw-r--r-- | awt/org/apache/harmony/awt/gl/render/JavaBlitter.java | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java new file mode 100644 index 0000000..67e0a59 --- /dev/null +++ b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java @@ -0,0 +1,611 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 18.11.2005 + * + */ +package org.apache.harmony.awt.gl.render; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.XORComposite; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * Java implenetation of the Blitter interface. Using when we can't + * draw images natively. + */ +public class JavaBlitter implements Blitter { + + /** + * Instead of multiplication and division we are using values from + * Lookup tables. + */ + static byte mulLUT[][]; // Lookup table for multiplication + static byte divLUT[][]; // Lookup table for division + + static{ + mulLUT = new byte[256][256]; + for(int i = 0; i < 256; i++){ + for(int j = 0; j < 256; j++){ + mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f); + } + } + divLUT = new byte[256][256]; + for(int i = 1; i < 256; i++){ + for(int j = 0; j < i; j++){ + divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f); + } + for(int j = i; j < 256; j++){ + divLUT[i][j] = (byte)255; + } + } + } + + final static int AlphaCompositeMode = 1; + final static int XORMode = 2; + + final static JavaBlitter inst = new JavaBlitter(); + + public static JavaBlitter getInstance(){ + return inst; + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, AffineTransform sysxform, + AffineTransform xform, Composite comp, Color bgcolor, + MultiRectArea clip) { + + if(xform == null){ + blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height, + sysxform, comp, bgcolor, clip); + }else{ + double scaleX = xform.getScaleX(); + double scaleY = xform.getScaleY(); + double scaledX = dstX / scaleX; + double scaledY = dstY / scaleY; + AffineTransform at = new AffineTransform(); + at.setToTranslation(scaledX, scaledY); + xform.concatenate(at); + sysxform.concatenate(xform); + blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height, + sysxform, comp, bgcolor, clip); + } + + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, AffineTransform sysxform, + Composite comp, Color bgcolor, MultiRectArea clip) { + + if(sysxform == null) { + sysxform = new AffineTransform(); + } + int type = sysxform.getType(); + switch(type){ + case AffineTransform.TYPE_TRANSLATION: + dstX += sysxform.getTranslateX(); + dstY += sysxform.getTranslateY(); + case AffineTransform.TYPE_IDENTITY: + blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, + width, height, comp, bgcolor, clip); + break; + default: + int srcW = srcSurf.getWidth(); + int srcH = srcSurf.getHeight(); + + int w = srcX + width < srcW ? width : srcW - srcX; + int h = srcY + height < srcH ? height : srcH - srcY; + + ColorModel srcCM = srcSurf.getColorModel(); + Raster srcR = srcSurf.getRaster().createChild(srcX, srcY, + w, h, 0, 0, null); + + ColorModel dstCM = dstSurf.getColorModel(); + WritableRaster dstR = dstSurf.getRaster(); + + transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h, + sysxform, comp, bgcolor, clip); + + } + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, Composite comp, + Color bgcolor, MultiRectArea clip) { + + javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(), + srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY, + dstSurf.getWidth(), dstSurf.getHeight(), + dstSurf.getColorModel(), dstSurf.getRaster(), + width, height, comp, bgcolor, clip); + + } + public void javaBlt(int srcX, int srcY, int srcW, int srcH, + ColorModel srcCM, Raster srcRast, int dstX, int dstY, + int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast, + int width, int height, Composite comp, Color bgcolor, + MultiRectArea clip){ + + int srcX2 = srcW - 1; + int srcY2 = srcH - 1; + int dstX2 = dstW - 1; + int dstY2 = dstH - 1; + + if(srcX < 0){ + width += srcX; + srcX = 0; + } + if(srcY < 0){ + height += srcY; + srcY = 0; + } + + if(dstX < 0){ + width += dstX; + srcX -= dstX; + dstX = 0; + } + if(dstY < 0){ + height += dstY; + srcY -= dstY; + dstY = 0; + } + + if(srcX > srcX2 || srcY > srcY2) { + return; + } + if(dstX > dstX2 || dstY > dstY2) { + return; + } + + if(srcX + width > srcX2) { + width = srcX2 - srcX + 1; + } + if(srcY + height > srcY2) { + height = srcY2 - srcY + 1; + } + if(dstX + width > dstX2) { + width = dstX2 - dstX + 1; + } + if(dstY + height > dstY2) { + height = dstY2 - dstY + 1; + } + + if(width <= 0 || height <= 0) { + return; + } + + int clipRects[]; + if(clip != null) { + clipRects = clip.rect; + } else { + clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1}; + } + + boolean isAlphaComp = false; + int rule = 0; + float alpha = 0; + boolean isXORComp = false; + Color xorcolor = null; + CompositeContext cont = null; + + if(comp instanceof AlphaComposite){ + isAlphaComp = true; + AlphaComposite ac = (AlphaComposite) comp; + rule = ac.getRule(); + alpha = ac.getAlpha(); + }else if(comp instanceof XORComposite){ + isXORComp = true; + XORComposite xcomp = (XORComposite) comp; + xorcolor = xcomp.getXORColor(); + }else{ + cont = comp.createContext(srcCM, dstCM, null); + } + + for(int i = 1; i < clipRects[0]; i += 4){ + int _sx = srcX; + int _sy = srcY; + + int _dx = dstX; + int _dy = dstY; + + int _w = width; + int _h = height; + + int cx = clipRects[i]; // Clipping left top X + int cy = clipRects[i + 1]; // Clipping left top Y + int cx2 = clipRects[i + 2]; // Clipping right bottom X + int cy2 = clipRects[i + 3]; // Clipping right bottom Y + + if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) { + continue; + } + + if(cx > _dx){ + int shx = cx - _dx; + _w -= shx; + _dx = cx; + _sx += shx; + } + + if(cy > _dy){ + int shy = cy - _dy; + _h -= shy; + _dy = cy; + _sy += shy; + } + + if(_dx + _w > cx2 + 1){ + _w = cx2 - _dx + 1; + } + + if(_dy + _h > cy2 + 1){ + _h = cy2 - _dy + 1; + } + + if(_sx > srcX2 || _sy > srcY2) { + continue; + } + + if(isAlphaComp){ + alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, + dstCM, dstRast, _w, _h, rule, alpha, bgcolor); + }else if(isXORComp){ + xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, + dstCM, dstRast, _w, _h, xorcolor); + }else{ + Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null); + WritableRaster dr = dstRast.createWritableChild(_dx, _dy, + _w, _h, 0, 0, null); + cont.compose(sr, dr, dr); + } + } + } + + void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, + int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, + int width, int height, int rule, float alpha, Color bgcolor){ + + Object srcPixel, dstPixel; + int srcConstAllpha = (int)(alpha * 255 + 0.5f); + int srcRGB, dstRGB = 0; + + if(bgcolor != null){ + dstRGB = bgcolor.getRGB(); + } + + for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){ + for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){ + srcPixel = srcRast.getDataElements(sx, sy, null); + srcRGB = srcCM.getRGB(srcPixel); + if(bgcolor == null){ + dstPixel = dstRast.getDataElements(dx, dy, null); + dstRGB = dstCM.getRGB(dstPixel); + } + + dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(), + dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(), + rule, srcConstAllpha); + + dstPixel = dstCM.getDataElements(dstRGB, null); + dstRast.setDataElements(dx,dy,dstPixel); + } + } + } + + void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, + int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, + int width, int height, Color xorcolor){ + + Object srcPixel, dstPixel; + int xorRGB = xorcolor.getRGB(); + int srcRGB, dstRGB; + + for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){ + for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){ + srcPixel = srcRast.getDataElements(sx, sy, null); + dstPixel = dstRast.getDataElements(dx, dy, null); + + srcRGB = srcCM.getRGB(srcPixel); + dstRGB = dstCM.getRGB(dstPixel); + dstRGB = srcRGB ^ xorRGB ^ dstRGB; + + dstRGB = 0xff000000 | dstRGB; + dstPixel = dstCM.getDataElements(dstRGB, dstPixel); + dstRast.setDataElements(dx,dy,dstPixel); + + } + } + + } + + private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY, + ColorModel dstCM, WritableRaster dstR, int dstX, int dstY, + int width, int height, AffineTransform at, Composite comp, + Color bgcolor,MultiRectArea clip) { + + Rectangle srcBounds = new Rectangle(width, height); + Rectangle dstBlitBounds = new Rectangle(dstX, dstY, srcR.getWidth(), srcR.getHeight()); + + Rectangle transSrcBounds = getBounds2D(at, srcBounds).getBounds(); + Rectangle transDstBlitBounds = getBounds2D(at, dstBlitBounds).getBounds(); + + int translateX = transDstBlitBounds.x - transSrcBounds.x; + int translateY = transDstBlitBounds.y - transSrcBounds.y; + + AffineTransform inv = null; + try { + inv = at.createInverse(); + } catch (NoninvertibleTransformException e) { + return; + } + + double[] m = new double[6]; + inv.getMatrix(m); + + int clipRects[]; + if(clip != null) { + clipRects = clip.rect; + } else { + clipRects = new int[]{5, 0, 0, dstR.getWidth(), dstR.getHeight()}; + } + + int compType = 0; + int srcConstAlpha = 0; + int rule = 0; + int bgRGB = bgcolor == null ? 0 : bgcolor.getRGB(); + int srcRGB = 0, dstRGB = 0; + Object srcVal = null, dstVal = null; + if(comp instanceof AlphaComposite){ + compType = AlphaCompositeMode; + AlphaComposite ac = (AlphaComposite) comp; + rule = ac.getRule(); + srcConstAlpha = (int)(ac.getAlpha() * 255 + 0.5f); + }else if(comp instanceof XORComposite){ + compType = XORMode; + XORComposite xor = (XORComposite) comp; + bgRGB = xor.getXORColor().getRGB(); + } + + for(int i = 1; i < clipRects[0]; i += 4){ + Rectangle dstBounds = new Rectangle(clipRects[i], clipRects[i + 1], 0, 0); + dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 1]); + dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 3] + 1); + dstBounds.add(clipRects[i], clipRects[i + 3] + 1); + + Rectangle bounds = dstBounds.intersection(transDstBlitBounds); + + int minSrcX = srcBounds.x; + int minSrcY = srcBounds.y; + int maxSrcX = minSrcX + srcBounds.width; + int maxSrcY = minSrcY + srcBounds.height; + + int minX = bounds.x; + int minY = bounds.y; + int maxX = minX + bounds.width; + int maxY = minY + bounds.height; + + int hx = (int)((m[0] * 256) + 0.5); + int hy = (int)((m[1] * 256) + 0.5); + int vx = (int)((m[2] * 256) + 0.5); + int vy = (int)((m[3] * 256) + 0.5); + int sx = (int)((m[4] + m[0] * (bounds.x - translateX) + m[2] * (bounds.y - translateY)) * 256 + 0.5); + int sy = (int)((m[5] + m[1] * (bounds.x - translateX) + m[3] * (bounds.y - translateY)) * 256 + 0.5); + + vx -= hx * bounds.width; + vy -= hy * bounds.width; + + for(int y = minY; y < maxY; y++) { + for(int x = minX; x < maxX; x++) { + int px = sx >> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + switch(compType){ + case AlphaCompositeMode: + srcVal = srcR.getDataElements(px , py , null); + srcRGB = srcCM.getRGB(srcVal); + if(bgcolor != null){ + dstRGB = bgRGB; + }else{ + dstVal = dstR.getDataElements(x, y, null); + dstRGB = dstCM.getRGB(dstVal); + } + dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(), + dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(), + rule, srcConstAlpha); + dstVal = dstCM.getDataElements(dstRGB, null); + dstR.setDataElements(x, y, dstVal); + break; + + case XORMode: + srcVal = srcR.getDataElements(px , py , null); + srcRGB = srcCM.getRGB(srcVal); + dstVal = dstR.getDataElements(x, y, null); + dstRGB = dstCM.getRGB(dstVal); + dstRGB = srcRGB ^ bgRGB; + + dstRGB = 0xff000000 | dstRGB; + dstVal = dstCM.getDataElements(dstRGB, null); + dstR.setDataElements(x, y, dstVal); + break; + + default: + // awt.37=Unknown composite type {0} + throw new IllegalArgumentException(Messages.getString("awt.37", //$NON-NLS-1$ + comp.getClass())); + } + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } + + } + + private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) { + int x = r.x; + int y = r.y; + int width = r.width; + int height = r.height; + + float[] corners = { + x, y, + x + width, y, + x + width, y + height, + x, y + height + }; + + at.transform(corners, 0, corners, 0, 4); + + Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0); + bounds.add(corners[2], corners[3]); + bounds.add(corners[4], corners[5]); + bounds.add(corners[6], corners[7]); + + return bounds; + } + + private int compose(int srcRGB, boolean isSrcAlphaPre, + int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre, + int rule, int srcConstAlpha){ + + int sa, sr, sg, sb, da, dr, dg, db; + + sa = (srcRGB >> 24) & 0xff; + sr = (srcRGB >> 16) & 0xff; + sg = (srcRGB >> 8) & 0xff; + sb = srcRGB & 0xff; + + if(isSrcAlphaPre){ + sa = mulLUT[srcConstAlpha][sa] & 0xff; + sr = mulLUT[srcConstAlpha][sr] & 0xff; + sg = mulLUT[srcConstAlpha][sg] & 0xff; + sb = mulLUT[srcConstAlpha][sb] & 0xff; + }else{ + sa = mulLUT[srcConstAlpha][sa] & 0xff; + sr = mulLUT[sa][sr] & 0xff; + sg = mulLUT[sa][sg] & 0xff; + sb = mulLUT[sa][sb] & 0xff; + } + + da = (dstRGB >> 24) & 0xff; + dr = (dstRGB >> 16) & 0xff; + dg = (dstRGB >> 8) & 0xff; + db = dstRGB & 0xff; + + if(!isDstAlphaPre){ + dr = mulLUT[da][dr] & 0xff; + dg = mulLUT[da][dg] & 0xff; + db = mulLUT[da][db] & 0xff; + } + + int Fs = 0; + int Fd = 0; + switch(rule){ + case AlphaComposite.CLEAR: + break; + + case AlphaComposite.DST: + Fd = 255; + break; + + case AlphaComposite.DST_ATOP: + Fs = 255 - da; + Fd = sa; + break; + + case AlphaComposite.DST_IN: + Fd = sa; + break; + + case AlphaComposite.DST_OUT: + Fd = 255 - sa; + break; + + case AlphaComposite.DST_OVER: + Fs = 255 - da; + Fd = 255; + break; + + case AlphaComposite.SRC: + Fs = 255; + break; + + case AlphaComposite.SRC_ATOP: + Fs = da; + Fd = 255 - sa; + break; + + case AlphaComposite.SRC_IN: + Fs = da; + break; + + case AlphaComposite.SRC_OUT: + Fs = 255 - da; + break; + + case AlphaComposite.SRC_OVER: + Fs = 255; + Fd = 255 - sa; + break; + + case AlphaComposite.XOR: + Fs = 255 - da; + Fd = 255 - sa; + break; + } + dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff); + dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff); + db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff); + + da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff); + + if(!isDstAlphaPre){ + if(da != 255){ + dr = divLUT[da][dr] & 0xff; + dg = divLUT[da][dg] & 0xff; + db = divLUT[da][db] & 0xff; + } + } + if(!dstHasAlpha) { + da = 0xff; + } + dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db; + + return dstRGB; + + } + +} |