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