0001: /*
0002: *
0003: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0005: *
0006: * This program is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU General Public License version
0008: * 2 only, as published by the Free Software Foundation.
0009: *
0010: * This program is distributed in the hope that it will be useful, but
0011: * WITHOUT ANY WARRANTY; without even the implied warranty of
0012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013: * General Public License version 2 for more details (a copy is
0014: * included at /legal/license.txt).
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * version 2 along with this work; if not, write to the Free Software
0018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0019: * 02110-1301 USA
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0022: * Clara, CA 95054 or visit www.sun.com if you need additional
0023: * information or have any questions.
0024: */
0025:
0026: package com.sun.pisces;
0027:
0028: public class Blit {
0029:
0030: public static final int COMPOSITE_SRC_OVER = 1;
0031:
0032: private static final int TYPE_INT_RGB = Renderer.TYPE_INT_RGB;
0033: private static final int TYPE_INT_ARGB = Renderer.TYPE_INT_ARGB;
0034: private static final int TYPE_USHORT_565_RGB = Renderer.TYPE_USHORT_565_RGB;
0035: private static final int TYPE_BYTE_GRAY = Renderer.TYPE_BYTE_GRAY;
0036:
0037: private static final int MAX_ALPHA = 256;
0038: private static final int HALF_ALPHA = MAX_ALPHA >> 1;
0039: private static final int MIN_ALPHA = 0;
0040: private static final int ALPHA_SHIFT = 8;
0041:
0042: // Lookup tables to convert 5 or 6 bit color values to 8 bits
0043: // with proper rounding
0044: public static int[] convert8To5;
0045: public static int[] convert8To6;
0046:
0047: static {
0048: convert8To5 = new int[256];
0049: convert8To6 = new int[256];
0050:
0051: for (int i = 0; i < 256; i++) {
0052: convert8To5[i] = (i * 31 + 127) / 255;
0053: convert8To6[i] = (i * 63 + 127) / 255;
0054: }
0055: }
0056:
0057: // 8-bit blend against a constant RGB color
0058: private static void blend888(int[] intData, int iidx, int aval,
0059: int cred, int cgreen, int cblue) {
0060: int ival = intData[iidx];
0061: int red = (ival >> 16) & 0xff;
0062: int green = (ival >> 8) & 0xff;
0063: int blue = ival & 0xff;
0064:
0065: int nred = (red << ALPHA_SHIFT) + (cred - red) * aval
0066: + HALF_ALPHA;
0067: nred >>= ALPHA_SHIFT;
0068:
0069: int ngreen = (green << ALPHA_SHIFT) + (cgreen - green) * aval
0070: + HALF_ALPHA;
0071: ngreen >>= ALPHA_SHIFT;
0072:
0073: int nblue = (blue << ALPHA_SHIFT) + (cblue - blue) * aval
0074: + HALF_ALPHA;
0075: nblue >>= ALPHA_SHIFT;
0076:
0077: ival = 0xff000000 | (nred << 16) | (ngreen << 8) | nblue;
0078: intData[iidx] = ival;
0079: }
0080:
0081: // 8-bit blend against an ARGB color
0082: private static void blend8888(int[] intData, int iidx, int aval,
0083: int sred, int sgreen, int sblue) {
0084: int ival = intData[iidx];
0085: int dalpha = (ival >> 24) & 0xff;
0086: int dred = (ival >> 16) & 0xff;
0087: int dgreen = (ival >> 8) & 0xff;
0088: int dblue = ival & 0xff;
0089:
0090: int denom = 256 * dalpha + aval * (255 - dalpha);
0091: if (denom == 0) {
0092: // dalpha and aval must both be 0
0093: // The output is transparent black
0094: intData[iidx] = 0x00000000;
0095: } else {
0096: long recip = (1L << 24) / denom;
0097: long fa = (256 - aval) * dalpha * recip;
0098: long fb = 255 * aval * recip;
0099: int oalpha = denom >> 8;
0100: int ored = (int) ((fa * dred + fb * sred) >> 24);
0101: int ogreen = (int) ((fa * dgreen + fb * sgreen) >> 24);
0102: int oblue = (int) ((fa * dblue + fb * sblue) >> 24);
0103:
0104: ival = (oalpha << 24) | (ored << 16) | (ogreen << 8)
0105: | oblue;
0106: intData[iidx] = ival;
0107:
0108: // float fsalpha = aval/256.0f; // N.B.: 256 not 255
0109: // float fsred = sred/255.0f;
0110: // float fsgreen = sgreen/255.0f;
0111: // float fsblue = sblue/255.0f;
0112: // float fdalpha = dalpha/255.0f;
0113: // float fdred = dred/255.0f;
0114: // float fdgreen = dgreen/255.0f;
0115: // float fdblue = dblue/255.0f;
0116: // float fsred_pre = fsred*fsalpha;
0117: // float fsgreen_pre = fsgreen*fsalpha;
0118: // float fsblue_pre = fsblue*fsalpha;
0119: // float fdred_pre = fdred*fdalpha;
0120: // float fdgreen_pre = fdgreen*fdalpha;
0121: // float fdblue_pre = fdblue*fdalpha;
0122: // float foalpha = fsalpha + fdalpha*(1.0f - fsalpha);
0123: // float fored_pre = fsred_pre + fdred_pre*(1.0f - fsalpha);
0124: // float fogreen_pre = fsgreen_pre + fdgreen_pre*(1.0f - fsalpha);
0125: // float foblue_pre = fsblue_pre + fdblue_pre*(1.0f - fsalpha);
0126: // float fored = fored_pre/foalpha;
0127: // float fogreen = fogreen_pre/foalpha;
0128: // float foblue = foblue_pre/foalpha;
0129: // int oalpha2 = (int)(foalpha*255.0f);
0130: // int ored2 = (int)(fored*255.0f);
0131: // int ogreen2 = (int)(fogreen*255.0f);
0132: // int oblue2 = (int)(foblue*255.0f);
0133:
0134: // if ((Math.abs(oalpha2 - oalpha) > 1) ||
0135: // (Math.abs(ored2 - ored) > 1) ||
0136: // (Math.abs(ogreen2 - ogreen) > 1) ||
0137: // (Math.abs(oblue2 - oblue) > 1)) {
0138: // System.out.println("\naval = " + aval);
0139: // System.out.println("sred = " + sred);
0140: // System.out.println("sgreen = " + sgreen);
0141: // System.out.println("sblue = " + sblue);
0142: // System.out.println("dalpha = " + dalpha);
0143: // System.out.println("dred = " + dred);
0144: // System.out.println("dgreen = " + dgreen);
0145: // System.out.println("dblue = " + dblue);
0146:
0147: // System.out.println("oalpha = " + oalpha);
0148: // System.out.println("oalpha2 = " + oalpha2);
0149: // System.out.println("ored = " + ored);
0150: // System.out.println("ored2 = " + ored2);
0151: // System.out.println("ogreen = " + ogreen);
0152: // System.out.println("ogreen2 = " + ogreen2);
0153: // System.out.println("oblue = " + oblue);
0154: // System.out.println("oblue2 = " + oblue2);
0155: // }
0156: }
0157: }
0158:
0159: // public static void main(String[] args) {
0160: // int[] intData = new int[1];
0161: // java.util.Random r = new java.util.Random();
0162:
0163: // System.out.println("Testing general case");
0164: // for (int i = 0; i < 10000000; i++) {
0165: // int da = r.nextInt(256);
0166: // int dr = r.nextInt(256);
0167: // int dg = r.nextInt(256);
0168: // int db = r.nextInt(256);
0169:
0170: // int aval = r.nextInt(257);
0171: // int sr = r.nextInt(256);
0172: // int sg = r.nextInt(256);
0173: // int sb = r.nextInt(256);
0174:
0175: // intData[0] = (da << 24) | (dr << 16) | (dg << 8) | db;
0176: // blend8888(intData, 0, aval, sr, sg, sb);
0177: // }
0178:
0179: // System.out.println("Testing aval = 256, da = 255");
0180: // for (int i = 0; i < 10000000; i++) {
0181: // int da = r.nextInt(256);
0182: // int dr = r.nextInt(256);
0183: // int dg = r.nextInt(256);
0184: // int db = r.nextInt(256);
0185:
0186: // int aval = r.nextInt(257);
0187: // int sr = r.nextInt(256);
0188: // int sg = r.nextInt(256);
0189: // int sb = r.nextInt(256);
0190:
0191: // aval = 256;
0192: // da = 255;
0193:
0194: // intData[0] = (da << 24) | (dr << 16) | (dg << 8) | db;
0195: // blend8888(intData, 0, aval, sr, sg, sb);
0196: // }
0197:
0198: // System.out.println("Testing aval = 256, da = 0");
0199: // for (int i = 0; i < 10000000; i++) {
0200: // int da = r.nextInt(256);
0201: // int dr = r.nextInt(256);
0202: // int dg = r.nextInt(256);
0203: // int db = r.nextInt(256);
0204:
0205: // int aval = r.nextInt(257);
0206: // int sr = r.nextInt(256);
0207: // int sg = r.nextInt(256);
0208: // int sb = r.nextInt(256);
0209:
0210: // aval = 256;
0211: // da = 0;
0212:
0213: // intData[0] = (da << 24) | (dr << 16) | (dg << 8) | db;
0214: // blend8888(intData, 0, aval, sr, sg, sb);
0215: // }
0216:
0217: // System.out.println("Testing aval = 0, da = 255");
0218: // for (int i = 0; i < 10000000; i++) {
0219: // int da = r.nextInt(256);
0220: // int dr = r.nextInt(256);
0221: // int dg = r.nextInt(256);
0222: // int db = r.nextInt(256);
0223:
0224: // int aval = r.nextInt(257);
0225: // int sr = r.nextInt(256);
0226: // int sg = r.nextInt(256);
0227: // int sb = r.nextInt(256);
0228:
0229: // aval = 0;
0230: // da = 255;
0231:
0232: // intData[0] = (da << 24) | (dr << 16) | (dg << 8) | db;
0233: // blend8888(intData, 0, aval, sr, sg, sb);
0234: // }
0235:
0236: // System.out.println("Testing aval = 0, da = 0");
0237: // for (int i = 0; i < 10000000; i++) {
0238: // int da = r.nextInt(256);
0239: // int dr = r.nextInt(256);
0240: // int dg = r.nextInt(256);
0241: // int db = r.nextInt(256);
0242:
0243: // int aval = r.nextInt(257);
0244: // int sr = r.nextInt(256);
0245: // int sg = r.nextInt(256);
0246: // int sb = r.nextInt(256);
0247:
0248: // aval = 0;
0249: // da = 0;
0250:
0251: // intData[0] = (da << 24) | (dr << 16) | (dg << 8) | db;
0252: // blend8888(intData, 0, aval, sr, sg, sb);
0253: // }
0254: // }
0255:
0256: private static void blend565(short[] shortData, int iidx, int aval,
0257: int cred5, int cgreen6, int cblue5) {
0258: short sval = shortData[iidx];
0259: int red = (sval >> 11) & 0x1f;
0260: int green = (sval >> 5) & 0x3f;
0261: int blue = sval & 0x1f;
0262:
0263: int nred = (red << ALPHA_SHIFT) + (cred5 - red) * aval
0264: + HALF_ALPHA;
0265: nred >>= ALPHA_SHIFT;
0266:
0267: int ngreen = (green << ALPHA_SHIFT) + (cgreen6 - green) * aval
0268: + HALF_ALPHA;
0269: ngreen >>= ALPHA_SHIFT;
0270:
0271: int nblue = (blue << ALPHA_SHIFT) + (cblue5 - blue) * aval
0272: + HALF_ALPHA;
0273: nblue >>= ALPHA_SHIFT;
0274:
0275: sval = (short) ((nred << 11) | (ngreen << 5) | nblue);
0276: shortData[iidx] = sval;
0277: }
0278:
0279: private static void blend8(byte[] byteData, int iidx, int aval,
0280: int cgray) {
0281: int gray = byteData[iidx] & 0xff;
0282:
0283: int ngray = (gray << ALPHA_SHIFT) + (cgray - gray) * aval
0284: + HALF_ALPHA;
0285: ngray >>= ALPHA_SHIFT;
0286:
0287: byteData[iidx] = (byte) ngray;
0288: }
0289:
0290: private static void blitSrcOver888(int[] intData, int imageOffset,
0291: int imageScanlineStride, int imagePixelStride,
0292: byte[] alpha, int alphaOffset, int width, int height,
0293: int[] minTouched, int[] maxTouched, int[] rowOffsets,
0294: int cred, int cgreen, int cblue, int calpha, int[] alphaMap) {
0295: int cval = 0xff000000 | (cred << 16) | (cgreen << 8) | cblue;
0296:
0297: for (int j = 0; j < height; j++) {
0298: int minX = minTouched[j];
0299: int maxX = maxTouched[j];
0300:
0301: int aidx = alphaOffset + rowOffsets[j] + minX;
0302: int iidx = imageOffset + minX * imagePixelStride;
0303: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0304: if (w + minX > width) {
0305: w = width - minX;
0306: }
0307:
0308: for (int i = 0; i < w; i++, aidx++, iidx += imagePixelStride) {
0309: int aval = alphaMap[alpha[aidx] & 0xff];
0310: if (aval == 0) {
0311: continue;
0312: } else if (aval == MAX_ALPHA) {
0313: intData[iidx] = cval;
0314: } else {
0315: blend888(intData, iidx, aval, cred, cgreen, cblue);
0316: }
0317: }
0318:
0319: imageOffset += imageScanlineStride;
0320: }
0321: }
0322:
0323: private static void blitSrcOver8888(int[] intData, int imageOffset,
0324: int imageScanlineStride, int imagePixelStride,
0325: byte[] alpha, int alphaOffset, int width, int height,
0326: int[] minTouched, int[] maxTouched, int[] rowOffsets,
0327: int cred, int cgreen, int cblue, int calpha, int[] alphaMap) {
0328: int cval = 0xff000000 | (cred << 16) | (cgreen << 8) | cblue;
0329:
0330: for (int j = 0; j < height; j++) {
0331: int minX = minTouched[j];
0332: int maxX = maxTouched[j];
0333:
0334: int aidx = alphaOffset + rowOffsets[j] + minX;
0335: int iidx = imageOffset + minX * imagePixelStride;
0336: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0337: if (w + minX > width) {
0338: w = width - minX;
0339: }
0340:
0341: for (int i = 0; i < w; i++, aidx++, iidx += imagePixelStride) {
0342: int aval = alphaMap[alpha[aidx] & 0xff];
0343: if (aval == 0) {
0344: continue;
0345: } else if (aval == MAX_ALPHA) {
0346: intData[iidx] = cval;
0347: } else {
0348: blend8888(intData, iidx, aval, cred, cgreen, cblue);
0349: }
0350: }
0351:
0352: imageOffset += imageScanlineStride;
0353: }
0354: }
0355:
0356: private static void blitSrcOver565(short[] shortData,
0357: int imageOffset, int imageScanlineStride,
0358: int imagePixelStride, byte[] alpha, int alphaOffset,
0359: int width, int height, int[] minTouched, int[] maxTouched,
0360: int[] rowOffsets, int cred5, int cgreen6, int cblue5,
0361: int calpha, int[] alphaMap) {
0362: short cval = (short) ((cred5 << 11) | (cgreen6 << 5) | (cblue5));
0363:
0364: for (int j = 0; j < height; j++) {
0365: int minX = minTouched[j];
0366: int maxX = maxTouched[j];
0367:
0368: int aidx = alphaOffset + rowOffsets[j] + minX;
0369: int iidx = imageOffset + minX * imagePixelStride;
0370: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0371: if (w + minX > width) {
0372: w = width - minX;
0373: }
0374:
0375: for (int i = 0; i < w; i++, aidx++, iidx += imagePixelStride) {
0376: int aval = alphaMap[alpha[aidx] & 0xff];
0377: if (aval == MIN_ALPHA) {
0378: continue;
0379: } else if (aval == MAX_ALPHA) {
0380: shortData[iidx] = cval;
0381: } else {
0382: blend565(shortData, iidx, aval, cred5, cgreen6,
0383: cblue5);
0384: }
0385: }
0386:
0387: imageOffset += imageScanlineStride;
0388: }
0389: }
0390:
0391: private static void blitSrcOver8(byte[] byteData, int imageOffset,
0392: int imageScanlineStride, int imagePixelStride,
0393: byte[] alpha, int alphaOffset, int width, int height,
0394: int[] minTouched, int[] maxTouched, int[] rowOffsets,
0395: int cgray, int calpha, int[] alphaMap) {
0396: byte cval = (byte) cgray;
0397:
0398: for (int j = 0; j < height; j++) {
0399: int minX = minTouched[j];
0400: int maxX = maxTouched[j];
0401:
0402: int aidx = alphaOffset + rowOffsets[j] + minX;
0403: int iidx = imageOffset + minX * imagePixelStride;
0404: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0405: if (w + minX > width) {
0406: w = width - minX;
0407: }
0408:
0409: for (int i = 0; i < w; i++, aidx++, iidx += imagePixelStride) {
0410: int aval = alphaMap[alpha[aidx] & 0xff];
0411: if (aval == 0) {
0412: continue;
0413: } else if (aval == MAX_ALPHA) {
0414: byteData[iidx] = cval;
0415: } else {
0416: blend8(byteData, iidx, aval, cgray);
0417: }
0418: }
0419:
0420: imageOffset += imageScanlineStride;
0421: }
0422: }
0423:
0424: // blit 888 w/ paint
0425: private static void blitSrcOver888(int[] intData, int imageOffset,
0426: int imageScanlineStride, int imagePixelStride,
0427: byte[] alpha, int alphaOffset, int width, int height,
0428: int[] minTouched, int[] maxTouched, int[] rowOffsets,
0429: int[] paintData, int paintOffset, int paintScanlineStride,
0430: int[] alphaMap) {
0431: for (int j = 0; j < height; j++) {
0432: int minX = minTouched[j];
0433: int maxX = maxTouched[j];
0434:
0435: int aidx = alphaOffset + rowOffsets[j] + minX;
0436: int pidx = paintOffset + minX;
0437: int iidx = imageOffset + minX * imagePixelStride;
0438: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0439: if (w + minX > width) {
0440: w = width - minX;
0441: }
0442:
0443: for (int i = 0; i < w; i++, aidx++, pidx++, iidx += imagePixelStride) {
0444: int aval = alphaMap[alpha[aidx] & 0xff];
0445:
0446: // Combine AA alpha with paint alpha
0447: // IMPL NOTE : This could be sped up somehow...
0448: int paint = paintData[pidx];
0449: int calpha = (paint >> 24) & 0xff;
0450: aval = (aval * calpha + 127) / 255;
0451:
0452: if (aval == 0) {
0453: continue;
0454: } else if (aval == MAX_ALPHA) {
0455: // Force output alpha to 1
0456: intData[iidx] = paintData[pidx] | 0xff000000;
0457: } else {
0458: int cred = (paint >> 16) & 0xff;
0459: int cgreen = (paint >> 8) & 0xff;
0460: int cblue = paint & 0xff;
0461:
0462: blend888(intData, iidx, aval, cred, cgreen, cblue);
0463: }
0464: }
0465:
0466: paintOffset += paintScanlineStride;
0467: imageOffset += imageScanlineStride;
0468: }
0469: }
0470:
0471: // blit 8888 w/ paint
0472: private static void blitSrcOver8888(int[] intData, int imageOffset,
0473: int imageScanlineStride, int imagePixelStride,
0474: byte[] alpha, int alphaOffset, int width, int height,
0475: int[] minTouched, int[] maxTouched, int[] rowOffsets,
0476: int[] paintData, int paintOffset, int paintScanlineStride,
0477: int[] alphaMap) {
0478: for (int j = 0; j < height; j++) {
0479: int minX = minTouched[j];
0480: int maxX = maxTouched[j];
0481:
0482: int aidx = alphaOffset + rowOffsets[j] + minX;
0483: int pidx = paintOffset + minX;
0484: int iidx = imageOffset + minX * imagePixelStride;
0485: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0486: if (w + minX > width) {
0487: w = width - minX;
0488: }
0489:
0490: for (int i = 0; i < w; i++, aidx++, pidx++, iidx += imagePixelStride) {
0491: int aval = alphaMap[alpha[aidx] & 0xff];
0492:
0493: // Combine AA alpha with paint alpha
0494: // IMPL NOTE : This could be sped up somehow...
0495: int paint = paintData[pidx];
0496: int calpha = (paint >> 24) & 0xff;
0497: aval = (aval * calpha + 127) / 255;
0498:
0499: if (aval == 0) {
0500: continue;
0501: } else if (aval == MAX_ALPHA) {
0502: intData[iidx] = paintData[pidx];
0503: } else {
0504: int cred = (paint >> 16) & 0xff;
0505: int cgreen = (paint >> 8) & 0xff;
0506: int cblue = paint & 0xff;
0507:
0508: blend8888(intData, iidx, aval, cred, cgreen, cblue);
0509: }
0510: }
0511:
0512: paintOffset += paintScanlineStride;
0513: imageOffset += imageScanlineStride;
0514: }
0515: }
0516:
0517: // blit 565 w/ paint
0518: private static void blitSrcOver565(short[] shortData,
0519: int imageOffset, int imageScanlineStride,
0520: int imagePixelStride, byte[] alpha, int alphaOffset,
0521: int width, int height, int[] minTouched, int[] maxTouched,
0522: int[] rowOffsets, int[] paintData, int paintOffset,
0523: int paintScanlineStride, int[] alphaMap) {
0524: for (int j = 0; j < height; j++) {
0525: int minX = minTouched[j];
0526: int maxX = maxTouched[j];
0527:
0528: int aidx = alphaOffset + rowOffsets[j] + minX;
0529: int pidx = paintOffset + minX;
0530: int iidx = imageOffset + minX * imagePixelStride;
0531: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0532: if (w + minX > width) {
0533: w = width - minX;
0534: }
0535:
0536: for (int i = 0; i < w; i++, aidx++, pidx++, iidx += imagePixelStride) {
0537: int aval = alphaMap[alpha[aidx] & 0xff];
0538: int paint = paintData[pidx];
0539: int calpha = (paint >> 24) & 0xff;
0540: // IMPL NOTE : This could be sped up somehow...
0541: aval = (aval * calpha + 127) / 255;
0542:
0543: if (aval == MIN_ALPHA) {
0544: continue;
0545: }
0546:
0547: int cred5 = convert8To5[(paint >> 16) & 0xff];
0548: int cgreen6 = convert8To6[(paint >> 8) & 0xff];
0549: int cblue5 = convert8To5[paint & 0xff];
0550:
0551: if (aval == MAX_ALPHA) {
0552: shortData[iidx] = (short) ((cred5 << 11)
0553: | (cgreen6 << 5) | cblue5);
0554: } else {
0555: blend565(shortData, iidx, aval, cred5, cgreen6,
0556: cblue5);
0557: }
0558: }
0559:
0560: paintOffset += paintScanlineStride;
0561: imageOffset += imageScanlineStride;
0562: }
0563: }
0564:
0565: // blit 8 w/ paint
0566: private static void blitSrcOver8(byte[] byteData, int imageOffset,
0567: int imageScanlineStride, int imagePixelStride,
0568: byte[] alpha, int alphaOffset, int width, int height,
0569: int[] minTouched, int[] maxTouched, int[] rowOffsets,
0570: int[] paintData, int paintOffset, int paintScanlineStride,
0571: int[] alphaMap) {
0572: for (int j = 0; j < height; j++) {
0573: int minX = minTouched[j];
0574: int maxX = maxTouched[j];
0575:
0576: int aidx = alphaOffset + rowOffsets[j] + minX;
0577: int pidx = paintOffset + minX;
0578: int iidx = imageOffset + minX * imagePixelStride;
0579: int w = (maxX >= minX) ? (maxX - minX + 1) : 0;
0580: if (w + minX > width) {
0581: w = width - minX;
0582: }
0583:
0584: for (int i = 0; i < w; i++, aidx++, pidx++, iidx += imagePixelStride) {
0585: int aval = alphaMap[alpha[aidx] & 0xff];
0586: int paint = paintData[pidx];
0587: int calpha = (paint >> 24) & 0xff;
0588: // IMPL NOTE : This could be sped up somehow...
0589: aval = (aval * calpha + 127) / 255;
0590:
0591: if (aval == MIN_ALPHA) {
0592: continue;
0593: }
0594:
0595: int cred = (paint >> 16) & 0xff;
0596: int cgreen = (paint >> 8) & 0xff;
0597: int cblue = paint & 0xff;
0598:
0599: // gray = .3*red + .59*green + .11*blue
0600: int cgray = (19961 * cred + 38666 * cgreen + 7209 * cblue) >> 16;
0601:
0602: if (aval == MAX_ALPHA) {
0603: byteData[iidx] = (byte) cgray;
0604: } else {
0605: blend8(byteData, iidx, aval, cgray);
0606: }
0607: }
0608:
0609: paintOffset += paintScanlineStride;
0610: imageOffset += imageScanlineStride;
0611: }
0612: }
0613:
0614: private static void blendLine(Object imageData, int imageType,
0615: int imageOffset, int imageStride, int length, int alpha,
0616: int red, int green, int blue) {
0617: if (imageType == TYPE_INT_RGB) {
0618: int[] intData = (int[]) imageData;
0619: for (int i = 0; i < length; i++) {
0620: blend888(intData, imageOffset, alpha, red, green, blue);
0621: imageOffset += imageStride;
0622: }
0623: } else if (imageType == TYPE_INT_ARGB) {
0624: int[] intData = (int[]) imageData;
0625: for (int i = 0; i < length; i++) {
0626: blend8888(intData, imageOffset, alpha, red, green, blue);
0627: imageOffset += imageStride;
0628: }
0629: } else if (imageType == TYPE_USHORT_565_RGB) {
0630: short[] shortData = (short[]) imageData;
0631: for (int i = 0; i < length; i++) {
0632: blend565(shortData, imageOffset, alpha, red, green,
0633: blue);
0634: imageOffset += imageStride;
0635: }
0636: } else if (imageType == TYPE_USHORT_565_RGB) {
0637: byte[] byteData = (byte[]) imageData;
0638: for (int i = 0; i < length; i++) {
0639: blend8(byteData, imageOffset, alpha, red);
0640: imageOffset += imageStride;
0641: }
0642: }
0643: }
0644:
0645: // Assumes x0, y1, x1, y1 are in supersampled coordinate space
0646: //
0647: // All are >= 0
0648: // x0, x1 < width*SUBPIXEL_POSITIONS_X,
0649: // y0, y1 < height*SUBPIXEL_POSITIONS_Y
0650:
0651: public static void fillRectSrcOver(Renderer rdr, Object imageData,
0652: int imageType, int imageOffset, int imageScanlineStride,
0653: int imagePixelStride, int width, int height, int x0,
0654: int y0, int x1, int y1, int red, int green, int blue) {
0655: int SUBPIXEL_LG_POSITIONS_X = rdr.getSubpixelLgPositionsX();
0656: int SUBPIXEL_LG_POSITIONS_Y = rdr.getSubpixelLgPositionsY();
0657: int SUBPIXEL_MASK_X = (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1;
0658: int SUBPIXEL_MASK_Y = (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1;
0659: int SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X);
0660: int SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
0661:
0662: int xmask_l = SUBPIXEL_POSITIONS_X - (x0 & SUBPIXEL_MASK_X);
0663: if (xmask_l == SUBPIXEL_POSITIONS_X) {
0664: xmask_l = 0;
0665: } else {
0666: x0 += SUBPIXEL_POSITIONS_X;
0667: }
0668: int xmask_r = x1 & SUBPIXEL_MASK_X;
0669:
0670: int ymask_t = SUBPIXEL_POSITIONS_X - (y0 & SUBPIXEL_MASK_X);
0671: if (ymask_t == SUBPIXEL_POSITIONS_Y) {
0672: ymask_t = 0;
0673: } else {
0674: y0 += SUBPIXEL_POSITIONS_Y;
0675: }
0676: int ymask_b = y1 & SUBPIXEL_MASK_X;
0677:
0678: int ix0 = x0 >> SUBPIXEL_LG_POSITIONS_X;
0679: int ix1 = (x1 >> SUBPIXEL_LG_POSITIONS_X) - 1;
0680: int iy0 = y0 >> SUBPIXEL_LG_POSITIONS_Y;
0681: int iy1 = (y1 >> SUBPIXEL_LG_POSITIONS_Y) - 1;
0682:
0683: width = ix1 - ix0 + 1;
0684: height = iy1 - iy0 + 1;
0685:
0686: int[] intData = null;
0687: short[] shortData = null;
0688: byte[] byteData = null;
0689: int intVal = 0;
0690: short shortVal = (short) 0;
0691: byte byteVal = (byte) 0;
0692:
0693: if (imageType == TYPE_INT_RGB || imageType == TYPE_INT_ARGB) {
0694: intData = (int[]) imageData;
0695: intVal = 0xff000000 | (red << 16) | (green << 8) | blue;
0696: } else if (imageType == TYPE_USHORT_565_RGB) {
0697: shortData = (short[]) imageData;
0698: shortVal = (short) ((red << 11) | (green << 5) | (blue));
0699: } else if (imageType == TYPE_BYTE_GRAY) {
0700: byteData = (byte[]) imageData;
0701: int gray = (19961 * red + 38666 * green + 7209 * blue) >> 16;
0702: red = green = blue = gray;
0703: byteVal = (byte) gray;
0704: }
0705:
0706: if (width > 0 && height > 0) {
0707: int offset = imageOffset + iy0 * imageScanlineStride + ix0
0708: * imagePixelStride;
0709: if (intData != null) {
0710: for (int j = 0; j < height; j++) {
0711: int iidx = offset;
0712: for (int i = 0; i < width; i++) {
0713: intData[iidx] = intVal;
0714: iidx += imagePixelStride;
0715: }
0716: offset += imageScanlineStride;
0717: }
0718: } else if (shortData != null) {
0719: for (int j = 0; j < height; j++) {
0720: int iidx = offset;
0721: for (int i = 0; i < width; i++) {
0722: shortData[iidx] = shortVal;
0723: iidx += imagePixelStride;
0724: }
0725: offset += imageScanlineStride;
0726: }
0727: } else if (byteData != null) {
0728: for (int j = 0; j < height; j++) {
0729: int iidx = offset;
0730: for (int i = 0; i < width; i++) {
0731: byteData[iidx] = byteVal;
0732: iidx += imagePixelStride;
0733: }
0734: offset += imageScanlineStride;
0735: }
0736: }
0737: }
0738:
0739: int RECT_LR_SIDE_ALPHA_SHIFT = ALPHA_SHIFT
0740: - SUBPIXEL_LG_POSITIONS_X;
0741: int RECT_TB_SIDE_ALPHA_SHIFT = ALPHA_SHIFT
0742: - SUBPIXEL_LG_POSITIONS_Y;
0743: int RECT_CORNER_ALPHA_SHIFT = ALPHA_SHIFT
0744: - (SUBPIXEL_LG_POSITIONS_X + SUBPIXEL_LG_POSITIONS_Y);
0745:
0746: if (xmask_l != 0) {
0747: int offset = imageOffset + iy0 * imageScanlineStride
0748: + (ix0 - 1) * imagePixelStride;
0749: int alpha = xmask_l << RECT_LR_SIDE_ALPHA_SHIFT;
0750: blendLine(imageData, imageType, offset,
0751: imageScanlineStride, height, alpha, red, green,
0752: blue);
0753: }
0754:
0755: if (xmask_r != 0) {
0756: int offset = imageOffset + iy0 * imageScanlineStride
0757: + (ix1 + 1) * imagePixelStride;
0758: int alpha = xmask_r << RECT_LR_SIDE_ALPHA_SHIFT;
0759: blendLine(imageData, imageType, offset,
0760: imageScanlineStride, height, alpha, red, green,
0761: blue);
0762: }
0763:
0764: if (ymask_t != 0) {
0765: int offset = imageOffset + (iy0 - 1) * imageScanlineStride
0766: + ix0 * imagePixelStride;
0767: int alpha = ymask_t << RECT_TB_SIDE_ALPHA_SHIFT;
0768: blendLine(imageData, imageType, offset, imagePixelStride,
0769: width, alpha, red, green, blue);
0770: }
0771:
0772: if (ymask_b != 0) {
0773: int offset = imageOffset + (iy1 + 1) * imageScanlineStride
0774: + ix0 * imagePixelStride;
0775: int alpha = ymask_b << RECT_TB_SIDE_ALPHA_SHIFT;
0776: blendLine(imageData, imageType, offset, imagePixelStride,
0777: width, alpha, red, green, blue);
0778: }
0779:
0780: int alphaUL = xmask_l * ymask_t << RECT_CORNER_ALPHA_SHIFT;
0781: int alphaUR = xmask_r * ymask_t << RECT_CORNER_ALPHA_SHIFT;
0782: int alphaLL = xmask_l * ymask_b << RECT_CORNER_ALPHA_SHIFT;
0783: int alphaLR = xmask_r * ymask_b << RECT_CORNER_ALPHA_SHIFT;
0784:
0785: switch (imageType) {
0786: case TYPE_INT_RGB:
0787: if (alphaUL > 0) {
0788: blend888(intData, imageOffset + (iy0 - 1)
0789: * imageScanlineStride + (ix0 - 1)
0790: * imagePixelStride, alphaUL, red, green, blue);
0791: }
0792: if (alphaUR > 0) {
0793: blend888(intData, imageOffset + (iy0 - 1)
0794: * imageScanlineStride + (ix1 + 1)
0795: * imagePixelStride, alphaUR, red, green, blue);
0796: }
0797: if (alphaLL > 0) {
0798: blend888(intData, imageOffset + (iy1 + 1)
0799: * imageScanlineStride + (ix0 - 1)
0800: * imagePixelStride, alphaLL, red, green, blue);
0801: }
0802: if (alphaLR > 0) {
0803: blend888(intData, imageOffset + (iy1 + 1)
0804: * imageScanlineStride + (ix1 + 1)
0805: * imagePixelStride, alphaLR, red, green, blue);
0806: }
0807: break;
0808:
0809: case TYPE_INT_ARGB:
0810: if (alphaUL > 0) {
0811: blend8888(intData, imageOffset + (iy0 - 1)
0812: * imageScanlineStride + (ix0 - 1)
0813: * imagePixelStride, alphaUL, red, green, blue);
0814: }
0815: if (alphaUR > 0) {
0816: blend8888(intData, imageOffset + (iy0 - 1)
0817: * imageScanlineStride + (ix1 + 1)
0818: * imagePixelStride, alphaUR, red, green, blue);
0819: }
0820: if (alphaLL > 0) {
0821: blend8888(intData, imageOffset + (iy1 + 1)
0822: * imageScanlineStride + (ix0 - 1)
0823: * imagePixelStride, alphaLL, red, green, blue);
0824: }
0825: if (alphaLR > 0) {
0826: blend8888(intData, imageOffset + (iy1 + 1)
0827: * imageScanlineStride + (ix1 + 1)
0828: * imagePixelStride, alphaLR, red, green, blue);
0829: }
0830: break;
0831:
0832: case TYPE_USHORT_565_RGB:
0833: if (alphaUL > 0) {
0834: blend565(shortData, imageOffset + (iy0 - 1)
0835: * imageScanlineStride + (ix0 - 1)
0836: * imagePixelStride, alphaUL, red, green, blue);
0837: }
0838: if (alphaUR > 0) {
0839: blend565(shortData, imageOffset + (iy0 - 1)
0840: * imageScanlineStride + (ix1 + 1)
0841: * imagePixelStride, alphaUR, red, green, blue);
0842: }
0843: if (alphaLL > 0) {
0844: blend565(shortData, imageOffset + (iy1 + 1)
0845: * imageScanlineStride + (ix0 - 1)
0846: * imagePixelStride, alphaLL, red, green, blue);
0847: }
0848: if (alphaLR > 0) {
0849: blend565(shortData, imageOffset + (iy1 + 1)
0850: * imageScanlineStride + (ix1 + 1)
0851: * imagePixelStride, alphaLR, red, green, blue);
0852: }
0853: break;
0854:
0855: case TYPE_BYTE_GRAY:
0856: if (alphaUL > 0) {
0857: blend8(byteData, imageOffset + (iy0 - 1)
0858: * imageScanlineStride + (ix0 - 1)
0859: * imagePixelStride, alphaUL, red);
0860: }
0861: if (alphaUR > 0) {
0862: blend8(byteData, imageOffset + (iy0 - 1)
0863: * imageScanlineStride + (ix1 + 1)
0864: * imagePixelStride, alphaUR, red);
0865: }
0866: if (alphaLL > 0) {
0867: blend8(byteData, imageOffset + (iy1 + 1)
0868: * imageScanlineStride + (ix0 - 1)
0869: * imagePixelStride, alphaLL, red);
0870: }
0871: if (alphaLR > 0) {
0872: blend8(byteData, imageOffset + (iy1 + 1)
0873: * imageScanlineStride + (ix1 + 1)
0874: * imagePixelStride, alphaLR, red);
0875: }
0876: break;
0877: }
0878: }
0879:
0880: public static void blit(Object imageData, int imageType,
0881: int imageOffset, int imageScanlineStride,
0882: int imagePixelStride, byte[] alphaData, int alphaOffset,
0883: int width, int height, int[] minTouched, int[] maxTouched,
0884: int[] rowOffsets, int compositeRule, int red, int green,
0885: int blue, int alpha, int[] alphaMap) {
0886: switch (compositeRule) {
0887: case COMPOSITE_SRC_OVER:
0888: switch (imageType) {
0889: case TYPE_INT_RGB:
0890: blitSrcOver888((int[]) imageData, imageOffset,
0891: imageScanlineStride, imagePixelStride,
0892: alphaData, alphaOffset, width, height,
0893: minTouched, maxTouched, rowOffsets, red, green,
0894: blue, alpha, alphaMap);
0895: return;
0896:
0897: case TYPE_INT_ARGB:
0898: blitSrcOver8888((int[]) imageData, imageOffset,
0899: imageScanlineStride, imagePixelStride,
0900: alphaData, alphaOffset, width, height,
0901: minTouched, maxTouched, rowOffsets, red, green,
0902: blue, alpha, alphaMap);
0903: return;
0904:
0905: case TYPE_USHORT_565_RGB:
0906: blitSrcOver565((short[]) imageData, imageOffset,
0907: imageScanlineStride, imagePixelStride,
0908: alphaData, alphaOffset, width, height,
0909: minTouched, maxTouched, rowOffsets, red, green,
0910: blue, alpha, alphaMap);
0911: return;
0912:
0913: case TYPE_BYTE_GRAY:
0914: int gray = (int) (0.3f * red + 0.59f * green + 0.11f
0915: * blue + 0.5f);
0916: blitSrcOver8((byte[]) imageData, imageOffset,
0917: imageScanlineStride, imagePixelStride,
0918: alphaData, alphaOffset, width, height,
0919: minTouched, maxTouched, rowOffsets, gray,
0920: alpha, alphaMap);
0921: return;
0922: }
0923: break;
0924:
0925: default:
0926: throw new RuntimeException("Unknown composite rule!");
0927: }
0928:
0929: throw new RuntimeException(
0930: "Unknown composite/type combination!");
0931: }
0932:
0933: public static void blit(Object imageData, int imageType,
0934: int imageOffset, int imageScanlineStride,
0935: int imagePixelStride, byte[] alphaData, int alphaOffset,
0936: int width, int height, int[] minTouched, int[] maxTouched,
0937: int[] rowOffsets, int compositeRule, int[] paintData,
0938: int paintOffset, int paintScanlineStride, int[] alphaMap) {
0939: switch (compositeRule) {
0940:
0941: case COMPOSITE_SRC_OVER:
0942: switch (imageType) {
0943: case TYPE_INT_RGB:
0944: blitSrcOver888((int[]) imageData, imageOffset,
0945: imageScanlineStride, imagePixelStride,
0946: alphaData, alphaOffset, width, height,
0947: minTouched, maxTouched, rowOffsets, paintData,
0948: paintOffset, paintScanlineStride, alphaMap);
0949: return;
0950:
0951: case TYPE_INT_ARGB:
0952: blitSrcOver8888((int[]) imageData, imageOffset,
0953: imageScanlineStride, imagePixelStride,
0954: alphaData, alphaOffset, width, height,
0955: minTouched, maxTouched, rowOffsets, paintData,
0956: paintOffset, paintScanlineStride, alphaMap);
0957: return;
0958:
0959: case TYPE_USHORT_565_RGB:
0960: blitSrcOver565((short[]) imageData, imageOffset,
0961: imageScanlineStride, imagePixelStride,
0962: alphaData, alphaOffset, width, height,
0963: minTouched, maxTouched, rowOffsets, paintData,
0964: paintOffset, paintScanlineStride, alphaMap);
0965: return;
0966:
0967: case TYPE_BYTE_GRAY:
0968: blitSrcOver8((byte[]) imageData, imageOffset,
0969: imageScanlineStride, imagePixelStride,
0970: alphaData, alphaOffset, width, height,
0971: minTouched, maxTouched, rowOffsets, paintData,
0972: paintOffset, paintScanlineStride, alphaMap);
0973: return;
0974: }
0975:
0976: default:
0977: throw new RuntimeException("Unknown composite rule!");
0978: }
0979: }
0980:
0981: private static void clearRect8888(int[] intData, int imageOffset,
0982: int imageScanlineStride, int imagePixelStride, int x,
0983: int y, int width, int height, int calpha, int cred,
0984: int cgreen, int cblue) {
0985: int cval = (calpha << 24) | (cred << 16) | (cgreen << 8)
0986: | cblue;
0987: int scanlineSkip = imageScanlineStride - width
0988: * imagePixelStride;
0989: int iidx = imageOffset + y * imageScanlineStride + x
0990: * imagePixelStride;
0991:
0992: for (; height > 0; --height) {
0993: for (int w = width; w > 0; --w) {
0994: intData[iidx] = cval;
0995: iidx += imagePixelStride;
0996: }
0997: iidx += scanlineSkip;
0998: }
0999: }
1000:
1001: private static void clearRect565(short[] shortData,
1002: int imageOffset, int imageScanlineStride,
1003: int imagePixelStride, int x, int y, int width, int height,
1004: int calpha, int cred, int cgreen, int cblue) {
1005: short cval = (short) ((convert8To5[cred] << 11)
1006: | (convert8To6[cgreen] << 5) | convert8To5[cblue]);
1007: int scanlineSkip = imageScanlineStride - width
1008: * imagePixelStride;
1009: int iidx = imageOffset + y * imageScanlineStride + x
1010: * imagePixelStride;
1011:
1012: for (; height > 0; --height) {
1013: for (int w = width; w > 0; --w) {
1014: shortData[iidx] = cval;
1015: iidx += imagePixelStride;
1016: }
1017: iidx += scanlineSkip;
1018: }
1019: }
1020:
1021: private static void clearRect8(byte[] byteData, int imageOffset,
1022: int imageScanlineStride, int imagePixelStride, int x,
1023: int y, int width, int height, int calpha, int cred,
1024: int cgreen, int cblue) {
1025: byte cval = (byte) ((19961 * cred + 38666 * cgreen + 7209 * cblue) >> 16);
1026: int scanlineSkip = imageScanlineStride - width
1027: * imagePixelStride;
1028: int iidx = imageOffset + y * imageScanlineStride + x
1029: * imagePixelStride;
1030:
1031: for (; height > 0; --height) {
1032: for (int w = width; w > 0; --w) {
1033: byteData[iidx] = cval;
1034: iidx += imagePixelStride;
1035: }
1036: iidx += scanlineSkip;
1037: }
1038: }
1039:
1040: public static void clearRect(Object imageData, int imageType,
1041: int imageOffset, int imageScanlineStride,
1042: int imagePixelStride, int x, int y, int width, int height,
1043: int alpha, int red, int green, int blue) {
1044: switch (imageType) {
1045: case TYPE_INT_RGB:
1046: case TYPE_INT_ARGB:
1047: clearRect8888((int[]) imageData, imageOffset,
1048: imageScanlineStride, imagePixelStride, x, y, width,
1049: height, alpha, red, green, blue);
1050: break;
1051: case TYPE_USHORT_565_RGB:
1052: clearRect565((short[]) imageData, imageOffset,
1053: imageScanlineStride, imagePixelStride, x, y, width,
1054: height, alpha, red, green, blue);
1055: break;
1056: case TYPE_BYTE_GRAY:
1057: clearRect8((byte[]) imageData, imageOffset,
1058: imageScanlineStride, imagePixelStride, x, y, width,
1059: height, alpha, red, green, blue);
1060: break;
1061: }
1062: }
1063: }
|