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