1. /*
  2. * @(#)GradientPaintContext.java 1.19 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.awt;
  11. import java.awt.image.Raster;
  12. import java.awt.image.WritableRaster;
  13. import sun.awt.image.IntegerComponentRaster;
  14. import java.awt.image.ColorModel;
  15. import java.awt.image.DirectColorModel;
  16. import java.awt.geom.Point2D;
  17. import java.awt.geom.AffineTransform;
  18. import java.awt.geom.NoninvertibleTransformException;
  19. class GradientPaintContext implements PaintContext {
  20. static ColorModel xrgbmodel =
  21. new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
  22. double x1;
  23. double y1;
  24. double dx;
  25. double dy;
  26. boolean cyclic;
  27. int interp[];
  28. Raster saved;
  29. ColorModel model;
  30. public GradientPaintContext(Point2D p1, Point2D p2, AffineTransform xform,
  31. Color c1, Color c2, boolean cyclic) {
  32. // First calculate the distance moved in user space when
  33. // we move a single unit along the X & Y axes in device space.
  34. Point2D xvec = new Point2D.Double(1, 0);
  35. Point2D yvec = new Point2D.Double(0, 1);
  36. try {
  37. AffineTransform inverse = xform.createInverse();
  38. inverse.deltaTransform(xvec, xvec);
  39. inverse.deltaTransform(yvec, yvec);
  40. } catch (NoninvertibleTransformException e) {
  41. xvec.setLocation(0, 0);
  42. yvec.setLocation(0, 0);
  43. }
  44. // Now calculate the (square of the) user space distance
  45. // between the anchor points. This value equals:
  46. // (UserVec . UserVec)
  47. double udx = p2.getX() - p1.getX();
  48. double udy = p2.getY() - p1.getY();
  49. double ulenSq = udx * udx + udy * udy;
  50. if (ulenSq <= Double.MIN_VALUE) {
  51. dx = 0;
  52. dy = 0;
  53. } else {
  54. // Now calculate the proportional distance moved along the
  55. // vector from p1 to p2 when we move a unit along X & Y in
  56. // device space.
  57. //
  58. // The length of the projection of the Device Axis Vector is
  59. // its dot product with the Unit User Vector:
  60. // (DevAxisVec . (UserVec / Len(UserVec))
  61. //
  62. // The "proportional" length is that length divided again
  63. // by the length of the User Vector:
  64. // (DevAxisVec . (UserVec / Len(UserVec))) / Len(UserVec)
  65. // which simplifies to:
  66. // ((DevAxisVec . UserVec) / Len(UserVec)) / Len(UserVec)
  67. // which simplifies to:
  68. // (DevAxisVec . UserVec) / LenSquared(UserVec)
  69. dx = (xvec.getX() * udx + xvec.getY() * udy) / ulenSq;
  70. dy = (yvec.getX() * udx + yvec.getY() * udy) / ulenSq;
  71. if (cyclic) {
  72. dx = dx % 1.0;
  73. dy = dy % 1.0;
  74. } else {
  75. // We are acyclic
  76. if (dx < 0) {
  77. // If we are using the acyclic form below, we need
  78. // dx to be non-negative for simplicity of scanning
  79. // across the scan lines for the transition points.
  80. // To ensure that constraint, we negate the dx/dy
  81. // values and swap the points and colors.
  82. Point2D p = p1; p1 = p2; p2 = p;
  83. Color c = c1; c1 = c2; c2 = c;
  84. dx = -dx;
  85. dy = -dy;
  86. }
  87. }
  88. }
  89. Point2D dp1 = xform.transform(p1, null);
  90. this.x1 = dp1.getX();
  91. this.y1 = dp1.getY();
  92. this.cyclic = cyclic;
  93. int rgb1 = c1.getRGB();
  94. int rgb2 = c2.getRGB();
  95. int a1 = (rgb1 >> 24) & 0xff;
  96. int r1 = (rgb1 >> 16) & 0xff;
  97. int g1 = (rgb1 >> 8) & 0xff;
  98. int b1 = (rgb1 ) & 0xff;
  99. int da = ((rgb2 >> 24) & 0xff) - a1;
  100. int dr = ((rgb2 >> 16) & 0xff) - r1;
  101. int dg = ((rgb2 >> 8) & 0xff) - g1;
  102. int db = ((rgb2 ) & 0xff) - b1;
  103. if (((rgb1 & rgb2) >>> 24) == 0xff) {
  104. model = xrgbmodel;
  105. } else {
  106. model = ColorModel.getRGBdefault();
  107. }
  108. interp = new int[cyclic ? 513 : 257];
  109. for (int i = 0; i <= 256; i++) {
  110. float rel = i / 256.0f;
  111. int rgb =
  112. (((int) (a1 + da * rel)) << 24) |
  113. (((int) (r1 + dr * rel)) << 16) |
  114. (((int) (g1 + dg * rel)) << 8) |
  115. (((int) (b1 + db * rel)) );
  116. interp[i] = rgb;
  117. if (cyclic) {
  118. interp[512 - i] = rgb;
  119. }
  120. }
  121. }
  122. /**
  123. * Release the resources allocated for the operation.
  124. */
  125. public void dispose() {
  126. saved = null;
  127. }
  128. /**
  129. * Return the ColorModel of the output.
  130. */
  131. public ColorModel getColorModel() {
  132. return model;
  133. }
  134. /**
  135. * Return a Raster containing the colors generated for the graphics
  136. * operation.
  137. * @param x,y,w,h The area in device space for which colors are
  138. * generated.
  139. */
  140. public Raster getRaster(int x, int y, int w, int h) {
  141. double rowrel = (x - x1) * dx + (y - y1) * dy;
  142. Raster rast = saved;
  143. if (rast == null || rast.getWidth() < w || rast.getHeight() < h) {
  144. rast = getColorModel().createCompatibleWritableRaster(w, h);
  145. saved = rast;
  146. }
  147. IntegerComponentRaster irast = (IntegerComponentRaster) rast;
  148. int off = irast.getDataOffset(0);
  149. int adjust = irast.getScanlineStride() - w;
  150. int[] pixels = irast.getDataStorage();
  151. if (cyclic) {
  152. cycleFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);
  153. } else {
  154. clipFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);
  155. }
  156. return rast;
  157. }
  158. void cycleFillRaster(int[] pixels, int off, int adjust, int w, int h,
  159. double rowrel, double dx, double dy) {
  160. rowrel = rowrel % 2.0;
  161. int irowrel = ((int) (rowrel * (1 << 30))) << 1;
  162. int idx = (int) (-dx * (1 << 31));
  163. int idy = (int) (-dy * (1 << 31));
  164. while (--h >= 0) {
  165. int icolrel = irowrel;
  166. for (int j = w; j > 0; j--) {
  167. pixels[off++] = interp[icolrel >>> 23];
  168. icolrel += idx;
  169. }
  170. off += adjust;
  171. irowrel += idy;
  172. }
  173. }
  174. void clipFillRaster(int[] pixels, int off, int adjust, int w, int h,
  175. double rowrel, double dx, double dy) {
  176. while (--h >= 0) {
  177. double colrel = rowrel;
  178. int j = w;
  179. if (colrel <= 0.0) {
  180. int rgb = interp[0];
  181. do {
  182. pixels[off++] = rgb;
  183. colrel += dx;
  184. } while (--j > 0 && colrel <= 0.0);
  185. }
  186. while (colrel < 1.0 && --j >= 0) {
  187. pixels[off++] = interp[(int) (colrel * 256)];
  188. colrel += dx;
  189. }
  190. if (j > 0) {
  191. int rgb = interp[256];
  192. do {
  193. pixels[off++] = rgb;
  194. } while (--j > 0);
  195. }
  196. off += adjust;
  197. rowrel += dy;
  198. }
  199. }
  200. }