< prev index next >

src/java.desktop/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java

Print this page




  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.marlin;
  27 
  28 import sun.awt.geom.PathConsumer2D;
  29 import java.awt.geom.AffineTransform;
  30 import java.awt.geom.Path2D;

  31 
  32 final class TransformingPathConsumer2D {
  33 
  34     TransformingPathConsumer2D() {
  35         // used by RendererContext
  36     }

  37 
  38     // recycled PathConsumer2D instance from wrapPath2d()
  39     private final Path2DWrapper        wp_Path2DWrapper        = new Path2DWrapper();
  40 



















  41     PathConsumer2D wrapPath2d(Path2D.Float p2d)
  42     {
  43         return wp_Path2DWrapper.init(p2d);
  44     }
  45 
  46     // recycled PathConsumer2D instances from deltaTransformConsumer()
  47     private final DeltaScaleFilter     dt_DeltaScaleFilter     = new DeltaScaleFilter();
  48     private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();













  49 
  50     PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
  51                                           AffineTransform at)
  52     {
  53         if (at == null) {
  54             return out;
  55         }
  56         float mxx = (float) at.getScaleX();
  57         float mxy = (float) at.getShearX();
  58         float myx = (float) at.getShearY();
  59         float myy = (float) at.getScaleY();
  60 
  61         if (mxy == 0.0f && myx == 0.0f) {
  62             if (mxx == 1.0f && myy == 1.0f) {
  63                 return out;
  64             } else {





  65                 return dt_DeltaScaleFilter.init(out, mxx, myy);
  66             }
  67         } else {




  68             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
  69         }
  70     }
  71 
  72     // recycled PathConsumer2D instances from inverseDeltaTransformConsumer()
  73     private final DeltaScaleFilter     iv_DeltaScaleFilter     = new DeltaScaleFilter();
  74     private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
































































  75 
  76     PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
  77                                                  AffineTransform at)
  78     {
  79         if (at == null) {
  80             return out;
  81         }
  82         float mxx = (float) at.getScaleX();
  83         float mxy = (float) at.getShearX();
  84         float myx = (float) at.getShearY();
  85         float myy = (float) at.getScaleY();
  86 
  87         if (mxy == 0.0f && myx == 0.0f) {
  88             if (mxx == 1.0f && myy == 1.0f) {
  89                 return out;
  90             } else {
  91                 return iv_DeltaScaleFilter.init(out, 1.0f/mxx, 1.0f/myy);
  92             }
  93         } else {
  94             float det = mxx * myy - mxy * myx;
  95             return iv_DeltaTransformFilter.init(out,
  96                                                 myy / det,
  97                                                -mxy / det,
  98                                                -myx / det,
  99                                                 mxx / det);
 100         }
 101     }
 102 
 103 
 104     static final class DeltaScaleFilter implements PathConsumer2D {
 105         private PathConsumer2D out;
 106         private float sx, sy;
 107 
 108         DeltaScaleFilter() {}
 109 
 110         DeltaScaleFilter init(PathConsumer2D out,
 111                               float mxx, float myy)
 112         {
 113             this.out = out;
 114             sx = mxx;
 115             sy = myy;
 116             return this; // fluent API
 117         }
 118 
 119         @Override
 120         public void moveTo(float x0, float y0) {
 121             out.moveTo(x0 * sx, y0 * sy);
 122         }
 123 


 251 
 252         @Override
 253         public void closePath() {
 254             p2d.closePath();
 255         }
 256 
 257         @Override
 258         public void pathDone() {}
 259 
 260         @Override
 261         public void curveTo(float x1, float y1,
 262                             float x2, float y2,
 263                             float x3, float y3)
 264         {
 265             p2d.curveTo(x1, y1, x2, y2, x3, y3);
 266         }
 267 
 268         @Override
 269         public void quadTo(float x1, float y1, float x2, float y2) {
 270             p2d.quadTo(x1, y1, x2, y2);




















































































































































 271         }
 272 
 273         @Override
 274         public long getNativeConsumer() {
 275             throw new InternalError("Not using a native peer");
 276         }
 277     }
 278 }


  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.marlin;
  27 
  28 import sun.awt.geom.PathConsumer2D;
  29 import java.awt.geom.AffineTransform;
  30 import java.awt.geom.Path2D;
  31 import sun.java2d.marlin.Helpers.PolyStack;
  32 
  33 final class TransformingPathConsumer2D {
  34 
  35     private final RendererContext rdrCtx;
  36 
  37     // recycled ClosedPathDetector instance from detectClosedPath()
  38     private final ClosedPathDetector   cpDetector;
  39 
  40     // recycled PathConsumer2D instance from wrapPath2d()
  41     private final Path2DWrapper        wp_Path2DWrapper        = new Path2DWrapper();
  42 
  43     // recycled PathConsumer2D instances from deltaTransformConsumer()
  44     private final DeltaScaleFilter     dt_DeltaScaleFilter     = new DeltaScaleFilter();
  45     private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
  46 
  47     // recycled PathConsumer2D instances from inverseDeltaTransformConsumer()
  48     private final DeltaScaleFilter     iv_DeltaScaleFilter     = new DeltaScaleFilter();
  49     private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
  50 
  51     // recycled PathTracer instances from tracer...() methods
  52     private final PathTracer tracerInput      = new PathTracer("[Input]");
  53     private final PathTracer tracerCPDetector = new PathTracer("ClosedPathDetector");
  54     private final PathTracer tracerStroker    = new PathTracer("Stroker");
  55 
  56     TransformingPathConsumer2D(final RendererContext rdrCtx) {
  57         // used by RendererContext
  58         this.rdrCtx = rdrCtx;
  59         this.cpDetector = new ClosedPathDetector(rdrCtx);
  60     }
  61 
  62     PathConsumer2D wrapPath2d(Path2D.Float p2d)
  63     {
  64         return wp_Path2DWrapper.init(p2d);
  65     }
  66 
  67     PathConsumer2D traceInput(PathConsumer2D out) {
  68         return tracerInput.init(out);
  69     }
  70 
  71     PathConsumer2D traceClosedPathDetector(PathConsumer2D out) {
  72         return tracerCPDetector.init(out);
  73     }
  74 
  75     PathConsumer2D traceStroker(PathConsumer2D out) {
  76         return tracerStroker.init(out);
  77     }
  78 
  79     PathConsumer2D detectClosedPath(PathConsumer2D out)
  80     {
  81         return cpDetector.init(out);
  82     }
  83 
  84     PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
  85                                           AffineTransform at)
  86     {
  87         if (at == null) {
  88             return out;
  89         }
  90         final float mxx = (float) at.getScaleX();
  91         final float mxy = (float) at.getShearX();
  92         final float myx = (float) at.getShearY();
  93         final float myy = (float) at.getScaleY();
  94 
  95         if (mxy == 0.0f && myx == 0.0f) {
  96             if (mxx == 1.0f && myy == 1.0f) {
  97                 return out;
  98             } else {
  99                 // Scale only
 100                 if (rdrCtx.doClip) {
 101                     // adjust clip rectangle (ymin, ymax, xmin, xmax):
 102                     adjustClipScale(rdrCtx.clipRect, mxx, myy);
 103                 }
 104                 return dt_DeltaScaleFilter.init(out, mxx, myy);
 105             }
 106         } else {
 107             if (rdrCtx.doClip) {
 108                 // adjust clip rectangle (ymin, ymax, xmin, xmax):
 109                 adjustClipInverseDelta(rdrCtx.clipRect, mxx, mxy, myx, myy);
 110             }
 111             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
 112         }
 113     }
 114 
 115     private static void adjustClipOffset(final float[] clipRect) {
 116         clipRect[0] += Renderer.RDR_OFFSET_Y;
 117         clipRect[1] += Renderer.RDR_OFFSET_Y;
 118         clipRect[2] += Renderer.RDR_OFFSET_X;
 119         clipRect[3] += Renderer.RDR_OFFSET_X;
 120     }
 121 
 122     private static void adjustClipScale(final float[] clipRect,
 123                                         final float mxx, final float myy)
 124     {
 125         adjustClipOffset(clipRect);
 126 
 127         // Adjust the clipping rectangle (iv_DeltaScaleFilter):
 128         clipRect[0] /= myy;
 129         clipRect[1] /= myy;
 130         clipRect[2] /= mxx;
 131         clipRect[3] /= mxx;
 132     }
 133 
 134     private static void adjustClipInverseDelta(final float[] clipRect,
 135                                                final float mxx, final float mxy,
 136                                                final float myx, final float myy)
 137     {
 138         adjustClipOffset(clipRect);
 139 
 140         // Adjust the clipping rectangle (iv_DeltaTransformFilter):
 141         final float det = mxx * myy - mxy * myx;
 142         final float imxx =  myy / det;
 143         final float imxy = -mxy / det;
 144         final float imyx = -myx / det;
 145         final float imyy =  mxx / det;
 146 
 147         float xmin, xmax, ymin, ymax;
 148         float x, y;
 149         // xmin, ymin:
 150         x = clipRect[2] * imxx + clipRect[0] * imxy;
 151         y = clipRect[2] * imyx + clipRect[0] * imyy;
 152 
 153         xmin = xmax = x;
 154         ymin = ymax = y;
 155 
 156         // xmax, ymin:
 157         x = clipRect[3] * imxx + clipRect[0] * imxy;
 158         y = clipRect[3] * imyx + clipRect[0] * imyy;
 159 
 160         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 161         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 162 
 163         // xmin, ymax:
 164         x = clipRect[2] * imxx + clipRect[1] * imxy;
 165         y = clipRect[2] * imyx + clipRect[1] * imyy;
 166 
 167         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 168         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 169 
 170         // xmax, ymax:
 171         x = clipRect[3] * imxx + clipRect[1] * imxy;
 172         y = clipRect[3] * imyx + clipRect[1] * imyy;
 173 
 174         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 175         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 176 
 177         clipRect[0] = ymin;
 178         clipRect[1] = ymax;
 179         clipRect[2] = xmin;
 180         clipRect[3] = xmax;
 181     }
 182 
 183     PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
 184                                                  AffineTransform at)
 185     {
 186         if (at == null) {
 187             return out;
 188         }
 189         float mxx = (float) at.getScaleX();
 190         float mxy = (float) at.getShearX();
 191         float myx = (float) at.getShearY();
 192         float myy = (float) at.getScaleY();
 193 
 194         if (mxy == 0.0f && myx == 0.0f) {
 195             if (mxx == 1.0f && myy == 1.0f) {
 196                 return out;
 197             } else {
 198                 return iv_DeltaScaleFilter.init(out, 1.0f/mxx, 1.0f/myy);
 199             }
 200         } else {
 201             final float det = mxx * myy - mxy * myx;
 202             return iv_DeltaTransformFilter.init(out,
 203                                                 myy / det,
 204                                                -mxy / det,
 205                                                -myx / det,
 206                                                 mxx / det);
 207         }
 208     }
 209 

 210     static final class DeltaScaleFilter implements PathConsumer2D {
 211         private PathConsumer2D out;
 212         private float sx, sy;
 213 
 214         DeltaScaleFilter() {}
 215 
 216         DeltaScaleFilter init(PathConsumer2D out,
 217                               float mxx, float myy)
 218         {
 219             this.out = out;
 220             sx = mxx;
 221             sy = myy;
 222             return this; // fluent API
 223         }
 224 
 225         @Override
 226         public void moveTo(float x0, float y0) {
 227             out.moveTo(x0 * sx, y0 * sy);
 228         }
 229 


 357 
 358         @Override
 359         public void closePath() {
 360             p2d.closePath();
 361         }
 362 
 363         @Override
 364         public void pathDone() {}
 365 
 366         @Override
 367         public void curveTo(float x1, float y1,
 368                             float x2, float y2,
 369                             float x3, float y3)
 370         {
 371             p2d.curveTo(x1, y1, x2, y2, x3, y3);
 372         }
 373 
 374         @Override
 375         public void quadTo(float x1, float y1, float x2, float y2) {
 376             p2d.quadTo(x1, y1, x2, y2);
 377         }
 378 
 379         @Override
 380         public long getNativeConsumer() {
 381             throw new InternalError("Not using a native peer");
 382         }
 383     }
 384 
 385     static final class ClosedPathDetector implements PathConsumer2D {
 386 
 387         private final RendererContext rdrCtx;
 388         private final PolyStack stack;
 389 
 390         private PathConsumer2D out;
 391 
 392         ClosedPathDetector(final RendererContext rdrCtx) {
 393             this.rdrCtx = rdrCtx;
 394             this.stack = (rdrCtx.stats != null) ?
 395                 new PolyStack(rdrCtx,
 396                         rdrCtx.stats.stat_cpd_polystack_types,
 397                         rdrCtx.stats.stat_cpd_polystack_curves,
 398                         rdrCtx.stats.hist_cpd_polystack_curves,
 399                         rdrCtx.stats.stat_array_cpd_polystack_curves,
 400                         rdrCtx.stats.stat_array_cpd_polystack_types)
 401                 : new PolyStack(rdrCtx);
 402         }
 403 
 404         ClosedPathDetector init(PathConsumer2D out) {
 405             this.out = out;
 406             return this; // fluent API
 407         }
 408 
 409         /**
 410          * Disposes this instance:
 411          * clean up before reusing this instance
 412          */
 413         void dispose() {
 414             stack.dispose();
 415         }
 416 
 417         @Override
 418         public void pathDone() {
 419             // previous path is not closed:
 420             finish(false);
 421             out.pathDone();
 422 
 423             // TODO: fix possible leak if exception happened
 424             // Dispose this instance:
 425             dispose();
 426         }
 427 
 428         @Override
 429         public void closePath() {
 430             // path is closed
 431             finish(true);
 432             out.closePath();
 433         }
 434 
 435         @Override
 436         public void moveTo(float x0, float y0) {
 437             // previous path is not closed:
 438             finish(false);
 439             out.moveTo(x0, y0);
 440         }
 441 
 442         private void finish(final boolean closed) {
 443             rdrCtx.closedPath = closed;
 444             stack.pullAll(out);
 445         }
 446 
 447         @Override
 448         public void lineTo(float x1, float y1) {
 449             stack.pushLine(x1, y1);
 450         }
 451 
 452         @Override
 453         public void curveTo(float x3, float y3,
 454                             float x2, float y2,
 455                             float x1, float y1)
 456         {
 457             stack.pushCubic(x1, y1, x2, y2, x3, y3);
 458         }
 459 
 460         @Override
 461         public void quadTo(float x2, float y2, float x1, float y1) {
 462             stack.pushQuad(x1, y1, x2, y2);
 463         }
 464 
 465         @Override
 466         public long getNativeConsumer() {
 467             throw new InternalError("Not using a native peer");
 468         }
 469     }
 470 
 471     static final class PathTracer implements PathConsumer2D {
 472         private final String prefix;
 473         private PathConsumer2D out;
 474 
 475         PathTracer(String name) {
 476             this.prefix = name + ": ";
 477         }
 478 
 479         PathTracer init(PathConsumer2D out) {
 480             this.out = out;
 481             return this; // fluent API
 482         }
 483 
 484         @Override
 485         public void moveTo(float x0, float y0) {
 486             log("moveTo (" + x0 + ", " + y0 + ')');
 487             out.moveTo(x0, y0);
 488         }
 489 
 490         @Override
 491         public void lineTo(float x1, float y1) {
 492             log("lineTo (" + x1 + ", " + y1 + ')');
 493             out.lineTo(x1, y1);
 494         }
 495 
 496         @Override
 497         public void curveTo(float x1, float y1,
 498                             float x2, float y2,
 499                             float x3, float y3)
 500         {
 501             log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ") P3(" + x3 + ", " + y3 + ')');
 502             out.curveTo(x1, y1, x2, y2, x3, y3);
 503         }
 504 
 505         @Override
 506         public void quadTo(float x1, float y1, float x2, float y2) {
 507             log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ')');
 508             out.quadTo(x1, y1, x2, y2);
 509         }
 510 
 511         @Override
 512         public void closePath() {
 513             log("closePath");
 514             out.closePath();
 515         }
 516 
 517         @Override
 518         public void pathDone() {
 519             log("pathDone");
 520             out.pathDone();
 521         }
 522 
 523         private void log(final String message) {
 524             System.out.println(prefix + message);
 525         }
 526 
 527         @Override
 528         public long getNativeConsumer() {
 529             throw new InternalError("Not using a native peer");
 530         }
 531     }
 532 }
< prev index next >