1 /*
   2  * Copyright (c) 1998, 2016, 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 /*
  27  * @author Charlton Innovations, Inc.
  28  */
  29 
  30 package sun.java2d.loops;
  31 
  32 import java.awt.image.WritableRaster;
  33 import java.awt.image.DataBuffer;
  34 import java.awt.image.ColorModel;
  35 import java.awt.geom.Path2D;
  36 import sun.java2d.pipe.Region;
  37 import sun.java2d.pipe.SpanIterator;
  38 import sun.java2d.SunGraphics2D;
  39 import sun.java2d.SurfaceData;
  40 import sun.java2d.loops.ProcessPath;
  41 import sun.font.GlyphList;
  42 
  43 /**
  44  * GeneralRenderer collection
  45  * Basically, a collection of components which permit basic
  46  * rendering to occur on rasters of any format
  47  */
  48 
  49 public final class GeneralRenderer {
  50     public static void register() {
  51         Class<?> owner = GeneralRenderer.class;
  52         GraphicsPrimitive[] primitives = {
  53             new  GraphicsPrimitiveProxy(owner, "SetFillRectANY",
  54                                         FillRect.methodSignature,
  55                                         FillRect.primTypeID,
  56                                         SurfaceType.AnyColor,
  57                                         CompositeType.SrcNoEa,
  58                                         SurfaceType.Any),
  59             new  GraphicsPrimitiveProxy(owner, "SetFillPathANY",
  60                                         FillPath.methodSignature,
  61                                         FillPath.primTypeID,
  62                                         SurfaceType.AnyColor,
  63                                         CompositeType.SrcNoEa,
  64                                         SurfaceType.Any),
  65             new  GraphicsPrimitiveProxy(owner, "SetFillSpansANY",
  66                                         FillSpans.methodSignature,
  67                                         FillSpans.primTypeID,
  68                                         SurfaceType.AnyColor,
  69                                         CompositeType.SrcNoEa,
  70                                         SurfaceType.Any),
  71             new  GraphicsPrimitiveProxy(owner, "SetDrawLineANY",
  72                                         DrawLine.methodSignature,
  73                                         DrawLine.primTypeID,
  74                                         SurfaceType.AnyColor,
  75                                         CompositeType.SrcNoEa,
  76                                         SurfaceType.Any),
  77             new  GraphicsPrimitiveProxy(owner, "SetDrawPolygonsANY",
  78                                         DrawPolygons.methodSignature,
  79                                         DrawPolygons.primTypeID,
  80                                         SurfaceType.AnyColor,
  81                                         CompositeType.SrcNoEa,
  82                                         SurfaceType.Any),
  83             new  GraphicsPrimitiveProxy(owner, "SetDrawPathANY",
  84                                         DrawPath.methodSignature,
  85                                         DrawPath.primTypeID,
  86                                         SurfaceType.AnyColor,
  87                                         CompositeType.SrcNoEa,
  88                                         SurfaceType.Any),
  89             new  GraphicsPrimitiveProxy(owner, "SetDrawRectANY",
  90                                         DrawRect.methodSignature,
  91                                         DrawRect.primTypeID,
  92                                         SurfaceType.AnyColor,
  93                                         CompositeType.SrcNoEa,
  94                                         SurfaceType.Any),
  95 
  96             new  GraphicsPrimitiveProxy(owner, "XorFillRectANY",
  97                                         FillRect.methodSignature,
  98                                         FillRect.primTypeID,
  99                                         SurfaceType.AnyColor,
 100                                         CompositeType.Xor,
 101                                         SurfaceType.Any),
 102             new  GraphicsPrimitiveProxy(owner, "XorFillPathANY",
 103                                         FillPath.methodSignature,
 104                                         FillPath.primTypeID,
 105                                         SurfaceType.AnyColor,
 106                                         CompositeType.Xor,
 107                                         SurfaceType.Any),
 108             new  GraphicsPrimitiveProxy(owner, "XorFillSpansANY",
 109                                         FillSpans.methodSignature,
 110                                         FillSpans.primTypeID,
 111                                         SurfaceType.AnyColor,
 112                                         CompositeType.Xor,
 113                                         SurfaceType.Any),
 114             new  GraphicsPrimitiveProxy(owner, "XorDrawLineANY",
 115                                         DrawLine.methodSignature,
 116                                         DrawLine.primTypeID,
 117                                         SurfaceType.AnyColor,
 118                                         CompositeType.Xor,
 119                                         SurfaceType.Any),
 120             new  GraphicsPrimitiveProxy(owner, "XorDrawPolygonsANY",
 121                                         DrawPolygons.methodSignature,
 122                                         DrawPolygons.primTypeID,
 123                                         SurfaceType.AnyColor,
 124                                         CompositeType.Xor,
 125                                         SurfaceType.Any),
 126             new  GraphicsPrimitiveProxy(owner, "XorDrawPathANY",
 127                                         DrawPath.methodSignature,
 128                                         DrawPath.primTypeID,
 129                                         SurfaceType.AnyColor,
 130                                         CompositeType.Xor,
 131                                         SurfaceType.Any),
 132             new  GraphicsPrimitiveProxy(owner, "XorDrawRectANY",
 133                                         DrawRect.methodSignature,
 134                                         DrawRect.primTypeID,
 135                                         SurfaceType.AnyColor,
 136                                         CompositeType.Xor,
 137                                         SurfaceType.Any),
 138             new  GraphicsPrimitiveProxy(owner, "XorDrawGlyphListANY",
 139                                         DrawGlyphList.methodSignature,
 140                                         DrawGlyphList.primTypeID,
 141                                         SurfaceType.AnyColor,
 142                                         CompositeType.Xor,
 143                                         SurfaceType.Any),
 144             new  GraphicsPrimitiveProxy(owner, "XorDrawGlyphListAAANY",
 145                                         DrawGlyphListAA.methodSignature,
 146                                         DrawGlyphListAA.primTypeID,
 147                                         SurfaceType.AnyColor,
 148                                         CompositeType.Xor,
 149                                         SurfaceType.Any),
 150         };
 151         GraphicsPrimitiveMgr.register(primitives);
 152     }
 153 
 154     static void doDrawPoly(SurfaceData sData, PixelWriter pw,
 155                            int xPoints[], int yPoints[], int off, int nPoints,
 156                            Region clip, int transx, int transy, boolean close)
 157     {
 158         int mx, my, x1, y1;
 159         int[] tmp = null;
 160 
 161         if (nPoints <= 0) {
 162             return;
 163         }
 164         mx = x1 = xPoints[off] + transx;
 165         my = y1 = yPoints[off] + transy;
 166         while (--nPoints > 0) {
 167             ++off;
 168             int x2 = xPoints[off] + transx;
 169             int y2 = yPoints[off] + transy;
 170             tmp = GeneralRenderer.doDrawLine(sData, pw, tmp, clip,
 171                                              x1, y1, x2, y2);
 172             x1 = x2;
 173             y1 = y2;
 174         }
 175         if (close && (x1 != mx || y1 != my)) {
 176             tmp = GeneralRenderer.doDrawLine(sData, pw, tmp, clip,
 177                                              x1, y1, mx, my);
 178         }
 179     }
 180 
 181     static void doSetRect(SurfaceData sData, PixelWriter pw,
 182                           int x1, int y1, int x2, int y2) {
 183         WritableRaster dstRast =
 184             (WritableRaster) sData.getRaster(x1, y1, x2-x1, y2-y1);
 185         pw.setRaster(dstRast);
 186 
 187         while (y1 < y2) {
 188             for (int x = x1; x < x2; x++) {
 189                 pw.writePixel(x, y1);
 190             }
 191             y1++;
 192         }
 193     }
 194 
 195     static int[] doDrawLine(SurfaceData sData, PixelWriter pw, int[] boundPts,
 196                             Region clip,
 197                             int origx1, int origy1, int origx2, int origy2)
 198     {
 199         if (boundPts == null) {
 200             boundPts = new int[8];
 201         }
 202         boundPts[0] = origx1;
 203         boundPts[1] = origy1;
 204         boundPts[2] = origx2;
 205         boundPts[3] = origy2;
 206         if (!adjustLine(boundPts,
 207                         clip.getLoX(), clip.getLoY(),
 208                         clip.getHiX(), clip.getHiY()))
 209         {
 210             return boundPts;
 211         }
 212         int x1 = boundPts[0];
 213         int y1 = boundPts[1];
 214         int x2 = boundPts[2];
 215         int y2 = boundPts[3];
 216 
 217         WritableRaster dstRast = (WritableRaster)
 218             sData.getRaster(Math.min(x1, x2), Math.min(y1, y2),
 219                             Math.abs(x1 - x2) + 1, Math.abs(y1 - y2) + 1);
 220         pw.setRaster(dstRast);
 221 
 222         /* this could be made smaller, more elegant, more traditional. */
 223         if (x1 == x2) {
 224             if (y1 > y2) {
 225                 do {
 226                     pw.writePixel(x1, y1);
 227                     y1--;
 228                 } while (y1 >= y2);
 229             } else {
 230                 do {
 231                     pw.writePixel(x1, y1);
 232                     y1++;
 233                 } while (y1 <= y2);
 234             }
 235         } else if (y1 == y2) {
 236             if (x1 > x2) {
 237                 do {
 238                     pw.writePixel(x1, y1);
 239                     x1--;
 240                 } while (x1 >= x2);
 241             } else {
 242                 do {
 243                     pw.writePixel(x1, y1);
 244                     x1++;
 245                 } while (x1 <= x2);
 246             }
 247         } else {
 248             int dx = boundPts[4];
 249             int dy = boundPts[5];
 250             int ax = boundPts[6];
 251             int ay = boundPts[7];
 252             int steps;
 253             int bumpmajor;
 254             int bumpminor;
 255             int errminor;
 256             int errmajor;
 257             int error;
 258             boolean xmajor;
 259 
 260             if (ax >= ay) {
 261                 /* x is dominant */
 262                 xmajor = true;
 263                 errmajor = ay * 2;
 264                 errminor = ax * 2;
 265                 bumpmajor = (dx < 0) ? -1 : 1;
 266                 bumpminor = (dy < 0) ? -1 : 1;
 267                 ax = -ax; /* For clipping adjustment below */
 268                 steps = x2 - x1;
 269             } else {
 270                 /* y is dominant */
 271                 xmajor = false;
 272                 errmajor = ax * 2;
 273                 errminor = ay * 2;
 274                 bumpmajor = (dy < 0) ? -1 : 1;
 275                 bumpminor = (dx < 0) ? -1 : 1;
 276                 ay = -ay; /* For clipping adjustment below */
 277                 steps = y2 - y1;
 278             }
 279             error = - (errminor / 2);
 280             if (y1 != origy1) {
 281                 int ysteps = y1 - origy1;
 282                 if (ysteps < 0) {
 283                     ysteps = -ysteps;
 284                 }
 285                 error += ysteps * ax * 2;
 286             }
 287             if (x1 != origx1) {
 288                 int xsteps = x1 - origx1;
 289                 if (xsteps < 0) {
 290                     xsteps = -xsteps;
 291                 }
 292                 error += xsteps * ay * 2;
 293             }
 294             if (steps < 0) {
 295                 steps = -steps;
 296             }
 297             if (xmajor) {
 298                 do {
 299                     pw.writePixel(x1, y1);
 300                     x1 += bumpmajor;
 301                     error += errmajor;
 302                     if (error >= 0) {
 303                         y1 += bumpminor;
 304                         error -= errminor;
 305                     }
 306                 } while (--steps >= 0);
 307             } else {
 308                 do {
 309                     pw.writePixel(x1, y1);
 310                     y1 += bumpmajor;
 311                     error += errmajor;
 312                     if (error >= 0) {
 313                         x1 += bumpminor;
 314                         error -= errminor;
 315                     }
 316                 } while (--steps >= 0);
 317             }
 318         }
 319         return boundPts;
 320     }
 321 
 322     public static void doDrawRect(PixelWriter pw,
 323                                   SunGraphics2D sg2d, SurfaceData sData,
 324                                   int x, int y, int w, int h)
 325     {
 326         if (w < 0 || h < 0) {
 327             return;
 328         }
 329         int x2 = Region.dimAdd(Region.dimAdd(x, w), 1);
 330         int y2 = Region.dimAdd(Region.dimAdd(y, h), 1);
 331         Region r = sg2d.getCompClip().getBoundsIntersectionXYXY(x, y, x2, y2);
 332         if (r.isEmpty()) {
 333             return;
 334         }
 335         int cx1 = r.getLoX();
 336         int cy1 = r.getLoY();
 337         int cx2 = r.getHiX();
 338         int cy2 = r.getHiY();
 339 
 340         if (w < 2 || h < 2) {
 341             doSetRect(sData, pw, cx1, cy1, cx2, cy2);
 342             return;
 343         }
 344 
 345 
 346         if (cy1 == y) {
 347             doSetRect(sData, pw,   cx1,   cy1,   cx2, cy1+1);
 348         }
 349         if (cx1 == x) {
 350             doSetRect(sData, pw,   cx1, cy1+1, cx1+1, cy2-1);
 351         }
 352         if (cx2 == x2) {
 353             doSetRect(sData, pw, cx2-1, cy1+1,   cx2, cy2-1);
 354         }
 355         if (cy2 == y2) {
 356             doSetRect(sData, pw,   cx1, cy2-1,   cx2,   cy2);
 357         }
 358     }
 359 
 360     /*
 361      * REMIND: For now this will field both AA and non-AA requests and
 362      * use a simple threshold to choose pixels if the supplied grey
 363      * bits are antialiased.  We should really find a way to disable
 364      * AA text at a higher level or to have the GlyphList be able to
 365      * reset the glyphs to non-AA after construction.
 366      */
 367     static void doDrawGlyphList(SurfaceData sData, PixelWriter pw,
 368                                 GlyphList gl, Region clip)
 369     {
 370         int[] bounds = gl.getBounds();
 371         clip.clipBoxToBounds(bounds);
 372         int cx1 = bounds[0];
 373         int cy1 = bounds[1];
 374         int cx2 = bounds[2];
 375         int cy2 = bounds[3];
 376 
 377         WritableRaster dstRast =
 378             (WritableRaster) sData.getRaster(cx1, cy1, cx2 - cx1, cy2 - cy1);
 379         pw.setRaster(dstRast);
 380 
 381         int num = gl.getNumGlyphs();
 382         for (int i = 0; i < num; i++) {
 383             gl.setGlyphIndex(i);
 384             int metrics[] = gl.getMetrics();
 385             int gx1 = metrics[0];
 386             int gy1 = metrics[1];
 387             int w = metrics[2];
 388             int gx2 = gx1 + w;
 389             int gy2 = gy1 + metrics[3];
 390             int off = 0;
 391             if (gx1 < cx1) {
 392                 off = cx1 - gx1;
 393                 gx1 = cx1;
 394             }
 395             if (gy1 < cy1) {
 396                 off += (cy1 - gy1) * w;
 397                 gy1 = cy1;
 398             }
 399             if (gx2 > cx2) gx2 = cx2;
 400             if (gy2 > cy2) gy2 = cy2;
 401             if (gx2 > gx1 && gy2 > gy1) {
 402                 byte alpha[] = gl.getGrayBits();
 403                 w -= (gx2 - gx1);
 404                 for (int y = gy1; y < gy2; y++) {
 405                     for (int x = gx1; x < gx2; x++) {
 406                         if (alpha[off++] < 0) {
 407                             pw.writePixel(x, y);
 408                         }
 409                     }
 410                     off += w;
 411                 }
 412             }
 413         }
 414     }
 415 
 416     static final int OUTCODE_TOP     = 1;
 417     static final int OUTCODE_BOTTOM  = 2;
 418     static final int OUTCODE_LEFT    = 4;
 419     static final int OUTCODE_RIGHT   = 8;
 420 
 421     static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax) {
 422         int code;
 423         if (y < ymin) {
 424             code = OUTCODE_TOP;
 425         } else if (y > ymax) {
 426             code = OUTCODE_BOTTOM;
 427         } else {
 428             code = 0;
 429         }
 430         if (x < xmin) {
 431             code |= OUTCODE_LEFT;
 432         } else if (x > xmax) {
 433             code |= OUTCODE_RIGHT;
 434         }
 435         return code;
 436     }
 437 
 438     public static boolean adjustLine(int [] boundPts,
 439                                      int cxmin, int cymin, int cx2, int cy2)
 440     {
 441         int cxmax = cx2 - 1;
 442         int cymax = cy2 - 1;
 443         int x1 = boundPts[0];
 444         int y1 = boundPts[1];
 445         int x2 = boundPts[2];
 446         int y2 = boundPts[3];
 447 
 448         if ((cxmax < cxmin) || (cymax < cymin)) {
 449             return false;
 450         }
 451 
 452         if (x1 == x2) {
 453             if (x1 < cxmin || x1 > cxmax) {
 454                 return false;
 455             }
 456             if (y1 > y2) {
 457                 int t = y1;
 458                 y1 = y2;
 459                 y2 = t;
 460             }
 461             if (y1 < cymin) {
 462                 y1 = cymin;
 463             }
 464             if (y2 > cymax) {
 465                 y2 = cymax;
 466             }
 467             if (y1 > y2) {
 468                 return false;
 469             }
 470             boundPts[1] = y1;
 471             boundPts[3] = y2;
 472         } else if (y1 == y2) {
 473             if (y1 < cymin || y1 > cymax) {
 474                 return false;
 475             }
 476             if (x1 > x2) {
 477                 int t = x1;
 478                 x1 = x2;
 479                 x2 = t;
 480             }
 481             if (x1 < cxmin) {
 482                 x1 = cxmin;
 483             }
 484             if (x2 > cxmax) {
 485                 x2 = cxmax;
 486             }
 487             if (x1 > x2) {
 488                 return false;
 489             }
 490             boundPts[0] = x1;
 491             boundPts[2] = x2;
 492         } else {
 493             /* REMIND: This could overflow... */
 494             int outcode1, outcode2;
 495             int dx = x2 - x1;
 496             int dy = y2 - y1;
 497             int ax = (dx < 0) ? -dx : dx;
 498             int ay = (dy < 0) ? -dy : dy;
 499             boolean xmajor = (ax >= ay);
 500 
 501             outcode1 = outcode(x1, y1, cxmin, cymin, cxmax, cymax);
 502             outcode2 = outcode(x2, y2, cxmin, cymin, cxmax, cymax);
 503             while ((outcode1 | outcode2) != 0) {
 504                 int xsteps, ysteps;
 505                 if ((outcode1 & outcode2) != 0) {
 506                     return false;
 507                 }
 508                 if (outcode1 != 0) {
 509                     if (0 != (outcode1 & (OUTCODE_TOP | OUTCODE_BOTTOM))) {
 510                         if (0 != (outcode1 & OUTCODE_TOP)) {
 511                             y1 = cymin;
 512                         } else {
 513                             y1 = cymax;
 514                         }
 515                         ysteps = y1 - boundPts[1];
 516                         if (ysteps < 0) {
 517                             ysteps = -ysteps;
 518                         }
 519                         xsteps = 2 * ysteps * ax + ay;
 520                         if (xmajor) {
 521                             xsteps += ay - ax - 1;
 522                         }
 523                         xsteps = xsteps / (2 * ay);
 524                         if (dx < 0) {
 525                             xsteps = -xsteps;
 526                         }
 527                         x1 = boundPts[0] + xsteps;
 528                     } else if (0 !=
 529                                (outcode1 & (OUTCODE_LEFT | OUTCODE_RIGHT))) {
 530                         if (0 != (outcode1 & OUTCODE_LEFT)) {
 531                             x1 = cxmin;
 532                         } else {
 533                             x1 = cxmax;
 534                         }
 535                         xsteps = x1 - boundPts[0];
 536                         if (xsteps < 0) {
 537                             xsteps = -xsteps;
 538                         }
 539                         ysteps = 2 * xsteps * ay + ax;
 540                         if (!xmajor) {
 541                             ysteps += ax - ay - 1;
 542                         }
 543                         ysteps = ysteps / (2 * ax);
 544                         if (dy < 0) {
 545                             ysteps = -ysteps;
 546                         }
 547                         y1 = boundPts[1] + ysteps;
 548                     }
 549                     outcode1 = outcode(x1, y1, cxmin, cymin, cxmax, cymax);
 550                 } else {
 551                     if (0 != (outcode2 & (OUTCODE_TOP | OUTCODE_BOTTOM))) {
 552                         if (0 != (outcode2 & OUTCODE_TOP)) {
 553                             y2 = cymin;
 554                         } else {
 555                             y2 = cymax;
 556                         }
 557                         ysteps = y2 - boundPts[3];
 558                         if (ysteps < 0) {
 559                             ysteps = -ysteps;
 560                         }
 561                         xsteps = 2 * ysteps * ax + ay;
 562                         if (xmajor) {
 563                             xsteps += ay - ax;
 564                         } else {
 565                             xsteps -= 1;
 566                         }
 567                         xsteps = xsteps / (2 * ay);
 568                         if (dx > 0) {
 569                             xsteps = -xsteps;
 570                         }
 571                         x2 = boundPts[2] + xsteps;
 572                     } else if (0 !=
 573                                (outcode2 & (OUTCODE_LEFT | OUTCODE_RIGHT))) {
 574                         if (0 != (outcode2 & OUTCODE_LEFT)) {
 575                             x2 = cxmin;
 576                         } else {
 577                             x2 = cxmax;
 578                         }
 579                         xsteps = x2 - boundPts[2];
 580                         if (xsteps < 0) {
 581                             xsteps = -xsteps;
 582                         }
 583                         ysteps = 2 * xsteps * ay + ax;
 584                         if (xmajor) {
 585                             ysteps -= 1;
 586                         } else {
 587                             ysteps += ax - ay;
 588                         }
 589                         ysteps = ysteps / (2 * ax);
 590                         if (dy > 0) {
 591                             ysteps = -ysteps;
 592                         }
 593                         y2 = boundPts[3] + ysteps;
 594                     }
 595                     outcode2 = outcode(x2, y2, cxmin, cymin, cxmax, cymax);
 596                 }
 597             }
 598             boundPts[0] = x1;
 599             boundPts[1] = y1;
 600             boundPts[2] = x2;
 601             boundPts[3] = y2;
 602             boundPts[4] = dx;
 603             boundPts[5] = dy;
 604             boundPts[6] = ax;
 605             boundPts[7] = ay;
 606         }
 607         return true;
 608     }
 609 
 610     static PixelWriter createSolidPixelWriter(SunGraphics2D sg2d,
 611                                               SurfaceData sData)
 612     {
 613         ColorModel dstCM = sData.getColorModel();
 614         Object srcPixel = dstCM.getDataElements(sg2d.eargb, null);
 615 
 616         return new SolidPixelWriter(srcPixel);
 617     }
 618 
 619     static PixelWriter createXorPixelWriter(SunGraphics2D sg2d,
 620                                             SurfaceData sData)
 621     {
 622         ColorModel dstCM = sData.getColorModel();
 623 
 624         Object srcPixel = dstCM.getDataElements(sg2d.eargb, null);
 625 
 626         XORComposite comp = (XORComposite)sg2d.getComposite();
 627         int xorrgb = comp.getXorColor().getRGB();
 628         Object xorPixel = dstCM.getDataElements(xorrgb, null);
 629 
 630         switch (dstCM.getTransferType()) {
 631         case DataBuffer.TYPE_BYTE:
 632             return new XorPixelWriter.ByteData(srcPixel, xorPixel);
 633         case DataBuffer.TYPE_SHORT:
 634         case DataBuffer.TYPE_USHORT:
 635             return new XorPixelWriter.ShortData(srcPixel, xorPixel);
 636         case DataBuffer.TYPE_INT:
 637             return new XorPixelWriter.IntData(srcPixel, xorPixel);
 638         case DataBuffer.TYPE_FLOAT:
 639             return new XorPixelWriter.FloatData(srcPixel, xorPixel);
 640         case DataBuffer.TYPE_DOUBLE:
 641             return new XorPixelWriter.DoubleData(srcPixel, xorPixel);
 642         default:
 643             throw new InternalError("Unsupported XOR pixel type");
 644         }
 645     }
 646 }
 647 
 648 class SetFillRectANY extends FillRect {
 649     SetFillRectANY() {
 650         super(SurfaceType.AnyColor,
 651               CompositeType.SrcNoEa,
 652               SurfaceType.Any);
 653     }
 654 
 655     public void FillRect(SunGraphics2D sg2d, SurfaceData sData,
 656                          int x, int y, int w, int h)
 657     {
 658         PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData);
 659 
 660         Region r = sg2d.getCompClip().getBoundsIntersectionXYWH(x, y, w, h);
 661 
 662         GeneralRenderer.doSetRect(sData, pw,
 663                                   r.getLoX(), r.getLoY(),
 664                                   r.getHiX(), r.getHiY());
 665     }
 666 }
 667 
 668 class PixelWriterDrawHandler extends ProcessPath.DrawHandler {
 669     PixelWriter pw;
 670     SurfaceData sData;
 671     Region clip;
 672 
 673     public PixelWriterDrawHandler(SurfaceData sData, PixelWriter pw,
 674                                   Region clip, int strokeHint) {
 675         super(clip.getLoX(), clip.getLoY(),
 676               clip.getHiX(), clip.getHiY(),
 677               strokeHint);
 678         this.sData = sData;
 679         this.pw = pw;
 680         this.clip = clip;
 681     }
 682 
 683     public void drawLine(int x0, int y0, int x1, int y1) {
 684         GeneralRenderer.doDrawLine(sData, pw, null, clip,
 685                                    x0, y0, x1, y1);
 686     }
 687 
 688     public void drawPixel(int x0, int y0) {
 689         GeneralRenderer.doSetRect(sData, pw, x0, y0, x0 + 1, y0 + 1);
 690     }
 691 
 692     public void drawScanline(int x0, int x1, int y0) {
 693         GeneralRenderer.doSetRect(sData, pw, x0, y0, x1 + 1, y0 + 1);
 694     }
 695 }
 696 
 697 class SetFillPathANY extends FillPath {
 698     SetFillPathANY() {
 699         super(SurfaceType.AnyColor, CompositeType.SrcNoEa,
 700               SurfaceType.Any);
 701     }
 702 
 703     public void FillPath(SunGraphics2D sg2d, SurfaceData sData,
 704                          int transx, int transy,
 705                          Path2D.Float p2df)
 706     {
 707         PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData);
 708         ProcessPath.fillPath(
 709             new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(),
 710                                        sg2d.strokeHint),
 711             p2df, transx, transy);
 712     }
 713 }
 714 
 715 class SetFillSpansANY extends FillSpans {
 716     SetFillSpansANY() {
 717         super(SurfaceType.AnyColor,
 718               CompositeType.SrcNoEa,
 719               SurfaceType.Any);
 720     }
 721 
 722     public void FillSpans(SunGraphics2D sg2d, SurfaceData sData,
 723                           SpanIterator si)
 724     {
 725         PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData);
 726 
 727         int span[] = new int[4];
 728         while (si.nextSpan(span)) {
 729             GeneralRenderer.doSetRect(sData, pw,
 730                                       span[0], span[1], span[2], span[3]);
 731         }
 732     }
 733 }
 734 
 735 class SetDrawLineANY extends DrawLine {
 736     SetDrawLineANY() {
 737         super(SurfaceType.AnyColor,
 738               CompositeType.SrcNoEa,
 739               SurfaceType.Any);
 740     }
 741 
 742     public void DrawLine(SunGraphics2D sg2d, SurfaceData sData,
 743                          int x1, int y1, int x2, int y2)
 744     {
 745         PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData);
 746 
 747         if (y1 >= y2) {
 748             GeneralRenderer.doDrawLine(sData, pw, null,
 749                                        sg2d.getCompClip(),
 750                                        x2, y2, x1, y1);
 751         } else {
 752             GeneralRenderer.doDrawLine(sData, pw, null,
 753                                        sg2d.getCompClip(),
 754                                        x1, y1, x2, y2);
 755         }
 756     }
 757 }
 758 
 759 class SetDrawPolygonsANY extends DrawPolygons {
 760     SetDrawPolygonsANY() {
 761         super(SurfaceType.AnyColor,
 762               CompositeType.SrcNoEa,
 763               SurfaceType.Any);
 764     }
 765 
 766     public void DrawPolygons(SunGraphics2D sg2d, SurfaceData sData,
 767                              int xPoints[], int yPoints[],
 768                              int nPoints[], int numPolys,
 769                              int transx, int transy,
 770                              boolean close)
 771     {
 772         PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData);
 773 
 774         int off = 0;
 775         Region clip = sg2d.getCompClip();
 776         for (int i = 0; i < numPolys; i++) {
 777             int numpts = nPoints[i];
 778             GeneralRenderer.doDrawPoly(sData, pw,
 779                                        xPoints, yPoints, off, numpts,
 780                                        clip, transx, transy, close);
 781             off += numpts;
 782         }
 783     }
 784 }
 785 
 786 class SetDrawPathANY extends DrawPath {
 787     SetDrawPathANY() {
 788         super(SurfaceType.AnyColor,
 789               CompositeType.SrcNoEa,
 790               SurfaceType.Any);
 791     }
 792 
 793     public void DrawPath(SunGraphics2D sg2d, SurfaceData sData,
 794                          int transx, int transy,
 795                          Path2D.Float p2df)
 796     {
 797         PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData);
 798         ProcessPath.drawPath(
 799             new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(),
 800                                        sg2d.strokeHint),
 801             p2df, transx, transy
 802         );
 803     }
 804 }
 805 
 806 class SetDrawRectANY extends DrawRect {
 807     SetDrawRectANY() {
 808         super(SurfaceType.AnyColor,
 809               CompositeType.SrcNoEa,
 810               SurfaceType.Any);
 811     }
 812 
 813     public void DrawRect(SunGraphics2D sg2d, SurfaceData sData,
 814                          int x, int y, int w, int h)
 815     {
 816         PixelWriter pw = GeneralRenderer.createSolidPixelWriter(sg2d, sData);
 817 
 818         GeneralRenderer.doDrawRect(pw, sg2d, sData, x, y, w, h);
 819     }
 820 }
 821 
 822 class XorFillRectANY extends FillRect {
 823     XorFillRectANY() {
 824         super(SurfaceType.AnyColor,
 825               CompositeType.Xor,
 826               SurfaceType.Any);
 827     }
 828 
 829     public void FillRect(SunGraphics2D sg2d, SurfaceData sData,
 830                             int x, int y, int w, int h)
 831     {
 832         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 833 
 834         Region r = sg2d.getCompClip().getBoundsIntersectionXYWH(x, y, w, h);
 835 
 836         GeneralRenderer.doSetRect(sData, pw,
 837                                   r.getLoX(), r.getLoY(),
 838                                   r.getHiX(), r.getHiY());
 839     }
 840 }
 841 
 842 class XorFillPathANY extends FillPath {
 843     XorFillPathANY() {
 844         super(SurfaceType.AnyColor, CompositeType.Xor,
 845               SurfaceType.Any);
 846     }
 847 
 848     public void FillPath(SunGraphics2D sg2d, SurfaceData sData,
 849                          int transx, int transy,
 850                          Path2D.Float p2df)
 851     {
 852         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 853         ProcessPath.fillPath(
 854             new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(),
 855                                        sg2d.strokeHint),
 856             p2df, transx, transy);
 857     }
 858 }
 859 
 860 class XorFillSpansANY extends FillSpans {
 861     XorFillSpansANY() {
 862         super(SurfaceType.AnyColor,
 863               CompositeType.Xor,
 864               SurfaceType.Any);
 865     }
 866 
 867     public void FillSpans(SunGraphics2D sg2d, SurfaceData sData,
 868                           SpanIterator si)
 869     {
 870         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 871 
 872         int span[] = new int[4];
 873         while (si.nextSpan(span)) {
 874             GeneralRenderer.doSetRect(sData, pw,
 875                                       span[0], span[1], span[2], span[3]);
 876         }
 877     }
 878 }
 879 
 880 class XorDrawLineANY extends DrawLine {
 881     XorDrawLineANY() {
 882         super(SurfaceType.AnyColor,
 883               CompositeType.Xor,
 884               SurfaceType.Any);
 885     }
 886 
 887     public void DrawLine(SunGraphics2D sg2d, SurfaceData sData,
 888                          int x1, int y1, int x2, int y2)
 889     {
 890         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 891 
 892         if (y1 >= y2) {
 893             GeneralRenderer.doDrawLine(sData, pw, null,
 894                                        sg2d.getCompClip(),
 895                                        x2, y2, x1, y1);
 896         } else {
 897             GeneralRenderer.doDrawLine(sData, pw, null,
 898                                        sg2d.getCompClip(),
 899                                        x1, y1, x2, y2);
 900         }
 901     }
 902 }
 903 
 904 class XorDrawPolygonsANY extends DrawPolygons {
 905     XorDrawPolygonsANY() {
 906         super(SurfaceType.AnyColor,
 907               CompositeType.Xor,
 908               SurfaceType.Any);
 909     }
 910 
 911     public void DrawPolygons(SunGraphics2D sg2d, SurfaceData sData,
 912                              int xPoints[], int yPoints[],
 913                              int nPoints[], int numPolys,
 914                              int transx, int transy,
 915                              boolean close)
 916     {
 917         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 918 
 919         int off = 0;
 920         Region clip = sg2d.getCompClip();
 921         for (int i = 0; i < numPolys; i++) {
 922             int numpts = nPoints[i];
 923             GeneralRenderer.doDrawPoly(sData, pw,
 924                                        xPoints, yPoints, off, numpts,
 925                                        clip, transx, transy, close);
 926             off += numpts;
 927         }
 928     }
 929 }
 930 
 931 class XorDrawPathANY extends DrawPath {
 932     XorDrawPathANY() {
 933         super(SurfaceType.AnyColor,
 934               CompositeType.Xor,
 935               SurfaceType.Any);
 936     }
 937 
 938     public void DrawPath(SunGraphics2D sg2d, SurfaceData sData,
 939                          int transx, int transy, Path2D.Float p2df)
 940     {
 941         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 942         ProcessPath.drawPath(
 943             new PixelWriterDrawHandler(sData, pw, sg2d.getCompClip(),
 944                                        sg2d.strokeHint),
 945             p2df, transx, transy
 946         );
 947     }
 948 }
 949 
 950 class XorDrawRectANY extends DrawRect {
 951     XorDrawRectANY() {
 952         super(SurfaceType.AnyColor,
 953               CompositeType.Xor,
 954               SurfaceType.Any);
 955     }
 956 
 957     public void DrawRect(SunGraphics2D sg2d, SurfaceData sData,
 958                          int x, int y, int w, int h)
 959     {
 960         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 961 
 962         GeneralRenderer.doDrawRect(pw, sg2d, sData, x, y, w, h);
 963     }
 964 }
 965 
 966 class XorDrawGlyphListANY extends DrawGlyphList {
 967     XorDrawGlyphListANY() {
 968         super(SurfaceType.AnyColor,
 969               CompositeType.Xor,
 970               SurfaceType.Any);
 971     }
 972 
 973     public void DrawGlyphList(SunGraphics2D sg2d, SurfaceData sData,
 974                               GlyphList gl)
 975     {
 976         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 977         GeneralRenderer.doDrawGlyphList(sData, pw, gl, sg2d.getCompClip());
 978     }
 979 }
 980 
 981 class XorDrawGlyphListAAANY extends DrawGlyphListAA {
 982     XorDrawGlyphListAAANY() {
 983         super(SurfaceType.AnyColor,
 984               CompositeType.Xor,
 985               SurfaceType.Any);
 986     }
 987 
 988     public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData sData,
 989                                 GlyphList gl)
 990     {
 991         PixelWriter pw = GeneralRenderer.createXorPixelWriter(sg2d, sData);
 992         GeneralRenderer.doDrawGlyphList(sData, pw, gl, sg2d.getCompClip());
 993     }
 994 }
 995 
 996 abstract class PixelWriter {
 997     protected WritableRaster dstRast;
 998 
 999     public void setRaster(WritableRaster dstRast) {
1000         this.dstRast = dstRast;
1001     }
1002 
1003     public abstract void writePixel(int x, int y);
1004 }
1005 
1006 class SolidPixelWriter extends PixelWriter {
1007     protected Object srcData;
1008 
1009     SolidPixelWriter(Object srcPixel) {
1010         this.srcData = srcPixel;
1011     }
1012 
1013     public void writePixel(int x, int y) {
1014         dstRast.setDataElements(x, y, srcData);
1015     }
1016 }
1017 
1018 abstract class XorPixelWriter extends PixelWriter {
1019     protected ColorModel dstCM;
1020 
1021     public void writePixel(int x, int y) {
1022         Object dstPixel = dstRast.getDataElements(x, y, null);
1023         xorPixel(dstPixel);
1024         dstRast.setDataElements(x, y, dstPixel);
1025     }
1026 
1027     protected abstract void xorPixel(Object pixData);
1028 
1029     public static class ByteData extends XorPixelWriter {
1030         byte[] xorData;
1031 
1032         ByteData(Object srcPixel, Object xorPixel) {
1033             this.xorData = (byte[]) srcPixel;
1034             xorPixel(xorPixel);
1035             this.xorData = (byte[]) xorPixel;
1036         }
1037 
1038         protected void xorPixel(Object pixData) {
1039             byte[] dstData = (byte[]) pixData;
1040             for (int i = 0; i < dstData.length; i++) {
1041                 dstData[i] ^= xorData[i];
1042             }
1043         }
1044     }
1045 
1046     public static class ShortData extends XorPixelWriter {
1047         short[] xorData;
1048 
1049         ShortData(Object srcPixel, Object xorPixel) {
1050             this.xorData = (short[]) srcPixel;
1051             xorPixel(xorPixel);
1052             this.xorData = (short[]) xorPixel;
1053         }
1054 
1055         protected void xorPixel(Object pixData) {
1056             short[] dstData = (short[]) pixData;
1057             for (int i = 0; i < dstData.length; i++) {
1058                 dstData[i] ^= xorData[i];
1059             }
1060         }
1061     }
1062 
1063     public static class IntData extends XorPixelWriter {
1064         int[] xorData;
1065 
1066         IntData(Object srcPixel, Object xorPixel) {
1067             this.xorData = (int[]) srcPixel;
1068             xorPixel(xorPixel);
1069             this.xorData = (int[]) xorPixel;
1070         }
1071 
1072         protected void xorPixel(Object pixData) {
1073             int[] dstData = (int[]) pixData;
1074             for (int i = 0; i < dstData.length; i++) {
1075                 dstData[i] ^= xorData[i];
1076             }
1077         }
1078     }
1079 
1080     public static class FloatData extends XorPixelWriter {
1081         int[] xorData;
1082 
1083         FloatData(Object srcPixel, Object xorPixel) {
1084             float[] srcData = (float[]) srcPixel;
1085             float[] xorData = (float[]) xorPixel;
1086             this.xorData = new int[srcData.length];
1087             for (int i = 0; i < srcData.length; i++) {
1088                 this.xorData[i] = (Float.floatToIntBits(srcData[i]) ^
1089                                    Float.floatToIntBits(xorData[i]));
1090             }
1091         }
1092 
1093         protected void xorPixel(Object pixData) {
1094             float[] dstData = (float[]) pixData;
1095             for (int i = 0; i < dstData.length; i++) {
1096                 int v = Float.floatToIntBits(dstData[i]) ^ xorData[i];
1097                 dstData[i] = Float.intBitsToFloat(v);
1098             }
1099         }
1100     }
1101 
1102     public static class DoubleData extends XorPixelWriter {
1103         long[] xorData;
1104 
1105         DoubleData(Object srcPixel, Object xorPixel) {
1106             double[] srcData = (double[]) srcPixel;
1107             double[] xorData = (double[]) xorPixel;
1108             this.xorData = new long[srcData.length];
1109             for (int i = 0; i < srcData.length; i++) {
1110                 this.xorData[i] = (Double.doubleToLongBits(srcData[i]) ^
1111                                    Double.doubleToLongBits(xorData[i]));
1112             }
1113         }
1114 
1115         protected void xorPixel(Object pixData) {
1116             double[] dstData = (double[]) pixData;
1117             for (int i = 0; i < dstData.length; i++) {
1118                 long v = Double.doubleToLongBits(dstData[i]) ^ xorData[i];
1119                 dstData[i] = Double.longBitsToDouble(v);
1120             }
1121         }
1122     }
1123 }