summaryrefslogtreecommitdiffstats
path: root/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
diff options
context:
space:
mode:
Diffstat (limited to 'awt/org/apache/harmony/awt/gl/render/JavaBlitter.java')
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaBlitter.java611
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;
+
+ }
+
+}