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