History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/java2d/pipe/DrawImage.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/java2d/pipe/DrawImage.java+1110−0
@@ -0,0 +1,1110 @@
1+/*
2+ * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.java2d.pipe;
27+
28+import java.awt.AlphaComposite;
29+import java.awt.Color;
30+import java.awt.Graphics2D;
31+import java.awt.Image;
32+import java.awt.Rectangle;
33+import java.awt.Transparency;
34+import java.awt.geom.AffineTransform;
35+import java.awt.geom.NoninvertibleTransformException;
36+import java.awt.image.AffineTransformOp;
37+import java.awt.image.BufferedImage;
38+import java.awt.image.BufferedImageOp;
39+import java.awt.image.ColorModel;
40+import java.awt.image.DataBuffer;
41+import java.awt.image.DirectColorModel;
42+import java.awt.image.ImageObserver;
43+import java.awt.image.IndexColorModel;
44+import java.awt.image.Raster;
45+import java.awt.image.VolatileImage;
46+import java.awt.image.WritableRaster;
47+import java.awt.image.ImagingOpException;
48+import sun.awt.SunHints;
49+import sun.awt.image.ImageRepresentation;
50+import sun.awt.image.ToolkitImage;
51+import sun.java2d.InvalidPipeException;
52+import sun.java2d.SunGraphics2D;
53+import sun.java2d.SurfaceData;
54+import sun.java2d.loops.Blit;
55+import sun.java2d.loops.BlitBg;
56+import sun.java2d.loops.TransformHelper;
57+import sun.java2d.loops.MaskBlit;
58+import sun.java2d.loops.CompositeType;
59+import sun.java2d.loops.ScaledBlit;
60+import sun.java2d.loops.SurfaceType;
61+
62+public class DrawImage implements DrawImagePipe
63+{
64+ public boolean copyImage(SunGraphics2D sg, Image img,
65+ int x, int y,
66+ Color bgColor)
67+ {
68+ int imgw = img.getWidth(null);
69+ int imgh = img.getHeight(null);
70+ if (isSimpleTranslate(sg)) {
71+ return renderImageCopy(sg, img, bgColor,
72+ x + sg.transX, y + sg.transY,
73+ 0, 0, imgw, imgh);
74+ }
75+ AffineTransform atfm = sg.transform;
76+ if ((x | y) != 0) {
77+ atfm = new AffineTransform(atfm);
78+ atfm.translate(x, y);
79+ }
80+ transformImage(sg, img, atfm, sg.interpolationType,
81+ 0, 0, imgw, imgh, bgColor);
82+ return true;
83+ }
84+
85+ public boolean copyImage(SunGraphics2D sg, Image img,
86+ int dx, int dy, int sx, int sy, int w, int h,
87+ Color bgColor)
88+ {
89+ if (isSimpleTranslate(sg)) {
90+ return renderImageCopy(sg, img, bgColor,
91+ dx + sg.transX, dy + sg.transY,
92+ sx, sy, w, h);
93+ }
94+ scaleImage(sg, img, dx, dy, (dx + w), (dy + h),
95+ sx, sy, (sx + w), (sy + h), bgColor);
96+ return true;
97+ }
98+
99+ public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y,
100+ int width, int height,
101+ Color bgColor)
102+ {
103+ int imgw = img.getWidth(null);
104+ int imgh = img.getHeight(null);
105+ // Only accelerate scale if:
106+ // - w/h positive values
107+ // - sg transform integer translate/identity only
108+ // - no bgColor in operation
109+ if ((width > 0) && (height > 0) && isSimpleTranslate(sg)) {
110+ double dx1 = x + sg.transX;
111+ double dy1 = y + sg.transY;
112+ double dx2 = dx1 + width;
113+ double dy2 = dy1 + height;
114+ if (renderImageScale(sg, img, bgColor, sg.interpolationType,
115+ 0, 0, imgw, imgh,
116+ dx1, dy1, dx2, dy2))
117+ {
118+ return true;
119+ }
120+ }
121+
122+ AffineTransform atfm = sg.transform;
123+ if ((x | y) != 0 || width != imgw || height != imgh) {
124+ atfm = new AffineTransform(atfm);
125+ atfm.translate(x, y);
126+ atfm.scale(((double)width)/imgw, ((double)height)/imgh);
127+ }
128+ transformImage(sg, img, atfm, sg.interpolationType,
129+ 0, 0, imgw, imgh, bgColor);
130+ return true;
131+ }
132+
133+ /*
134+ * This method is only called in those circumstances where the
135+ * operation has a non-null secondary transform specfied. Its
136+ * role is to check for various optimizations based on the types
137+ * of both the secondary and SG2D transforms and to do some
138+ * quick calculations to avoid having to combine the transforms
139+ * and/or to call a more generalized method.
140+ */
141+ protected void transformImage(SunGraphics2D sg, Image img, int x, int y,
142+ AffineTransform extraAT, int interpType)
143+ {
144+ int txtype = extraAT.getType();
145+ int imgw = img.getWidth(null);
146+ int imgh = img.getHeight(null);
147+ boolean checkfinalxform;
148+
149+ if (sg.transformState <= sg.TRANSFORM_ANY_TRANSLATE &&
150+ (txtype == AffineTransform.TYPE_IDENTITY ||
151+ txtype == AffineTransform.TYPE_TRANSLATION))
152+ {
153+ // First optimization - both are some kind of translate
154+
155+ // Combine the translations and check if interpolation is necessary.
156+ double tx = extraAT.getTranslateX();
157+ double ty = extraAT.getTranslateY();
158+ tx += sg.transform.getTranslateX();
159+ ty += sg.transform.getTranslateY();
160+ int itx = (int) Math.floor(tx + 0.5);
161+ int ity = (int) Math.floor(ty + 0.5);
162+ if (interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR ||
163+ (closeToInteger(itx, tx) && closeToInteger(ity, ty)))
164+ {
165+ renderImageCopy(sg, img, null, x+itx, y+ity, 0, 0, imgw, imgh);
166+ return;
167+ }
168+ checkfinalxform = false;
169+ } else if (sg.transformState <= sg.TRANSFORM_TRANSLATESCALE &&
170+ ((txtype & (AffineTransform.TYPE_FLIP |
171+ AffineTransform.TYPE_MASK_ROTATION |
172+ AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0))
173+ {
174+ // Second optimization - both are some kind of translate or scale
175+
176+ // Combine the scales and check if interpolation is necessary.
177+
178+ // Transform source bounds by extraAT,
179+ // then translate the bounds again by x, y
180+ // then transform the bounds again by sg.transform
181+ double coords[] = new double[] {
182+ 0, 0, imgw, imgh,
183+ };
184+ extraAT.transform(coords, 0, coords, 0, 2);
185+ coords[0] += x;
186+ coords[1] += y;
187+ coords[2] += x;
188+ coords[3] += y;
189+ sg.transform.transform(coords, 0, coords, 0, 2);
190+
191+ if (tryCopyOrScale(sg, img, 0, 0, imgw, imgh,
192+ null, interpType, coords))
193+ {
194+ return;
195+ }
196+ checkfinalxform = false;
197+ } else {
198+ checkfinalxform = true;
199+ }
200+
201+ // Begin Transform
202+ AffineTransform tx = new AffineTransform(sg.transform);
203+ tx.translate(x, y);
204+ tx.concatenate(extraAT);
205+
206+ // Do not try any more optimizations if either of the cases
207+ // above was tried as we have already verified that the
208+ // resulting transform will not simplify.
209+ if (checkfinalxform) {
210+ // In this case neither of the above simple transform
211+ // pairs was found so we will do some final tests on
212+ // the final rendering transform which may be the
213+ // simple product of two complex transforms.
214+ transformImage(sg, img, tx, interpType, 0, 0, imgw, imgh, null);
215+ } else {
216+ renderImageXform(sg, img, tx, interpType, 0, 0, imgw, imgh, null);
217+ }
218+ }
219+
220+ /*
221+ * This method is called with a final rendering transform that
222+ * has combined all of the information about the Graphics2D
223+ * transform attribute with the transformations specified by
224+ * the arguments to the drawImage call.
225+ * Its role is to see if the combined transform ends up being
226+ * acceleratable by either a renderImageCopy or renderImageScale
227+ * once all of the math is done.
228+ *
229+ * Note: The transform supplied here has an origin that is
230+ * already adjusted to point to the device location where
231+ * the (sx1, sy1) location of the source image should be placed.
232+ */
233+ protected void transformImage(SunGraphics2D sg, Image img,
234+ AffineTransform tx, int interpType,
235+ int sx1, int sy1, int sx2, int sy2,
236+ Color bgColor)
237+ {
238+ // Transform 3 source corners by tx and analyze them
239+ // for simplified operations (Copy or Scale). Using
240+ // 3 points lets us analyze any kind of transform,
241+ // even transforms that involve very tiny amounts of
242+ // rotation or skew to see if they degenerate to a
243+ // simple scale or copy operation within the allowable
244+ // error bounds.
245+ // Note that we use (0,0,w,h) instead of (sx1,sy1,sx2,sy2)
246+ // because the transform is already translated such that
247+ // the origin is where sx1, sy1 should go.
248+ double coords[] = new double[6];
249+ /* index: 0 1 2 3 4 5 */
250+ /* coord: (0, 0), (w, h), (0, h) */
251+ coords[2] = sx2 - sx1;
252+ coords[3] = coords[5] = sy2 - sy1;
253+ tx.transform(coords, 0, coords, 0, 3);
254+ // First test if the X coords of the transformed UL
255+ // and LL points match and that the Y coords of the
256+ // transformed LR and LL points also match.
257+ // If they do then it is a "rectilinear" transform and
258+ // tryCopyOrScale will make sure it is upright and
259+ // integer-based.
260+ if (Math.abs(coords[0] - coords[4]) < MAX_TX_ERROR &&
261+ Math.abs(coords[3] - coords[5]) < MAX_TX_ERROR &&
262+ tryCopyOrScale(sg, img, sx1, sy1, sx2, sy2,
263+ bgColor, interpType, coords))
264+ {
265+ return;
266+ }
267+
268+ renderImageXform(sg, img, tx, interpType, sx1, sy1, sx2, sy2, bgColor);
269+ }
270+
271+ /*
272+ * Check the bounding coordinates of the transformed source
273+ * image to see if they fall on integer coordinates such
274+ * that they will cause no interpolation anomalies if we
275+ * use our simplified Blit or ScaledBlit operations instead
276+ * of a full transform operation.
277+ */
278+ protected boolean tryCopyOrScale(SunGraphics2D sg,
279+ Image img,
280+ int sx1, int sy1,
281+ int sx2, int sy2,
282+ Color bgColor, int interpType,
283+ double coords[])
284+ {
285+ double dx = coords[0];
286+ double dy = coords[1];
287+ double dw = coords[2] - dx;
288+ double dh = coords[3] - dy;
289+ // First check if width and height are very close to img w&h.
290+ if (closeToInteger(sx2-sx1, dw) && closeToInteger(sy2-sy1, dh)) {
291+ // Round location to nearest pixel and then test
292+ // if it will cause interpolation anomalies.
293+ int idx = (int) Math.floor(dx + 0.5);
294+ int idy = (int) Math.floor(dy + 0.5);
295+ if (interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR ||
296+ (closeToInteger(idx, dx) && closeToInteger(idy, dy)))
297+ {
298+ renderImageCopy(sg, img, bgColor,
299+ idx, idy,
300+ sx1, sy1, sx2-sx1, sy2-sy1);
301+ return true;
302+ }
303+ }
304+ // (For now) We can only use our ScaledBlits if the image
305+ // is upright (i.e. dw & dh both > 0)
306+ if (dw > 0 && dh > 0) {
307+ if (renderImageScale(sg, img, bgColor, interpType,
308+ sx1, sy1, sx2, sy2,
309+ coords[0], coords[1], coords[2], coords[3]))
310+ {
311+ return true;
312+ }
313+ }
314+ return false;
315+ }
316+
317+ /*
318+ * Return a BufferedImage of the requested type with the indicated
319+ * subimage of the original image located at 0,0 in the new image.
320+ * If a bgColor is supplied, composite the original image over that
321+ * color with a SrcOver operation, otherwise make a SrcNoEa copy.
322+ */
323+ BufferedImage makeBufferedImage(Image img, Color bgColor, int type,
324+ int sx1, int sy1, int sx2, int sy2)
325+ {
326+ BufferedImage bimg = new BufferedImage(sx2-sx1, sy2-sy1, type);
327+ Graphics2D g2d = bimg.createGraphics();
328+ g2d.setComposite(AlphaComposite.Src);
329+ if (bgColor != null) {
330+ g2d.setColor(bgColor);
331+ g2d.fillRect(0, 0, sx2-sx1, sy2-sy1);
332+ g2d.setComposite(AlphaComposite.SrcOver);
333+ }
334+ g2d.drawImage(img, -sx1, -sy1, null);
335+ g2d.dispose();
336+ return bimg;
337+ }
338+
339+ protected void renderImageXform(SunGraphics2D sg, Image img,
340+ AffineTransform tx, int interpType,
341+ int sx1, int sy1, int sx2, int sy2,
342+ Color bgColor)
343+ {
344+ Region clip = sg.getCompClip();
345+ SurfaceData dstData = sg.surfaceData;
346+ SurfaceData srcData = dstData.getSourceSurfaceData(img,
347+ sg.TRANSFORM_GENERIC,
348+ sg.imageComp,
349+ bgColor);
350+
351+ if (srcData == null) {
352+ img = getBufferedImage(img);
353+ srcData = dstData.getSourceSurfaceData(img,
354+ sg.TRANSFORM_GENERIC,
355+ sg.imageComp,
356+ bgColor);
357+ if (srcData == null) {
358+ // REMIND: Is this correct? Can this happen?
359+ return;
360+ }
361+ }
362+
363+ if (isBgOperation(srcData, bgColor)) {
364+ // We cannot perform bg operations during transform so make
365+ // an opaque temp image with the appropriate background
366+ // and work from there.
367+ img = makeBufferedImage(img, bgColor, BufferedImage.TYPE_INT_RGB,
368+ sx1, sy1, sx2, sy2);
369+ // Temp image has appropriate subimage at 0,0 now.
370+ sx2 -= sx1;
371+ sy2 -= sy1;
372+ sx1 = sy1 = 0;
373+
374+ srcData = dstData.getSourceSurfaceData(img,
375+ sg.TRANSFORM_GENERIC,
376+ sg.imageComp,
377+ bgColor);
378+ }
379+
380+ SurfaceType srcType = srcData.getSurfaceType();
381+ TransformHelper helper = TransformHelper.getFromCache(srcType);
382+
383+ if (helper == null) {
384+ /* We have no helper for this source image type.
385+ * But we know that we do have helpers for both RGB and ARGB,
386+ * so convert to one of those types depending on transparency.
387+ * ARGB_PRE might be a better choice if the source image has
388+ * alpha, but it may cause some recursion here since we only
389+ * tend to have converters that convert to ARGB.
390+ */
391+ int type = ((srcData.getTransparency() == Transparency.OPAQUE)
392+ ? BufferedImage.TYPE_INT_RGB
393+ : BufferedImage.TYPE_INT_ARGB);
394+ img = makeBufferedImage(img, null, type, sx1, sy1, sx2, sy2);
395+ // Temp image has appropriate subimage at 0,0 now.
396+ sx2 -= sx1;
397+ sy2 -= sy1;
398+ sx1 = sy1 = 0;
399+
400+ srcData = dstData.getSourceSurfaceData(img,
401+ sg.TRANSFORM_GENERIC,
402+ sg.imageComp,
403+ null);
404+ srcType = srcData.getSurfaceType();
405+ helper = TransformHelper.getFromCache(srcType);
406+ // assert(helper != null);
407+ }
408+
409+ AffineTransform itx;
410+ try {
411+ itx = tx.createInverse();
412+ } catch (NoninvertibleTransformException e) {
413+ // Non-invertible transform means no output
414+ return;
415+ }
416+
417+ /*
418+ * Find the maximum bounds on the destination that will be
419+ * affected by the transformed source. First, transform all
420+ * four corners of the source and then min and max the resulting
421+ * destination coordinates of the transformed corners.
422+ * Note that tx already has the offset to sx1,sy1 accounted
423+ * for so we use the box (0, 0, sx2-sx1, sy2-sy1) as the
424+ * source coordinates.
425+ */
426+ double coords[] = new double[8];
427+ /* corner: UL UR LL LR */
428+ /* index: 0 1 2 3 4 5 6 7 */
429+ /* coord: (0, 0), (w, 0), (0, h), (w, h) */
430+ coords[2] = coords[6] = sx2 - sx1;
431+ coords[5] = coords[7] = sy2 - sy1;
432+ tx.transform(coords, 0, coords, 0, 4);
433+ double ddx1, ddy1, ddx2, ddy2;
434+ ddx1 = ddx2 = coords[0];
435+ ddy1 = ddy2 = coords[1];
436+ for (int i = 2; i < coords.length; i += 2) {
437+ double d = coords[i];
438+ if (ddx1 > d) ddx1 = d;
439+ else if (ddx2 < d) ddx2 = d;
440+ d = coords[i+1];
441+ if (ddy1 > d) ddy1 = d;
442+ else if (ddy2 < d) ddy2 = d;
443+ }
444+ int dx1 = (int) Math.floor(ddx1);
445+ int dy1 = (int) Math.floor(ddy1);
446+ int dx2 = (int) Math.ceil(ddx2);
447+ int dy2 = (int) Math.ceil(ddy2);
448+
449+ SurfaceType dstType = dstData.getSurfaceType();
450+ MaskBlit maskblit;
451+ Blit blit;
452+ if (sg.compositeState <= sg.COMP_ALPHA) {
453+ /* NOTE: We either have, or we can make,
454+ * a MaskBlit for any alpha composite type
455+ */
456+ maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
457+ sg.imageComp,
458+ dstType);
459+
460+ /* NOTE: We can only use the native TransformHelper
461+ * func to go directly to the dest if both the helper
462+ * and the MaskBlit are native.
463+ * All helpers are native at this point, but some MaskBlit
464+ * objects are implemented in Java, so we need to check.
465+ */
466+ if (maskblit.getNativePrim() != 0) {
467+ // We can render directly.
468+ helper.Transform(maskblit, srcData, dstData,
469+ sg.composite, clip,
470+ itx, interpType,
471+ sx1, sy1, sx2, sy2,
472+ dx1, dy1, dx2, dy2,
473+ null, 0, 0);
474+ return;
475+ }
476+ blit = null;
477+ } else {
478+ /* NOTE: We either have, or we can make,
479+ * a Blit for any composite type, even Custom
480+ */
481+ maskblit = null;
482+ blit = Blit.getFromCache(SurfaceType.IntArgbPre,
483+ sg.imageComp,
484+ dstType);
485+ }
486+
487+ // We need to transform to a temp image and then copy
488+ // just the pieces that are valid data to the dest.
489+ BufferedImage tmpimg = new BufferedImage(dx2-dx1, dy2-dy1,
490+ BufferedImage.TYPE_INT_ARGB);
491+ SurfaceData tmpData = SurfaceData.getPrimarySurfaceData(tmpimg);
492+ SurfaceType tmpType = tmpData.getSurfaceType();
493+ MaskBlit tmpmaskblit =
494+ MaskBlit.getFromCache(SurfaceType.IntArgbPre,
495+ CompositeType.SrcNoEa,
496+ tmpType);
497+ /*
498+ * The helper function fills a temporary edges buffer
499+ * for us with the bounding coordinates of each scanline
500+ * in the following format:
501+ *
502+ * edges[0, 1] = [top y, bottom y)
503+ * edges[2, 3] = [left x, right x) of top row
504+ * ...
505+ * edges[h*2, h*2+1] = [left x, right x) of bottom row
506+ *
507+ * all coordinates in the edges array will be relative to dx1, dy1
508+ *
509+ * edges thus has to be h*2+2 in length
510+ */
511+ int edges[] = new int[(dy2-dy1)*2+2];
512+ // It is important that edges[0]=edges[1]=0 when we call
513+ // Transform in case it must return early and we would
514+ // not want to render anything on an error condition.
515+ helper.Transform(tmpmaskblit, srcData, tmpData,
516+ AlphaComposite.Src, null,
517+ itx, interpType,
518+ sx1, sy1, sx2, sy2,
519+ 0, 0, dx2-dx1, dy2-dy1,
520+ edges, dx1, dy1);
521+
522+ /*
523+ * Now copy the results, scanline by scanline, into the dest.
524+ * The edges array helps us minimize the work.
525+ */
526+ int index = 2;
527+ for (int y = edges[0]; y < edges[1]; y++) {
528+ int relx1 = edges[index++];
529+ int relx2 = edges[index++];
530+ if (relx1 >= relx2) {
531+ continue;
532+ }
533+ if (maskblit != null) {
534+ maskblit.MaskBlit(tmpData, dstData,
535+ sg.composite, clip,
536+ relx1, y,
537+ dx1+relx1, dy1+y,
538+ relx2 - relx1, 1,
539+ null, 0, 0);
540+ } else {
541+ blit.Blit(tmpData, dstData,
542+ sg.composite, clip,
543+ relx1, y,
544+ dx1+relx1, dy1+y,
545+ relx2 - relx1, 1);
546+ }
547+ }
548+ }
549+
550+ // Render an image using only integer translation
551+ // (no scale or transform or sub-pixel interpolated translations).
552+ protected boolean renderImageCopy(SunGraphics2D sg, Image img,
553+ Color bgColor,
554+ int dx, int dy,
555+ int sx, int sy,
556+ int w, int h)
557+ {
558+ Region clip = sg.getCompClip();
559+ SurfaceData dstData = sg.surfaceData;
560+
561+ int attempts = 0;
562+ // Loop up to twice through; this gives us a chance to
563+ // revalidate the surfaceData objects in case of an exception
564+ // and try it once more
565+ while (true) {
566+ SurfaceData srcData =
567+ dstData.getSourceSurfaceData(img,
568+ sg.TRANSFORM_ISIDENT,
569+ sg.imageComp,
570+ bgColor);
571+ if (srcData == null) {
572+ return false;
573+ }
574+
575+ try {
576+ SurfaceType srcType = srcData.getSurfaceType();
577+ SurfaceType dstType = dstData.getSurfaceType();
578+ blitSurfaceData(sg, clip,
579+ srcData, dstData, srcType, dstType,
580+ sx, sy, dx, dy, w, h, bgColor);
581+ return true;
582+ } catch (NullPointerException e) {
583+ if (!(SurfaceData.isNull(dstData) ||
584+ SurfaceData.isNull(srcData)))
585+ {
586+ // Something else caused the exception, throw it...
587+ throw e;
588+ }
589+ return false;
590+ // NOP if we have been disposed
591+ } catch (InvalidPipeException e) {
592+ // Always catch the exception; try this a couple of times
593+ // and fail silently if the system is not yet ready to
594+ // revalidate the source or dest surfaceData objects.
595+ ++attempts;
596+ clip = sg.getCompClip(); // ensures sg.surfaceData is valid
597+ dstData = sg.surfaceData;
598+ if (SurfaceData.isNull(dstData) ||
599+ SurfaceData.isNull(srcData) || (attempts > 1))
600+ {
601+ return false;
602+ }
603+ }
604+ }
605+ }
606+
607+ // Render an image using only integer scaling (no transform).
608+ protected boolean renderImageScale(SunGraphics2D sg, Image img,
609+ Color bgColor, int interpType,
610+ int sx1, int sy1,
611+ int sx2, int sy2,
612+ double dx1, double dy1,
613+ double dx2, double dy2)
614+ {
615+ // Currently only NEAREST_NEIGHBOR interpolation is implemented
616+ // for ScaledBlit operations.
617+ if (interpType != AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
618+ return false;
619+ }
620+
621+ Region clip = sg.getCompClip();
622+ SurfaceData dstData = sg.surfaceData;
623+
624+ int attempts = 0;
625+ // Loop up to twice through; this gives us a chance to
626+ // revalidate the surfaceData objects in case of an exception
627+ // and try it once more
628+ while (true) {
629+ SurfaceData srcData =
630+ dstData.getSourceSurfaceData(img,
631+ sg.TRANSFORM_TRANSLATESCALE,
632+ sg.imageComp,
633+ bgColor);
634+
635+ if (srcData == null || isBgOperation(srcData, bgColor)) {
636+ return false;
637+ }
638+
639+ try {
640+ SurfaceType srcType = srcData.getSurfaceType();
641+ SurfaceType dstType = dstData.getSurfaceType();
642+ return scaleSurfaceData(sg, clip,
643+ srcData, dstData, srcType, dstType,
644+ sx1, sy1, sx2, sy2,
645+ dx1, dy1, dx2, dy2);
646+ } catch (NullPointerException e) {
647+ if (!SurfaceData.isNull(dstData)) {
648+ // Something else caused the exception, throw it...
649+ throw e;
650+ }
651+ return false;
652+ // NOP if we have been disposed
653+ } catch (InvalidPipeException e) {
654+ // Always catch the exception; try this a couple of times
655+ // and fail silently if the system is not yet ready to
656+ // revalidate the source or dest surfaceData objects.
657+ ++attempts;
658+ clip = sg.getCompClip(); // ensures sg.surfaceData is valid
659+ dstData = sg.surfaceData;
660+ if (SurfaceData.isNull(dstData) ||
661+ SurfaceData.isNull(srcData) || (attempts > 1))
662+ {
663+ return false;
664+ }
665+ }
666+ }
667+ }
668+
669+ public boolean scaleImage(SunGraphics2D sg, Image img,
670+ int dx1, int dy1, int dx2, int dy2,
671+ int sx1, int sy1, int sx2, int sy2,
672+ Color bgColor)
673+ {
674+ int srcW, srcH, dstW, dstH;
675+ int srcX, srcY, dstX, dstY;
676+ boolean srcWidthFlip = false;
677+ boolean srcHeightFlip = false;
678+ boolean dstWidthFlip = false;
679+ boolean dstHeightFlip = false;
680+
681+ if (sx2 > sx1) {
682+ srcW = sx2 - sx1;
683+ srcX = sx1;
684+ } else {
685+ srcWidthFlip = true;
686+ srcW = sx1 - sx2;
687+ srcX = sx2;
688+ }
689+ if (sy2 > sy1) {
690+ srcH = sy2-sy1;
691+ srcY = sy1;
692+ } else {
693+ srcHeightFlip = true;
694+ srcH = sy1-sy2;
695+ srcY = sy2;
696+ }
697+ if (dx2 > dx1) {
698+ dstW = dx2 - dx1;
699+ dstX = dx1;
700+ } else {
701+ dstW = dx1 - dx2;
702+ dstWidthFlip = true;
703+ dstX = dx2;
704+ }
705+ if (dy2 > dy1) {
706+ dstH = dy2 - dy1;
707+ dstY = dy1;
708+ } else {
709+ dstH = dy1 - dy2;
710+ dstHeightFlip = true;
711+ dstY = dy2;
712+ }
713+ if (srcW <= 0 || srcH <= 0) {
714+ return true;
715+ }
716+ // Only accelerate scale if it does not involve a flip or transform
717+ if ((srcWidthFlip == dstWidthFlip) &&
718+ (srcHeightFlip == dstHeightFlip) &&
719+ isSimpleTranslate(sg))
720+ {
721+ double ddx1 = dstX + sg.transX;
722+ double ddy1 = dstY + sg.transY;
723+ double ddx2 = ddx1 + dstW;
724+ double ddy2 = ddy1 + dstH;
725+ if (renderImageScale(sg, img, bgColor, sg.interpolationType,
726+ srcX, srcY, srcX+srcW, srcY+srcH,
727+ ddx1, ddy1, ddx2, ddy2))
728+ {
729+ return true;
730+ }
731+ }
732+
733+ AffineTransform atfm = new AffineTransform(sg.transform);
734+ atfm.translate(dx1, dy1);
735+ double m00 = (double)(dx2-dx1)/(sx2-sx1);
736+ double m11 = (double)(dy2-dy1)/(sy2-sy1);
737+ atfm.scale(m00, m11);
738+ atfm.translate(srcX-sx1, srcY-sy1);
739+
740+ int imgW = img.getWidth(null);
741+ int imgH = img.getHeight(null);
742+ srcW += srcX;
743+ srcH += srcY;
744+ // Make sure we are not out of bounds
745+ if (srcW > imgW) {
746+ srcW = imgW;
747+ }
748+ if (srcH > imgH) {
749+ srcH = imgH;
750+ }
751+ if (srcX < 0) {
752+ atfm.translate(-srcX, 0);
753+ srcX = 0;
754+ }
755+ if (srcY < 0) {
756+ atfm.translate(0, -srcY);
757+ srcY = 0;
758+ }
759+ if (srcX >= srcW || srcY >= srcH) {
760+ return true;
761+ }
762+ // Note: src[WH] are currently the right and bottom coordinates.
763+ // The following two lines would adjust src[WH] back to being
764+ // dimensions.
765+ // srcW -= srcX;
766+ // srcH -= srcY;
767+ // Since transformImage needs right and bottom coords we will
768+ // omit this adjustment.
769+
770+ transformImage(sg, img, atfm, sg.interpolationType,
771+ srcX, srcY, srcW, srcH, bgColor);
772+ return true;
773+ }
774+
775+ /**
776+ ** Utilities
777+ ** The following methods are used by the public methods above
778+ ** for performing various operations
779+ **/
780+
781+ /*
782+ * This constant represents a tradeoff between the
783+ * need to make sure that image transformations are
784+ * "very close" to integer device coordinates before
785+ * we decide to use an integer scale or copy operation
786+ * as a substitute and the fact that roundoff errors
787+ * in AffineTransforms are frequently introduced by
788+ * performing multiple sequential operations on them.
789+ *
790+ * The evaluation of bug 4990624 details the potential
791+ * for this error cutoff to result in display anomalies
792+ * in different types of image operations and how this
793+ * value represents a good compromise here.
794+ */
795+ private static final double MAX_TX_ERROR = .0001;
796+
797+ public static boolean closeToInteger(int i, double d) {
798+ return (Math.abs(d-i) < MAX_TX_ERROR);
799+ }
800+
801+ public static boolean isSimpleTranslate(SunGraphics2D sg) {
802+ int ts = sg.transformState;
803+ if (ts <= sg.TRANSFORM_INT_TRANSLATE) {
804+ // Integer translates are always "simple"
805+ return true;
806+ }
807+ if (ts >= sg.TRANSFORM_TRANSLATESCALE) {
808+ // Scales and beyond are always "not simple"
809+ return false;
810+ }
811+ // non-integer translates are only simple when not interpolating
812+ if (sg.interpolationType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
813+ return true;
814+ }
815+ return false;
816+ }
817+
818+ protected static boolean isBgOperation(SurfaceData srcData, Color bgColor) {
819+ // If we cannot get the srcData, then cannot assume anything about
820+ // the image
821+ return ((srcData == null) ||
822+ ((bgColor != null) &&
823+ (srcData.getTransparency() != Transparency.OPAQUE)));
824+ }
825+
826+ protected BufferedImage getBufferedImage(Image img) {
827+ if (img instanceof BufferedImage) {
828+ return (BufferedImage)img;
829+ }
830+ // Must be VolatileImage; get BufferedImage representation
831+ return ((VolatileImage)img).getSnapshot();
832+ }
833+
834+ /*
835+ * Return the color model to be used with this BufferedImage and
836+ * transform.
837+ */
838+ private ColorModel getTransformColorModel(SunGraphics2D sg,
839+ BufferedImage bImg,
840+ AffineTransform tx) {
841+ ColorModel cm = bImg.getColorModel();
842+ ColorModel dstCM = cm;
843+
844+ if (tx.isIdentity()) {
845+ return dstCM;
846+ }
847+ int type = tx.getType();
848+ boolean needTrans =
849+ ((type&(tx.TYPE_MASK_ROTATION|tx.TYPE_GENERAL_TRANSFORM)) != 0);
850+ if (! needTrans && type != tx.TYPE_TRANSLATION && type != tx.TYPE_IDENTITY)
851+ {
852+ double[] mtx = new double[4];
853+ tx.getMatrix(mtx);
854+ // Check out the matrix. A non-integral scale will force ARGB
855+ // since the edge conditions cannot be guaranteed.
856+ needTrans = (mtx[0] != (int)mtx[0] || mtx[3] != (int)mtx[3]);
857+ }
858+
859+ if (sg.renderHint != SunHints.INTVAL_RENDER_QUALITY) {
860+ if (cm instanceof IndexColorModel) {
861+ Raster raster = bImg.getRaster();
862+ IndexColorModel icm = (IndexColorModel) cm;
863+ // Just need to make sure that we have a transparent pixel
864+ if (needTrans && cm.getTransparency() == cm.OPAQUE) {
865+ // Fix 4221407
866+ if (raster instanceof sun.awt.image.BytePackedRaster) {
867+ dstCM = ColorModel.getRGBdefault();
868+ }
869+ else {
870+ double[] matrix = new double[6];
871+ tx.getMatrix(matrix);
872+ if (matrix[1] == 0. && matrix[2] ==0.
873+ && matrix[4] == 0. && matrix[5] == 0.) {
874+ // Only scaling so do not need to create
875+ }
876+ else {
877+ int mapSize = icm.getMapSize();
878+ if (mapSize < 256) {
879+ int[] cmap = new int[mapSize+1];
880+ icm.getRGBs(cmap);
881+ cmap[mapSize] = 0x0000;
882+ dstCM = new
883+ IndexColorModel(icm.getPixelSize(),
884+ mapSize+1,
885+ cmap, 0, true, mapSize,
886+ DataBuffer.TYPE_BYTE);
887+ }
888+ else {
889+ dstCM = ColorModel.getRGBdefault();
890+ }
891+ } /* if (matrix[0] < 1.f ...) */
892+ } /* raster instanceof sun.awt.image.BytePackedRaster */
893+ } /* if (cm.getTransparency() == cm.OPAQUE) */
894+ } /* if (cm instanceof IndexColorModel) */
895+ else if (needTrans && cm.getTransparency() == cm.OPAQUE) {
896+ // Need a bitmask transparency
897+ // REMIND: for now, use full transparency since no loops
898+ // for bitmask
899+ dstCM = ColorModel.getRGBdefault();
900+ }
901+ } /* if (sg.renderHint == RENDER_QUALITY) */
902+ else {
903+
904+ if (cm instanceof IndexColorModel ||
905+ (needTrans && cm.getTransparency() == cm.OPAQUE))
906+ {
907+ // Need a bitmask transparency
908+ // REMIND: for now, use full transparency since no loops
909+ // for bitmask
910+ dstCM = ColorModel.getRGBdefault();
911+ }
912+ }
913+
914+ return dstCM;
915+ }
916+
917+ protected void blitSurfaceData(SunGraphics2D sg,
918+ Region clipRegion,
919+ SurfaceData srcData,
920+ SurfaceData dstData,
921+ SurfaceType srcType,
922+ SurfaceType dstType,
923+ int sx, int sy, int dx, int dy,
924+ int w, int h,
925+ Color bgColor)
926+ {
927+ if (w <= 0 || h <= 0) {
928+ /*
929+ * Fix for bugid 4783274 - BlitBg throws an exception for
930+ * a particular set of anomalous parameters.
931+ * REMIND: The native loops do proper clipping and would
932+ * detect this situation themselves, but the Java loops
933+ * all seem to trust their parameters a little too well
934+ * to the point where they will try to process a negative
935+ * area of pixels and throw exceptions. The real fix is
936+ * to modify the Java loops to do proper clipping so that
937+ * they can deal with negative dimensions as well as
938+ * improperly large dimensions, but that fix is too risky
939+ * to integrate for Mantis at this point. In the meantime
940+ * eliminating the negative or zero dimensions here is
941+ * "correct" and saves them from some nasty exceptional
942+ * conditions, one of which is the test case of 4783274.
943+ */
944+ return;
945+ }
946+ CompositeType comp = sg.imageComp;
947+ if (CompositeType.SrcOverNoEa.equals(comp) &&
948+ (srcData.getTransparency() == Transparency.OPAQUE ||
949+ (bgColor != null &&
950+ bgColor.getTransparency() == Transparency.OPAQUE)))
951+ {
952+ comp = CompositeType.SrcNoEa;
953+ }
954+ if (!isBgOperation(srcData, bgColor)) {
955+ Blit blit = Blit.getFromCache(srcType, comp, dstType);
956+ blit.Blit(srcData, dstData, sg.composite, clipRegion,
957+ sx, sy, dx, dy, w, h);
958+ } else {
959+ BlitBg blit = BlitBg.getFromCache(srcType, comp, dstType);
960+ blit.BlitBg(srcData, dstData, sg.composite, clipRegion,
961+ bgColor.getRGB(), sx, sy, dx, dy, w, h);
962+ }
963+ }
964+
965+ protected boolean scaleSurfaceData(SunGraphics2D sg,
966+ Region clipRegion,
967+ SurfaceData srcData,
968+ SurfaceData dstData,
969+ SurfaceType srcType,
970+ SurfaceType dstType,
971+ int sx1, int sy1,
972+ int sx2, int sy2,
973+ double dx1, double dy1,
974+ double dx2, double dy2)
975+ {
976+ CompositeType comp = sg.imageComp;
977+ if (CompositeType.SrcOverNoEa.equals(comp) &&
978+ (srcData.getTransparency() == Transparency.OPAQUE))
979+ {
980+ comp = CompositeType.SrcNoEa;
981+ }
982+
983+ ScaledBlit blit = ScaledBlit.getFromCache(srcType, comp, dstType);
984+ if (blit != null) {
985+ blit.Scale(srcData, dstData, sg.composite, clipRegion,
986+ sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
987+ return true;
988+ }
989+ return false;
990+ }
991+
992+ protected static boolean imageReady(ToolkitImage sunimg,
993+ ImageObserver observer)
994+ {
995+ if (sunimg.hasError()) {
996+ if (observer != null) {
997+ observer.imageUpdate(sunimg,
998+ ImageObserver.ERROR|ImageObserver.ABORT,
999+ -1, -1, -1, -1);
1000+ }
1001+ return false;
1002+ }
1003+ return true;
1004+ }
1005+
1006+ public boolean copyImage(SunGraphics2D sg, Image img,
1007+ int x, int y,
1008+ Color bgColor,
1009+ ImageObserver observer) {
1010+ if (!(img instanceof ToolkitImage)) {
1011+ return copyImage(sg, img, x, y, bgColor);
1012+ } else {
1013+ ToolkitImage sunimg = (ToolkitImage)img;
1014+ if (!imageReady(sunimg, observer)) {
1015+ return false;
1016+ }
1017+ ImageRepresentation ir = sunimg.getImageRep();
1018+ return ir.drawToBufImage(sg, sunimg, x, y, bgColor, observer);
1019+ }
1020+ }
1021+
1022+ public boolean copyImage(SunGraphics2D sg, Image img,
1023+ int dx, int dy, int sx, int sy, int w, int h,
1024+ Color bgColor,
1025+ ImageObserver observer) {
1026+ if (!(img instanceof ToolkitImage)) {
1027+ return copyImage(sg, img, dx, dy, sx, sy, w, h, bgColor);
1028+ } else {
1029+ ToolkitImage sunimg = (ToolkitImage)img;
1030+ if (!imageReady(sunimg, observer)) {
1031+ return false;
1032+ }
1033+ ImageRepresentation ir = sunimg.getImageRep();
1034+ return ir.drawToBufImage(sg, sunimg,
1035+ dx, dy, (dx + w), (dy + h),
1036+ sx, sy, (sx + w), (sy + h),
1037+ bgColor, observer);
1038+ }
1039+ }
1040+
1041+ public boolean scaleImage(SunGraphics2D sg, Image img,
1042+ int x, int y,
1043+ int width, int height,
1044+ Color bgColor,
1045+ ImageObserver observer) {
1046+ if (!(img instanceof ToolkitImage)) {
1047+ return scaleImage(sg, img, x, y, width, height, bgColor);
1048+ } else {
1049+ ToolkitImage sunimg = (ToolkitImage)img;
1050+ if (!imageReady(sunimg, observer)) {
1051+ return false;
1052+ }
1053+ ImageRepresentation ir = sunimg.getImageRep();
1054+ return ir.drawToBufImage(sg, sunimg, x, y, width, height, bgColor,
1055+ observer);
1056+ }
1057+ }
1058+
1059+ public boolean scaleImage(SunGraphics2D sg, Image img,
1060+ int dx1, int dy1, int dx2, int dy2,
1061+ int sx1, int sy1, int sx2, int sy2,
1062+ Color bgColor,
1063+ ImageObserver observer) {
1064+ if (!(img instanceof ToolkitImage)) {
1065+ return scaleImage(sg, img, dx1, dy1, dx2, dy2,
1066+ sx1, sy1, sx2, sy2, bgColor);
1067+ } else {
1068+ ToolkitImage sunimg = (ToolkitImage)img;
1069+ if (!imageReady(sunimg, observer)) {
1070+ return false;
1071+ }
1072+ ImageRepresentation ir = sunimg.getImageRep();
1073+ return ir.drawToBufImage(sg, sunimg, dx1, dy1, dx2, dy2,
1074+ sx1, sy1, sx2, sy2, bgColor, observer);
1075+ }
1076+ }
1077+
1078+ public boolean transformImage(SunGraphics2D sg, Image img,
1079+ AffineTransform atfm,
1080+ ImageObserver observer) {
1081+ if (!(img instanceof ToolkitImage)) {
1082+ transformImage(sg, img, 0, 0, atfm, sg.interpolationType);
1083+ return true;
1084+ } else {
1085+ ToolkitImage sunimg = (ToolkitImage)img;
1086+ if (!imageReady(sunimg, observer)) {
1087+ return false;
1088+ }
1089+ ImageRepresentation ir = sunimg.getImageRep();
1090+ return ir.drawToBufImage(sg, sunimg, atfm, observer);
1091+ }
1092+ }
1093+
1094+ public void transformImage(SunGraphics2D sg, BufferedImage img,
1095+ BufferedImageOp op, int x, int y)
1096+ {
1097+ if (op != null) {
1098+ if (op instanceof AffineTransformOp) {
1099+ AffineTransformOp atop = (AffineTransformOp) op;
1100+ transformImage(sg, img, x, y,
1101+ atop.getTransform(),
1102+ atop.getInterpolationType());
1103+ return;
1104+ } else {
1105+ img = op.filter(img, null);
1106+ }
1107+ }
1108+ copyImage(sg, img, x, y, null);
1109+ }
1110+}