1. /*
  2. * @(#)GradientPaintContext.java 1.22 03/01/23
  3. *
  4. * Copyright 2003 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. import java.lang.ref.WeakReference;
  17. class GradientPaintContext implements PaintContext {
  18. static ColorModel xrgbmodel =
  19. new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
  20. static ColorModel xbgrmodel =
  21. new DirectColorModel(24, 0x000000ff, 0x0000ff00, 0x00ff0000);
  22. static ColorModel cachedModel;
  23. static WeakReference cached;
  24. static synchronized Raster getCachedRaster(ColorModel cm, int w, int h) {
  25. if (cm == cachedModel) {
  26. if (cached != null) {
  27. Raster ras = (Raster) cached.get();
  28. if (ras != null &&
  29. ras.getWidth() >= w &&
  30. ras.getHeight() >= h)
  31. {
  32. cached = null;
  33. return ras;
  34. }
  35. }
  36. }
  37. return cm.createCompatibleWritableRaster(w, h);
  38. }
  39. static synchronized void putCachedRaster(ColorModel cm, Raster ras) {
  40. if (cached != null) {
  41. Raster cras = (Raster) cached.get();
  42. if (cras != null) {
  43. int cw = cras.getWidth();
  44. int ch = cras.getHeight();
  45. int iw = ras.getWidth();
  46. int ih = ras.getHeight();
  47. if (cw >= iw && ch >= ih) {
  48. return;
  49. }
  50. if (cw * ch >= iw * ih) {
  51. return;
  52. }
  53. }
  54. }
  55. cachedModel = cm;
  56. cached = new WeakReference(ras);
  57. }
  58. double x1;
  59. double y1;
  60. double dx;
  61. double dy;
  62. boolean cyclic;
  63. int interp[];
  64. Raster saved;
  65. ColorModel model;
  66. public GradientPaintContext(ColorModel cm,
  67. Point2D p1, Point2D p2, AffineTransform xform,
  68. Color c1, Color c2, boolean cyclic) {
  69. // First calculate the distance moved in user space when
  70. // we move a single unit along the X & Y axes in device space.
  71. Point2D xvec = new Point2D.Double(1, 0);
  72. Point2D yvec = new Point2D.Double(0, 1);
  73. try {
  74. AffineTransform inverse = xform.createInverse();
  75. inverse.deltaTransform(xvec, xvec);
  76. inverse.deltaTransform(yvec, yvec);
  77. } catch (NoninvertibleTransformException e) {
  78. xvec.setLocation(0, 0);
  79. yvec.setLocation(0, 0);
  80. }
  81. // Now calculate the (square of the) user space distance
  82. // between the anchor points. This value equals:
  83. // (UserVec . UserVec)
  84. double udx = p2.getX() - p1.getX();
  85. double udy = p2.getY() - p1.getY();
  86. double ulenSq = udx * udx + udy * udy;
  87. if (ulenSq <= Double.MIN_VALUE) {
  88. dx = 0;
  89. dy = 0;
  90. } else {
  91. // Now calculate the proportional distance moved along the
  92. // vector from p1 to p2 when we move a unit along X & Y in
  93. // device space.
  94. //
  95. // The length of the projection of the Device Axis Vector is
  96. // its dot product with the Unit User Vector:
  97. // (DevAxisVec . (UserVec / Len(UserVec))
  98. //
  99. // The "proportional" length is that length divided again
  100. // by the length of the User Vector:
  101. // (DevAxisVec . (UserVec / Len(UserVec))) / Len(UserVec)
  102. // which simplifies to:
  103. // ((DevAxisVec . UserVec) / Len(UserVec)) / Len(UserVec)
  104. // which simplifies to:
  105. // (DevAxisVec . UserVec) / LenSquared(UserVec)
  106. dx = (xvec.getX() * udx + xvec.getY() * udy) / ulenSq;
  107. dy = (yvec.getX() * udx + yvec.getY() * udy) / ulenSq;
  108. if (cyclic) {
  109. dx = dx % 1.0;
  110. dy = dy % 1.0;
  111. } else {
  112. // We are acyclic
  113. if (dx < 0) {
  114. // If we are using the acyclic form below, we need
  115. // dx to be non-negative for simplicity of scanning
  116. // across the scan lines for the transition points.
  117. // To ensure that constraint, we negate the dx/dy
  118. // values and swap the points and colors.
  119. Point2D p = p1; p1 = p2; p2 = p;
  120. Color c = c1; c1 = c2; c2 = c;
  121. dx = -dx;
  122. dy = -dy;
  123. }
  124. }
  125. }
  126. Point2D dp1 = xform.transform(p1, null);
  127. this.x1 = dp1.getX();
  128. this.y1 = dp1.getY();
  129. this.cyclic = cyclic;
  130. int rgb1 = c1.getRGB();
  131. int rgb2 = c2.getRGB();
  132. int a1 = (rgb1 >> 24) & 0xff;
  133. int r1 = (rgb1 >> 16) & 0xff;
  134. int g1 = (rgb1 >> 8) & 0xff;
  135. int b1 = (rgb1 ) & 0xff;
  136. int da = ((rgb2 >> 24) & 0xff) - a1;
  137. int dr = ((rgb2 >> 16) & 0xff) - r1;
  138. int dg = ((rgb2 >> 8) & 0xff) - g1;
  139. int db = ((rgb2 ) & 0xff) - b1;
  140. if (a1 == 0xff && da == 0) {
  141. model = xrgbmodel;
  142. if (cm instanceof DirectColorModel) {
  143. DirectColorModel dcm = (DirectColorModel) cm;
  144. int tmp = dcm.getAlphaMask();
  145. if ((tmp == 0 || tmp == 0xff) &&
  146. dcm.getRedMask() == 0xff &&
  147. dcm.getGreenMask() == 0xff00 &&
  148. dcm.getBlueMask() == 0xff0000)
  149. {
  150. model = xbgrmodel;
  151. tmp = r1; r1 = b1; b1 = tmp;
  152. tmp = dr; dr = db; db = tmp;
  153. }
  154. }
  155. } else {
  156. model = ColorModel.getRGBdefault();
  157. }
  158. interp = new int[cyclic ? 513 : 257];
  159. for (int i = 0; i <= 256; i++) {
  160. float rel = i / 256.0f;
  161. int rgb =
  162. (((int) (a1 + da * rel)) << 24) |
  163. (((int) (r1 + dr * rel)) << 16) |
  164. (((int) (g1 + dg * rel)) << 8) |
  165. (((int) (b1 + db * rel)) );
  166. interp[i] = rgb;
  167. if (cyclic) {
  168. interp[512 - i] = rgb;
  169. }
  170. }
  171. }
  172. /**
  173. * Release the resources allocated for the operation.
  174. */
  175. public void dispose() {
  176. if (saved != null) {
  177. putCachedRaster(model, saved);
  178. saved = null;
  179. }
  180. }
  181. /**
  182. * Return the ColorModel of the output.
  183. */
  184. public ColorModel getColorModel() {
  185. return model;
  186. }
  187. /**
  188. * Return a Raster containing the colors generated for the graphics
  189. * operation.
  190. * @param x,y,w,h The area in device space for which colors are
  191. * generated.
  192. */
  193. public Raster getRaster(int x, int y, int w, int h) {
  194. double rowrel = (x - x1) * dx + (y - y1) * dy;
  195. Raster rast = saved;
  196. if (rast == null || rast.getWidth() < w || rast.getHeight() < h) {
  197. rast = getCachedRaster(model, w, h);
  198. saved = rast;
  199. }
  200. IntegerComponentRaster irast = (IntegerComponentRaster) rast;
  201. int off = irast.getDataOffset(0);
  202. int adjust = irast.getScanlineStride() - w;
  203. int[] pixels = irast.getDataStorage();
  204. if (cyclic) {
  205. cycleFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);
  206. } else {
  207. clipFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);
  208. }
  209. return rast;
  210. }
  211. void cycleFillRaster(int[] pixels, int off, int adjust, int w, int h,
  212. double rowrel, double dx, double dy) {
  213. rowrel = rowrel % 2.0;
  214. int irowrel = ((int) (rowrel * (1 << 30))) << 1;
  215. int idx = (int) (-dx * (1 << 31));
  216. int idy = (int) (-dy * (1 << 31));
  217. while (--h >= 0) {
  218. int icolrel = irowrel;
  219. for (int j = w; j > 0; j--) {
  220. pixels[off++] = interp[icolrel >>> 23];
  221. icolrel += idx;
  222. }
  223. off += adjust;
  224. irowrel += idy;
  225. }
  226. }
  227. void clipFillRaster(int[] pixels, int off, int adjust, int w, int h,
  228. double rowrel, double dx, double dy) {
  229. while (--h >= 0) {
  230. double colrel = rowrel;
  231. int j = w;
  232. if (colrel <= 0.0) {
  233. int rgb = interp[0];
  234. do {
  235. pixels[off++] = rgb;
  236. colrel += dx;
  237. } while (--j > 0 && colrel <= 0.0);
  238. }
  239. while (colrel < 1.0 && --j >= 0) {
  240. pixels[off++] = interp[(int) (colrel * 256)];
  241. colrel += dx;
  242. }
  243. if (j > 0) {
  244. int rgb = interp[256];
  245. do {
  246. pixels[off++] = rgb;
  247. } while (--j > 0);
  248. }
  249. off += adjust;
  250. rowrel += dy;
  251. }
  252. }
  253. }