223 * Called also if scale+transform is set |
223 * Called also if scale+transform is set |
224 * |
224 * |
225 * @author Clemens Eisserer |
225 * @author Clemens Eisserer |
226 */ |
226 */ |
227 class XRPMTransformedBlit extends TransformBlit { |
227 class XRPMTransformedBlit extends TransformBlit { |
|
228 final Rectangle compositeBounds = new Rectangle(); |
|
229 final double[] srcCoords = new double[8]; |
|
230 final double[] dstCoords = new double[8]; |
228 |
231 |
229 public XRPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) { |
232 public XRPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) { |
230 super(srcType, CompositeType.AnyAlpha, dstType); |
233 super(srcType, CompositeType.AnyAlpha, dstType); |
231 } |
234 } |
232 |
235 |
233 /* |
236 /* |
234 * Calculates the composite-rectangle required for transformed blits. This |
237 * Calculates the composite-rectangle required for transformed blits. This |
235 * method is functionally equal to: Shape shp = |
238 * method is functionally equal to: Shape shp = |
236 * xform.createTransformedShape(rect); Rectangle bounds = shp.getBounds(); |
239 * xform.createTransformedShape(rect); Rectangle bounds = shp.getBounds(); |
237 * but performs significantly better. |
240 * but performs significantly better. |
|
241 * Returns true if the destination shape is parallel to x/y axis |
238 */ |
242 */ |
239 public Rectangle getCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) { |
243 protected boolean adjustCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) { |
240 double[] compBounds = new double[8]; |
244 srcCoords[0] = dstx; |
241 compBounds[0] = dstx; |
245 srcCoords[1] = dsty; |
242 compBounds[1] = dsty; |
246 srcCoords[2] = dstx + width; |
243 compBounds[2] = dstx + width; |
247 srcCoords[3] = dsty; |
244 compBounds[3] = dsty; |
248 srcCoords[4] = dstx + width; |
245 compBounds[4] = dstx + width; |
249 srcCoords[5] = dsty + height; |
246 compBounds[5] = dsty + height; |
250 srcCoords[6] = dstx; |
247 compBounds[6] = dstx; |
251 srcCoords[7] = dsty + height; |
248 compBounds[7] = dsty + height; |
252 |
249 |
253 tr.transform(srcCoords, 0, dstCoords, 0, 4); |
250 tr.transform(compBounds, 0, compBounds, 0, 4); |
254 |
251 |
255 double minX = Math.min(dstCoords[0], Math.min(dstCoords[2], Math.min(dstCoords[4], dstCoords[6]))); |
252 double minX = Math.min(compBounds[0], Math.min(compBounds[2], Math.min(compBounds[4], compBounds[6]))); |
256 double minY = Math.min(dstCoords[1], Math.min(dstCoords[3], Math.min(dstCoords[5], dstCoords[7]))); |
253 double minY = Math.min(compBounds[1], Math.min(compBounds[3], Math.min(compBounds[5], compBounds[7]))); |
257 double maxX = Math.max(dstCoords[0], Math.max(dstCoords[2], Math.max(dstCoords[4], dstCoords[6]))); |
254 double maxX = Math.max(compBounds[0], Math.max(compBounds[2], Math.max(compBounds[4], compBounds[6]))); |
258 double maxY = Math.max(dstCoords[1], Math.max(dstCoords[3], Math.max(dstCoords[5], dstCoords[7]))); |
255 double maxY = Math.max(compBounds[1], Math.max(compBounds[3], Math.max(compBounds[5], compBounds[7]))); |
259 |
256 |
260 minX = Math.round(minX); |
257 minX = Math.floor(minX); |
261 minY = Math.round(minY); |
258 minY = Math.floor(minY); |
262 maxX = Math.round(maxX); |
259 maxX = Math.ceil(maxX); |
263 maxY = Math.round(maxY); |
260 maxY = Math.ceil(maxY); |
264 |
261 |
265 compositeBounds.x = (int) minX; |
262 return new Rectangle((int) minX, (int) minY, (int) (maxX - minX), (int) (maxY - minY)); |
266 compositeBounds.y = (int) minY; |
263 } |
267 compositeBounds.width = (int) (maxX - minX); |
264 |
268 compositeBounds.height = (int) (maxY - minY); |
265 public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, int hint, int srcx, int srcy, |
269 |
266 int dstx, int dsty, int width, int height) { |
270 boolean is0or180 = (dstCoords[1] == dstCoords[3]) && (dstCoords[2] == dstCoords[4]); |
|
271 boolean is90or270 = (dstCoords[0] == dstCoords[2]) && (dstCoords[3] == dstCoords[5]); |
|
272 |
|
273 return is0or180 || is90or270; |
|
274 } |
|
275 |
|
276 public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, |
|
277 int hint, int srcx, int srcy, int dstx, int dsty, int width, int height) { |
267 try { |
278 try { |
268 SunToolkit.awtLock(); |
279 SunToolkit.awtLock(); |
269 |
280 |
|
281 XRSurfaceData x11sdDst = (XRSurfaceData) dst; |
|
282 XRSurfaceData x11sdSrc = (XRSurfaceData) src; |
|
283 |
270 int filter = XRUtils.ATransOpToXRQuality(hint); |
284 int filter = XRUtils.ATransOpToXRQuality(hint); |
271 |
285 boolean isAxisAligned = adjustCompositeBounds(xform, dstx, dsty, width, height); |
272 XRSurfaceData x11sdDst = (XRSurfaceData) dst; |
286 |
273 x11sdDst.validateAsDestination(null, clip); |
287 x11sdDst.validateAsDestination(null, clip); |
274 XRSurfaceData x11sdSrc = (XRSurfaceData) src; |
|
275 x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null); |
288 x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null); |
276 |
289 |
277 Rectangle bounds = getCompositeBounds(xform, dstx, dsty, width, height); |
290 AffineTransform trx = AffineTransform.getTranslateInstance(-compositeBounds.x, -compositeBounds.y); |
278 |
|
279 AffineTransform trx = AffineTransform.getTranslateInstance((-bounds.x), (-bounds.y)); |
|
280 trx.concatenate(xform); |
291 trx.concatenate(xform); |
281 AffineTransform maskTX = (AffineTransform) trx.clone(); |
292 AffineTransform maskTX = (AffineTransform) trx.clone(); |
282 |
|
283 trx.translate(-srcx, -srcy); |
293 trx.translate(-srcx, -srcy); |
284 |
294 |
285 try { |
295 try { |
286 trx.invert(); |
296 trx.invert(); |
287 } catch (NoninvertibleTransformException ex) { |
297 } catch (NoninvertibleTransformException ex) { |
288 trx.setToIdentity(); |
298 trx.setToIdentity(); |
289 System.err.println("Reseted to identity!"); |
299 } |
290 } |
300 |
291 |
301 boolean omitMask = (filter == XRUtils.FAST) |
292 boolean omitMask = isMaskOmittable(trx, comp, filter); |
302 || (isAxisAligned && ((AlphaComposite) comp).getAlpha() == 1.0f); |
293 |
303 |
294 if (!omitMask) { |
304 if (!omitMask) { |
295 XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage(); |
305 XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage(); |
296 |
306 |
297 x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter); |
307 x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter); |
298 int maskPicture = mask.prepareBlitMask(x11sdDst, maskTX, width, height); |
308 int maskPicture = mask.prepareBlitMask(x11sdDst, maskTX, width, height); |
299 x11sdDst.maskBuffer.con.renderComposite(XRCompositeManager.getInstance(x11sdSrc).getCompRule(), x11sdSrc.picture, maskPicture, x11sdDst.picture, |
309 x11sdDst.maskBuffer.con.renderComposite(XRCompositeManager.getInstance(x11sdSrc).getCompRule(), x11sdSrc.picture, maskPicture, x11sdDst.picture, |
300 0, 0, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height); |
310 0, 0, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height); |
301 } else { |
311 } else { |
302 int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad; |
312 int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad; |
303 |
313 |
304 x11sdSrc.validateAsSource(trx, repeat, filter); |
314 x11sdSrc.validateAsSource(trx, repeat, filter); |
305 x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height); |
315 x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height); |
306 } |
316 } |
307 } finally { |
317 } finally { |
308 SunToolkit.awtUnlock(); |
318 SunToolkit.awtUnlock(); |
309 } |
319 } |
310 } |
|
311 |
|
312 /* TODO: Is mask ever omitable??? ... should be for 90 degree rotation and no shear, but we always need to use RepeatPad */ |
|
313 protected static boolean isMaskOmittable(AffineTransform trx, Composite comp, int filter) { |
|
314 return (filter == XRUtils.FAST || trx.getTranslateX() == (int) trx.getTranslateX() /* |
|
315 * If |
|
316 * translate |
|
317 * is |
|
318 * integer |
|
319 * only |
|
320 */ |
|
321 && trx.getTranslateY() == (int) trx.getTranslateY() && (trx.getShearX() == 0 && trx.getShearY() == 0 // Only |
|
322 // 90 degree |
|
323 // rotation |
|
324 || trx.getShearX() == -trx.getShearY())) && ((AlphaComposite) comp).getAlpha() == 1.0f; // No |
|
325 // ExtraAlpha!=1 |
|
326 } |
320 } |
327 } |
321 } |
328 |
322 |
329 class XrSwToPMBlit extends Blit { |
323 class XrSwToPMBlit extends Blit { |
330 Blit pmToSurfaceBlit; |
324 Blit pmToSurfaceBlit; |