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