1 /*
   2  * Copyright (c) 2007, 2015, 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.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 transformConsumer()
  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 transformConsumer()
  47     private final TranslateFilter      tx_TranslateFilter      = new TranslateFilter();
  48     private final DeltaScaleFilter     tx_DeltaScaleFilter     = new DeltaScaleFilter();
  49     private final ScaleFilter          tx_ScaleFilter          = new ScaleFilter();
  50     private final DeltaTransformFilter tx_DeltaTransformFilter = new DeltaTransformFilter();
  51     private final TransformFilter      tx_TransformFilter      = new TransformFilter();
  52 
  53     PathConsumer2D transformConsumer(PathConsumer2D out,
  54                                      AffineTransform at)
  55     {
  56         if (at == null) {
  57             return out;
  58         }
  59         float mxx = (float) at.getScaleX();
  60         float mxy = (float) at.getShearX();
  61         float mxt = (float) at.getTranslateX();
  62         float myx = (float) at.getShearY();
  63         float myy = (float) at.getScaleY();
  64         float myt = (float) at.getTranslateY();
  65         if (mxy == 0f && myx == 0f) {
  66             if (mxx == 1f && myy == 1f) {
  67                 if (mxt == 0f && myt == 0f) {
  68                     return out;
  69                 } else {
  70                     return tx_TranslateFilter.init(out, mxt, myt);
  71                 }
  72             } else {
  73                 if (mxt == 0f && myt == 0f) {
  74                     return tx_DeltaScaleFilter.init(out, mxx, myy);
  75                 } else {
  76                     return tx_ScaleFilter.init(out, mxx, myy, mxt, myt);
  77                 }
  78             }
  79         } else if (mxt == 0f && myt == 0f) {
  80             return tx_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
  81         } else {
  82             return tx_TransformFilter.init(out, mxx, mxy, mxt, myx, myy, myt);
  83         }
  84     }
  85 
  86     // recycled PathConsumer2D instances from deltaTransformConsumer()
  87     private final DeltaScaleFilter     dt_DeltaScaleFilter     = new DeltaScaleFilter();
  88     private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
  89 
  90     PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
  91                                           AffineTransform at)
  92     {
  93         if (at == null) {
  94             return out;
  95         }
  96         float mxx = (float) at.getScaleX();
  97         float mxy = (float) at.getShearX();
  98         float myx = (float) at.getShearY();
  99         float myy = (float) at.getScaleY();
 100         if (mxy == 0f && myx == 0f) {
 101             if (mxx == 1f && myy == 1f) {
 102                 return out;
 103             } else {
 104                 return dt_DeltaScaleFilter.init(out, mxx, myy);
 105             }
 106         } else {
 107             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
 108         }
 109     }
 110 
 111     // recycled PathConsumer2D instances from inverseDeltaTransformConsumer()
 112     private final DeltaScaleFilter     iv_DeltaScaleFilter     = new DeltaScaleFilter();
 113     private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
 114 
 115     PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
 116                                                  AffineTransform at)
 117     {
 118         if (at == null) {
 119             return out;
 120         }
 121         float mxx = (float) at.getScaleX();
 122         float mxy = (float) at.getShearX();
 123         float myx = (float) at.getShearY();
 124         float myy = (float) at.getScaleY();
 125         if (mxy == 0f && myx == 0f) {
 126             if (mxx == 1f && myy == 1f) {
 127                 return out;
 128             } else {
 129                 return iv_DeltaScaleFilter.init(out, 1.0f/mxx, 1.0f/myy);
 130             }
 131         } else {
 132             float det = mxx * myy - mxy * myx;
 133             return iv_DeltaTransformFilter.init(out,
 134                                                 myy / det,
 135                                                -mxy / det,
 136                                                -myx / det,
 137                                                 mxx / det);
 138         }
 139     }
 140 
 141     static final class TranslateFilter implements PathConsumer2D {
 142         private PathConsumer2D out;
 143         private float tx, ty;
 144 
 145         TranslateFilter() {}
 146 
 147         TranslateFilter init(PathConsumer2D out,
 148                              float tx, float ty)
 149         {
 150             this.out = out;
 151             this.tx = tx;
 152             this.ty = ty;
 153             return this; // fluent API
 154         }
 155 
 156         @Override
 157         public void moveTo(float x0, float y0) {
 158             out.moveTo(x0 + tx, y0 + ty);
 159         }
 160 
 161         @Override
 162         public void lineTo(float x1, float y1) {
 163             out.lineTo(x1 + tx, y1 + ty);
 164         }
 165 
 166         @Override
 167         public void quadTo(float x1, float y1,
 168                            float x2, float y2)
 169         {
 170             out.quadTo(x1 + tx, y1 + ty,
 171                        x2 + tx, y2 + ty);
 172         }
 173 
 174         @Override
 175         public void curveTo(float x1, float y1,
 176                             float x2, float y2,
 177                             float x3, float y3)
 178         {
 179             out.curveTo(x1 + tx, y1 + ty,
 180                         x2 + tx, y2 + ty,
 181                         x3 + tx, y3 + ty);
 182         }
 183 
 184         @Override
 185         public void closePath() {
 186             out.closePath();
 187         }
 188 
 189         @Override
 190         public void pathDone() {
 191             out.pathDone();
 192         }
 193 
 194         @Override
 195         public long getNativeConsumer() {
 196             return 0;
 197         }
 198     }
 199 
 200     static final class ScaleFilter implements PathConsumer2D {
 201         private PathConsumer2D out;
 202         private float sx, sy, tx, ty;
 203 
 204         ScaleFilter() {}
 205 
 206         ScaleFilter init(PathConsumer2D out,
 207                          float sx, float sy,
 208                          float tx, float ty)
 209         {
 210             this.out = out;
 211             this.sx = sx;
 212             this.sy = sy;
 213             this.tx = tx;
 214             this.ty = ty;
 215             return this; // fluent API
 216         }
 217 
 218         @Override
 219         public void moveTo(float x0, float y0) {
 220             out.moveTo(x0 * sx + tx, y0 * sy + ty);
 221         }
 222 
 223         @Override
 224         public void lineTo(float x1, float y1) {
 225             out.lineTo(x1 * sx + tx, y1 * sy + ty);
 226         }
 227 
 228         @Override
 229         public void quadTo(float x1, float y1,
 230                            float x2, float y2)
 231         {
 232             out.quadTo(x1 * sx + tx, y1 * sy + ty,
 233                        x2 * sx + tx, y2 * sy + ty);
 234         }
 235 
 236         @Override
 237         public void curveTo(float x1, float y1,
 238                             float x2, float y2,
 239                             float x3, float y3)
 240         {
 241             out.curveTo(x1 * sx + tx, y1 * sy + ty,
 242                         x2 * sx + tx, y2 * sy + ty,
 243                         x3 * sx + tx, y3 * sy + ty);
 244         }
 245 
 246         @Override
 247         public void closePath() {
 248             out.closePath();
 249         }
 250 
 251         @Override
 252         public void pathDone() {
 253             out.pathDone();
 254         }
 255 
 256         @Override
 257         public long getNativeConsumer() {
 258             return 0;
 259         }
 260     }
 261 
 262     static final class TransformFilter implements PathConsumer2D {
 263         private PathConsumer2D out;
 264         private float mxx, mxy, mxt, myx, myy, myt;
 265 
 266         TransformFilter() {}
 267 
 268         TransformFilter init(PathConsumer2D out,
 269                              float mxx, float mxy, float mxt,
 270                              float myx, float myy, float myt)
 271         {
 272             this.out = out;
 273             this.mxx = mxx;
 274             this.mxy = mxy;
 275             this.mxt = mxt;
 276             this.myx = myx;
 277             this.myy = myy;
 278             this.myt = myt;
 279             return this; // fluent API
 280         }
 281 
 282         @Override
 283         public void moveTo(float x0, float y0) {
 284             out.moveTo(x0 * mxx + y0 * mxy + mxt,
 285                        x0 * myx + y0 * myy + myt);
 286         }
 287 
 288         @Override
 289         public void lineTo(float x1, float y1) {
 290             out.lineTo(x1 * mxx + y1 * mxy + mxt,
 291                        x1 * myx + y1 * myy + myt);
 292         }
 293 
 294         @Override
 295         public void quadTo(float x1, float y1,
 296                            float x2, float y2)
 297         {
 298             out.quadTo(x1 * mxx + y1 * mxy + mxt,
 299                        x1 * myx + y1 * myy + myt,
 300                        x2 * mxx + y2 * mxy + mxt,
 301                        x2 * myx + y2 * myy + myt);
 302         }
 303 
 304         @Override
 305         public void curveTo(float x1, float y1,
 306                             float x2, float y2,
 307                             float x3, float y3)
 308         {
 309             out.curveTo(x1 * mxx + y1 * mxy + mxt,
 310                         x1 * myx + y1 * myy + myt,
 311                         x2 * mxx + y2 * mxy + mxt,
 312                         x2 * myx + y2 * myy + myt,
 313                         x3 * mxx + y3 * mxy + mxt,
 314                         x3 * myx + y3 * myy + myt);
 315         }
 316 
 317         @Override
 318         public void closePath() {
 319             out.closePath();
 320         }
 321 
 322         @Override
 323         public void pathDone() {
 324             out.pathDone();
 325         }
 326 
 327         @Override
 328         public long getNativeConsumer() {
 329             return 0;
 330         }
 331     }
 332 
 333     static final class DeltaScaleFilter implements PathConsumer2D {
 334         private PathConsumer2D out;
 335         private float sx, sy;
 336 
 337         DeltaScaleFilter() {}
 338 
 339         DeltaScaleFilter init(PathConsumer2D out,
 340                               float mxx, float myy)
 341         {
 342             this.out = out;
 343             sx = mxx;
 344             sy = myy;
 345             return this; // fluent API
 346         }
 347 
 348         @Override
 349         public void moveTo(float x0, float y0) {
 350             out.moveTo(x0 * sx, y0 * sy);
 351         }
 352 
 353         @Override
 354         public void lineTo(float x1, float y1) {
 355             out.lineTo(x1 * sx, y1 * sy);
 356         }
 357 
 358         @Override
 359         public void quadTo(float x1, float y1,
 360                            float x2, float y2)
 361         {
 362             out.quadTo(x1 * sx, y1 * sy,
 363                        x2 * sx, y2 * sy);
 364         }
 365 
 366         @Override
 367         public void curveTo(float x1, float y1,
 368                             float x2, float y2,
 369                             float x3, float y3)
 370         {
 371             out.curveTo(x1 * sx, y1 * sy,
 372                         x2 * sx, y2 * sy,
 373                         x3 * sx, y3 * sy);
 374         }
 375 
 376         @Override
 377         public void closePath() {
 378             out.closePath();
 379         }
 380 
 381         @Override
 382         public void pathDone() {
 383             out.pathDone();
 384         }
 385 
 386         @Override
 387         public long getNativeConsumer() {
 388             return 0;
 389         }
 390     }
 391 
 392     static final class DeltaTransformFilter implements PathConsumer2D {
 393         private PathConsumer2D out;
 394         private float mxx, mxy, myx, myy;
 395 
 396         DeltaTransformFilter() {}
 397 
 398         DeltaTransformFilter init(PathConsumer2D out,
 399                                   float mxx, float mxy,
 400                                   float myx, float myy)
 401         {
 402             this.out = out;
 403             this.mxx = mxx;
 404             this.mxy = mxy;
 405             this.myx = myx;
 406             this.myy = myy;
 407             return this; // fluent API
 408         }
 409 
 410         @Override
 411         public void moveTo(float x0, float y0) {
 412             out.moveTo(x0 * mxx + y0 * mxy,
 413                        x0 * myx + y0 * myy);
 414         }
 415 
 416         @Override
 417         public void lineTo(float x1, float y1) {
 418             out.lineTo(x1 * mxx + y1 * mxy,
 419                        x1 * myx + y1 * myy);
 420         }
 421 
 422         @Override
 423         public void quadTo(float x1, float y1,
 424                            float x2, float y2)
 425         {
 426             out.quadTo(x1 * mxx + y1 * mxy,
 427                        x1 * myx + y1 * myy,
 428                        x2 * mxx + y2 * mxy,
 429                        x2 * myx + y2 * myy);
 430         }
 431 
 432         @Override
 433         public void curveTo(float x1, float y1,
 434                             float x2, float y2,
 435                             float x3, float y3)
 436         {
 437             out.curveTo(x1 * mxx + y1 * mxy,
 438                         x1 * myx + y1 * myy,
 439                         x2 * mxx + y2 * mxy,
 440                         x2 * myx + y2 * myy,
 441                         x3 * mxx + y3 * mxy,
 442                         x3 * myx + y3 * myy);
 443         }
 444 
 445         @Override
 446         public void closePath() {
 447             out.closePath();
 448         }
 449 
 450         @Override
 451         public void pathDone() {
 452             out.pathDone();
 453         }
 454 
 455         @Override
 456         public long getNativeConsumer() {
 457             return 0;
 458         }
 459     }
 460 
 461     static final class Path2DWrapper implements PathConsumer2D {
 462         private Path2D.Float p2d;
 463 
 464         Path2DWrapper() {}
 465 
 466         Path2DWrapper init(Path2D.Float p2d) {
 467             this.p2d = p2d;
 468             return this;
 469         }
 470 
 471         @Override
 472         public void moveTo(float x0, float y0) {
 473             p2d.moveTo(x0, y0);
 474         }
 475 
 476         @Override
 477         public void lineTo(float x1, float y1) {
 478             p2d.lineTo(x1, y1);
 479         }
 480 
 481         @Override
 482         public void closePath() {
 483             p2d.closePath();
 484         }
 485 
 486         @Override
 487         public void pathDone() {}
 488 
 489         @Override
 490         public void curveTo(float x1, float y1,
 491                             float x2, float y2,
 492                             float x3, float y3)
 493         {
 494             p2d.curveTo(x1, y1, x2, y2, x3, y3);
 495         }
 496 
 497         @Override
 498         public void quadTo(float x1, float y1, float x2, float y2) {
 499             p2d.quadTo(x1, y1, x2, y2);
 500         }
 501 
 502         @Override
 503         public long getNativeConsumer() {
 504             throw new InternalError("Not using a native peer");
 505         }
 506     }
 507 }