001 /*
002 * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.awt;
027
028 import java.awt.image.BufferedImage;
029 import java.awt.image.Raster;
030 import java.awt.image.WritableRaster;
031 import java.awt.image.ColorModel;
032 import java.awt.image.DirectColorModel;
033 import java.awt.image.IndexColorModel;
034 import java.awt.geom.AffineTransform;
035 import java.awt.geom.NoninvertibleTransformException;
036 import java.lang.ref.WeakReference;
037 import sun.awt.image.SunWritableRaster;
038 import sun.awt.image.IntegerInterleavedRaster;
039 import sun.awt.image.ByteInterleavedRaster;
040
041 abstract class TexturePaintContext implements PaintContext {
042 public static ColorModel xrgbmodel = new DirectColorModel(24,
043 0xff0000, 0xff00, 0xff);
044 public static ColorModel argbmodel = ColorModel.getRGBdefault();
045
046 ColorModel colorModel;
047 int bWidth;
048 int bHeight;
049 int maxWidth;
050
051 WritableRaster outRas;
052
053 double xOrg;
054 double yOrg;
055 double incXAcross;
056 double incYAcross;
057 double incXDown;
058 double incYDown;
059
060 int colincx;
061 int colincy;
062 int colincxerr;
063 int colincyerr;
064 int rowincx;
065 int rowincy;
066 int rowincxerr;
067 int rowincyerr;
068
069 public static PaintContext getContext(BufferedImage bufImg,
070 AffineTransform xform, RenderingHints hints,
071 Rectangle devBounds) {
072 WritableRaster raster = bufImg.getRaster();
073 ColorModel cm = bufImg.getColorModel();
074 int maxw = devBounds.width;
075 Object val = hints.get(hints.KEY_INTERPOLATION);
076 boolean filter = (val == null ? (hints.get(hints.KEY_RENDERING) == hints.VALUE_RENDER_QUALITY)
077 : (val != hints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR));
078 if (raster instanceof IntegerInterleavedRaster
079 && (!filter || isFilterableDCM(cm))) {
080 IntegerInterleavedRaster iir = (IntegerInterleavedRaster) raster;
081 if (iir.getNumDataElements() == 1
082 && iir.getPixelStride() == 1) {
083 return new Int(iir, cm, xform, maxw, filter);
084 }
085 } else if (raster instanceof ByteInterleavedRaster) {
086 ByteInterleavedRaster bir = (ByteInterleavedRaster) raster;
087 if (bir.getNumDataElements() == 1
088 && bir.getPixelStride() == 1) {
089 if (filter) {
090 if (isFilterableICM(cm)) {
091 return new ByteFilter(bir, cm, xform, maxw);
092 }
093 } else {
094 return new Byte(bir, cm, xform, maxw);
095 }
096 }
097 }
098 return new Any(raster, cm, xform, maxw, filter);
099 }
100
101 public static boolean isFilterableICM(ColorModel cm) {
102 if (cm instanceof IndexColorModel) {
103 IndexColorModel icm = (IndexColorModel) cm;
104 if (icm.getMapSize() <= 256) {
105 return true;
106 }
107 }
108 return false;
109 }
110
111 public static boolean isFilterableDCM(ColorModel cm) {
112 if (cm instanceof DirectColorModel) {
113 DirectColorModel dcm = (DirectColorModel) cm;
114 return (isMaskOK(dcm.getAlphaMask(), true)
115 && isMaskOK(dcm.getRedMask(), false)
116 && isMaskOK(dcm.getGreenMask(), false) && isMaskOK(
117 dcm.getBlueMask(), false));
118 }
119 return false;
120 }
121
122 public static boolean isMaskOK(int mask, boolean canbezero) {
123 if (canbezero && mask == 0) {
124 return true;
125 }
126 return (mask == 0xff || mask == 0xff00 || mask == 0xff0000 || mask == 0xff000000);
127 }
128
129 public static ColorModel getInternedColorModel(ColorModel cm) {
130 if (xrgbmodel == cm || xrgbmodel.equals(cm)) {
131 return xrgbmodel;
132 }
133 if (argbmodel == cm || argbmodel.equals(cm)) {
134 return argbmodel;
135 }
136 return cm;
137 }
138
139 TexturePaintContext(ColorModel cm, AffineTransform xform,
140 int bWidth, int bHeight, int maxw) {
141 this .colorModel = getInternedColorModel(cm);
142 this .bWidth = bWidth;
143 this .bHeight = bHeight;
144 this .maxWidth = maxw;
145
146 try {
147 xform = xform.createInverse();
148 } catch (NoninvertibleTransformException e) {
149 xform.setToScale(0, 0);
150 }
151 this .incXAcross = mod(xform.getScaleX(), bWidth);
152 this .incYAcross = mod(xform.getShearY(), bHeight);
153 this .incXDown = mod(xform.getShearX(), bWidth);
154 this .incYDown = mod(xform.getScaleY(), bHeight);
155 this .xOrg = xform.getTranslateX();
156 this .yOrg = xform.getTranslateY();
157 this .colincx = (int) incXAcross;
158 this .colincy = (int) incYAcross;
159 this .colincxerr = fractAsInt(incXAcross);
160 this .colincyerr = fractAsInt(incYAcross);
161 this .rowincx = (int) incXDown;
162 this .rowincy = (int) incYDown;
163 this .rowincxerr = fractAsInt(incXDown);
164 this .rowincyerr = fractAsInt(incYDown);
165
166 }
167
168 static int fractAsInt(double d) {
169 return (int) ((d % 1.0) * Integer.MAX_VALUE);
170 }
171
172 static double mod(double num, double den) {
173 num = num % den;
174 if (num < 0) {
175 num += den;
176 if (num >= den) {
177 // For very small negative numerators, the answer might
178 // be such a tiny bit less than den that the difference
179 // is smaller than the mantissa of a double allows and
180 // the result would then be rounded to den. If that is
181 // the case then we map that number to 0 as the nearest
182 // modulus representation.
183 num = 0;
184 }
185 }
186 return num;
187 }
188
189 /**
190 * Release the resources allocated for the operation.
191 */
192 public void dispose() {
193 dropRaster(colorModel, outRas);
194 }
195
196 /**
197 * Return the ColorModel of the output.
198 */
199 public ColorModel getColorModel() {
200 return colorModel;
201 }
202
203 /**
204 * Return a Raster containing the colors generated for the graphics
205 * operation.
206 * @param x,y,w,h The area in device space for which colors are
207 * generated.
208 */
209 public Raster getRaster(int x, int y, int w, int h) {
210 if (outRas == null || outRas.getWidth() < w
211 || outRas.getHeight() < h) {
212 // If h==1, we will probably get lots of "scanline" rects
213 outRas = makeRaster((h == 1 ? Math.max(w, maxWidth) : w), h);
214 }
215 double X = mod(xOrg + x * incXAcross + y * incXDown, bWidth);
216 double Y = mod(yOrg + x * incYAcross + y * incYDown, bHeight);
217
218 setRaster((int) X, (int) Y, fractAsInt(X), fractAsInt(Y), w, h,
219 bWidth, bHeight, colincx, colincxerr, colincy,
220 colincyerr, rowincx, rowincxerr, rowincy, rowincyerr);
221
222 SunWritableRaster.markDirty(outRas);
223
224 return outRas;
225 }
226
227 private static WeakReference xrgbRasRef;
228 private static WeakReference argbRasRef;
229
230 synchronized static WritableRaster makeRaster(ColorModel cm,
231 Raster srcRas, int w, int h) {
232 if (xrgbmodel == cm) {
233 if (xrgbRasRef != null) {
234 WritableRaster wr = (WritableRaster) xrgbRasRef.get();
235 if (wr != null && wr.getWidth() >= w
236 && wr.getHeight() >= h) {
237 xrgbRasRef = null;
238 return wr;
239 }
240 }
241 // If we are going to cache this Raster, make it non-tiny
242 if (w <= 32 && h <= 32) {
243 w = h = 32;
244 }
245 } else if (argbmodel == cm) {
246 if (argbRasRef != null) {
247 WritableRaster wr = (WritableRaster) argbRasRef.get();
248 if (wr != null && wr.getWidth() >= w
249 && wr.getHeight() >= h) {
250 argbRasRef = null;
251 return wr;
252 }
253 }
254 // If we are going to cache this Raster, make it non-tiny
255 if (w <= 32 && h <= 32) {
256 w = h = 32;
257 }
258 }
259 if (srcRas != null) {
260 return srcRas.createCompatibleWritableRaster(w, h);
261 } else {
262 return cm.createCompatibleWritableRaster(w, h);
263 }
264 }
265
266 synchronized static void dropRaster(ColorModel cm, Raster outRas) {
267 if (outRas == null) {
268 return;
269 }
270 if (xrgbmodel == cm) {
271 xrgbRasRef = new WeakReference(outRas);
272 } else if (argbmodel == cm) {
273 argbRasRef = new WeakReference(outRas);
274 }
275 }
276
277 private static WeakReference byteRasRef;
278
279 synchronized static WritableRaster makeByteRaster(Raster srcRas,
280 int w, int h) {
281 if (byteRasRef != null) {
282 WritableRaster wr = (WritableRaster) byteRasRef.get();
283 if (wr != null && wr.getWidth() >= w && wr.getHeight() >= h) {
284 byteRasRef = null;
285 return wr;
286 }
287 }
288 // If we are going to cache this Raster, make it non-tiny
289 if (w <= 32 && h <= 32) {
290 w = h = 32;
291 }
292 return srcRas.createCompatibleWritableRaster(w, h);
293 }
294
295 synchronized static void dropByteRaster(Raster outRas) {
296 if (outRas == null) {
297 return;
298 }
299 byteRasRef = new WeakReference(outRas);
300 }
301
302 public abstract WritableRaster makeRaster(int w, int h);
303
304 public abstract void setRaster(int x, int y, int xerr, int yerr,
305 int w, int h, int bWidth, int bHeight, int colincx,
306 int colincxerr, int colincy, int colincyerr, int rowincx,
307 int rowincxerr, int rowincy, int rowincyerr);
308
309 /*
310 * Blends the four ARGB values in the rgbs array using the factors
311 * described by xmul and ymul in the following ratio:
312 *
313 * rgbs[0] * (1-xmul) * (1-ymul) +
314 * rgbs[1] * ( xmul) * (1-ymul) +
315 * rgbs[2] * (1-xmul) * ( ymul) +
316 * rgbs[3] * ( xmul) * ( ymul)
317 *
318 * xmul and ymul are integer values in the half-open range [0, 2^31)
319 * where 0 == 0.0 and 2^31 == 1.0.
320 *
321 * Note that since the range is half-open, the values are always
322 * logically less than 1.0. This makes sense because while choosing
323 * pixels to blend, when the error values reach 1.0 we move to the
324 * next pixel and reset them to 0.0.
325 */
326 public static int blend(int rgbs[], int xmul, int ymul) {
327 // xmul/ymul are 31 bits wide, (0 => 2^31-1)
328 // shift them to 12 bits wide, (0 => 2^12-1)
329 xmul = (xmul >>> 19);
330 ymul = (ymul >>> 19);
331 int accumA, accumR, accumG, accumB;
332 accumA = accumR = accumG = accumB = 0;
333 for (int i = 0; i < 4; i++) {
334 int rgb = rgbs[i];
335 // The complement of the [xy]mul values (1-[xy]mul) can result
336 // in new values in the range (1 => 2^12). Thus for any given
337 // loop iteration, the values could be anywhere in (0 => 2^12).
338 xmul = (1 << 12) - xmul;
339 if ((i & 1) == 0) {
340 ymul = (1 << 12) - ymul;
341 }
342 // xmul and ymul are each 12 bits (0 => 2^12)
343 // factor is thus 24 bits (0 => 2^24)
344 int factor = xmul * ymul;
345 if (factor != 0) {
346 // accum variables will accumulate 32 bits
347 // bytes extracted from rgb fit in 8 bits (0 => 255)
348 // byte * factor thus fits in 32 bits (0 => 255 * 2^24)
349 accumA += (((rgb >>> 24)) * factor);
350 accumR += (((rgb >>> 16) & 0xff) * factor);
351 accumG += (((rgb >>> 8) & 0xff) * factor);
352 accumB += (((rgb) & 0xff) * factor);
353 }
354 }
355 return ((((accumA + (1 << 23)) >>> 24) << 24)
356 | (((accumR + (1 << 23)) >>> 24) << 16)
357 | (((accumG + (1 << 23)) >>> 24) << 8) | (((accumB + (1 << 23)) >>> 24)));
358 }
359
360 static class Int extends TexturePaintContext {
361 IntegerInterleavedRaster srcRas;
362 int inData[];
363 int inOff;
364 int inSpan;
365 int outData[];
366 int outOff;
367 int outSpan;
368 boolean filter;
369
370 public Int(IntegerInterleavedRaster srcRas, ColorModel cm,
371 AffineTransform xform, int maxw, boolean filter) {
372 super (cm, xform, srcRas.getWidth(), srcRas.getHeight(),
373 maxw);
374 this .srcRas = srcRas;
375 this .inData = srcRas.getDataStorage();
376 this .inSpan = srcRas.getScanlineStride();
377 this .inOff = srcRas.getDataOffset(0);
378 this .filter = filter;
379 }
380
381 public WritableRaster makeRaster(int w, int h) {
382 WritableRaster ras = makeRaster(colorModel, srcRas, w, h);
383 IntegerInterleavedRaster iiRas = (IntegerInterleavedRaster) ras;
384 outData = iiRas.getDataStorage();
385 outSpan = iiRas.getScanlineStride();
386 outOff = iiRas.getDataOffset(0);
387 return ras;
388 }
389
390 public void setRaster(int x, int y, int xerr, int yerr, int w,
391 int h, int bWidth, int bHeight, int colincx,
392 int colincxerr, int colincy, int colincyerr,
393 int rowincx, int rowincxerr, int rowincy, int rowincyerr) {
394 int[] inData = this .inData;
395 int[] outData = this .outData;
396 int out = outOff;
397 int inSpan = this .inSpan;
398 int inOff = this .inOff;
399 int outSpan = this .outSpan;
400 boolean filter = this .filter;
401 boolean normalx = (colincx == 1 && colincxerr == 0
402 && colincy == 0 && colincyerr == 0)
403 && !filter;
404 int rowx = x;
405 int rowy = y;
406 int rowxerr = xerr;
407 int rowyerr = yerr;
408 if (normalx) {
409 outSpan -= w;
410 }
411 int rgbs[] = filter ? new int[4] : null;
412 for (int j = 0; j < h; j++) {
413 if (normalx) {
414 int in = inOff + rowy * inSpan + bWidth;
415 x = bWidth - rowx;
416 out += w;
417 if (bWidth >= 32) {
418 int i = w;
419 while (i > 0) {
420 int copyw = (i < x) ? i : x;
421 System.arraycopy(inData, in - x, outData,
422 out - i, copyw);
423 i -= copyw;
424 if ((x -= copyw) == 0) {
425 x = bWidth;
426 }
427 }
428 } else {
429 for (int i = w; i > 0; i--) {
430 outData[out - i] = inData[in - x];
431 if (--x == 0) {
432 x = bWidth;
433 }
434 }
435 }
436 } else {
437 x = rowx;
438 y = rowy;
439 xerr = rowxerr;
440 yerr = rowyerr;
441 for (int i = 0; i < w; i++) {
442 if (filter) {
443 int nextx, nexty;
444 if ((nextx = x + 1) >= bWidth) {
445 nextx = 0;
446 }
447 if ((nexty = y + 1) >= bHeight) {
448 nexty = 0;
449 }
450 rgbs[0] = inData[inOff + y * inSpan + x];
451 rgbs[1] = inData[inOff + y * inSpan + nextx];
452 rgbs[2] = inData[inOff + nexty * inSpan + x];
453 rgbs[3] = inData[inOff + nexty * inSpan
454 + nextx];
455 outData[out + i] = TexturePaintContext
456 .blend(rgbs, xerr, yerr);
457 } else {
458 outData[out + i] = inData[inOff + y
459 * inSpan + x];
460 }
461 if ((xerr += colincxerr) < 0) {
462 xerr &= Integer.MAX_VALUE;
463 x++;
464 }
465 if ((x += colincx) >= bWidth) {
466 x -= bWidth;
467 }
468 if ((yerr += colincyerr) < 0) {
469 yerr &= Integer.MAX_VALUE;
470 y++;
471 }
472 if ((y += colincy) >= bHeight) {
473 y -= bHeight;
474 }
475 }
476 }
477 if ((rowxerr += rowincxerr) < 0) {
478 rowxerr &= Integer.MAX_VALUE;
479 rowx++;
480 }
481 if ((rowx += rowincx) >= bWidth) {
482 rowx -= bWidth;
483 }
484 if ((rowyerr += rowincyerr) < 0) {
485 rowyerr &= Integer.MAX_VALUE;
486 rowy++;
487 }
488 if ((rowy += rowincy) >= bHeight) {
489 rowy -= bHeight;
490 }
491 out += outSpan;
492 }
493 }
494 }
495
496 static class Byte extends TexturePaintContext {
497 ByteInterleavedRaster srcRas;
498 byte inData[];
499 int inOff;
500 int inSpan;
501 byte outData[];
502 int outOff;
503 int outSpan;
504
505 public Byte(ByteInterleavedRaster srcRas, ColorModel cm,
506 AffineTransform xform, int maxw) {
507 super (cm, xform, srcRas.getWidth(), srcRas.getHeight(),
508 maxw);
509 this .srcRas = srcRas;
510 this .inData = srcRas.getDataStorage();
511 this .inSpan = srcRas.getScanlineStride();
512 this .inOff = srcRas.getDataOffset(0);
513 }
514
515 public WritableRaster makeRaster(int w, int h) {
516 WritableRaster ras = makeByteRaster(srcRas, w, h);
517 ByteInterleavedRaster biRas = (ByteInterleavedRaster) ras;
518 outData = biRas.getDataStorage();
519 outSpan = biRas.getScanlineStride();
520 outOff = biRas.getDataOffset(0);
521 return ras;
522 }
523
524 public void dispose() {
525 dropByteRaster(outRas);
526 }
527
528 public void setRaster(int x, int y, int xerr, int yerr, int w,
529 int h, int bWidth, int bHeight, int colincx,
530 int colincxerr, int colincy, int colincyerr,
531 int rowincx, int rowincxerr, int rowincy, int rowincyerr) {
532 byte[] inData = this .inData;
533 byte[] outData = this .outData;
534 int out = outOff;
535 int inSpan = this .inSpan;
536 int inOff = this .inOff;
537 int outSpan = this .outSpan;
538 boolean normalx = (colincx == 1 && colincxerr == 0
539 && colincy == 0 && colincyerr == 0);
540 int rowx = x;
541 int rowy = y;
542 int rowxerr = xerr;
543 int rowyerr = yerr;
544 if (normalx) {
545 outSpan -= w;
546 }
547 for (int j = 0; j < h; j++) {
548 if (normalx) {
549 int in = inOff + rowy * inSpan + bWidth;
550 x = bWidth - rowx;
551 out += w;
552 if (bWidth >= 32) {
553 int i = w;
554 while (i > 0) {
555 int copyw = (i < x) ? i : x;
556 System.arraycopy(inData, in - x, outData,
557 out - i, copyw);
558 i -= copyw;
559 if ((x -= copyw) == 0) {
560 x = bWidth;
561 }
562 }
563 } else {
564 for (int i = w; i > 0; i--) {
565 outData[out - i] = inData[in - x];
566 if (--x == 0) {
567 x = bWidth;
568 }
569 }
570 }
571 } else {
572 x = rowx;
573 y = rowy;
574 xerr = rowxerr;
575 yerr = rowyerr;
576 for (int i = 0; i < w; i++) {
577 outData[out + i] = inData[inOff + y * inSpan
578 + x];
579 if ((xerr += colincxerr) < 0) {
580 xerr &= Integer.MAX_VALUE;
581 x++;
582 }
583 if ((x += colincx) >= bWidth) {
584 x -= bWidth;
585 }
586 if ((yerr += colincyerr) < 0) {
587 yerr &= Integer.MAX_VALUE;
588 y++;
589 }
590 if ((y += colincy) >= bHeight) {
591 y -= bHeight;
592 }
593 }
594 }
595 if ((rowxerr += rowincxerr) < 0) {
596 rowxerr &= Integer.MAX_VALUE;
597 rowx++;
598 }
599 if ((rowx += rowincx) >= bWidth) {
600 rowx -= bWidth;
601 }
602 if ((rowyerr += rowincyerr) < 0) {
603 rowyerr &= Integer.MAX_VALUE;
604 rowy++;
605 }
606 if ((rowy += rowincy) >= bHeight) {
607 rowy -= bHeight;
608 }
609 out += outSpan;
610 }
611 }
612 }
613
614 static class ByteFilter extends TexturePaintContext {
615 ByteInterleavedRaster srcRas;
616 int inPalette[];
617 byte inData[];
618 int inOff;
619 int inSpan;
620 int outData[];
621 int outOff;
622 int outSpan;
623
624 public ByteFilter(ByteInterleavedRaster srcRas, ColorModel cm,
625 AffineTransform xform, int maxw) {
626 super (
627 (cm.getTransparency() == Transparency.OPAQUE ? xrgbmodel
628 : argbmodel), xform, srcRas.getWidth(),
629 srcRas.getHeight(), maxw);
630 this .inPalette = new int[256];
631 ((IndexColorModel) cm).getRGBs(this .inPalette);
632 this .srcRas = srcRas;
633 this .inData = srcRas.getDataStorage();
634 this .inSpan = srcRas.getScanlineStride();
635 this .inOff = srcRas.getDataOffset(0);
636 }
637
638 public WritableRaster makeRaster(int w, int h) {
639 // Note that we do not pass srcRas to makeRaster since it
640 // is a Byte Raster and this colorModel needs an Int Raster
641 WritableRaster ras = makeRaster(colorModel, null, w, h);
642 IntegerInterleavedRaster iiRas = (IntegerInterleavedRaster) ras;
643 outData = iiRas.getDataStorage();
644 outSpan = iiRas.getScanlineStride();
645 outOff = iiRas.getDataOffset(0);
646 return ras;
647 }
648
649 public void setRaster(int x, int y, int xerr, int yerr, int w,
650 int h, int bWidth, int bHeight, int colincx,
651 int colincxerr, int colincy, int colincyerr,
652 int rowincx, int rowincxerr, int rowincy, int rowincyerr) {
653 byte[] inData = this .inData;
654 int[] outData = this .outData;
655 int out = outOff;
656 int inSpan = this .inSpan;
657 int inOff = this .inOff;
658 int outSpan = this .outSpan;
659 int rowx = x;
660 int rowy = y;
661 int rowxerr = xerr;
662 int rowyerr = yerr;
663 int rgbs[] = new int[4];
664 for (int j = 0; j < h; j++) {
665 x = rowx;
666 y = rowy;
667 xerr = rowxerr;
668 yerr = rowyerr;
669 for (int i = 0; i < w; i++) {
670 int nextx, nexty;
671 if ((nextx = x + 1) >= bWidth) {
672 nextx = 0;
673 }
674 if ((nexty = y + 1) >= bHeight) {
675 nexty = 0;
676 }
677 rgbs[0] = inPalette[0xff & inData[inOff + x
678 + inSpan * y]];
679 rgbs[1] = inPalette[0xff & inData[inOff + nextx
680 + inSpan * y]];
681 rgbs[2] = inPalette[0xff & inData[inOff + x
682 + inSpan * nexty]];
683 rgbs[3] = inPalette[0xff & inData[inOff + nextx
684 + inSpan * nexty]];
685 outData[out + i] = TexturePaintContext.blend(rgbs,
686 xerr, yerr);
687 if ((xerr += colincxerr) < 0) {
688 xerr &= Integer.MAX_VALUE;
689 x++;
690 }
691 if ((x += colincx) >= bWidth) {
692 x -= bWidth;
693 }
694 if ((yerr += colincyerr) < 0) {
695 yerr &= Integer.MAX_VALUE;
696 y++;
697 }
698 if ((y += colincy) >= bHeight) {
699 y -= bHeight;
700 }
701 }
702 if ((rowxerr += rowincxerr) < 0) {
703 rowxerr &= Integer.MAX_VALUE;
704 rowx++;
705 }
706 if ((rowx += rowincx) >= bWidth) {
707 rowx -= bWidth;
708 }
709 if ((rowyerr += rowincyerr) < 0) {
710 rowyerr &= Integer.MAX_VALUE;
711 rowy++;
712 }
713 if ((rowy += rowincy) >= bHeight) {
714 rowy -= bHeight;
715 }
716 out += outSpan;
717 }
718 }
719 }
720
721 static class Any extends TexturePaintContext {
722 WritableRaster srcRas;
723 boolean filter;
724
725 public Any(WritableRaster srcRas, ColorModel cm,
726 AffineTransform xform, int maxw, boolean filter) {
727 super (cm, xform, srcRas.getWidth(), srcRas.getHeight(),
728 maxw);
729 this .srcRas = srcRas;
730 this .filter = filter;
731 }
732
733 public WritableRaster makeRaster(int w, int h) {
734 return makeRaster(colorModel, srcRas, w, h);
735 }
736
737 public void setRaster(int x, int y, int xerr, int yerr, int w,
738 int h, int bWidth, int bHeight, int colincx,
739 int colincxerr, int colincy, int colincyerr,
740 int rowincx, int rowincxerr, int rowincy, int rowincyerr) {
741 Object data = null;
742 int rowx = x;
743 int rowy = y;
744 int rowxerr = xerr;
745 int rowyerr = yerr;
746 WritableRaster srcRas = this .srcRas;
747 WritableRaster outRas = this .outRas;
748 int rgbs[] = filter ? new int[4] : null;
749 for (int j = 0; j < h; j++) {
750 x = rowx;
751 y = rowy;
752 xerr = rowxerr;
753 yerr = rowyerr;
754 for (int i = 0; i < w; i++) {
755 data = srcRas.getDataElements(x, y, data);
756 if (filter) {
757 int nextx, nexty;
758 if ((nextx = x + 1) >= bWidth) {
759 nextx = 0;
760 }
761 if ((nexty = y + 1) >= bHeight) {
762 nexty = 0;
763 }
764 rgbs[0] = colorModel.getRGB(data);
765 data = srcRas.getDataElements(nextx, y, data);
766 rgbs[1] = colorModel.getRGB(data);
767 data = srcRas.getDataElements(x, nexty, data);
768 rgbs[2] = colorModel.getRGB(data);
769 data = srcRas.getDataElements(nextx, nexty,
770 data);
771 rgbs[3] = colorModel.getRGB(data);
772 int rgb = TexturePaintContext.blend(rgbs, xerr,
773 yerr);
774 data = colorModel.getDataElements(rgb, data);
775 }
776 outRas.setDataElements(i, j, data);
777 if ((xerr += colincxerr) < 0) {
778 xerr &= Integer.MAX_VALUE;
779 x++;
780 }
781 if ((x += colincx) >= bWidth) {
782 x -= bWidth;
783 }
784 if ((yerr += colincyerr) < 0) {
785 yerr &= Integer.MAX_VALUE;
786 y++;
787 }
788 if ((y += colincy) >= bHeight) {
789 y -= bHeight;
790 }
791 }
792 if ((rowxerr += rowincxerr) < 0) {
793 rowxerr &= Integer.MAX_VALUE;
794 rowx++;
795 }
796 if ((rowx += rowincx) >= bWidth) {
797 rowx -= bWidth;
798 }
799 if ((rowyerr += rowincyerr) < 0) {
800 rowyerr &= Integer.MAX_VALUE;
801 rowy++;
802 }
803 if ((rowy += rowincy) >= bHeight) {
804 rowy -= bHeight;
805 }
806 }
807 }
808 }
809 }
|