1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/** 18 * @author Igor V. Stolyarov 19 * @version $Revision$ 20 * Created on 18.11.2005 21 * 22 */ 23package org.apache.harmony.awt.gl.render; 24 25import java.awt.AlphaComposite; 26import java.awt.Color; 27import java.awt.Composite; 28import java.awt.CompositeContext; 29import java.awt.Rectangle; 30import java.awt.geom.AffineTransform; 31import java.awt.geom.NoninvertibleTransformException; 32import java.awt.geom.Rectangle2D; 33import java.awt.image.ColorModel; 34import java.awt.image.Raster; 35import java.awt.image.WritableRaster; 36 37import org.apache.harmony.awt.gl.MultiRectArea; 38import org.apache.harmony.awt.gl.Surface; 39import org.apache.harmony.awt.gl.XORComposite; 40import org.apache.harmony.awt.internal.nls.Messages; 41 42/** 43 * Java implenetation of the Blitter interface. Using when we can't 44 * draw images natively. 45 */ 46public class JavaBlitter implements Blitter { 47 48 /** 49 * Instead of multiplication and division we are using values from 50 * Lookup tables. 51 */ 52 static byte mulLUT[][]; // Lookup table for multiplication 53 static byte divLUT[][]; // Lookup table for division 54 55 static{ 56 mulLUT = new byte[256][256]; 57 for(int i = 0; i < 256; i++){ 58 for(int j = 0; j < 256; j++){ 59 mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f); 60 } 61 } 62 divLUT = new byte[256][256]; 63 for(int i = 1; i < 256; i++){ 64 for(int j = 0; j < i; j++){ 65 divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f); 66 } 67 for(int j = i; j < 256; j++){ 68 divLUT[i][j] = (byte)255; 69 } 70 } 71 } 72 73 final static int AlphaCompositeMode = 1; 74 final static int XORMode = 2; 75 76 final static JavaBlitter inst = new JavaBlitter(); 77 78 public static JavaBlitter getInstance(){ 79 return inst; 80 } 81 82 public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, 83 Surface dstSurf, int width, int height, AffineTransform sysxform, 84 AffineTransform xform, Composite comp, Color bgcolor, 85 MultiRectArea clip) { 86 87 if(xform == null){ 88 blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height, 89 sysxform, comp, bgcolor, clip); 90 }else{ 91 double scaleX = xform.getScaleX(); 92 double scaleY = xform.getScaleY(); 93 double scaledX = dstX / scaleX; 94 double scaledY = dstY / scaleY; 95 AffineTransform at = new AffineTransform(); 96 at.setToTranslation(scaledX, scaledY); 97 xform.concatenate(at); 98 sysxform.concatenate(xform); 99 blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height, 100 sysxform, comp, bgcolor, clip); 101 } 102 103 } 104 105 public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, 106 Surface dstSurf, int width, int height, AffineTransform sysxform, 107 Composite comp, Color bgcolor, MultiRectArea clip) { 108 109 if(sysxform == null) { 110 sysxform = new AffineTransform(); 111 } 112 int type = sysxform.getType(); 113 switch(type){ 114 case AffineTransform.TYPE_TRANSLATION: 115 dstX += sysxform.getTranslateX(); 116 dstY += sysxform.getTranslateY(); 117 case AffineTransform.TYPE_IDENTITY: 118 blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, 119 width, height, comp, bgcolor, clip); 120 break; 121 default: 122 int srcW = srcSurf.getWidth(); 123 int srcH = srcSurf.getHeight(); 124 125 int w = srcX + width < srcW ? width : srcW - srcX; 126 int h = srcY + height < srcH ? height : srcH - srcY; 127 128 ColorModel srcCM = srcSurf.getColorModel(); 129 Raster srcR = srcSurf.getRaster().createChild(srcX, srcY, 130 w, h, 0, 0, null); 131 132 ColorModel dstCM = dstSurf.getColorModel(); 133 WritableRaster dstR = dstSurf.getRaster(); 134 135 transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h, 136 sysxform, comp, bgcolor, clip); 137 138 } 139 } 140 141 public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, 142 Surface dstSurf, int width, int height, Composite comp, 143 Color bgcolor, MultiRectArea clip) { 144 145 javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(), 146 srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY, 147 dstSurf.getWidth(), dstSurf.getHeight(), 148 dstSurf.getColorModel(), dstSurf.getRaster(), 149 width, height, comp, bgcolor, clip); 150 151 } 152 public void javaBlt(int srcX, int srcY, int srcW, int srcH, 153 ColorModel srcCM, Raster srcRast, int dstX, int dstY, 154 int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast, 155 int width, int height, Composite comp, Color bgcolor, 156 MultiRectArea clip){ 157 158 int srcX2 = srcW - 1; 159 int srcY2 = srcH - 1; 160 int dstX2 = dstW - 1; 161 int dstY2 = dstH - 1; 162 163 if(srcX < 0){ 164 width += srcX; 165 srcX = 0; 166 } 167 if(srcY < 0){ 168 height += srcY; 169 srcY = 0; 170 } 171 172 if(dstX < 0){ 173 width += dstX; 174 srcX -= dstX; 175 dstX = 0; 176 } 177 if(dstY < 0){ 178 height += dstY; 179 srcY -= dstY; 180 dstY = 0; 181 } 182 183 if(srcX > srcX2 || srcY > srcY2) { 184 return; 185 } 186 if(dstX > dstX2 || dstY > dstY2) { 187 return; 188 } 189 190 if(srcX + width > srcX2) { 191 width = srcX2 - srcX + 1; 192 } 193 if(srcY + height > srcY2) { 194 height = srcY2 - srcY + 1; 195 } 196 if(dstX + width > dstX2) { 197 width = dstX2 - dstX + 1; 198 } 199 if(dstY + height > dstY2) { 200 height = dstY2 - dstY + 1; 201 } 202 203 if(width <= 0 || height <= 0) { 204 return; 205 } 206 207 int clipRects[]; 208 if(clip != null) { 209 clipRects = clip.rect; 210 } else { 211 clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1}; 212 } 213 214 boolean isAlphaComp = false; 215 int rule = 0; 216 float alpha = 0; 217 boolean isXORComp = false; 218 Color xorcolor = null; 219 CompositeContext cont = null; 220 221 if(comp instanceof AlphaComposite){ 222 isAlphaComp = true; 223 AlphaComposite ac = (AlphaComposite) comp; 224 rule = ac.getRule(); 225 alpha = ac.getAlpha(); 226 }else if(comp instanceof XORComposite){ 227 isXORComp = true; 228 XORComposite xcomp = (XORComposite) comp; 229 xorcolor = xcomp.getXORColor(); 230 }else{ 231 cont = comp.createContext(srcCM, dstCM, null); 232 } 233 234 for(int i = 1; i < clipRects[0]; i += 4){ 235 int _sx = srcX; 236 int _sy = srcY; 237 238 int _dx = dstX; 239 int _dy = dstY; 240 241 int _w = width; 242 int _h = height; 243 244 int cx = clipRects[i]; // Clipping left top X 245 int cy = clipRects[i + 1]; // Clipping left top Y 246 int cx2 = clipRects[i + 2]; // Clipping right bottom X 247 int cy2 = clipRects[i + 3]; // Clipping right bottom Y 248 249 if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) { 250 continue; 251 } 252 253 if(cx > _dx){ 254 int shx = cx - _dx; 255 _w -= shx; 256 _dx = cx; 257 _sx += shx; 258 } 259 260 if(cy > _dy){ 261 int shy = cy - _dy; 262 _h -= shy; 263 _dy = cy; 264 _sy += shy; 265 } 266 267 if(_dx + _w > cx2 + 1){ 268 _w = cx2 - _dx + 1; 269 } 270 271 if(_dy + _h > cy2 + 1){ 272 _h = cy2 - _dy + 1; 273 } 274 275 if(_sx > srcX2 || _sy > srcY2) { 276 continue; 277 } 278 279 if(isAlphaComp){ 280 alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, 281 dstCM, dstRast, _w, _h, rule, alpha, bgcolor); 282 }else if(isXORComp){ 283 xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, 284 dstCM, dstRast, _w, _h, xorcolor); 285 }else{ 286 Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null); 287 WritableRaster dr = dstRast.createWritableChild(_dx, _dy, 288 _w, _h, 0, 0, null); 289 cont.compose(sr, dr, dr); 290 } 291 } 292 } 293 294 void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, 295 int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, 296 int width, int height, int rule, float alpha, Color bgcolor){ 297 298 Object srcPixel, dstPixel; 299 int srcConstAllpha = (int)(alpha * 255 + 0.5f); 300 int srcRGB, dstRGB = 0; 301 302 if(bgcolor != null){ 303 dstRGB = bgcolor.getRGB(); 304 } 305 306 for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){ 307 for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){ 308 srcPixel = srcRast.getDataElements(sx, sy, null); 309 srcRGB = srcCM.getRGB(srcPixel); 310 if(bgcolor == null){ 311 dstPixel = dstRast.getDataElements(dx, dy, null); 312 dstRGB = dstCM.getRGB(dstPixel); 313 } 314 315 dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(), 316 dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(), 317 rule, srcConstAllpha); 318 319 dstPixel = dstCM.getDataElements(dstRGB, null); 320 dstRast.setDataElements(dx,dy,dstPixel); 321 } 322 } 323 } 324 325 void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, 326 int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, 327 int width, int height, Color xorcolor){ 328 329 Object srcPixel, dstPixel; 330 int xorRGB = xorcolor.getRGB(); 331 int srcRGB, dstRGB; 332 333 for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){ 334 for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){ 335 srcPixel = srcRast.getDataElements(sx, sy, null); 336 dstPixel = dstRast.getDataElements(dx, dy, null); 337 338 srcRGB = srcCM.getRGB(srcPixel); 339 dstRGB = dstCM.getRGB(dstPixel); 340 dstRGB = srcRGB ^ xorRGB ^ dstRGB; 341 342 dstRGB = 0xff000000 | dstRGB; 343 dstPixel = dstCM.getDataElements(dstRGB, dstPixel); 344 dstRast.setDataElements(dx,dy,dstPixel); 345 346 } 347 } 348 349 } 350 351 private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY, 352 ColorModel dstCM, WritableRaster dstR, int dstX, int dstY, 353 int width, int height, AffineTransform at, Composite comp, 354 Color bgcolor,MultiRectArea clip) { 355 356 Rectangle srcBounds = new Rectangle(width, height); 357 Rectangle dstBlitBounds = new Rectangle(dstX, dstY, srcR.getWidth(), srcR.getHeight()); 358 359 Rectangle transSrcBounds = getBounds2D(at, srcBounds).getBounds(); 360 Rectangle transDstBlitBounds = getBounds2D(at, dstBlitBounds).getBounds(); 361 362 int translateX = transDstBlitBounds.x - transSrcBounds.x; 363 int translateY = transDstBlitBounds.y - transSrcBounds.y; 364 365 AffineTransform inv = null; 366 try { 367 inv = at.createInverse(); 368 } catch (NoninvertibleTransformException e) { 369 return; 370 } 371 372 double[] m = new double[6]; 373 inv.getMatrix(m); 374 375 int clipRects[]; 376 if(clip != null) { 377 clipRects = clip.rect; 378 } else { 379 clipRects = new int[]{5, 0, 0, dstR.getWidth(), dstR.getHeight()}; 380 } 381 382 int compType = 0; 383 int srcConstAlpha = 0; 384 int rule = 0; 385 int bgRGB = bgcolor == null ? 0 : bgcolor.getRGB(); 386 int srcRGB = 0, dstRGB = 0; 387 Object srcVal = null, dstVal = null; 388 if(comp instanceof AlphaComposite){ 389 compType = AlphaCompositeMode; 390 AlphaComposite ac = (AlphaComposite) comp; 391 rule = ac.getRule(); 392 srcConstAlpha = (int)(ac.getAlpha() * 255 + 0.5f); 393 }else if(comp instanceof XORComposite){ 394 compType = XORMode; 395 XORComposite xor = (XORComposite) comp; 396 bgRGB = xor.getXORColor().getRGB(); 397 } 398 399 for(int i = 1; i < clipRects[0]; i += 4){ 400 Rectangle dstBounds = new Rectangle(clipRects[i], clipRects[i + 1], 0, 0); 401 dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 1]); 402 dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 3] + 1); 403 dstBounds.add(clipRects[i], clipRects[i + 3] + 1); 404 405 Rectangle bounds = dstBounds.intersection(transDstBlitBounds); 406 407 int minSrcX = srcBounds.x; 408 int minSrcY = srcBounds.y; 409 int maxSrcX = minSrcX + srcBounds.width; 410 int maxSrcY = minSrcY + srcBounds.height; 411 412 int minX = bounds.x; 413 int minY = bounds.y; 414 int maxX = minX + bounds.width; 415 int maxY = minY + bounds.height; 416 417 int hx = (int)((m[0] * 256) + 0.5); 418 int hy = (int)((m[1] * 256) + 0.5); 419 int vx = (int)((m[2] * 256) + 0.5); 420 int vy = (int)((m[3] * 256) + 0.5); 421 int sx = (int)((m[4] + m[0] * (bounds.x - translateX) + m[2] * (bounds.y - translateY)) * 256 + 0.5); 422 int sy = (int)((m[5] + m[1] * (bounds.x - translateX) + m[3] * (bounds.y - translateY)) * 256 + 0.5); 423 424 vx -= hx * bounds.width; 425 vy -= hy * bounds.width; 426 427 for(int y = minY; y < maxY; y++) { 428 for(int x = minX; x < maxX; x++) { 429 int px = sx >> 8; 430 int py = sy >> 8; 431 if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { 432 switch(compType){ 433 case AlphaCompositeMode: 434 srcVal = srcR.getDataElements(px , py , null); 435 srcRGB = srcCM.getRGB(srcVal); 436 if(bgcolor != null){ 437 dstRGB = bgRGB; 438 }else{ 439 dstVal = dstR.getDataElements(x, y, null); 440 dstRGB = dstCM.getRGB(dstVal); 441 } 442 dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(), 443 dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(), 444 rule, srcConstAlpha); 445 dstVal = dstCM.getDataElements(dstRGB, null); 446 dstR.setDataElements(x, y, dstVal); 447 break; 448 449 case XORMode: 450 srcVal = srcR.getDataElements(px , py , null); 451 srcRGB = srcCM.getRGB(srcVal); 452 dstVal = dstR.getDataElements(x, y, null); 453 dstRGB = dstCM.getRGB(dstVal); 454 dstRGB = srcRGB ^ bgRGB; 455 456 dstRGB = 0xff000000 | dstRGB; 457 dstVal = dstCM.getDataElements(dstRGB, null); 458 dstR.setDataElements(x, y, dstVal); 459 break; 460 461 default: 462 // awt.37=Unknown composite type {0} 463 throw new IllegalArgumentException(Messages.getString("awt.37", //$NON-NLS-1$ 464 comp.getClass())); 465 } 466 } 467 sx += hx; 468 sy += hy; 469 } 470 sx += vx; 471 sy += vy; 472 } 473 } 474 475 } 476 477 private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) { 478 int x = r.x; 479 int y = r.y; 480 int width = r.width; 481 int height = r.height; 482 483 float[] corners = { 484 x, y, 485 x + width, y, 486 x + width, y + height, 487 x, y + height 488 }; 489 490 at.transform(corners, 0, corners, 0, 4); 491 492 Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0); 493 bounds.add(corners[2], corners[3]); 494 bounds.add(corners[4], corners[5]); 495 bounds.add(corners[6], corners[7]); 496 497 return bounds; 498 } 499 500 private int compose(int srcRGB, boolean isSrcAlphaPre, 501 int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre, 502 int rule, int srcConstAlpha){ 503 504 int sa, sr, sg, sb, da, dr, dg, db; 505 506 sa = (srcRGB >> 24) & 0xff; 507 sr = (srcRGB >> 16) & 0xff; 508 sg = (srcRGB >> 8) & 0xff; 509 sb = srcRGB & 0xff; 510 511 if(isSrcAlphaPre){ 512 sa = mulLUT[srcConstAlpha][sa] & 0xff; 513 sr = mulLUT[srcConstAlpha][sr] & 0xff; 514 sg = mulLUT[srcConstAlpha][sg] & 0xff; 515 sb = mulLUT[srcConstAlpha][sb] & 0xff; 516 }else{ 517 sa = mulLUT[srcConstAlpha][sa] & 0xff; 518 sr = mulLUT[sa][sr] & 0xff; 519 sg = mulLUT[sa][sg] & 0xff; 520 sb = mulLUT[sa][sb] & 0xff; 521 } 522 523 da = (dstRGB >> 24) & 0xff; 524 dr = (dstRGB >> 16) & 0xff; 525 dg = (dstRGB >> 8) & 0xff; 526 db = dstRGB & 0xff; 527 528 if(!isDstAlphaPre){ 529 dr = mulLUT[da][dr] & 0xff; 530 dg = mulLUT[da][dg] & 0xff; 531 db = mulLUT[da][db] & 0xff; 532 } 533 534 int Fs = 0; 535 int Fd = 0; 536 switch(rule){ 537 case AlphaComposite.CLEAR: 538 break; 539 540 case AlphaComposite.DST: 541 Fd = 255; 542 break; 543 544 case AlphaComposite.DST_ATOP: 545 Fs = 255 - da; 546 Fd = sa; 547 break; 548 549 case AlphaComposite.DST_IN: 550 Fd = sa; 551 break; 552 553 case AlphaComposite.DST_OUT: 554 Fd = 255 - sa; 555 break; 556 557 case AlphaComposite.DST_OVER: 558 Fs = 255 - da; 559 Fd = 255; 560 break; 561 562 case AlphaComposite.SRC: 563 Fs = 255; 564 break; 565 566 case AlphaComposite.SRC_ATOP: 567 Fs = da; 568 Fd = 255 - sa; 569 break; 570 571 case AlphaComposite.SRC_IN: 572 Fs = da; 573 break; 574 575 case AlphaComposite.SRC_OUT: 576 Fs = 255 - da; 577 break; 578 579 case AlphaComposite.SRC_OVER: 580 Fs = 255; 581 Fd = 255 - sa; 582 break; 583 584 case AlphaComposite.XOR: 585 Fs = 255 - da; 586 Fd = 255 - sa; 587 break; 588 } 589 dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff); 590 dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff); 591 db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff); 592 593 da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff); 594 595 if(!isDstAlphaPre){ 596 if(da != 255){ 597 dr = divLUT[da][dr] & 0xff; 598 dg = divLUT[da][dg] & 0xff; 599 db = divLUT[da][db] & 0xff; 600 } 601 } 602 if(!dstHasAlpha) { 603 da = 0xff; 604 } 605 dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db; 606 607 return dstRGB; 608 609 } 610 611} 612