1 /* 2 * Copyright (c) 2011, 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 com.sun.prism.sw; 27 28 import com.sun.glass.ui.Screen; 29 import com.sun.javafx.font.FontResource; 30 import com.sun.javafx.font.FontStrike; 31 import com.sun.javafx.font.Glyph; 32 import com.sun.javafx.font.Metrics; 33 import com.sun.javafx.font.PrismFontFactory; 34 import com.sun.javafx.geom.Ellipse2D; 35 import com.sun.javafx.geom.Line2D; 36 import com.sun.javafx.geom.Point2D; 37 import com.sun.javafx.geom.RectBounds; 38 import com.sun.javafx.geom.Rectangle; 39 import com.sun.javafx.geom.RoundRectangle2D; 40 import com.sun.javafx.geom.Shape; 41 import com.sun.javafx.geom.transform.Affine2D; 42 import com.sun.javafx.geom.transform.BaseTransform; 43 import com.sun.javafx.geom.transform.NoninvertibleTransformException; 44 import com.sun.javafx.scene.text.GlyphList; 45 import com.sun.javafx.sg.prism.NGCamera; 46 import com.sun.javafx.sg.prism.NGLightBase; 47 import com.sun.javafx.sg.prism.NodePath; 48 import com.sun.pisces.GradientColorMap; 49 import com.sun.pisces.PiscesRenderer; 50 import com.sun.pisces.RendererBase; 51 import com.sun.pisces.Transform6; 52 import com.sun.prism.BasicStroke; 53 import com.sun.prism.CompositeMode; 54 import com.sun.prism.Graphics; 55 import com.sun.prism.PixelFormat; 56 import com.sun.prism.RTTexture; 57 import com.sun.prism.ReadbackGraphics; 58 import com.sun.prism.RenderTarget; 59 import com.sun.prism.Texture; 60 import com.sun.prism.impl.PrismSettings; 61 import com.sun.prism.paint.Color; 62 import com.sun.prism.paint.ImagePattern; 63 import com.sun.prism.paint.Paint; 64 65 final class SWGraphics implements ReadbackGraphics { 66 67 private static final BasicStroke DEFAULT_STROKE = 68 new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f); 69 private static final Paint DEFAULT_PAINT = Color.WHITE; 70 71 private final PiscesRenderer pr; 72 private final SWContext context; 73 private final SWRTTexture target; 74 private final SWPaint swPaint; 75 76 private final BaseTransform tx = new Affine2D(); 77 78 private CompositeMode compositeMode = CompositeMode.SRC_OVER; 79 80 private Rectangle clip; 81 private final Rectangle finalClip = new Rectangle(); 82 private RectBounds nodeBounds; 83 84 private int clipRectIndex; 85 86 private Paint paint = DEFAULT_PAINT; 87 private BasicStroke stroke = DEFAULT_STROKE; 88 89 private Ellipse2D ellipse2d; 90 private Line2D line2d; 91 private RoundRectangle2D rect2d; 92 93 private boolean antialiasedShape = true; 94 private boolean hasPreCullingBits = false; 95 private float pixelScaleX = 1.0f; 96 private float pixelScaleY = 1.0f; 97 98 private NodePath renderRoot; 99 @Override 100 public void setRenderRoot(NodePath root) { 101 this.renderRoot = root; 102 } 103 104 @Override 105 public NodePath getRenderRoot() { 106 return renderRoot; 107 } 108 109 public SWGraphics(SWRTTexture target, SWContext context, PiscesRenderer pr) { 110 this.target = target; 111 this.context = context; 112 this.pr = pr; 113 this.swPaint = new SWPaint(context, pr); 114 115 this.setClipRect(null); 116 } 117 118 public RenderTarget getRenderTarget() { 119 return target; 120 } 121 122 public SWResourceFactory getResourceFactory() { 123 return target.getResourceFactory(); 124 } 125 126 public Screen getAssociatedScreen() { 127 return target.getAssociatedScreen(); 128 } 129 130 public void sync() { 131 } 132 133 public BaseTransform getTransformNoClone() { 134 if (PrismSettings.debug) { 135 System.out.println("+ getTransformNoClone " + this + "; tr: " + tx); 136 } 137 return tx; 138 } 139 140 public void setTransform(BaseTransform xform) { 141 if (xform == null) { 142 xform = BaseTransform.IDENTITY_TRANSFORM; 143 } 144 if (PrismSettings.debug) { 145 System.out.println("+ setTransform " + this + "; tr: " + xform); 146 } 147 tx.setTransform(xform); 148 } 149 150 public void setTransform(double m00, double m10, 151 double m01, double m11, 152 double m02, double m12) { 153 tx.restoreTransform(m00, m10, m01, m11, m02, m12); 154 if (PrismSettings.debug) { 155 System.out.println("+ restoreTransform " + this + "; tr: " + tx); 156 } 157 } 158 159 public void setTransform3D(double mxx, double mxy, double mxz, double mxt, 160 double myx, double myy, double myz, double myt, 161 double mzx, double mzy, double mzz, double mzt) { 162 if (mxz != 0.0 || myz != 0.0 || 163 mzx != 0.0 || mzy != 0.0 || mzz != 1.0 || mzt != 0.0) 164 { 165 throw new UnsupportedOperationException("3D transforms not supported."); 166 } 167 setTransform(mxx, myx, mxy, myy, mxt, myt); 168 } 169 170 public void transform(BaseTransform xform) { 171 if (PrismSettings.debug) { 172 System.out.println("+ concatTransform " + this + "; tr: " + xform); 173 } 174 tx.deriveWithConcatenation(xform); 175 } 176 177 public void translate(float tx, float ty) { 178 if (PrismSettings.debug) { 179 System.out.println("+ concat translate " + this + "; tx: " + tx + "; ty: " + ty); 180 } 181 this.tx.deriveWithTranslation(tx, ty); 182 } 183 184 public void translate(float tx, float ty, float tz) { 185 throw new UnsupportedOperationException("translate3D: unimp"); 186 } 187 188 public void scale(float sx, float sy) { 189 if (PrismSettings.debug) { 190 System.out.println("+ concat scale " + this + "; sx: " + sx + "; sy: " + sy); 191 } 192 tx.deriveWithConcatenation(sx, 0, 0, sy, 0, 0); 193 } 194 195 public void scale(float sx, float sy, float sz) { 196 throw new UnsupportedOperationException("scale3D: unimp"); 197 } 198 199 public void setCamera(NGCamera camera) { 200 } 201 202 public NGCamera getCameraNoClone() { 203 throw new UnsupportedOperationException("getCameraNoClone: unimp"); 204 } 205 206 public void setDepthTest(boolean depthTest) { } 207 208 public boolean isDepthTest() { 209 return false; 210 } 211 212 public void setDepthBuffer(boolean depthBuffer) { } 213 214 public boolean isDepthBuffer() { 215 return false; 216 } 217 218 public boolean isAlphaTestShader() { 219 if (PrismSettings.verbose && PrismSettings.forceAlphaTestShader) { 220 System.out.println("SW pipe doesn't support shader with alpha testing"); 221 } 222 return false; 223 } 224 225 public void setAntialiasedShape(boolean aa) { 226 antialiasedShape = aa; 227 } 228 229 public boolean isAntialiasedShape() { 230 return antialiasedShape; 231 } 232 233 public Rectangle getClipRect() { 234 return (clip == null) ? null : new Rectangle(clip); 235 } 236 237 public Rectangle getClipRectNoClone() { 238 return clip; 239 } 240 241 public RectBounds getFinalClipNoClone() { 242 return finalClip.toRectBounds(); 243 } 244 245 public void setClipRect(Rectangle clipRect) { 246 finalClip.setBounds(target.getDimensions()); 247 if (clipRect == null) { 248 if (PrismSettings.debug) { 249 System.out.println("+ PR.resetClip"); 250 } 251 clip = null; 252 } else { 253 if (PrismSettings.debug) { 254 System.out.println("+ PR.setClip: " + clipRect); 255 } 256 finalClip.intersectWith(clipRect); 257 clip = new Rectangle(clipRect); 258 } 259 pr.setClip(finalClip.x, finalClip.y, finalClip.width, finalClip.height); 260 } 261 262 public void setHasPreCullingBits(boolean hasBits) { 263 this.hasPreCullingBits = hasBits; 264 } 265 266 public boolean hasPreCullingBits() { 267 return this.hasPreCullingBits; 268 } 269 270 public int getClipRectIndex() { 271 return clipRectIndex; 272 } 273 274 public void setClipRectIndex(int index) { 275 if (PrismSettings.debug) { 276 System.out.println("+ PR.setClipRectIndex: " + index); 277 } 278 clipRectIndex = index; 279 } 280 281 public float getExtraAlpha() { 282 return swPaint.getCompositeAlpha(); 283 } 284 285 public void setExtraAlpha(float extraAlpha) { 286 if (PrismSettings.debug) { 287 System.out.println("PR.setCompositeAlpha, value: " + extraAlpha); 288 } 289 swPaint.setCompositeAlpha(extraAlpha); 290 } 291 292 public Paint getPaint() { 293 return paint; 294 } 295 296 public void setPaint(Paint paint) { 297 this.paint = paint; 298 } 299 300 301 302 public BasicStroke getStroke() { 303 return stroke; 304 } 305 306 public void setStroke(BasicStroke stroke) { 307 this.stroke = stroke; 308 } 309 310 public CompositeMode getCompositeMode() { 311 return compositeMode; 312 } 313 314 public void setCompositeMode(CompositeMode mode) { 315 this.compositeMode = mode; 316 317 int piscesComp; 318 switch (mode) { 319 case CLEAR: 320 piscesComp = RendererBase.COMPOSITE_CLEAR; 321 if (PrismSettings.debug) { 322 System.out.println("PR.setCompositeRule - CLEAR"); 323 } 324 break; 325 case SRC: 326 piscesComp = RendererBase.COMPOSITE_SRC; 327 if (PrismSettings.debug) { 328 System.out.println("PR.setCompositeRule - SRC"); 329 } 330 break; 331 case SRC_OVER: 332 piscesComp = RendererBase.COMPOSITE_SRC_OVER; 333 if (PrismSettings.debug) { 334 System.out.println("PR.setCompositeRule - SRC_OVER"); 335 } 336 break; 337 default: 338 throw new InternalError("Unrecognized composite mode: "+mode); 339 } 340 this.pr.setCompositeRule(piscesComp); 341 } 342 343 public void setNodeBounds(RectBounds bounds) { 344 if (PrismSettings.debug) { 345 System.out.println("+ SWG.setNodeBounds: " + bounds); 346 } 347 nodeBounds = bounds; 348 } 349 350 public void clear() { 351 this.clear(Color.TRANSPARENT); 352 } 353 354 /** 355 * Clears the current {@code RenderTarget} with the given {@code Color}. 356 * Note that this operation is affected by the current clip rectangle, 357 * if set. To clear the entire surface, call {@code setClipRect(null)} 358 * prior to calling {@code clear()}. 359 */ 360 public void clear(Color color) { 361 if (PrismSettings.debug) { 362 System.out.println("+ PR.clear: " + color); 363 } 364 this.swPaint.setColor(color, 1f); 365 pr.clearRect(0, 0, target.getPhysicalWidth(), target.getPhysicalHeight()); 366 getRenderTarget().setOpaque(color.isOpaque()); 367 } 368 369 /** 370 * Clears the region represented by the given quad with transparent pixels. 371 * Note that this operation is affected by the current clip rectangle, 372 * if set, as well as the current transform (the quad is specified in 373 * user space). Also note that unlike the {@code clear()} methods, this 374 * method does not attempt to clear the depth buffer. 375 */ 376 public void clearQuad(float x1, float y1, float x2, float y2) { 377 final CompositeMode cm = this.compositeMode; 378 final Paint p = this.paint; 379 this.setCompositeMode(CompositeMode.SRC); 380 this.setPaint(Color.TRANSPARENT); 381 this.fillQuad(x1, y1, x2, y2); 382 this.setCompositeMode(cm); 383 this.setPaint(p); 384 } 385 386 public void fill(Shape shape) { 387 if (PrismSettings.debug) { 388 System.out.println("+ fill(Shape)"); 389 } 390 paintShape(shape, null, this.tx); 391 } 392 393 public void fillQuad(float x1, float y1, float x2, float y2) { 394 if (PrismSettings.debug) { 395 System.out.println("+ SWG.fillQuad"); 396 } 397 this.fillRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1)); 398 } 399 400 public void fillRect(float x, float y, float width, float height) { 401 if (PrismSettings.debug) { 402 System.out.printf("+ SWG.fillRect, x: %f, y: %f, w: %f, h: %f\n", x, y, width, height); 403 } 404 if (tx.getMxy() == 0 && tx.getMyx() == 0) { 405 if (PrismSettings.debug) { 406 System.out.println("GR: " + this); 407 System.out.println("target: " + target + " t.w: " + target.getPhysicalWidth() + ", t.h: " + target.getPhysicalHeight() + 408 ", t.dims: " + target.getDimensions()); 409 System.out.println("Tx: " + tx); 410 System.out.println("Clip: " + finalClip); 411 System.out.println("Composite rule: " + compositeMode); 412 } 413 414 final Point2D p1 = new Point2D(x, y); 415 final Point2D p2 = new Point2D(x + width, y + height); 416 tx.transform(p1, p1); 417 tx.transform(p2, p2); 418 419 if (this.paint.getType() == Paint.Type.IMAGE_PATTERN) { 420 // we can call pr.drawImage(...) directly 421 final ImagePattern ip = (ImagePattern)this.paint; 422 if (ip.getImage().getPixelFormat() == PixelFormat.BYTE_ALPHA) { 423 throw new UnsupportedOperationException("Alpha image is not supported as an image pattern."); 424 } else { 425 final Transform6 piscesTx = swPaint.computeSetTexturePaintTransform(this.paint, this.tx, this.nodeBounds, x, y, width, height); 426 final SWArgbPreTexture tex = context.validateImagePaintTexture(ip.getImage().getWidth(), ip.getImage().getHeight()); 427 tex.update(ip.getImage()); 428 429 final float compositeAlpha = swPaint.getCompositeAlpha(); 430 final int imageMode; 431 if (compositeAlpha == 1f) { 432 imageMode = RendererBase.IMAGE_MODE_NORMAL; 433 } else { 434 imageMode = RendererBase.IMAGE_MODE_MULTIPLY; 435 this.pr.setColor(255, 255, 255, (int)(255 * compositeAlpha)); 436 } 437 438 this.pr.drawImage(RendererBase.TYPE_INT_ARGB_PRE, imageMode, 439 tex.getDataNoClone(), tex.getContentWidth(), tex.getContentHeight(), 440 tex.getOffset(), tex.getPhysicalWidth(), 441 piscesTx, 442 tex.getWrapMode() == Texture.WrapMode.REPEAT, 443 (int)(Math.min(p1.x, p2.x) * SWUtils.TO_PISCES), (int)(Math.min(p1.y, p2.y) * SWUtils.TO_PISCES), 444 (int)(Math.abs(p2.x - p1.x) * SWUtils.TO_PISCES), (int)(Math.abs(p2.y - p1.y) * SWUtils.TO_PISCES), 445 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 446 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 447 0, 0, tex.getContentWidth()-1, tex.getContentHeight()-1, 448 tex.hasAlpha()); 449 } 450 } else { 451 swPaint.setPaintFromShape(this.paint, this.tx, null, this.nodeBounds, x, y, width, height); 452 this.pr.fillRect((int)(Math.min(p1.x, p2.x) * SWUtils.TO_PISCES), (int)(Math.min(p1.y, p2.y) * SWUtils.TO_PISCES), 453 (int)(Math.abs(p2.x - p1.x) * SWUtils.TO_PISCES), (int)(Math.abs(p2.y - p1.y) * SWUtils.TO_PISCES)); 454 } 455 } else { 456 this.fillRoundRect(x, y, width, height, 0, 0); 457 } 458 } 459 460 public void fillRoundRect(float x, float y, float width, float height, 461 float arcw, float arch) { 462 if (PrismSettings.debug) { 463 System.out.println("+ SWG.fillRoundRect"); 464 } 465 this.paintRoundRect(x, y, width, height, arcw, arch, null); 466 } 467 468 public void fillEllipse(float x, float y, float width, float height) { 469 if (PrismSettings.debug) { 470 System.out.println("+ SWG.fillEllipse"); 471 } 472 this.paintEllipse(x, y, width, height, null); 473 } 474 475 public void draw(Shape shape) { 476 if (PrismSettings.debug) { 477 System.out.println("+ draw(Shape)"); 478 } 479 paintShape(shape, this.stroke, this.tx); 480 } 481 482 private void paintShape(Shape shape, BasicStroke st, BaseTransform tr) { 483 if (this.finalClip.isEmpty()) { 484 if (PrismSettings.debug) { 485 System.out.println("Final clip is empty: not rendering the shape: " + shape); 486 } 487 return; 488 } 489 swPaint.setPaintFromShape(this.paint, this.tx, shape, this.nodeBounds, 0,0,0,0); 490 this.paintShapePaintAlreadySet(shape, st, tr); 491 } 492 493 private void paintShapePaintAlreadySet(Shape shape, BasicStroke st, BaseTransform tr) { 494 if (this.finalClip.isEmpty()) { 495 if (PrismSettings.debug) { 496 System.out.println("Final clip is empty: not rendering the shape: " + shape); 497 } 498 return; 499 } 500 501 if (PrismSettings.debug) { 502 System.out.println("GR: " + this); 503 System.out.println("target: " + target + " t.w: " + target.getPhysicalWidth() + ", t.h: " + target.getPhysicalHeight() + 504 ", t.dims: " + target.getDimensions()); 505 System.out.println("Shape: " + shape); 506 System.out.println("Stroke: " + st); 507 System.out.println("Tx: " + tr); 508 System.out.println("Clip: " + finalClip); 509 System.out.println("Composite rule: " + compositeMode); 510 } 511 context.renderShape(this.pr, shape, st, tr, this.finalClip, isAntialiasedShape()); 512 } 513 514 private void paintRoundRect(float x, float y, float width, float height, float arcw, float arch, BasicStroke st) { 515 if (rect2d == null) { 516 rect2d = new RoundRectangle2D(x, y, width, height, arcw, arch); 517 } else { 518 rect2d.setRoundRect(x, y, width, height, arcw, arch); 519 } 520 paintShape(this.rect2d, st, this.tx); 521 } 522 523 private void paintEllipse(float x, float y, float width, float height, BasicStroke st) { 524 if (ellipse2d == null) { 525 ellipse2d = new Ellipse2D(x, y, width, height); 526 } else { 527 ellipse2d.setFrame(x, y, width, height); 528 } 529 paintShape(this.ellipse2d, st, this.tx); 530 } 531 532 public void drawLine(float x1, float y1, float x2, float y2) { 533 if (PrismSettings.debug) { 534 System.out.println("+ drawLine"); 535 } 536 if (line2d == null) { 537 line2d = new Line2D(x1, y1, x2, y2); 538 } else { 539 line2d.setLine(x1, y1, x2, y2); 540 } 541 paintShape(this.line2d, this.stroke, this.tx); 542 } 543 544 public void drawRect(float x, float y, float width, float height) { 545 if (PrismSettings.debug) { 546 System.out.println("+ SWG.drawRect"); 547 } 548 this.drawRoundRect(x, y, width, height, 0, 0); 549 } 550 551 public void drawRoundRect(float x, float y, float width, float height, 552 float arcw, float arch) { 553 if (PrismSettings.debug) { 554 System.out.println("+ SWG.drawRoundRect"); 555 } 556 this.paintRoundRect(x, y, width, height, arcw, arch, stroke); 557 } 558 559 public void drawEllipse(float x, float y, float width, float height) { 560 if (PrismSettings.debug) { 561 System.out.println("+ SWG.drawEllipse"); 562 } 563 this.paintEllipse(x, y, width, height, stroke); 564 } 565 566 public void drawString(GlyphList gl, FontStrike strike, float x, float y, 567 Color selectColor, int selectStart, int selectEnd) { 568 569 if (PrismSettings.debug) { 570 System.out.println("+ SWG.drawGlyphList, gl.Count: " + gl.getGlyphCount() + 571 ", x: " + x + ", y: " + y + 572 ", selectStart: " + selectStart + ", selectEnd: " + selectEnd); 573 } 574 575 final float bx, by, bw, bh; 576 if (paint.isProportional()) { 577 if (nodeBounds != null) { 578 bx = nodeBounds.getMinX(); 579 by = nodeBounds.getMinY(); 580 bw = nodeBounds.getWidth(); 581 bh = nodeBounds.getHeight(); 582 } else { 583 Metrics m = strike.getMetrics(); 584 bx = 0; 585 by = m.getAscent(); 586 bw = gl.getWidth(); 587 bh = m.getLineHeight(); 588 } 589 } else { 590 bx = by = bw = bh = 0; 591 } 592 593 final boolean drawAsMasks = tx.isTranslateOrIdentity() && (!strike.drawAsShapes()); 594 final boolean doLCDText = drawAsMasks && 595 (strike.getAAMode() == FontResource.AA_LCD) && 596 getRenderTarget().isOpaque() && 597 (this.paint.getType() == Paint.Type.COLOR) && 598 tx.is2D(); 599 BaseTransform glyphTx = null; 600 601 if (doLCDText) { 602 this.pr.setLCDGammaCorrection(1f / PrismFontFactory.getLCDContrast()); 603 } else if (drawAsMasks) { 604 final FontResource fr = strike.getFontResource(); 605 final float origSize = strike.getSize(); 606 final BaseTransform origTx = strike.getTransform(); 607 strike = fr.getStrike(origSize, origTx, FontResource.AA_GREYSCALE); 608 } else { 609 glyphTx = new Affine2D(); 610 } 611 612 if (selectColor == null) { 613 swPaint.setPaintBeforeDraw(this.paint, this.tx, bx, by, bw, bh); 614 for (int i = 0; i < gl.getGlyphCount(); i++) { 615 this.drawGlyph(strike, gl, i, glyphTx, drawAsMasks, x, y); 616 } 617 } else { 618 for (int i = 0; i < gl.getGlyphCount(); i++) { 619 final int offset = gl.getCharOffset(i); 620 final boolean selected = selectStart <= offset && offset < selectEnd; 621 swPaint.setPaintBeforeDraw(selected ? selectColor : this.paint, this.tx, bx, by, bw, bh); 622 this.drawGlyph(strike, gl, i, glyphTx, drawAsMasks, x, y); 623 } 624 } 625 } 626 627 private void drawGlyph(FontStrike strike, GlyphList gl, int idx, BaseTransform glyphTx, 628 boolean drawAsMasks, float x, float y) 629 { 630 631 final Glyph g = strike.getGlyph(gl.getGlyphCode(idx)); 632 if (drawAsMasks) { 633 final Point2D pt = new Point2D((float)(x + tx.getMxt() + gl.getPosX(idx)), 634 (float)(y + tx.getMyt() + gl.getPosY(idx))); 635 int subPixel = strike.getQuantizedPosition(pt); 636 final byte pixelData[] = g.getPixelData(subPixel); 637 if (pixelData != null) { 638 final int intPosX = g.getOriginX() + (int)pt.x; 639 final int intPosY = g.getOriginY() + (int)pt.y; 640 if (g.isLCDGlyph()) { 641 this.pr.fillLCDAlphaMask(pixelData, intPosX, intPosY, 642 g.getWidth(), g.getHeight(), 643 0, g.getWidth()); 644 } else { 645 this.pr.fillAlphaMask(pixelData, intPosX, intPosY, 646 g.getWidth(), g.getHeight(), 647 0, g.getWidth()); 648 } 649 } 650 } else { 651 Shape shape = g.getShape(); 652 if (shape != null) { 653 glyphTx.setTransform(tx); 654 glyphTx.deriveWithTranslation(x + gl.getPosX(idx), y + gl.getPosY(idx)); 655 this.paintShapePaintAlreadySet(shape, null, glyphTx); 656 } 657 } 658 } 659 660 public void drawTexture(Texture tex, float x, float y, float w, float h) { 661 if (PrismSettings.debug) { 662 System.out.printf("+ drawTexture1, x: %f, y: %f, w: %f, h: %f\n", x, y, w, h); 663 } 664 this.drawTexture(tex, x, y, x + w, y + h, 0, 0, w, h); 665 } 666 667 public void drawTexture(Texture tex, 668 float dx1, float dy1, float dx2, float dy2, 669 float sx1, float sy1, float sx2, float sy2) 670 { 671 this.drawTexture(tex, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, 672 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 673 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 674 } 675 676 private void drawTexture(Texture tex, 677 float dx1, float dy1, float dx2, float dy2, 678 float sx1, float sy1, float sx2, float sy2, 679 int lEdge, int rEdge, int tEdge, int bEdge) { 680 final int imageMode; 681 final float compositeAlpha = swPaint.getCompositeAlpha(); 682 if (compositeAlpha == 1f) { 683 imageMode = RendererBase.IMAGE_MODE_NORMAL; 684 } else { 685 imageMode = RendererBase.IMAGE_MODE_MULTIPLY; 686 this.pr.setColor(255, 255, 255, (int)(255 * compositeAlpha)); 687 } 688 this.drawTexture(tex, imageMode, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, lEdge, rEdge, tEdge, bEdge); 689 } 690 691 private void drawTexture(Texture tex, int imageMode, 692 float dx1, float dy1, float dx2, float dy2, 693 float sx1, float sy1, float sx2, float sy2, 694 int lEdge, int rEdge, int tEdge, int bEdge) { 695 if (PrismSettings.debug) { 696 System.out.println("+ drawTexture: " + tex + ", imageMode: " + imageMode + 697 ", tex.w: " + tex.getPhysicalWidth() + ", tex.h: " + tex.getPhysicalHeight() + 698 ", tex.cw: " + tex.getContentWidth() + ", tex.ch: " + tex.getContentHeight()); 699 System.out.println("target: " + target + " t.w: " + target.getPhysicalWidth() + ", t.h: " + target.getPhysicalHeight() + 700 ", t.dims: " + target.getDimensions()); 701 System.out.println("GR: " + this); 702 System.out.println("dx1:" + dx1 + " dy1:" + dy1 + " dx2:" + dx2 + " dy2:" + dy2); 703 System.out.println("sx1:" + sx1 + " sy1:" + sy1 + " sx2:" + sx2 + " sy2:" + sy2); 704 System.out.println("Clip: " + finalClip); 705 System.out.println("Composite rule: " + compositeMode); 706 } 707 708 final SWArgbPreTexture swTex = (SWArgbPreTexture) tex; 709 int data[] = swTex.getDataNoClone(); 710 711 final RectBounds srcBBox = new RectBounds(Math.min(dx1, dx2), Math.min(dy1, dy2), 712 Math.max(dx1, dx2), Math.max(dy1, dy2)); 713 final RectBounds dstBBox = new RectBounds(); 714 tx.transform(srcBBox, dstBBox); 715 716 final Transform6 piscesTx = swPaint.computeDrawTexturePaintTransform(this.tx, 717 dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2); 718 719 if (PrismSettings.debug) { 720 System.out.println("tx: " + tx); 721 System.out.println("piscesTx: " + piscesTx); 722 723 System.out.println("srcBBox: " + srcBBox); 724 System.out.println("dstBBox: " + dstBBox); 725 } 726 727 // texture coordinates range 728 final int txMin = Math.max(0, SWUtils.fastFloor(Math.min(sx1, sx2))); 729 final int tyMin = Math.max(0, SWUtils.fastFloor(Math.min(sy1, sy2))); 730 final int txMax = Math.min(tex.getContentWidth() - 1, SWUtils.fastCeil(Math.max(sx1, sx2)) - 1); 731 final int tyMax = Math.min(tex.getContentHeight() - 1, SWUtils.fastCeil(Math.max(sy1, sy2)) - 1); 732 733 this.pr.drawImage(RendererBase.TYPE_INT_ARGB_PRE, imageMode, 734 data, tex.getContentWidth(), tex.getContentHeight(), 735 swTex.getOffset(), tex.getPhysicalWidth(), 736 piscesTx, 737 tex.getWrapMode() == Texture.WrapMode.REPEAT, 738 (int)(SWUtils.TO_PISCES * dstBBox.getMinX()), (int)(SWUtils.TO_PISCES * dstBBox.getMinY()), 739 (int)(SWUtils.TO_PISCES * dstBBox.getWidth()), (int)(SWUtils.TO_PISCES * dstBBox.getHeight()), 740 lEdge, rEdge, tEdge, bEdge, 741 txMin, tyMin, txMax, tyMax, 742 swTex.hasAlpha()); 743 744 if (PrismSettings.debug) { 745 System.out.println("* drawTexture, DONE"); 746 } 747 } 748 749 @Override 750 public void drawTexture3SliceH(Texture tex, 751 float dx1, float dy1, float dx2, float dy2, 752 float sx1, float sy1, float sx2, float sy2, 753 float dh1, float dh2, float sh1, float sh2) 754 { 755 drawTexture(tex, dx1, dy1, dh1, dy2, sx1, sy1, sh1, sy2, 756 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 757 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 758 drawTexture(tex, dh1, dy1, dh2, dy2, sh1, sy1, sh2, sy2, 759 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 760 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 761 drawTexture(tex, dh2, dy1, dx2, dy2, sh2, sy1, sx2, sy2, 762 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 763 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 764 } 765 766 @Override 767 public void drawTexture3SliceV(Texture tex, 768 float dx1, float dy1, float dx2, float dy2, 769 float sx1, float sy1, float sx2, float sy2, 770 float dv1, float dv2, float sv1, float sv2) 771 { 772 drawTexture(tex, dx1, dy1, dx2, dv1, sx1, sy1, sx2, sv1, 773 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 774 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 775 drawTexture(tex, dx1, dv1, dx2, dv2, sx1, sv1, sx2, sv2, 776 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 777 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 778 drawTexture(tex, dx1, dv2, dx2, dy2, sx1, sv2, sx2, sy2, 779 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 780 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 781 } 782 783 @Override 784 public void drawTexture9Slice(Texture tex, 785 float dx1, float dy1, float dx2, float dy2, 786 float sx1, float sy1, float sx2, float sy2, 787 float dh1, float dv1, float dh2, float dv2, 788 float sh1, float sv1, float sh2, float sv2) 789 { 790 drawTexture(tex, dx1, dy1, dh1, dv1, sx1, sy1, sh1, sv1, 791 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 792 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 793 drawTexture(tex, dh1, dy1, dh2, dv1, sh1, sy1, sh2, sv1, 794 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 795 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 796 drawTexture(tex, dh2, dy1, dx2, dv1, sh2, sy1, sx2, sv1, 797 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 798 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD); 799 800 drawTexture(tex, dx1, dv1, dh1, dv2, sx1, sv1, sh1, sv2, 801 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 802 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 803 drawTexture(tex, dh1, dv1, dh2, dv2, sh1, sv1, sh2, sv2, 804 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 805 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 806 drawTexture(tex, dh2, dv1, dx2, dv2, sh2, sv1, sx2, sv2, 807 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 808 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD); 809 810 drawTexture(tex, dx1, dv2, dh1, dy2, sx1, sv2, sh1, sy2, 811 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD, 812 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 813 drawTexture(tex, dh1, dv2, dh2, dy2, sh1, sv2, sh2, sy2, 814 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD, 815 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 816 drawTexture(tex, dh2, dv2, dx2, dy2, sh2, sv2, sx2, sy2, 817 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP, 818 RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP); 819 } 820 821 public void drawTextureVO(Texture tex, 822 float topopacity, float botopacity, 823 float dx1, float dy1, float dx2, float dy2, 824 float sx1, float sy1, float sx2, float sy2) 825 { 826 if (PrismSettings.debug) { 827 System.out.println("* drawTextureVO"); 828 } 829 final int[] fractions = { 0x0000, 0x10000 }; 830 final int[] argb = { 0xffffff | (((int)(topopacity * 255)) << 24), 831 0xffffff | (((int)(botopacity * 255)) << 24) }; 832 final Transform6 t6 = new Transform6(); 833 SWUtils.convertToPiscesTransform(this.tx, t6); 834 this.pr.setLinearGradient(0, (int)(SWUtils.TO_PISCES * dy1), 0, (int)(SWUtils.TO_PISCES * dy2), fractions, argb, 835 GradientColorMap.CYCLE_NONE, t6); 836 this.drawTexture(tex, RendererBase.IMAGE_MODE_MULTIPLY, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, 837 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP, 838 RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP); 839 } 840 841 public void drawTextureRaw(Texture tex, 842 float dx1, float dy1, float dx2, float dy2, 843 float tx1, float ty1, float tx2, float ty2) 844 { 845 if (PrismSettings.debug) { 846 System.out.println("+ drawTextureRaw"); 847 } 848 849 int w = tex.getContentWidth(); 850 int h = tex.getContentHeight(); 851 tx1 *= w; 852 ty1 *= h; 853 tx2 *= w; 854 ty2 *= h; 855 drawTexture(tex, dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2); 856 } 857 858 public void drawMappedTextureRaw(Texture tex, 859 float dx1, float dy1, float dx2, float dy2, 860 float tx11, float ty11, float tx21, float ty21, 861 float tx12, float ty12, float tx22, float ty22) 862 { 863 if (PrismSettings.debug) { 864 System.out.println("+ drawMappedTextureRaw"); 865 } 866 867 final double _mxx, _myx, _mxy, _myy, _mxt, _myt; 868 _mxx = tx.getMxx(); 869 _myx = tx.getMyx(); 870 _mxy = tx.getMxy(); 871 _myy = tx.getMyy(); 872 _mxt = tx.getMxt(); 873 _myt = tx.getMyt(); 874 875 try { 876 final float mxx = tx21-tx11; 877 final float myx = ty21-ty11; 878 final float mxy = tx12-tx11; 879 final float myy = ty12-ty11; 880 881 final BaseTransform tmpTx = new Affine2D(mxx, myx, mxy, myy, tx11, ty11); 882 tmpTx.invert(); 883 884 tx.setToIdentity(); 885 tx.deriveWithTranslation(dx1, dy1); 886 tx.deriveWithConcatenation(dx2 - dx1, 0, 0, dy2 - dy2, 0, 0); 887 tx.deriveWithConcatenation(tmpTx); 888 this.drawTexture(tex, 0, 0, 1, 1, 0, 0, tex.getContentWidth(), tex.getContentHeight()); 889 } catch (NoninvertibleTransformException e) { } 890 891 tx.restoreTransform(_mxx, _myx, _mxy, _myy, _mxt, _myt); 892 } 893 894 public boolean canReadBack() { 895 return true; 896 } 897 898 public RTTexture readBack(Rectangle view) { 899 if (PrismSettings.debug) { 900 System.out.println("+ readBack, rect: " + view + ", target.dims: " + target.getDimensions()); 901 } 902 903 final int w = Math.max(1, view.width); 904 final int h = Math.max(1, view.height); 905 final SWRTTexture rbb = context.validateRBBuffer(w, h); 906 907 if (view.isEmpty()) { 908 return rbb; 909 } 910 911 final int pixels[] = rbb.getDataNoClone(); 912 this.target.getSurface().getRGB(pixels, 0, rbb.getPhysicalWidth(), view.x, view.y, w, h); 913 return rbb; 914 } 915 916 public void releaseReadBackBuffer(RTTexture view) { 917 } 918 919 public void setState3D(boolean flag) { 920 } 921 922 public boolean isState3D() { 923 return false; 924 } 925 926 public void setup3DRendering() { 927 } 928 929 @Override 930 public void setPixelScaleFactors(float pixelScaleX, float pixelScaleY) { 931 this.pixelScaleX = pixelScaleX; 932 } 933 934 @Override 935 public float getPixelScaleFactorX() { 936 return pixelScaleX; 937 } 938 939 @Override 940 public float getPixelScaleFactorY() { 941 return pixelScaleY; 942 } 943 944 @Override 945 public void setLights(NGLightBase[] lights) { 946 // Light are not supported by SW pipeline 947 } 948 949 @Override 950 public NGLightBase[] getLights() { 951 // Light are not supported by SW pipeline 952 return null; 953 } 954 955 @Override 956 public void blit(RTTexture srcTex, RTTexture dstTex, 957 int srcX0, int srcY0, int srcX1, int srcY1, 958 int dstX0, int dstY0, int dstX1, int dstY1) { 959 Graphics g = dstTex.createGraphics(); 960 g.drawTexture(srcTex, 961 dstX0, dstY0, dstX1, dstY1, 962 srcX0, srcY0, srcX1, srcY1); 963 } 964 }