347 final int height = sy2 - sy1;
348 final BufferedImage bimg = new BufferedImage(width, height, type);
349 final SunGraphics2D g2d = (SunGraphics2D) bimg.createGraphics();
350 g2d.setComposite(AlphaComposite.Src);
351 bimg.setAccelerationPriority(0);
352 if (bgColor != null) {
353 g2d.setColor(bgColor);
354 g2d.fillRect(0, 0, width, height);
355 g2d.setComposite(AlphaComposite.SrcOver);
356 }
357 g2d.copyImage(img, 0, 0, sx1, sy1, width, height, null, null);
358 g2d.dispose();
359 return bimg;
360 }
361
362 protected void renderImageXform(SunGraphics2D sg, Image img,
363 AffineTransform tx, int interpType,
364 int sx1, int sy1, int sx2, int sy2,
365 Color bgColor)
366 {
367 Region clip = sg.getCompClip();
368 SurfaceData dstData = sg.surfaceData;
369 SurfaceData srcData = dstData.getSourceSurfaceData(img,
370 SunGraphics2D.TRANSFORM_GENERIC,
371 sg.imageComp,
372 bgColor);
373
374 if (srcData == null) {
375 img = getBufferedImage(img);
376 srcData = dstData.getSourceSurfaceData(img,
377 SunGraphics2D.TRANSFORM_GENERIC,
378 sg.imageComp,
379 bgColor);
380 if (srcData == null) {
381 // REMIND: Is this correct? Can this happen?
382 return;
383 }
384 }
385
386 if (isBgOperation(srcData, bgColor)) {
387 // We cannot perform bg operations during transform so make
388 // an opaque temp image with the appropriate background
412 * tend to have converters that convert to ARGB.
413 */
414 int type = ((srcData.getTransparency() == Transparency.OPAQUE)
415 ? BufferedImage.TYPE_INT_RGB
416 : BufferedImage.TYPE_INT_ARGB);
417 img = makeBufferedImage(img, null, type, sx1, sy1, sx2, sy2);
418 // Temp image has appropriate subimage at 0,0 now.
419 sx2 -= sx1;
420 sy2 -= sy1;
421 sx1 = sy1 = 0;
422
423 srcData = dstData.getSourceSurfaceData(img,
424 SunGraphics2D.TRANSFORM_GENERIC,
425 sg.imageComp,
426 null);
427 srcType = srcData.getSurfaceType();
428 helper = TransformHelper.getFromCache(srcType);
429 // assert(helper != null);
430 }
431
432 AffineTransform itx;
433 try {
434 itx = tx.createInverse();
435 } catch (NoninvertibleTransformException e) {
436 // Non-invertible transform means no output
437 return;
438 }
439
440 /*
441 * Find the maximum bounds on the destination that will be
442 * affected by the transformed source. First, transform all
443 * four corners of the source and then min and max the resulting
444 * destination coordinates of the transformed corners.
445 * Note that tx already has the offset to sx1,sy1 accounted
446 * for so we use the box (0, 0, sx2-sx1, sy2-sy1) as the
447 * source coordinates.
448 */
449 double coords[] = new double[8];
450 /* corner: UL UR LL LR */
451 /* index: 0 1 2 3 4 5 6 7 */
452 /* coord: (0, 0), (w, 0), (0, h), (w, h) */
453 coords[2] = coords[6] = sx2 - sx1;
454 coords[5] = coords[7] = sy2 - sy1;
455 tx.transform(coords, 0, coords, 0, 4);
456 double ddx1, ddy1, ddx2, ddy2;
457 ddx1 = ddx2 = coords[0];
458 ddy1 = ddy2 = coords[1];
459 for (int i = 2; i < coords.length; i += 2) {
460 double d = coords[i];
461 if (ddx1 > d) ddx1 = d;
462 else if (ddx2 < d) ddx2 = d;
463 d = coords[i+1];
464 if (ddy1 > d) ddy1 = d;
465 else if (ddy2 < d) ddy2 = d;
466 }
467 int dx1 = (int) Math.floor(ddx1);
468 int dy1 = (int) Math.floor(ddy1);
469 int dx2 = (int) Math.ceil(ddx2);
470 int dy2 = (int) Math.ceil(ddy2);
471
472 SurfaceType dstType = dstData.getSurfaceType();
473 MaskBlit maskblit;
474 Blit blit;
475 if (sg.compositeState <= SunGraphics2D.COMP_ALPHA) {
476 /* NOTE: We either have, or we can make,
477 * a MaskBlit for any alpha composite type
478 */
479 maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
480 sg.imageComp,
481 dstType);
482
483 /* NOTE: We can only use the native TransformHelper
484 * func to go directly to the dest if both the helper
485 * and the MaskBlit are native.
486 * All helpers are native at this point, but some MaskBlit
487 * objects are implemented in Java, so we need to check.
488 */
489 if (maskblit.getNativePrim() != 0) {
490 // We can render directly.
491 helper.Transform(maskblit, srcData, dstData,
492 sg.composite, clip,
493 itx, interpType,
494 sx1, sy1, sx2, sy2,
495 dx1, dy1, dx2, dy2,
496 null, 0, 0);
497 return;
498 }
499 blit = null;
500 } else {
501 /* NOTE: We either have, or we can make,
502 * a Blit for any composite type, even Custom
503 */
504 maskblit = null;
505 blit = Blit.getFromCache(SurfaceType.IntArgbPre,
506 sg.imageComp,
507 dstType);
508 }
509
510 // We need to transform to a temp image and then copy
511 // just the pieces that are valid data to the dest.
512 BufferedImage tmpimg = new BufferedImage(dx2-dx1, dy2-dy1,
513 BufferedImage.TYPE_INT_ARGB_PRE);
514 SurfaceData tmpData = SurfaceData.getPrimarySurfaceData(tmpimg);
515 SurfaceType tmpType = tmpData.getSurfaceType();
516 MaskBlit tmpmaskblit =
517 MaskBlit.getFromCache(SurfaceType.IntArgbPre,
518 CompositeType.SrcNoEa,
519 tmpType);
520 /*
521 * The helper function fills a temporary edges buffer
522 * for us with the bounding coordinates of each scanline
523 * in the following format:
524 *
525 * edges[0, 1] = [top y, bottom y)
526 * edges[2, 3] = [left x, right x) of top row
527 * ...
528 * edges[h*2, h*2+1] = [left x, right x) of bottom row
529 *
530 * all coordinates in the edges array will be relative to dx1, dy1
531 *
532 * edges thus has to be h*2+2 in length
533 */
534 int edges[] = new int[(dy2-dy1)*2+2];
535 // It is important that edges[0]=edges[1]=0 when we call
536 // Transform in case it must return early and we would
537 // not want to render anything on an error condition.
538 helper.Transform(tmpmaskblit, srcData, tmpData,
539 AlphaComposite.Src, null,
540 itx, interpType,
541 sx1, sy1, sx2, sy2,
542 0, 0, dx2-dx1, dy2-dy1,
543 edges, dx1, dy1);
544
545 /*
546 * Now copy the results, scanline by scanline, into the dest.
547 * The edges array helps us minimize the work.
548 */
549 int index = 2;
550 for (int y = edges[0]; y < edges[1]; y++) {
551 int relx1 = edges[index++];
552 int relx2 = edges[index++];
553 if (relx1 >= relx2) {
554 continue;
555 }
556 if (maskblit != null) {
557 maskblit.MaskBlit(tmpData, dstData,
558 sg.composite, clip,
559 relx1, y,
560 dx1+relx1, dy1+y,
561 relx2 - relx1, 1,
562 null, 0, 0);
563 } else {
564 blit.Blit(tmpData, dstData,
565 sg.composite, clip,
566 relx1, y,
567 dx1+relx1, dy1+y,
568 relx2 - relx1, 1);
569 }
570 }
571 }
572
573 // Render an image using only integer translation
574 // (no scale or transform or sub-pixel interpolated translations).
575 protected boolean renderImageCopy(SunGraphics2D sg, Image img,
576 Color bgColor,
577 int dx, int dy,
578 int sx, int sy,
579 int w, int h)
580 {
581 Region clip = sg.getCompClip();
582 SurfaceData dstData = sg.surfaceData;
583
584 int attempts = 0;
585 // Loop up to twice through; this gives us a chance to
586 // revalidate the surfaceData objects in case of an exception
587 // and try it once more
588 while (true) {
589 SurfaceData srcData =
590 dstData.getSourceSurfaceData(img,
|
347 final int height = sy2 - sy1;
348 final BufferedImage bimg = new BufferedImage(width, height, type);
349 final SunGraphics2D g2d = (SunGraphics2D) bimg.createGraphics();
350 g2d.setComposite(AlphaComposite.Src);
351 bimg.setAccelerationPriority(0);
352 if (bgColor != null) {
353 g2d.setColor(bgColor);
354 g2d.fillRect(0, 0, width, height);
355 g2d.setComposite(AlphaComposite.SrcOver);
356 }
357 g2d.copyImage(img, 0, 0, sx1, sy1, width, height, null, null);
358 g2d.dispose();
359 return bimg;
360 }
361
362 protected void renderImageXform(SunGraphics2D sg, Image img,
363 AffineTransform tx, int interpType,
364 int sx1, int sy1, int sx2, int sy2,
365 Color bgColor)
366 {
367 final AffineTransform itx;
368 try {
369 itx = tx.createInverse();
370 } catch (final NoninvertibleTransformException ignored) {
371 // Non-invertible transform means no output
372 return;
373 }
374
375 /*
376 * Find the maximum bounds on the destination that will be
377 * affected by the transformed source. First, transform all
378 * four corners of the source and then min and max the resulting
379 * destination coordinates of the transformed corners.
380 * Note that tx already has the offset to sx1,sy1 accounted
381 * for so we use the box (0, 0, sx2-sx1, sy2-sy1) as the
382 * source coordinates.
383 */
384 final double[] coords = new double[8];
385 /* corner: UL UR LL LR */
386 /* index: 0 1 2 3 4 5 6 7 */
387 /* coord: (0, 0), (w, 0), (0, h), (w, h) */
388 coords[2] = coords[6] = sx2 - sx1;
389 coords[5] = coords[7] = sy2 - sy1;
390 tx.transform(coords, 0, coords, 0, 4);
391 double ddx1, ddy1, ddx2, ddy2;
392 ddx1 = ddx2 = coords[0];
393 ddy1 = ddy2 = coords[1];
394 for (int i = 2; i < coords.length; i += 2) {
395 double d = coords[i];
396 if (ddx1 > d) ddx1 = d;
397 else if (ddx2 < d) ddx2 = d;
398 d = coords[i+1];
399 if (ddy1 > d) ddy1 = d;
400 else if (ddy2 < d) ddy2 = d;
401 }
402
403 Region clip = sg.getCompClip();
404 final int dx1 = Math.max((int) Math.floor(ddx1), clip.lox);
405 final int dy1 = Math.max((int) Math.floor(ddy1), clip.loy);
406 final int dx2 = Math.min((int) Math.ceil(ddx2), clip.hix);
407 final int dy2 = Math.min((int) Math.ceil(ddy2), clip.hiy);
408 if (dx2 <= dx1 || dy2 <= dy1) {
409 // empty destination means no output
410 return;
411 }
412
413 final SurfaceData dstData = sg.surfaceData;
414 SurfaceData srcData = dstData.getSourceSurfaceData(img,
415 SunGraphics2D.TRANSFORM_GENERIC,
416 sg.imageComp,
417 bgColor);
418
419 if (srcData == null) {
420 img = getBufferedImage(img);
421 srcData = dstData.getSourceSurfaceData(img,
422 SunGraphics2D.TRANSFORM_GENERIC,
423 sg.imageComp,
424 bgColor);
425 if (srcData == null) {
426 // REMIND: Is this correct? Can this happen?
427 return;
428 }
429 }
430
431 if (isBgOperation(srcData, bgColor)) {
432 // We cannot perform bg operations during transform so make
433 // an opaque temp image with the appropriate background
457 * tend to have converters that convert to ARGB.
458 */
459 int type = ((srcData.getTransparency() == Transparency.OPAQUE)
460 ? BufferedImage.TYPE_INT_RGB
461 : BufferedImage.TYPE_INT_ARGB);
462 img = makeBufferedImage(img, null, type, sx1, sy1, sx2, sy2);
463 // Temp image has appropriate subimage at 0,0 now.
464 sx2 -= sx1;
465 sy2 -= sy1;
466 sx1 = sy1 = 0;
467
468 srcData = dstData.getSourceSurfaceData(img,
469 SunGraphics2D.TRANSFORM_GENERIC,
470 sg.imageComp,
471 null);
472 srcType = srcData.getSurfaceType();
473 helper = TransformHelper.getFromCache(srcType);
474 // assert(helper != null);
475 }
476
477 SurfaceType dstType = dstData.getSurfaceType();
478 if (sg.compositeState <= SunGraphics2D.COMP_ALPHA) {
479 /* NOTE: We either have, or we can make,
480 * a MaskBlit for any alpha composite type
481 */
482 MaskBlit maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
483 sg.imageComp, dstType);
484
485 /* NOTE: We can only use the native TransformHelper
486 * func to go directly to the dest if both the helper
487 * and the MaskBlit are native.
488 * All helpers are native at this point, but some MaskBlit
489 * objects are implemented in Java, so we need to check.
490 */
491 if (maskblit.getNativePrim() != 0) {
492 // We can render directly.
493 helper.Transform(maskblit, srcData, dstData,
494 sg.composite, clip,
495 itx, interpType,
496 sx1, sy1, sx2, sy2,
497 dx1, dy1, dx2, dy2,
498 null, 0, 0);
499 return;
500 }
501 }
502
503 // We need to transform to a temp image and then copy
504 // just the pieces that are valid data to the dest.
505 final int w = dx2 - dx1;
506 final int h = dy2 - dy1;
507 BufferedImage tmpimg = new BufferedImage(w, h,
508 BufferedImage.TYPE_INT_ARGB_PRE);
509 SurfaceData tmpData = SurfaceData.getPrimarySurfaceData(tmpimg);
510 SurfaceType tmpType = tmpData.getSurfaceType();
511 MaskBlit tmpmaskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
512 CompositeType.SrcNoEa,
513 tmpType);
514 /*
515 * The helper function fills a temporary edges buffer
516 * for us with the bounding coordinates of each scanline
517 * in the following format:
518 *
519 * edges[0, 1] = [top y, bottom y)
520 * edges[2, 3] = [left x, right x) of top row
521 * ...
522 * edges[h*2, h*2+1] = [left x, right x) of bottom row
523 *
524 * all coordinates in the edges array will be relative to dx1, dy1
525 *
526 * edges thus has to be h*2+2 in length
527 */
528 final int[] edges = new int[h * 2 + 2];
529 // It is important that edges[0]=edges[1]=0 when we call
530 // Transform in case it must return early and we would
531 // not want to render anything on an error condition.
532 helper.Transform(tmpmaskblit, srcData, tmpData,
533 AlphaComposite.Src, null,
534 itx, interpType,
535 sx1, sy1, sx2, sy2,
536 0, 0, w, h,
537 edges, dx1, dy1);
538
539 final Region region = Region.getInstance(dx1, dy1, dx2, dy2, edges);
540 clip = clip.getIntersection(region);
541
542 /* NOTE: We either have, or we can make,
543 * a Blit for any composite type, even Custom
544 */
545 final Blit blit = Blit.getFromCache(tmpType, sg.imageComp, dstType);
546 blit.Blit(tmpData, dstData, sg.composite, clip, 0, 0, dx1, dy1, w, h);
547 }
548
549 // Render an image using only integer translation
550 // (no scale or transform or sub-pixel interpolated translations).
551 protected boolean renderImageCopy(SunGraphics2D sg, Image img,
552 Color bgColor,
553 int dx, int dy,
554 int sx, int sy,
555 int w, int h)
556 {
557 Region clip = sg.getCompClip();
558 SurfaceData dstData = sg.surfaceData;
559
560 int attempts = 0;
561 // Loop up to twice through; this gives us a chance to
562 // revalidate the surfaceData objects in case of an exception
563 // and try it once more
564 while (true) {
565 SurfaceData srcData =
566 dstData.getSourceSurfaceData(img,
|