Showing the changes to java/pkg/sun/java2d/pipe/PixelToParallelogramConverter.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,429 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 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 | package sun.java2d.pipe; | ||
| 27 | |||
| 28 | import java.awt.Shape; | ||
| 29 | import java.awt.BasicStroke; | ||
| 30 | import java.awt.geom.Line2D; | ||
| 31 | import java.awt.geom.Rectangle2D; | ||
| 32 | import java.awt.geom.AffineTransform; | ||
| 33 | import sun.java2d.SunGraphics2D; | ||
| 34 | import sun.awt.SunHints; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * This class converts calls to the basic pixel rendering methods | ||
| 38 | * into calls to the methods on a ParallelogramPipe. | ||
| 39 | * Most calls are transformed into calls to the fill(Shape) method | ||
| 40 | * by the parent PixelToShapeConverter class, but some calls are | ||
| 41 | * transformed into calls to fill/drawParallelogram(). | ||
| 42 | */ | ||
| 43 | public class PixelToParallelogramConverter extends PixelToShapeConverter | ||
| 44 | implements ShapeDrawPipe | ||
| 45 | { | ||
| 46 | ParallelogramPipe outrenderer; | ||
| 47 | double minPenSize; | ||
| 48 | double normPosition; | ||
| 49 | double normRoundingBias; | ||
| 50 | boolean adjustfill; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * @param shapepipe pipeline to forward shape calls to | ||
| 54 | * @param pgrampipe pipeline to forward parallelogram calls to | ||
| 55 | * (and drawLine calls if possible) | ||
| 56 | * @param minPenSize minimum pen size for dropout control | ||
| 57 | * @param normPosition sub-pixel location to normalize endpoints | ||
| 58 | * for STROKE_NORMALIZE cases | ||
| 59 | * @param adjustFill boolean to control whethere normalization | ||
| 60 | * constants are also applied to fill operations | ||
| 61 | * (normally true for non-AA, false for AA) | ||
| 62 | */ | ||
| 63 | public PixelToParallelogramConverter(ShapeDrawPipe shapepipe, | ||
| 64 | ParallelogramPipe pgrampipe, | ||
| 65 | double minPenSize, | ||
| 66 | double normPosition, | ||
| 67 | boolean adjustfill) | ||
| 68 | { | ||
| 69 | super(shapepipe); | ||
| 70 | outrenderer = pgrampipe; | ||
| 71 | this.minPenSize = minPenSize; | ||
| 72 | this.normPosition = normPosition; | ||
| 73 | this.normRoundingBias = 0.5 - normPosition; | ||
| 74 | this.adjustfill = adjustfill; | ||
| 75 | } | ||
| 76 | |||
| 77 | public void drawLine(SunGraphics2D sg2d, | ||
| 78 | int x1, int y1, int x2, int y2) | ||
| 79 | { | ||
| 80 | if (!drawGeneralLine(sg2d, x1, y1, x2, y2)) { | ||
| 81 | super.drawLine(sg2d, x1, y1, x2, y2); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public void drawRect(SunGraphics2D sg2d, | ||
| 86 | int x, int y, int w, int h) | ||
| 87 | { | ||
| 88 | if (w >= 0 && h >= 0) { | ||
| 89 | if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { | ||
| 90 | BasicStroke bs = ((BasicStroke) sg2d.stroke); | ||
| 91 | if (w > 0 && h > 0) { | ||
| 92 | if (bs.getLineJoin() == BasicStroke.JOIN_MITER && | ||
| 93 | bs.getDashArray() == null) | ||
| 94 | { | ||
| 95 | double lw = bs.getLineWidth(); | ||
| 96 | drawRectangle(sg2d, x, y, w, h, lw); | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | } else { | ||
| 100 | // Note: This calls the integer version which | ||
| 101 | // will verify that the local drawLine optimizations | ||
| 102 | // work and call super.drawLine(), if not. | ||
| 103 | drawLine(sg2d, x, y, x+w, y+h); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | super.drawRect(sg2d, x, y, w, h); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | public void fillRect(SunGraphics2D sg2d, | ||
| 112 | int x, int y, int w, int h) | ||
| 113 | { | ||
| 114 | if (w > 0 && h > 0) { | ||
| 115 | fillRectangle(sg2d, x, y, w, h); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | public void draw(SunGraphics2D sg2d, Shape s) { | ||
| 120 | if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { | ||
| 121 | BasicStroke bs = ((BasicStroke) sg2d.stroke); | ||
| 122 | if (s instanceof Rectangle2D) { | ||
| 123 | if (bs.getLineJoin() == BasicStroke.JOIN_MITER && | ||
| 124 | bs.getDashArray() == null) | ||
| 125 | { | ||
| 126 | Rectangle2D r2d = (Rectangle2D) s; | ||
| 127 | double w = r2d.getWidth(); | ||
| 128 | double h = r2d.getHeight(); | ||
| 129 | double x = r2d.getX(); | ||
| 130 | double y = r2d.getY(); | ||
| 131 | if (w >= 0 && h >= 0) { | ||
| 132 | double lw = bs.getLineWidth(); | ||
| 133 | drawRectangle(sg2d, x, y, w, h, lw); | ||
| 134 | } | ||
| 135 | return; | ||
| 136 | } | ||
| 137 | } else if (s instanceof Line2D) { | ||
| 138 | Line2D l2d = (Line2D) s; | ||
| 139 | if (drawGeneralLine(sg2d, | ||
| 140 | l2d.getX1(), l2d.getY1(), | ||
| 141 | l2d.getX2(), l2d.getY2())) | ||
| 142 | { | ||
| 143 | return; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | outpipe.draw(sg2d, s); | ||
| 149 | } | ||
| 150 | |||
| 151 | public void fill(SunGraphics2D sg2d, Shape s) { | ||
| 152 | if (s instanceof Rectangle2D) { | ||
| 153 | Rectangle2D r2d = (Rectangle2D) s; | ||
| 154 | double w = r2d.getWidth(); | ||
| 155 | double h = r2d.getHeight(); | ||
| 156 | if (w > 0 && h > 0) { | ||
| 157 | double x = r2d.getX(); | ||
| 158 | double y = r2d.getY(); | ||
| 159 | fillRectangle(sg2d, x, y, w, h); | ||
| 160 | } | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | |||
| 164 | outpipe.fill(sg2d, s); | ||
| 165 | } | ||
| 166 | |||
| 167 | static double len(double x, double y) { | ||
| 168 | return ((x == 0) ? Math.abs(y) | ||
| 169 | : ((y == 0) ? Math.abs(x) | ||
| 170 | : Math.sqrt(x * x + y * y))); | ||
| 171 | } | ||
| 172 | |||
| 173 | double normalize(double v) { | ||
| 174 | return Math.floor(v + normRoundingBias) + normPosition; | ||
| 175 | } | ||
| 176 | |||
| 177 | public boolean drawGeneralLine(SunGraphics2D sg2d, | ||
| 178 | double ux1, double uy1, | ||
| 179 | double ux2, double uy2) | ||
| 180 | { | ||
| 181 | if (sg2d.strokeState == SunGraphics2D.STROKE_CUSTOM || | ||
| 182 | sg2d.strokeState == SunGraphics2D.STROKE_THINDASHED) | ||
| 183 | { | ||
| 184 | return false; | ||
| 185 | } | ||
| 186 | BasicStroke bs = (BasicStroke) sg2d.stroke; | ||
| 187 | int cap = bs.getEndCap(); | ||
| 188 | if (cap == BasicStroke.CAP_ROUND || bs.getDashArray() != null) { | ||
| 189 | // TODO: we could construct the GeneralPath directly | ||
| 190 | // for CAP_ROUND and save a lot of processing in that case... | ||
| 191 | // And again, we would need to deal with dropout control... | ||
| 192 | return false; | ||
| 193 | } | ||
| 194 | double lw = bs.getLineWidth(); | ||
| 195 | // Save the original dx, dy in case we need it to transform | ||
| 196 | // the linewidth as a perpendicular vector below | ||
| 197 | double dx = ux2 - ux1; | ||
| 198 | double dy = uy2 - uy1; | ||
| 199 | double x1, y1, x2, y2; | ||
| 200 | switch (sg2d.transformState) { | ||
| 201 | case SunGraphics2D.TRANSFORM_GENERIC: | ||
| 202 | case SunGraphics2D.TRANSFORM_TRANSLATESCALE: | ||
| 203 | { | ||
| 204 | double coords[] = {ux1, uy1, ux2, uy2}; | ||
| 205 | sg2d.transform.transform(coords, 0, coords, 0, 2); | ||
| 206 | x1 = coords[0]; | ||
| 207 | y1 = coords[1]; | ||
| 208 | x2 = coords[2]; | ||
| 209 | y2 = coords[3]; | ||
| 210 | } | ||
| 211 | break; | ||
| 212 | case SunGraphics2D.TRANSFORM_ANY_TRANSLATE: | ||
| 213 | case SunGraphics2D.TRANSFORM_INT_TRANSLATE: | ||
| 214 | { | ||
| 215 | double tx = sg2d.transform.getTranslateX(); | ||
| 216 | double ty = sg2d.transform.getTranslateY(); | ||
| 217 | x1 = ux1 + tx; | ||
| 218 | y1 = uy1 + ty; | ||
| 219 | x2 = ux2 + tx; | ||
| 220 | y2 = uy2 + ty; | ||
| 221 | } | ||
| 222 | break; | ||
| 223 | case SunGraphics2D.TRANSFORM_ISIDENT: | ||
| 224 | x1 = ux1; | ||
| 225 | y1 = uy1; | ||
| 226 | x2 = ux2; | ||
| 227 | y2 = uy2; | ||
| 228 | break; | ||
| 229 | default: | ||
| 230 | throw new InternalError("unknown TRANSFORM state..."); | ||
| 231 | } | ||
| 232 | if (sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) { | ||
| 233 | if (sg2d.strokeState == SunGraphics2D.STROKE_THIN && | ||
| 234 | outrenderer instanceof PixelDrawPipe) | ||
| 235 | { | ||
| 236 | // PixelDrawPipes will add sg2d.transXY so we need to factor | ||
| 237 | // that out... | ||
| 238 | int ix1 = (int) Math.floor(x1 - sg2d.transX); | ||
| 239 | int iy1 = (int) Math.floor(y1 - sg2d.transY); | ||
| 240 | int ix2 = (int) Math.floor(x2 - sg2d.transX); | ||
| 241 | int iy2 = (int) Math.floor(y2 - sg2d.transY); | ||
| 242 | ((PixelDrawPipe)outrenderer).drawLine(sg2d, ix1, iy1, ix2, iy2); | ||
| 243 | return true; | ||
| 244 | } | ||
| 245 | x1 = normalize(x1); | ||
| 246 | y1 = normalize(y1); | ||
| 247 | x2 = normalize(x2); | ||
| 248 | y2 = normalize(y2); | ||
| 249 | } | ||
| 250 | if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { | ||
| 251 | // Transform the linewidth... | ||
| 252 | // calculate the scaling factor for a unit vector | ||
| 253 | // perpendicular to the original user space line. | ||
| 254 | double len = len(dx, dy); | ||
| 255 | if (len == 0) { | ||
| 256 | dx = len = 1; | ||
| 257 | // dy = 0; already | ||
| 258 | } | ||
| 259 | // delta transform the transposed (90 degree rotated) unit vector | ||
| 260 | double unitvector[] = {dy/len, -dx/len}; | ||
| 261 | sg2d.transform.deltaTransform(unitvector, 0, unitvector, 0, 1); | ||
| 262 | lw *= len(unitvector[0], unitvector[1]); | ||
| 263 | } | ||
| 264 | lw = Math.max(lw, minPenSize); | ||
| 265 | dx = x2 - x1; | ||
| 266 | dy = y2 - y1; | ||
| 267 | double len = len(dx, dy); | ||
| 268 | double udx, udy; | ||
| 269 | if (len == 0) { | ||
| 270 | if (cap == BasicStroke.CAP_BUTT) { | ||
| 271 | return true; | ||
| 272 | } | ||
| 273 | udx = lw; | ||
| 274 | udy = 0; | ||
| 275 | } else { | ||
| 276 | udx = lw * dx / len; | ||
| 277 | udy = lw * dy / len; | ||
| 278 | } | ||
| 279 | double px = x1 + udy / 2.0; | ||
| 280 | double py = y1 - udx / 2.0; | ||
| 281 | if (cap == BasicStroke.CAP_SQUARE) { | ||
| 282 | px -= udx / 2.0; | ||
| 283 | py -= udy / 2.0; | ||
| 284 | dx += udx; | ||
| 285 | dy += udy; | ||
| 286 | } | ||
| 287 | outrenderer.fillParallelogram(sg2d, ux1, uy1, ux2, uy2, | ||
| 288 | px, py, -udy, udx, dx, dy); | ||
| 289 | return true; | ||
| 290 | } | ||
| 291 | |||
| 292 | public void fillRectangle(SunGraphics2D sg2d, | ||
| 293 | double rx, double ry, | ||
| 294 | double rw, double rh) | ||
| 295 | { | ||
| 296 | double px, py; | ||
| 297 | double dx1, dy1, dx2, dy2; | ||
| 298 | AffineTransform txform = sg2d.transform; | ||
| 299 | dx1 = txform.getScaleX(); | ||
| 300 | dy1 = txform.getShearY(); | ||
| 301 | dx2 = txform.getShearX(); | ||
| 302 | dy2 = txform.getScaleY(); | ||
| 303 | px = rx * dx1 + ry * dx2 + txform.getTranslateX(); | ||
| 304 | py = rx * dy1 + ry * dy2 + txform.getTranslateY(); | ||
| 305 | dx1 *= rw; | ||
| 306 | dy1 *= rw; | ||
| 307 | dx2 *= rh; | ||
| 308 | dy2 *= rh; | ||
| 309 | if (adjustfill && | ||
| 310 | sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM && | ||
| 311 | sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) | ||
| 312 | { | ||
| 313 | double newx = normalize(px); | ||
| 314 | double newy = normalize(py); | ||
| 315 | dx1 = normalize(px + dx1) - newx; | ||
| 316 | dy1 = normalize(py + dy1) - newy; | ||
| 317 | dx2 = normalize(px + dx2) - newx; | ||
| 318 | dy2 = normalize(py + dy2) - newy; | ||
| 319 | px = newx; | ||
| 320 | py = newy; | ||
| 321 | } | ||
| 322 | outrenderer.fillParallelogram(sg2d, rx, ry, rx+rw, ry+rh, | ||
| 323 | px, py, dx1, dy1, dx2, dy2); | ||
| 324 | } | ||
| 325 | |||
| 326 | public void drawRectangle(SunGraphics2D sg2d, | ||
| 327 | double rx, double ry, | ||
| 328 | double rw, double rh, | ||
| 329 | double lw) | ||
| 330 | { | ||
| 331 | double px, py; | ||
| 332 | double dx1, dy1, dx2, dy2; | ||
| 333 | double lw1, lw2; | ||
| 334 | AffineTransform txform = sg2d.transform; | ||
| 335 | dx1 = txform.getScaleX(); | ||
| 336 | dy1 = txform.getShearY(); | ||
| 337 | dx2 = txform.getShearX(); | ||
| 338 | dy2 = txform.getScaleY(); | ||
| 339 | px = rx * dx1 + ry * dx2 + txform.getTranslateX(); | ||
| 340 | py = rx * dy1 + ry * dy2 + txform.getTranslateY(); | ||
| 341 | // lw along dx1,dy1 scale by transformed length of dx2,dy2 vectors | ||
| 342 | // and vice versa | ||
| 343 | lw1 = len(dx1, dy1) * lw; | ||
| 344 | lw2 = len(dx2, dy2) * lw; | ||
| 345 | dx1 *= rw; | ||
| 346 | dy1 *= rw; | ||
| 347 | dx2 *= rh; | ||
| 348 | dy2 *= rh; | ||
| 349 | if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM && | ||
| 350 | sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) | ||
| 351 | { | ||
| 352 | double newx = normalize(px); | ||
| 353 | double newy = normalize(py); | ||
| 354 | dx1 = normalize(px + dx1) - newx; | ||
| 355 | dy1 = normalize(py + dy1) - newy; | ||
| 356 | dx2 = normalize(px + dx2) - newx; | ||
| 357 | dy2 = normalize(py + dy2) - newy; | ||
| 358 | px = newx; | ||
| 359 | py = newy; | ||
| 360 | } | ||
| 361 | lw1 = Math.max(lw1, minPenSize); | ||
| 362 | lw2 = Math.max(lw2, minPenSize); | ||
| 363 | double len1 = len(dx1, dy1); | ||
| 364 | double len2 = len(dx2, dy2); | ||
| 365 | if (lw1 >= len1 || lw2 >= len2) { | ||
| 366 | // The line widths are large enough to consume the | ||
| 367 | // entire hole in the middle of the parallelogram | ||
| 368 | // so we can just fill the outer parallelogram. | ||
| 369 | fillOuterParallelogram(sg2d, | ||
| 370 | rx, ry, rx+rw, ry+rh, | ||
| 371 | px, py, dx1, dy1, dx2, dy2, | ||
| 372 | len1, len2, lw1, lw2); | ||
| 373 | } else { | ||
| 374 | outrenderer.drawParallelogram(sg2d, | ||
| 375 | rx, ry, rx+rw, ry+rh, | ||
| 376 | px, py, dx1, dy1, dx2, dy2, | ||
| 377 | lw1 / len1, lw2 / len2); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | /** | ||
| 382 | * This utility function handles the case where a drawRectangle | ||
| 383 | * operation discovered that the interior hole in the rectangle | ||
| 384 | * or parallelogram has been completely filled in by the stroke | ||
| 385 | * width. It calculates the outer parallelogram of the stroke | ||
| 386 | * and issues a single fillParallelogram request to fill it. | ||
| 387 | */ | ||
| 388 | public void fillOuterParallelogram(SunGraphics2D sg2d, | ||
| 389 | double ux1, double uy1, | ||
| 390 | double ux2, double uy2, | ||
| 391 | double px, double py, | ||
| 392 | double dx1, double dy1, | ||
| 393 | double dx2, double dy2, | ||
| 394 | double len1, double len2, | ||
| 395 | double lw1, double lw2) | ||
| 396 | { | ||
| 397 | double udx1 = dx1 / len1; | ||
| 398 | double udy1 = dy1 / len1; | ||
| 399 | double udx2 = dx2 / len2; | ||
| 400 | double udy2 = dy2 / len2; | ||
| 401 | if (len1 == 0) { | ||
| 402 | // len1 is 0, replace udxy1 with perpendicular of udxy2 | ||
| 403 | if (len2 == 0) { | ||
| 404 | // both are 0, use a unit Y vector for udxy2 | ||
| 405 | udx2 = 0; | ||
| 406 | udy2 = 1; | ||
| 407 | } | ||
| 408 | udx1 = udy2; | ||
| 409 | udy1 = -udx2; | ||
| 410 | } else if (len2 == 0) { | ||
| 411 | // len2 is 0, replace udxy2 with perpendicular of udxy1 | ||
| 412 | udx2 = udy1; | ||
| 413 | udy2 = -udx1; | ||
| 414 | } | ||
| 415 | udx1 *= lw1; | ||
| 416 | udy1 *= lw1; | ||
| 417 | udx2 *= lw2; | ||
| 418 | udy2 *= lw2; | ||
| 419 | px -= (udx1 + udx2) / 2; | ||
| 420 | py -= (udy1 + udy2) / 2; | ||
| 421 | dx1 += udx1; | ||
| 422 | dy1 += udy1; | ||
| 423 | dx2 += udx2; | ||
| 424 | dy2 += udy2; | ||
| 425 | |||
| 426 | outrenderer.fillParallelogram(sg2d, ux1, uy1, ux2, uy2, | ||
| 427 | px, py, dx1, dy1, dx2, dy2); | ||
| 428 | } | ||
| 429 | } | ||