AndroidGraphics2D.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright 2007, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.awt; 18 19import com.android.internal.awt.AndroidGraphicsConfiguration; 20import com.android.internal.graphics.NativeUtils; 21 22import java.awt.AlphaComposite; 23import java.awt.BasicStroke; 24import java.awt.Color; 25import java.awt.Composite; 26import java.awt.Font; 27import java.awt.FontMetrics; 28import java.awt.Graphics; 29import java.awt.Graphics2D; 30import java.awt.GraphicsConfiguration; 31import java.awt.Image; 32import java.awt.Polygon; 33import java.awt.Rectangle; 34import java.awt.RenderingHints; 35import java.awt.Shape; 36import java.awt.Stroke; 37import java.awt.font.FontRenderContext; 38import java.awt.font.GlyphVector; 39import java.awt.geom.AffineTransform; 40import java.awt.geom.Area; 41import java.awt.geom.GeneralPath; 42import java.awt.geom.NoninvertibleTransformException; 43import java.awt.geom.PathIterator; 44import java.awt.image.AffineTransformOp; 45import java.awt.image.BufferedImage; 46import java.awt.image.BufferedImageOp; 47import java.awt.image.DataBuffer; 48import java.awt.image.DirectColorModel; 49import java.awt.image.ImageObserver; 50import java.awt.image.Raster; 51import java.awt.image.RenderedImage; 52import java.awt.image.SinglePixelPackedSampleModel; 53import java.awt.image.WritableRaster; 54import java.awt.image.renderable.RenderableImage; 55import java.text.AttributedCharacterIterator; 56import java.util.Map; 57 58import org.apache.harmony.awt.gl.ImageSurface; 59import org.apache.harmony.awt.gl.MultiRectArea; 60import org.apache.harmony.awt.gl.Surface; 61import org.apache.harmony.awt.gl.font.AndroidGlyphVector; 62import org.apache.harmony.awt.gl.font.FontMetricsImpl; 63import org.apache.harmony.awt.gl.image.OffscreenImage; 64 65import android.graphics.Bitmap; 66import android.graphics.Canvas; 67import android.graphics.Matrix; 68import android.graphics.Paint; 69import android.graphics.Path; 70 71import android.graphics.Rect; 72import android.graphics.RectF; 73import android.graphics.Region; 74import android.graphics.Typeface; 75import android.graphics.PixelXorXfermode; 76import android.view.Display; 77import android.view.WindowManager; 78import android.content.Context; 79 80public class AndroidGraphics2D extends Graphics2D { 81 82 private int displayWidth, displayHeight; 83 84 protected Surface dstSurf = null; 85 protected MultiRectArea clip = null; 86 87 protected Composite composite = AlphaComposite.SrcOver; 88 protected AffineTransform transform = new AffineTransform(); 89 90 private static AndroidGraphics2D mAg; 91 private static Canvas mC; 92 93 // Android Paint 94 public static Paint mP; 95 96 private static java.awt.Font mFnt; 97 98 // Cached Matrix 99 public static Matrix mM; 100 private static FontMetrics mFm; 101 private static RenderingHints mRh; 102 private static Color mBc; 103 104 private Area mCurrClip; 105 106 public final static double RAD_360 = Math.PI / 180 * 360; 107 108 // Image drawing 109 private AndroidJavaBlitter blitter; 110 private DirectColorModel cm; 111 private SinglePixelPackedSampleModel sm; 112 private WritableRaster wr; 113 114 115 public static AndroidGraphics2D getInstance() { 116 if (mAg == null) { 117 throw new RuntimeException("AndroidGraphics2D not instantiated!"); 118 } 119 return mAg; 120 } 121 122 public static AndroidGraphics2D getInstance(Context ctx, Canvas c, Paint p) { 123 if (c == null || ctx == null) { 124 throw new RuntimeException( 125 "Illegal argument, Canvas cannot be null!"); 126 } 127 mAg = new AndroidGraphics2D(ctx, c, p); 128 return mAg; 129 } 130 131 private AndroidGraphics2D(Context ctx, Canvas c, Paint p) { 132 super(); 133 mC = c; 134 mP = p; 135 mM = new Matrix(); 136 mM.reset(); 137 mM = mC.getMatrix(); 138 Rect r = mC.getClipBounds(); 139 int cl[] = {-1, r.top, r.left, -2, r.top, r.right, -2, r.bottom, r.right, -2, r.bottom, r.left}; 140 mCurrClip = new Area(createShape(cl)); 141 if(ctx != null) { 142 WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE); 143 Display d = wm.getDefaultDisplay(); 144 displayWidth = d.getWidth(); 145 displayHeight = d.getHeight(); 146 } 147 blitter = new AndroidJavaBlitter(c); 148 cm = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000); 149 sm = new SinglePixelPackedSampleModel( 150 DataBuffer.TYPE_INT, displayWidth, displayHeight, cm.getMasks()); 151 wr = Raster.createWritableRaster(sm, null); 152 dstSurf = new ImageSurface(cm, wr); 153 } 154 155 @Override 156 public void addRenderingHints(Map<?, ?> hints) { 157 if (mRh == null) { 158 mRh = (RenderingHints) hints; 159 } 160 mRh.add((RenderingHints) hints); 161 } 162 163 public float[] getMatrix() { 164 float[] f = new float[9]; 165 mC.getMatrix().getValues(f); 166 return f; 167 } 168 169 /** 170 * 171 * @return a Matrix in Android format 172 */ 173 public float[] getInverseMatrix() { 174 AffineTransform af = new AffineTransform(createAWTMatrix(getMatrix())); 175 try { 176 af = af.createInverse(); 177 } catch (NoninvertibleTransformException e) { 178 } 179 return createMatrix(af); 180 } 181 182 private Path getPath(Shape s) { 183 Path path = new Path(); 184 PathIterator pi = s.getPathIterator(null); 185 while (pi.isDone() == false) { 186 getCurrentSegment(pi, path); 187 pi.next(); 188 } 189 return path; 190 } 191 192 private void getCurrentSegment(PathIterator pi, Path path) { 193 float[] coordinates = new float[6]; 194 int type = pi.currentSegment(coordinates); 195 switch (type) { 196 case PathIterator.SEG_MOVETO: 197 path.moveTo(coordinates[0], coordinates[1]); 198 break; 199 case PathIterator.SEG_LINETO: 200 path.lineTo(coordinates[0], coordinates[1]); 201 break; 202 case PathIterator.SEG_QUADTO: 203 path.quadTo(coordinates[0], coordinates[1], coordinates[2], 204 coordinates[3]); 205 break; 206 case PathIterator.SEG_CUBICTO: 207 path.cubicTo(coordinates[0], coordinates[1], coordinates[2], 208 coordinates[3], coordinates[4], coordinates[5]); 209 break; 210 case PathIterator.SEG_CLOSE: 211 path.close(); 212 break; 213 default: 214 break; 215 } 216 } 217 218 private Shape createShape(int[] arr) { 219 Shape s = new GeneralPath(); 220 for(int i = 0; i < arr.length; i++) { 221 int type = arr[i]; 222 switch (type) { 223 case -1: 224 //MOVETO 225 ((GeneralPath)s).moveTo(arr[++i], arr[++i]); 226 break; 227 case -2: 228 //LINETO 229 ((GeneralPath)s).lineTo(arr[++i], arr[++i]); 230 break; 231 case -3: 232 //QUADTO 233 ((GeneralPath)s).quadTo(arr[++i], arr[++i], arr[++i], 234 arr[++i]); 235 break; 236 case -4: 237 //CUBICTO 238 ((GeneralPath)s).curveTo(arr[++i], arr[++i], arr[++i], 239 arr[++i], arr[++i], arr[++i]); 240 break; 241 case -5: 242 //CLOSE 243 return s; 244 default: 245 break; 246 } 247 } 248 return s; 249 } 250 /* 251 public int[] getPixels() { 252 return mC.getPixels(); 253 }*/ 254 255 public static float getRadian(float degree) { 256 return (float) ((Math.PI / 180) * degree); 257 } 258 259 private Shape getShape() { 260 return null; 261 } 262 263 public static float getDegree(float radian) { 264 return (float) ((180 / Math.PI) * radian); 265 } 266 267 /* 268 * Degree in radian 269 */ 270 public static float getEllipsisX(float degree, float princAxis) { 271 return (float) Math.cos(degree) * princAxis; 272 } 273 274 public static float getEllipsisY(float degree, float conAxis) { 275 return (float) Math.sin(degree) * conAxis; 276 } 277 278 @Override 279 public void clip(Shape s) { 280 mC.clipPath(getPath(s)); 281 } 282 283 public void setCanvas(Canvas c) { 284 mC = c; 285 } 286 287 @Override 288 public void draw(Shape s) { 289 if (mP == null) { 290 mP = new Paint(); 291 } 292 Paint.Style tmp = mP.getStyle(); 293 mP.setStyle(Paint.Style.STROKE); 294 mC.drawPath(getPath(s), mP); 295 mP.setStyle(tmp); 296 } 297/* 298 private ArrayList getSegments(Shape s) { 299 ArrayList arr = new ArrayList(); 300 PathIterator pi = s.getPathIterator(null); 301 while (pi.isDone() == false) { 302 getCurrentSegment(pi, arr); 303 pi.next(); 304 } 305 return arr; 306 } 307 308 private void getCurrentSegment(PathIterator pi, ArrayList arr) { 309 float[] coordinates = new float[6]; 310 int type = pi.currentSegment(coordinates); 311 switch (type) { 312 case PathIterator.SEG_MOVETO: 313 arr.add(new Integer(-1)); 314 break; 315 case PathIterator.SEG_LINETO: 316 arr.add(new Integer(-2)); 317 break; 318 case PathIterator.SEG_QUADTO: 319 arr.add(new Integer(-3)); 320 break; 321 case PathIterator.SEG_CUBICTO: 322 arr.add(new Integer(-4)); 323 break; 324 case PathIterator.SEG_CLOSE: 325 arr.add(new Integer(-5)); 326 break; 327 default: 328 break; 329 } 330 } 331*/ 332 /* 333 * Convenience method, not standard AWT 334 */ 335 public void draw(Path s) { 336 if (mP == null) { 337 mP = new Paint(); 338 } 339 Paint.Style tmp = mP.getStyle(); 340 mP.setStyle(Paint.Style.STROKE); 341 s.transform(mM); 342 mC.drawPath(s, mP); 343 mP.setStyle(tmp); 344 } 345 346 @Override 347 public void drawGlyphVector(GlyphVector g, float x, float y) { 348 // TODO draw at x, y 349 // draw(g.getOutline()); 350 /* 351 Matrix matrix = new Matrix(); 352 matrix.setTranslate(x, y); 353 Path pth = getPath(g.getOutline()); 354 pth.transform(matrix); 355 draw(pth); 356 */ 357 Path path = new Path(); 358 char[] c = ((AndroidGlyphVector)g).getGlyphs(); 359 mP.getTextPath(c, 0, c.length, x, y, path); 360 mC.drawPath(path, mP); 361 } 362 363 @Override 364 public void drawRenderableImage(RenderableImage img, AffineTransform xform) { 365 throw new RuntimeException("Not implemented!"); 366 } 367 368 @Override 369 public void drawRenderedImage(RenderedImage img, AffineTransform xform) { 370 throw new RuntimeException("Not implemented!"); 371 } 372 373 @Override 374 public void drawString(AttributedCharacterIterator iterator, float x, 375 float y) { 376 throw new RuntimeException("AttributedCharacterIterator not supported!"); 377 378 } 379 380 @Override 381 public void drawString(AttributedCharacterIterator iterator, int x, int y) { 382 throw new RuntimeException("AttributedCharacterIterator not supported!"); 383 384 } 385 386 @Override 387 public void drawString(String s, float x, float y) { 388 if (mP == null) { 389 mP = new Paint(); 390 } 391 Paint.Style tmp = mP.getStyle(); 392 393 mP.setStyle(Paint.Style.FILL); 394 Path pth = new Path(); 395 mP.getTextPath(s, 0, s.length(), x, y, pth); 396 mC.drawPath(pth, mP); 397 mP.setStyle(tmp); 398 } 399 400 @Override 401 public void drawString(String str, int x, int y) { 402 if (mP == null) { 403 mP = new Paint(); 404 } 405 Paint.Style tmp = mP.getStyle(); 406 mP.setStrokeWidth(0); 407 408 mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y, 409 mP); 410 mP.setStyle(tmp); 411 } 412 413 @Override 414 public void fill(Shape s) { 415 if (mP == null) { 416 mP = new Paint(); 417 } 418 Paint.Style tmp = mP.getStyle(); 419 mP.setStyle(Paint.Style.FILL); 420 mC.drawPath(getPath(s), mP); 421 mP.setStyle(tmp); 422 } 423 424 @Override 425 public Color getBackground() { 426 return mBc; 427 } 428 429 @Override 430 public Composite getComposite() { 431 throw new RuntimeException("Composite not implemented!"); 432 } 433 434 @Override 435 public GraphicsConfiguration getDeviceConfiguration() { 436 return new AndroidGraphicsConfiguration(); 437 } 438 439 @Override 440 public FontRenderContext getFontRenderContext() { 441 return new FontRenderContext(getTransform(), mP.isAntiAlias(), true); 442 } 443 444 @Override 445 public java.awt.Paint getPaint() { 446 throw new RuntimeException("AWT Paint not implemented in Android!"); 447 } 448 449 public static Canvas getAndroidCanvas() { 450 return mC; 451 } 452 453 public static Paint getAndroidPaint() { 454 return mP; 455 } 456 457 @Override 458 public RenderingHints getRenderingHints() { 459 return mRh; 460 } 461 462 @Override 463 public Stroke getStroke() { 464 if (mP != null) { 465 return new BasicStroke(mP.getStrokeWidth(), mP.getStrokeCap() 466 .ordinal(), mP.getStrokeJoin().ordinal()); 467 } 468 return null; 469 } 470 471 @Override 472 public AffineTransform getTransform() { 473 return new AffineTransform(createAWTMatrix(getMatrix())); 474 } 475 476 @Override 477 public boolean hit(Rectangle rect, Shape s, boolean onStroke) { 478 // ???AWT TODO check if on stroke 479 return s.intersects(rect.getX(), rect.getY(), rect.getWidth(), rect 480 .getHeight()); 481 } 482 483 @Override 484 public void rotate(double theta) { 485 mM.preRotate((float) AndroidGraphics2D 486 .getDegree((float) (RAD_360 - theta))); 487 mC.concat(mM); 488 } 489 490 @Override 491 public void rotate(double theta, double x, double y) { 492 mM.preRotate((float) AndroidGraphics2D.getDegree((float) theta), 493 (float) x, (float) y); 494 mC.concat(mM); 495 } 496 497 @Override 498 public void scale(double sx, double sy) { 499 mM.setScale((float) sx, (float) sy); 500 mC.concat(mM); 501 } 502 503 @Override 504 public void setBackground(Color color) { 505 mBc = color; 506 mC.clipRect(new Rect(0, 0, mC.getWidth(), mC.getHeight())); 507 // TODO don't limit to current clip 508 mC.drawARGB(color.getAlpha(), color.getRed(), color.getGreen(), color 509 .getBlue()); 510 } 511 512 @Override 513 public void setComposite(Composite comp) { 514 throw new RuntimeException("Composite not implemented!"); 515 } 516 517 public void setSpaint(Paint paint) { 518 mP = paint; 519 } 520 521 @Override 522 public void setPaint(java.awt.Paint paint) { 523 setColor((Color)paint); 524 } 525 526 @Override 527 public Object getRenderingHint(RenderingHints.Key key) { 528 if (mRh == null) { 529 return null; 530 } 531 return mRh.get(key); 532 } 533 534 @Override 535 public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { 536 if (mRh == null) { 537 mRh = new RenderingHints(hintKey, hintValue); 538 } else { 539 mRh.put(hintKey, hintValue); 540 } 541 applyHints(); 542 } 543 544 @Override 545 public void setRenderingHints(Map<?, ?> hints) { 546 mRh = (RenderingHints) hints; 547 applyHints(); 548 } 549 550 private void applyHints() { 551 Object o; 552 553 // TODO do something like this: 554 /* 555 * Set s = mRh.keySet(); Iterator it = s.iterator(); while(it.hasNext()) { 556 * o = it.next(); } 557 */ 558 559 // ///////////////////////////////////////////////////////////////////// 560 // not supported in skia 561 /* 562 * o = mRh.get(RenderingHints.KEY_ALPHA_INTERPOLATION); if 563 * (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) { } else 564 * if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) { } 565 * else if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) { } 566 * 567 * o = mRh.get(RenderingHints.KEY_COLOR_RENDERING); if 568 * (o.equals(RenderingHints.VALUE_COLOR_RENDER_DEFAULT)) { } else if 569 * (o.equals(RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { } else if 570 * (o.equals(RenderingHints.VALUE_COLOR_RENDER_SPEED)) { } 571 * 572 * o = mRh.get(RenderingHints.KEY_DITHERING); if 573 * (o.equals(RenderingHints.VALUE_DITHER_DEFAULT)) { } else if 574 * (o.equals(RenderingHints.VALUE_DITHER_DISABLE)) { } else if 575 * (o.equals(RenderingHints.VALUE_DITHER_ENABLE)) { } 576 * 577 * o = mRh.get(RenderingHints.KEY_FRACTIONALMETRICS); if 578 * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT)) { } else 579 * if (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_OFF)) { } else if 580 * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_ON)) { } 581 * 582 * o = mRh.get(RenderingHints.KEY_INTERPOLATION); if 583 * (o.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) { } else if 584 * (o.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) { } else if 585 * (o .equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) { } 586 * 587 * o = mRh.get(RenderingHints.KEY_RENDERING); if 588 * (o.equals(RenderingHints.VALUE_RENDER_DEFAULT)) { } else if 589 * (o.equals(RenderingHints.VALUE_RENDER_QUALITY)) { } else if 590 * (o.equals(RenderingHints.VALUE_RENDER_SPEED)) { } 591 * 592 * o = mRh.get(RenderingHints.KEY_STROKE_CONTROL); if 593 * (o.equals(RenderingHints.VALUE_STROKE_DEFAULT)) { } else if 594 * (o.equals(RenderingHints.VALUE_STROKE_NORMALIZE)) { } else if 595 * (o.equals(RenderingHints.VALUE_STROKE_PURE)) { } 596 */ 597 598 o = mRh.get(RenderingHints.KEY_ANTIALIASING); 599 if (o != null) { 600 if (o.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) { 601 mP.setAntiAlias(false); 602 } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) { 603 mP.setAntiAlias(false); 604 } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_ON)) { 605 mP.setAntiAlias(true); 606 } 607 } 608 609 o = mRh.get(RenderingHints.KEY_TEXT_ANTIALIASING); 610 if (o != null) { 611 if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) { 612 mP.setAntiAlias(false); 613 } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) { 614 mP.setAntiAlias(false); 615 } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) { 616 mP.setAntiAlias(true); 617 } 618 } 619 } 620 621 @Override 622 public void setStroke(Stroke s) { 623 if (mP == null) { 624 mP = new Paint(); 625 } 626 BasicStroke bs = (BasicStroke) s; 627 mP.setStyle(Paint.Style.STROKE); 628 mP.setStrokeWidth(bs.getLineWidth()); 629 630 int cap = bs.getEndCap(); 631 if (cap == 0) { 632 mP.setStrokeCap(Paint.Cap.BUTT); 633 } else if (cap == 1) { 634 mP.setStrokeCap(Paint.Cap.ROUND); 635 } else if (cap == 2) { 636 mP.setStrokeCap(Paint.Cap.SQUARE); 637 } 638 639 int join = bs.getLineJoin(); 640 if (join == 0) { 641 mP.setStrokeJoin(Paint.Join.MITER); 642 } else if (join == 1) { 643 mP.setStrokeJoin(Paint.Join.ROUND); 644 } else if (join == 2) { 645 mP.setStrokeJoin(Paint.Join.BEVEL); 646 } 647 } 648 649 public static float[] createMatrix(AffineTransform Tx) { 650 double[] at = new double[9]; 651 Tx.getMatrix(at); 652 float[] f = new float[at.length]; 653 f[0] = (float) at[0]; 654 f[1] = (float) at[2]; 655 f[2] = (float) at[4]; 656 f[3] = (float) at[1]; 657 f[4] = (float) at[3]; 658 f[5] = (float) at[5]; 659 f[6] = 0; 660 f[7] = 0; 661 f[8] = 1; 662 return f; 663 } 664 665 private float[] createAWTMatrix(float[] matrix) { 666 float[] at = new float[9]; 667 at[0] = matrix[0]; 668 at[1] = matrix[3]; 669 at[2] = matrix[1]; 670 at[3] = matrix[4]; 671 at[4] = matrix[2]; 672 at[5] = matrix[5]; 673 at[6] = 0; 674 at[7] = 0; 675 at[8] = 1; 676 return at; 677 } 678 679 public static Matrix createMatrixObj(AffineTransform Tx) { 680 Matrix m = new Matrix(); 681 m.reset(); 682 m.setValues(createMatrix(Tx)); 683 return m; 684 } 685 686 @Override 687 public void setTransform(AffineTransform Tx) { 688 mM.reset(); 689 /* 690 * if(Tx.isIdentity()) { mM = new Matrix(); } 691 */ 692 mM.setValues(createMatrix(Tx)); 693 Matrix m = new Matrix(); 694 m.setValues(getInverseMatrix()); 695 mC.concat(m); 696 mC.concat(mM); 697 } 698 699 @Override 700 public void shear(double shx, double shy) { 701 mM.setSkew((float) shx, (float) shy); 702 mC.concat(mM); 703 } 704 705 @Override 706 public void transform(AffineTransform Tx) { 707 Matrix m = new Matrix(); 708 m.setValues(createMatrix(Tx)); 709 mC.concat(m); 710 } 711 712 @Override 713 public void translate(double tx, double ty) { 714 mM.setTranslate((float) tx, (float) ty); 715 mC.concat(mM); 716 } 717 718 @Override 719 public void translate(int x, int y) { 720 mM.setTranslate((float) x, (float) y); 721 mC.concat(mM); 722 } 723 724 @Override 725 public void clearRect(int x, int y, int width, int height) { 726 mC.clipRect(x, y, x + width, y + height); 727 if (mBc != null) { 728 mC.drawARGB(mBc.getAlpha(), mBc.getBlue(), mBc.getGreen(), mBc 729 .getRed()); 730 } else { 731 mC.drawARGB(0xff, 0xff, 0xff, 0xff); 732 } 733 } 734 735 @Override 736 public void clipRect(int x, int y, int width, int height) { 737 int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y}; 738 Shape shp = createShape(cl); 739 mCurrClip.intersect(new Area(shp)); 740 mC.clipRect(new Rect(x, y, x + width, y + height), Region.Op.INTERSECT); 741 } 742 743 @Override 744 public void copyArea(int sx, int sy, int width, int height, int dx, int dy) { 745 copyArea(mC, sx, sy, width + dx, height + dy, dx, dy); 746 } 747 748 @Override 749 public Graphics create() { 750 return this; 751 } 752 753 @Override 754 public void dispose() { 755 mC = null; 756 mP = null; 757 } 758 759 @Override 760 public void drawArc(int x, int y, int width, int height, int sa, int ea) { 761 if (mP == null) { 762 mP = new Paint(); 763 } 764 mP.setStrokeWidth(0); 765 mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (ea + sa), 766 ea, true, mP); 767 } 768 769 770 // ???AWT: only used for debuging, delete in final version 771 public void drawBitmap(Bitmap bm, float x, float y, Paint p) { 772 mC.drawBitmap(bm, x, y, null); 773 } 774 775 @Override 776 public boolean drawImage(Image image, int x, int y, Color bgcolor, 777 ImageObserver imageObserver) { 778 779 if(image == null) { 780 return true; 781 } 782 783 boolean done = false; 784 boolean somebits = false; 785 Surface srcSurf = null; 786 if(image instanceof OffscreenImage){ 787 OffscreenImage oi = (OffscreenImage) image; 788 if((oi.getState() & ImageObserver.ERROR) != 0) { 789 return false; 790 } 791 done = oi.prepareImage(imageObserver); 792 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 793 srcSurf = oi.getImageSurface(); 794 }else{ 795 done = true; 796 srcSurf = Surface.getImageSurface(image); 797 } 798 799 if(done || somebits) { 800 int w = srcSurf.getWidth(); 801 int h = srcSurf.getHeight(); 802 803 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(), 804 composite, bgcolor, clip); 805 } 806 return done; 807 } 808 809 @Override 810 public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) { 811 return drawImage(image, x, y, null, imageObserver); 812 } 813 814 @Override 815 public boolean drawImage(Image image, int x, int y, int width, int height, 816 Color bgcolor, ImageObserver imageObserver) { 817 818 if(image == null) { 819 return true; 820 } 821 if(width == 0 || height == 0) { 822 return true; 823 } 824 825 boolean done = false; 826 boolean somebits = false; 827 Surface srcSurf = null; 828 829 if(image instanceof OffscreenImage){ 830 OffscreenImage oi = (OffscreenImage) image; 831 if((oi.getState() & ImageObserver.ERROR) != 0) { 832 return false; 833 } 834 done = oi.prepareImage(imageObserver); 835 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 836 srcSurf = oi.getImageSurface(); 837 }else{ 838 done = true; 839 srcSurf = Surface.getImageSurface(image); 840 } 841 842 if(done || somebits) { 843 int w = srcSurf.getWidth(); 844 int h = srcSurf.getHeight(); 845 if(w == width && h == height){ 846 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 847 (AffineTransform) transform.clone(), 848 composite, bgcolor, clip); 849 }else{ 850 AffineTransform xform = new AffineTransform(); 851 xform.setToScale((float)width / w, (float)height / h); 852 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 853 (AffineTransform) transform.clone(), 854 xform, composite, bgcolor, clip); 855 } 856 } 857 return done; 858 } 859 860 @Override 861 public boolean drawImage(Image image, int x, int y, int width, int height, 862 ImageObserver imageObserver) { 863 return drawImage(image, x, y, width, height, null, imageObserver); 864 } 865 866 @Override 867 public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, 868 int sx1, int sy1, int sx2, int sy2, Color bgcolor, 869 ImageObserver imageObserver) { 870 871 if(image == null) { 872 return true; 873 } 874 if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) { 875 return true; 876 } 877 878 boolean done = false; 879 boolean somebits = false; 880 Surface srcSurf = null; 881 if(image instanceof OffscreenImage){ 882 OffscreenImage oi = (OffscreenImage) image; 883 if((oi.getState() & ImageObserver.ERROR) != 0) { 884 return false; 885 } 886 done = oi.prepareImage(imageObserver); 887 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 888 srcSurf = oi.getImageSurface(); 889 }else{ 890 done = true; 891 srcSurf = Surface.getImageSurface(image); 892 } 893 894 if(done || somebits) { 895 896 int dstX = dx1; 897 int dstY = dy1; 898 int srcX = sx1; 899 int srcY = sy1; 900 901 int dstW = dx2 - dx1; 902 int dstH = dy2 - dy1; 903 int srcW = sx2 - sx1; 904 int srcH = sy2 - sy1; 905 906 if(srcW == dstW && srcH == dstH){ 907 blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, 908 (AffineTransform) transform.clone(), 909 composite, bgcolor, clip); 910 }else{ 911 AffineTransform xform = new AffineTransform(); 912 xform.setToScale((float)dstW / srcW, (float)dstH / srcH); 913 blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, 914 (AffineTransform) transform.clone(), 915 xform, composite, bgcolor, clip); 916 } 917 } 918 return done; 919 } 920 921 @Override 922 public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, 923 int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) { 924 925 return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, 926 imageObserver); 927 } 928 929 @Override 930 public void drawImage(BufferedImage bufImage, BufferedImageOp op, 931 int x, int y) { 932 933 if(bufImage == null) { 934 return; 935 } 936 937 if(op == null) { 938 drawImage(bufImage, x, y, null); 939 } else if(op instanceof AffineTransformOp){ 940 AffineTransformOp atop = (AffineTransformOp) op; 941 AffineTransform xform = atop.getTransform(); 942 Surface srcSurf = Surface.getImageSurface(bufImage); 943 int w = srcSurf.getWidth(); 944 int h = srcSurf.getHeight(); 945 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 946 (AffineTransform) transform.clone(), xform, 947 composite, null, clip); 948 } else { 949 bufImage = op.filter(bufImage, null); 950 Surface srcSurf = Surface.getImageSurface(bufImage); 951 int w = srcSurf.getWidth(); 952 int h = srcSurf.getHeight(); 953 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 954 (AffineTransform) transform.clone(), 955 composite, null, clip); 956 } 957 } 958 959 @Override 960 public boolean drawImage(Image image, AffineTransform trans, 961 ImageObserver imageObserver) { 962 963 if(image == null) { 964 return true; 965 } 966 if(trans == null || trans.isIdentity()) { 967 return drawImage(image, 0, 0, imageObserver); 968 } 969 970 boolean done = false; 971 boolean somebits = false; 972 Surface srcSurf = null; 973 if(image instanceof OffscreenImage){ 974 OffscreenImage oi = (OffscreenImage) image; 975 if((oi.getState() & ImageObserver.ERROR) != 0) { 976 return false; 977 } 978 done = oi.prepareImage(imageObserver); 979 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 980 srcSurf = oi.getImageSurface(); 981 }else{ 982 done = true; 983 srcSurf = Surface.getImageSurface(image); 984 } 985 986 if(done || somebits) { 987 int w = srcSurf.getWidth(); 988 int h = srcSurf.getHeight(); 989 AffineTransform xform = (AffineTransform) transform.clone(); 990 xform.concatenate(trans); 991 blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite, 992 null, clip); 993 } 994 return done; 995 } 996 997 @Override 998 public void drawLine(int x1, int y1, int x2, int y2) { 999 if (mP == null) { 1000 mP = new Paint(); 1001 } 1002 mC.drawLine(x1, y1, x2, y2, mP); 1003 } 1004 1005 @Override 1006 public void drawOval(int x, int y, int width, int height) { 1007 if (mP == null) { 1008 mP = new Paint(); 1009 } 1010 mP.setStyle(Paint.Style.STROKE); 1011 mC.drawOval(new RectF(x, y, x + width, y + height), mP); 1012 } 1013 1014 @Override 1015 public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) { 1016 if (mP == null) { 1017 mP = new Paint(); 1018 } 1019 mC.drawLine(xpoints[npoints - 1], ypoints[npoints - 1], xpoints[0], 1020 ypoints[0], mP); 1021 for (int i = 0; i < npoints - 1; i++) { 1022 mC.drawLine(xpoints[i], ypoints[i], xpoints[i + 1], 1023 ypoints[i + 1], mP); 1024 } 1025 } 1026 1027 @Override 1028 public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) { 1029 for (int i = 0; i < npoints - 1; i++) { 1030 drawLine(xpoints[i], ypoints[i], xpoints[i + 1], ypoints[i + 1]); 1031 } 1032 1033 } 1034 1035 @Override 1036 public void drawRoundRect(int x, int y, int width, int height, 1037 int arcWidth, int arcHeight) { 1038 if (mP == null) { 1039 mP = new Paint(); 1040 } 1041 mC.drawRoundRect(new RectF(x, y, width, height), arcWidth, 1042 arcHeight, mP); 1043 } 1044 1045 @Override 1046 public void fillArc(int x, int y, int width, int height, int sa, int ea) { 1047 if (mP == null) { 1048 mP = new Paint(); 1049 } 1050 1051 Paint.Style tmp = mP.getStyle(); 1052 mP.setStyle(Paint.Style.FILL_AND_STROKE); 1053 mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (sa + ea), 1054 ea, true, mP); 1055 1056 mP.setStyle(tmp); 1057 } 1058 1059 @Override 1060 public void fillOval(int x, int y, int width, int height) { 1061 if (mP == null) { 1062 mP = new Paint(); 1063 } 1064 Paint.Style tmp = mP.getStyle(); 1065 mP.setStyle(Paint.Style.FILL); 1066 mC.drawOval(new RectF(x, y, x + width, y + height), mP); 1067 mP.setStyle(tmp); 1068 } 1069 1070 @Override 1071 public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) { 1072 if (mP == null) { 1073 mP = new Paint(); 1074 } 1075 Paint.Style tmp = mP.getStyle(); 1076 mC.save(Canvas.CLIP_SAVE_FLAG); 1077 1078 mP.setStyle(Paint.Style.FILL); 1079 1080 GeneralPath filledPolygon = new GeneralPath( 1081 GeneralPath.WIND_EVEN_ODD, npoints); 1082 filledPolygon.moveTo(xpoints[0], ypoints[0]); 1083 for (int index = 1; index < xpoints.length; index++) { 1084 filledPolygon.lineTo(xpoints[index], ypoints[index]); 1085 } 1086 filledPolygon.closePath(); 1087 Path path = getPath(filledPolygon); 1088 mC.clipPath(path); 1089 mC.drawPath(path, mP); 1090 1091 mP.setStyle(tmp); 1092 mC.restore(); 1093 } 1094 1095 @Override 1096 public void fillRect(int x, int y, int width, int height) { 1097 if (mP == null) { 1098 mP = new Paint(); 1099 } 1100 Paint.Style tmp = mP.getStyle(); 1101 mP.setStyle(Paint.Style.FILL); 1102 mC.drawRect(new Rect(x, y, x + width, y + height), mP); 1103 mP.setStyle(tmp); 1104 } 1105 1106 @Override 1107 public void drawRect(int x, int y, int width, int height) { 1108 int[] xpoints = { x, x, x + width, x + width }; 1109 int[] ypoints = { y, y + height, y + height, y }; 1110 drawPolygon(xpoints, ypoints, 4); 1111 } 1112 1113 @Override 1114 public void fillRoundRect(int x, int y, int width, int height, 1115 int arcWidth, int arcHeight) { 1116 if (mP == null) { 1117 mP = new Paint(); 1118 } 1119 mP.setStyle(Paint.Style.FILL); 1120 mC.drawRoundRect(new RectF(x, y, x + width, y + height), arcWidth, 1121 arcHeight, mP); 1122 } 1123 1124 @Override 1125 public Shape getClip() { 1126 return mCurrClip; 1127 } 1128 1129 @Override 1130 public Rectangle getClipBounds() { 1131 Rect r = mC.getClipBounds(); 1132 return new Rectangle(r.left, r.top, r.width(), r.height()); 1133 } 1134 1135 @Override 1136 public Color getColor() { 1137 if (mP != null) { 1138 return new Color(mP.getColor()); 1139 } 1140 return null; 1141 } 1142 1143 @Override 1144 public Font getFont() { 1145 return mFnt; 1146 } 1147 1148 @Override 1149 public FontMetrics getFontMetrics(Font font) { 1150 mFm = new FontMetricsImpl(font); 1151 return mFm; 1152 } 1153 1154 @Override 1155 public void setClip(int x, int y, int width, int height) { 1156 int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y}; 1157 mCurrClip = new Area(createShape(cl)); 1158 mC.clipRect(x, y, x + width, y + height, Region.Op.REPLACE); 1159 1160 } 1161 1162 @Override 1163 public void setClip(Shape clip) { 1164 mCurrClip = new Area(clip); 1165 mC.clipPath(getPath(clip), Region.Op.REPLACE); 1166 } 1167 1168 @Override 1169 public void setColor(Color c) { 1170 if (mP == null) { 1171 mP = new Paint(); 1172 } 1173 mP.setColor(c.getRGB()); 1174 } 1175 1176 /** 1177 * Font mapping: 1178 * 1179 * Family: 1180 * 1181 * Android AWT 1182 * ------------------------------------- 1183 * serif Serif / TimesRoman 1184 * sans-serif SansSerif / Helvetica 1185 * monospace Monospaced / Courier 1186 * 1187 * Style: 1188 * 1189 * Android AWT 1190 * ------------------------------------- 1191 * normal Plain 1192 * bold bold 1193 * italic italic 1194 * 1195 */ 1196 @Override 1197 public void setFont(Font font) { 1198 if (font == null) { 1199 return; 1200 } 1201 if (mP == null) { 1202 mP = new Paint(); 1203 } 1204 1205 mFnt = font; 1206 Typeface tf = null; 1207 int sty = font.getStyle(); 1208 String nam = font.getName(); 1209 String aF = ""; 1210 if (nam != null) { 1211 if (nam.equalsIgnoreCase("Serif") 1212 || nam.equalsIgnoreCase("TimesRoman")) { 1213 aF = "serif"; 1214 } else if (nam.equalsIgnoreCase("SansSerif") 1215 || nam.equalsIgnoreCase("Helvetica")) { 1216 aF = "sans-serif"; 1217 } else if (nam.equalsIgnoreCase("Monospaced") 1218 || nam.equalsIgnoreCase("Courier")) { 1219 aF = "monospace"; 1220 } 1221 } 1222 1223 switch (sty) { 1224 case Font.PLAIN: 1225 tf = Typeface.create(aF, Typeface.NORMAL); 1226 break; 1227 case Font.BOLD: 1228 tf = Typeface.create(aF, Typeface.BOLD); 1229 break; 1230 case Font.ITALIC: 1231 tf = Typeface.create(aF, Typeface.ITALIC); 1232 break; 1233 case Font.BOLD | Font.ITALIC: 1234 tf = Typeface.create(aF, Typeface.BOLD_ITALIC); 1235 break; 1236 default: 1237 tf = Typeface.DEFAULT; 1238 } 1239 1240 mP.setTextSize(font.getSize()); 1241 mP.setTypeface(tf); 1242 } 1243 1244 @Override 1245 public void drawBytes(byte[] data, int offset, int length, int x, int y) { 1246 drawString(new String(data, offset, length), x, y); 1247 } 1248 1249 @Override 1250 public void drawPolygon(Polygon p) { 1251 drawPolygon(p.xpoints, p.ypoints, p.npoints); 1252 } 1253 1254 @Override 1255 public void fillPolygon(Polygon p) { 1256 fillPolygon(p.xpoints, p.ypoints, p.npoints); 1257 } 1258 1259 @Override 1260 public Rectangle getClipBounds(Rectangle r) { 1261 Shape clip = getClip(); 1262 if (clip != null) { 1263 Rectangle b = clip.getBounds(); 1264 r.x = b.x; 1265 r.y = b.y; 1266 r.width = b.width; 1267 r.height = b.height; 1268 } 1269 return r; 1270 } 1271 1272 @Override 1273 public boolean hitClip(int x, int y, int width, int height) { 1274 return getClipBounds().intersects(new Rectangle(x, y, width, height)); 1275 } 1276 1277 @Override 1278 public void drawChars(char[] data, int offset, int length, int x, int y) { 1279 mC.drawText(data, offset, length, x, y, mP); 1280 } 1281 1282 @Override 1283 public void setPaintMode() { 1284 if (mP == null) { 1285 mP = new Paint(); 1286 } 1287 mP.setXfermode(null); 1288 } 1289 1290 @Override 1291 public void setXORMode(Color color) { 1292 if (mP == null) { 1293 mP = new Paint(); 1294 } 1295 mP.setXfermode(new PixelXorXfermode(color.getRGB())); 1296 } 1297 1298 @Override 1299 public void fill3DRect(int x, int y, int width, int height, boolean raised) { 1300 Color color = getColor(); 1301 Color colorUp, colorDown; 1302 if (raised) { 1303 colorUp = color.brighter(); 1304 colorDown = color.darker(); 1305 setColor(color); 1306 } else { 1307 colorUp = color.darker(); 1308 colorDown = color.brighter(); 1309 setColor(colorUp); 1310 } 1311 1312 width--; 1313 height--; 1314 fillRect(x+1, y+1, width-1, height-1); 1315 1316 setColor(colorUp); 1317 fillRect(x, y, width, 1); 1318 fillRect(x, y+1, 1, height); 1319 1320 setColor(colorDown); 1321 fillRect(x+width, y, 1, height); 1322 fillRect(x+1, y+height, width, 1); 1323 } 1324 1325 @Override 1326 public void draw3DRect(int x, int y, int width, int height, boolean raised) { 1327 Color color = getColor(); 1328 Color colorUp, colorDown; 1329 if (raised) { 1330 colorUp = color.brighter(); 1331 colorDown = color.darker(); 1332 } else { 1333 colorUp = color.darker(); 1334 colorDown = color.brighter(); 1335 } 1336 1337 setColor(colorUp); 1338 fillRect(x, y, width, 1); 1339 fillRect(x, y+1, 1, height); 1340 1341 setColor(colorDown); 1342 fillRect(x+width, y, 1, height); 1343 fillRect(x+1, y+height, width, 1); 1344 } 1345 1346 public void copyArea(Canvas canvas, int sx, int sy, int width, int height, int dx, int dy) { 1347 sx += getTransform().getTranslateX(); 1348 sy += getTransform().getTranslateY(); 1349 1350 NativeUtils.nativeScrollRect(canvas, 1351 new Rect(sx, sy, sx + width, sy + height), 1352 dx, dy); 1353 } 1354} 1355