1 /* 2 * Copyright (C) 2024 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 package com.android.internal.widget.remotecompose.core.operations.paint; 17 18 import com.android.internal.widget.remotecompose.core.PaintContext; 19 import com.android.internal.widget.remotecompose.core.RemoteContext; 20 import com.android.internal.widget.remotecompose.core.VariableSupport; 21 import com.android.internal.widget.remotecompose.core.WireBuffer; 22 import com.android.internal.widget.remotecompose.core.operations.Utils; 23 24 import java.util.Arrays; 25 26 /** 27 * Paint Bundle represents a delta of changes to a paint object 28 */ 29 public class PaintBundle { 30 int[] mArray = new int[200]; 31 int[] mOutArray = null; 32 int mPos = 0; 33 34 /** 35 * Apply changes to a PaintChanges interface 36 * @param paintContext 37 * @param p 38 */ applyPaintChange(PaintContext paintContext, PaintChanges p)39 public void applyPaintChange(PaintContext paintContext, PaintChanges p) { 40 int i = 0; 41 int mask = 0; 42 if (mOutArray == null) { 43 mOutArray = mArray; 44 } 45 while (i < mPos) { 46 int cmd = mOutArray[i++]; 47 mask = mask | (1 << (cmd - 1)); 48 switch (cmd & 0xFFFF) { 49 case TEXT_SIZE: { 50 p.setTextSize(Float.intBitsToFloat(mOutArray[i++])); 51 break; 52 } 53 case TYPEFACE: 54 int style = (cmd >> 16); 55 int weight = style & 0x3ff; 56 boolean italic = (style >> 10) > 0; 57 int font_type = mOutArray[i++]; 58 59 p.setTypeFace(font_type, weight, italic); 60 break; 61 case COLOR_ID: // mOutArray should have already decoded it 62 case COLOR: { 63 p.setColor(mOutArray[i++]); 64 break; 65 } 66 case STROKE_WIDTH: { 67 p.setStrokeWidth(Float.intBitsToFloat(mOutArray[i++])); 68 break; 69 } 70 case STROKE_MITER: { 71 p.setStrokeMiter(Float.intBitsToFloat(mOutArray[i++])); 72 break; 73 } 74 case STROKE_CAP: { 75 p.setStrokeCap(cmd >> 16); 76 break; 77 } 78 case STYLE: { 79 p.setStyle(cmd >> 16); 80 break; 81 } 82 case SHADER: { 83 p.setShader(mOutArray[i++]); 84 break; 85 } 86 case STROKE_JOIN: { 87 p.setStrokeJoin(cmd >> 16); 88 break; 89 } 90 case IMAGE_FILTER_QUALITY: { 91 p.setImageFilterQuality(cmd >> 16); 92 break; 93 } 94 case BLEND_MODE: { 95 p.setBlendMode(cmd >> 16); 96 break; 97 } 98 case FILTER_BITMAP: { 99 p.setFilterBitmap(!((cmd >> 16) == 0)); 100 break; 101 } 102 case GRADIENT: { 103 i = callSetGradient(cmd, mOutArray, i, p); 104 break; 105 } 106 case COLOR_FILTER: { 107 p.setColorFilter(mOutArray[i++], cmd >> 16); 108 break; 109 } 110 case ALPHA: { 111 p.setAlpha(Float.intBitsToFloat(mOutArray[i++])); 112 break; 113 } 114 } 115 } 116 117 mask = (~mask) & PaintChanges.VALID_BITS; 118 119 p.clear(mask); 120 } 121 toName(int id)122 private String toName(int id) { 123 switch (id) { 124 case TEXT_SIZE: 125 return "TEXT_SIZE"; 126 case COLOR: 127 return "COLOR"; 128 case STROKE_WIDTH: 129 return "STROKE_WIDTH"; 130 case STROKE_MITER: 131 return "STROKE_MITER"; 132 case TYPEFACE: 133 return "TYPEFACE"; 134 case STROKE_CAP: 135 return "CAP"; 136 case STYLE: 137 return "STYLE"; 138 case SHADER: 139 return "SHADER"; 140 case IMAGE_FILTER_QUALITY: 141 return "IMAGE_FILTER_QUALITY"; 142 case BLEND_MODE: 143 return "BLEND_MODE"; 144 case FILTER_BITMAP: 145 return "FILTER_BITMAP"; 146 case GRADIENT: 147 return "GRADIENT_LINEAR"; 148 case ALPHA: 149 return "ALPHA"; 150 case COLOR_FILTER: 151 return "COLOR_FILTER"; 152 } 153 return "????" + id + "????"; 154 } 155 colorInt(int color)156 private static String colorInt(int color) { 157 String str = "000000000000" + Integer.toHexString(color); 158 return "0x" + str.substring(str.length() - 8); 159 } 160 colorInt(int[] color)161 private static String colorInt(int[] color) { 162 String str = "["; 163 for (int i = 0; i < color.length; i++) { 164 if (i > 0) { 165 str += ", "; 166 } 167 str += colorInt(color[i]); 168 } 169 return str + "]"; 170 } 171 asFloatStr(int value)172 private static String asFloatStr(int value) { 173 float fValue = Float.intBitsToFloat(value); 174 if (Float.isNaN(fValue)) { 175 return "[" + Utils.idFromNan(fValue) + "]"; 176 } 177 return Float.toString(fValue); 178 } 179 180 @Override toString()181 public String toString() { 182 StringBuilder ret = new StringBuilder("\n"); 183 int i = 0; 184 while (i < mPos) { 185 int cmd = mArray[i++]; 186 int type = cmd & 0xFFFF; 187 switch (type) { 188 189 case TEXT_SIZE: { 190 ret.append(" TextSize(" 191 + asFloatStr(mArray[i++])); 192 } 193 194 break; 195 case TYPEFACE: { 196 int style = (cmd >> 16); 197 int weight = style & 0x3ff; 198 boolean italic = (style >> 10) > 0; 199 int font_type = mArray[i++]; 200 ret.append(" TypeFace(" + (font_type + ", " 201 + weight + ", " + italic)); 202 } 203 break; 204 case COLOR: { 205 ret.append(" Color(" + colorInt(mArray[i++])); 206 } 207 break; 208 case COLOR_ID: { 209 ret.append(" ColorId([" + mArray[i++] + "]"); 210 } 211 break; 212 case STROKE_WIDTH: { 213 ret.append(" StrokeWidth(" 214 + (asFloatStr(mArray[i++]))); 215 } 216 break; 217 case STROKE_MITER: { 218 ret.append(" StrokeMiter(" 219 + (asFloatStr(mArray[i++]))); 220 } 221 break; 222 case STROKE_CAP: { 223 ret.append(" StrokeCap(" 224 + (cmd >> 16)); 225 } 226 break; 227 case STYLE: { 228 ret.append(" Style(" + (cmd >> 16)); 229 } 230 break; 231 case COLOR_FILTER: { 232 ret.append(" ColorFilter(color=" 233 + colorInt(mArray[i++]) 234 + ", mode=" + blendModeString(cmd >> 16)); 235 } 236 break; 237 case SHADER: { 238 ret.append(" Shader(" + mArray[i++]); 239 } 240 break; 241 case ALPHA: { 242 ret.append(" Alpha(" 243 + (asFloatStr(mArray[i++]))); 244 } 245 break; 246 case IMAGE_FILTER_QUALITY: { 247 ret.append(" ImageFilterQuality(" + (cmd >> 16)); 248 } 249 break; 250 case BLEND_MODE: { 251 ret.append(" BlendMode(" + blendModeString(cmd >> 16)); 252 } 253 break; 254 case FILTER_BITMAP: { 255 ret.append(" FilterBitmap(" 256 + (!((cmd >> 16) == 0))); 257 } 258 break; 259 case STROKE_JOIN: { 260 ret.append(" StrokeJoin(" + (cmd >> 16)); 261 } 262 break; 263 case ANTI_ALIAS: { 264 ret.append(" AntiAlias(" + (cmd >> 16)); 265 } 266 break; 267 case GRADIENT: { 268 i = callPrintGradient(cmd, mArray, i, ret); 269 } 270 } 271 ret.append("),\n"); 272 } 273 return ret.toString(); 274 } 275 callPrintGradient(int cmd, int[] array, int i, StringBuilder p)276 int callPrintGradient(int cmd, int[] array, int i, StringBuilder p) { 277 int ret = i; 278 int type = (cmd >> 16); 279 switch (type) { 280 281 case 0: { 282 p.append(" LinearGradient(\n"); 283 int len = array[ret++]; 284 int[] colors = null; 285 if (len > 0) { 286 colors = new int[len]; 287 for (int j = 0; j < colors.length; j++) { 288 colors[j] = array[ret++]; 289 } 290 } 291 len = array[ret++]; 292 String[] stops = null; 293 if (len > 0) { 294 stops = new String[len]; 295 for (int j = 0; j < stops.length; j++) { 296 stops[j] = asFloatStr(array[ret++]); 297 } 298 } 299 300 p.append(" colors = " + colorInt(colors) + ",\n"); 301 p.append(" stops = " + Arrays.toString(stops) + ",\n"); 302 p.append(" start = "); 303 p.append("[" + asFloatStr(array[ret++])); 304 p.append(", " + asFloatStr(array[ret++]) + "],\n"); 305 p.append(" end = "); 306 p.append("[" + asFloatStr(array[ret++])); 307 p.append(", " + asFloatStr(array[ret++]) + "],\n"); 308 int tileMode = array[ret++]; 309 p.append(" tileMode = " + tileMode + "\n "); 310 } 311 312 break; 313 case 1: { 314 p.append(" RadialGradient(\n"); 315 int len = array[ret++]; 316 int[] colors = null; 317 if (len > 0) { 318 colors = new int[len]; 319 for (int j = 0; j < colors.length; j++) { 320 colors[j] = array[ret++]; 321 322 } 323 } 324 len = array[ret++]; 325 String[] stops = null; 326 if (len > 0) { 327 stops = new String[len]; 328 for (int j = 0; j < stops.length; j++) { 329 stops[j] = asFloatStr(array[ret++]); 330 } 331 } 332 333 p.append(" colors = " + colorInt(colors) + ",\n"); 334 p.append(" stops = " + Arrays.toString(stops) + ",\n"); 335 p.append(" center = "); 336 p.append("[" + asFloatStr(array[ret++])); 337 p.append(", " + asFloatStr(array[ret++]) + "],\n"); 338 p.append(" radius ="); 339 p.append(" " + asFloatStr(array[ret++]) + ",\n"); 340 int tileMode = array[ret++]; 341 p.append(" tileMode = " + tileMode + "\n "); 342 } 343 344 break; 345 case 2: { 346 p.append(" SweepGradient(\n"); 347 int len = array[ret++]; 348 int[] colors = null; 349 if (len > 0) { 350 colors = new int[len]; 351 for (int j = 0; j < colors.length; j++) { 352 colors[j] = array[ret++]; 353 354 } 355 } 356 len = array[ret++]; 357 String[] stops = null; 358 if (len > 0) { 359 stops = new String[len]; 360 for (int j = 0; j < stops.length; j++) { 361 stops[j] = asFloatStr(array[ret++]); 362 } 363 } 364 p.append(" colors = " + colorInt(colors) + ",\n"); 365 p.append(" stops = " + Arrays.toString(stops) + ",\n"); 366 p.append(" center = "); 367 p.append("[" + asFloatStr(array[ret++])); 368 p.append(", " 369 + asFloatStr(array[ret++]) + "],\n "); 370 } 371 break; 372 default: { 373 p.append("GRADIENT_??????!!!!"); 374 } 375 } 376 377 return ret; 378 } 379 callSetGradient(int cmd, int[] array, int i, PaintChanges p)380 int callSetGradient(int cmd, int[] array, int i, PaintChanges p) { 381 int ret = i; 382 int gradientType = (cmd >> 16); 383 384 int len = array[ret++]; 385 int[] colors = null; 386 if (len > 0) { 387 colors = new int[len]; 388 for (int j = 0; j < colors.length; j++) { 389 colors[j] = array[ret++]; 390 } 391 } 392 len = array[ret++]; 393 float[] stops = null; 394 if (len > 0) { 395 stops = new float[len]; 396 for (int j = 0; j < colors.length; j++) { 397 stops[j] = Float.intBitsToFloat(array[ret++]); 398 } 399 } 400 401 if (colors == null) { 402 return ret; 403 } 404 405 switch (gradientType) { 406 407 case LINEAR_GRADIENT: { 408 float startX = Float.intBitsToFloat(array[ret++]); 409 float startY = Float.intBitsToFloat(array[ret++]); 410 float endX = Float.intBitsToFloat(array[ret++]); 411 float endY = Float.intBitsToFloat(array[ret++]); 412 int tileMode = array[ret++]; 413 p.setLinearGradient(colors, stops, startX, 414 startY, endX, endY, tileMode); 415 } 416 417 break; 418 case RADIAL_GRADIENT: { 419 float centerX = Float.intBitsToFloat(array[ret++]); 420 float centerY = Float.intBitsToFloat(array[ret++]); 421 float radius = Float.intBitsToFloat(array[ret++]); 422 int tileMode = array[ret++]; 423 p.setRadialGradient(colors, stops, centerX, centerY, 424 radius, tileMode); 425 } 426 break; 427 case SWEEP_GRADIENT: { 428 float centerX = Float.intBitsToFloat(array[ret++]); 429 float centerY = Float.intBitsToFloat(array[ret++]); 430 p.setSweepGradient(colors, stops, centerX, centerY); 431 } 432 } 433 434 return ret; 435 } 436 writeBundle(WireBuffer buffer)437 public void writeBundle(WireBuffer buffer) { 438 buffer.writeInt(mPos); 439 for (int index = 0; index < mPos; index++) { 440 buffer.writeInt(mArray[index]); 441 } 442 } 443 readBundle(WireBuffer buffer)444 public void readBundle(WireBuffer buffer) { 445 int len = buffer.readInt(); 446 if (len <= 0 || len > 1024) { 447 throw new RuntimeException("buffer corrupt paint len = " + len); 448 } 449 mArray = new int[len]; 450 for (int i = 0; i < mArray.length; i++) { 451 mArray[i] = buffer.readInt(); 452 } 453 mPos = len; 454 } 455 456 public static final int TEXT_SIZE = 1; // float 457 458 public static final int COLOR = 4; // int 459 public static final int STROKE_WIDTH = 5; // float 460 public static final int STROKE_MITER = 6; 461 public static final int STROKE_CAP = 7; // int 462 public static final int STYLE = 8; // int 463 public static final int SHADER = 9; // int 464 public static final int IMAGE_FILTER_QUALITY = 10; // int 465 public static final int GRADIENT = 11; 466 public static final int ALPHA = 12; 467 public static final int COLOR_FILTER = 13; 468 public static final int ANTI_ALIAS = 14; 469 public static final int STROKE_JOIN = 15; 470 public static final int TYPEFACE = 16; 471 public static final int FILTER_BITMAP = 17; 472 public static final int BLEND_MODE = 18; 473 public static final int COLOR_ID = 19; // int 474 475 public static final int BLEND_MODE_CLEAR = 0; 476 public static final int BLEND_MODE_SRC = 1; 477 public static final int BLEND_MODE_DST = 2; 478 public static final int BLEND_MODE_SRC_OVER = 3; 479 public static final int BLEND_MODE_DST_OVER = 4; 480 public static final int BLEND_MODE_SRC_IN = 5; 481 public static final int BLEND_MODE_DST_IN = 6; 482 public static final int BLEND_MODE_SRC_OUT = 7; 483 public static final int BLEND_MODE_DST_OUT = 8; 484 public static final int BLEND_MODE_SRC_ATOP = 9; 485 public static final int BLEND_MODE_DST_ATOP = 10; 486 public static final int BLEND_MODE_XOR = 11; 487 public static final int BLEND_MODE_PLUS = 12; 488 public static final int BLEND_MODE_MODULATE = 13; 489 public static final int BLEND_MODE_SCREEN = 14; 490 public static final int BLEND_MODE_OVERLAY = 15; 491 public static final int BLEND_MODE_DARKEN = 16; 492 public static final int BLEND_MODE_LIGHTEN = 17; 493 public static final int BLEND_MODE_COLOR_DODGE = 18; 494 public static final int BLEND_MODE_COLOR_BURN = 19; 495 public static final int BLEND_MODE_HARD_LIGHT = 20; 496 public static final int BLEND_MODE_SOFT_LIGHT = 21; 497 public static final int BLEND_MODE_DIFFERENCE = 22; 498 public static final int BLEND_MODE_EXCLUSION = 23; 499 public static final int BLEND_MODE_MULTIPLY = 24; 500 public static final int BLEND_MODE_HUE = 25; 501 public static final int BLEND_MODE_SATURATION = 26; 502 public static final int BLEND_MODE_COLOR = 27; 503 public static final int BLEND_MODE_LUMINOSITY = 28; 504 public static final int BLEND_MODE_NULL = 29; 505 public static final int PORTER_MODE_ADD = 30; 506 507 public static final int FONT_NORMAL = 0; 508 public static final int FONT_BOLD = 1; 509 public static final int FONT_ITALIC = 2; 510 public static final int FONT_BOLD_ITALIC = 3; 511 512 public static final int FONT_TYPE_DEFAULT = 0; 513 public static final int FONT_TYPE_SANS_SERIF = 1; 514 public static final int FONT_TYPE_SERIF = 2; 515 public static final int FONT_TYPE_MONOSPACE = 3; 516 517 public static final int STYLE_FILL = 0; 518 public static final int STYLE_STROKE = 1; 519 public static final int STYLE_FILL_AND_STROKE = 2; 520 public static final int LINEAR_GRADIENT = 0; 521 public static final int RADIAL_GRADIENT = 1; 522 public static final int SWEEP_GRADIENT = 2; 523 524 /** 525 * sets a shader that draws a linear gradient along a line. 526 * 527 * @param startX The x-coordinate for the start of the gradient line 528 * @param startY The y-coordinate for the start of the gradient line 529 * @param endX The x-coordinate for the end of the gradient line 530 * @param endY The y-coordinate for the end of the gradient line 531 * @param colors The sRGB colors to be distributed along the gradient line 532 * @param stops May be null. The relative positions [0..1] of 533 * each corresponding color in the colors array. If this is null, 534 * the colors are distributed evenly along the gradient line. 535 * @param tileMode The Shader tiling mode 536 */ setLinearGradient(int[] colors, float[] stops, float startX, float startY, float endX, float endY, int tileMode)537 public void setLinearGradient(int[] colors, 538 float[] stops, 539 float startX, 540 float startY, 541 float endX, 542 float endY, 543 int tileMode) { 544 int startPos = mPos; 545 int len; 546 mArray[mPos++] = GRADIENT | (LINEAR_GRADIENT << 16); 547 mArray[mPos++] = len = (colors == null) ? 0 : colors.length; 548 for (int i = 0; i < len; i++) { 549 mArray[mPos++] = colors[i]; 550 } 551 552 mArray[mPos++] = len = (stops == null) ? 0 : stops.length; 553 for (int i = 0; i < len; i++) { 554 mArray[mPos++] = Float.floatToRawIntBits(stops[i]); 555 } 556 mArray[mPos++] = Float.floatToRawIntBits(startX); 557 mArray[mPos++] = Float.floatToRawIntBits(startY); 558 mArray[mPos++] = Float.floatToRawIntBits(endX); 559 mArray[mPos++] = Float.floatToRawIntBits(endY); 560 mArray[mPos++] = tileMode; 561 } 562 563 /** 564 * Set a shader that draws a sweep gradient around a center point. 565 * 566 * @param centerX The x-coordinate of the center 567 * @param centerY The y-coordinate of the center 568 * @param colors The sRGB colors to be distributed around the center. 569 * There must be at least 2 colors in the array. 570 * @param stops May be NULL. The relative position of 571 * each corresponding color in the colors array, beginning 572 * with 0 and ending with 1.0. If the values are not 573 * monotonic, the drawing may produce unexpected results. 574 * If positions is NULL, then the colors are automatically 575 * spaced evenly. 576 */ setSweepGradient(int[] colors, float[] stops, float centerX, float centerY)577 public void setSweepGradient(int[] colors, float[] stops, float centerX, float centerY) { 578 int startPos = mPos; 579 int len; 580 mArray[mPos++] = GRADIENT | (SWEEP_GRADIENT << 16); 581 mArray[mPos++] = len = (colors == null) ? 0 : colors.length; 582 for (int i = 0; i < len; i++) { 583 mArray[mPos++] = colors[i]; 584 } 585 586 mArray[mPos++] = len = (stops == null) ? 0 : stops.length; 587 for (int i = 0; i < len; i++) { 588 mArray[mPos++] = Float.floatToRawIntBits(stops[i]); 589 } 590 mArray[mPos++] = Float.floatToRawIntBits(centerX); 591 mArray[mPos++] = Float.floatToRawIntBits(centerY); 592 } 593 594 /** 595 * Sets a shader that draws a radial gradient given the center and radius. 596 * 597 * @param centerX The x-coordinate of the center of the radius 598 * @param centerY The y-coordinate of the center of the radius 599 * @param radius Must be positive. The radius of the gradient. 600 * @param colors The sRGB colors distributed between the center and edge 601 * @param stops May be <code>null</code>. 602 * Valid values are between <code>0.0f</code> and 603 * <code>1.0f</code>. The relative position of each 604 * corresponding color in 605 * the colors array. If <code>null</code>, colors are 606 * distributed evenly 607 * between the center and edge of the circle. 608 * @param tileMode The Shader tiling mode 609 */ setRadialGradient(int[] colors, float[] stops, float centerX, float centerY, float radius, int tileMode)610 public void setRadialGradient(int[] colors, 611 float[] stops, 612 float centerX, 613 float centerY, 614 float radius, 615 int tileMode) { 616 int startPos = mPos; 617 int len; 618 mArray[mPos++] = GRADIENT | (RADIAL_GRADIENT << 16); 619 mArray[mPos++] = len = (colors == null) ? 0 : colors.length; 620 for (int i = 0; i < len; i++) { 621 mArray[mPos++] = colors[i]; 622 } 623 mArray[mPos++] = len = (stops == null) ? 0 : stops.length; 624 625 for (int i = 0; i < len; i++) { 626 mArray[mPos++] = Float.floatToRawIntBits(stops[i]); 627 } 628 mArray[mPos++] = Float.floatToRawIntBits(centerX); 629 mArray[mPos++] = Float.floatToRawIntBits(centerY); 630 mArray[mPos++] = Float.floatToRawIntBits(radius); 631 mArray[mPos++] = tileMode; 632 633 } 634 635 /** 636 * Create a color filter that uses the specified color and Porter-Duff mode. 637 * 638 * @param color The ARGB source color used with the Porter-Duff mode 639 * @param mode The porter-duff mode that is applied 640 */ setColorFilter(int color, int mode)641 public void setColorFilter(int color, int mode) { 642 mArray[mPos] = COLOR_FILTER | (mode << 16); 643 mPos++; 644 mArray[mPos++] = color; 645 } 646 647 /** 648 * Set the paint's text size. This value must be > 0 649 * 650 * @param size set the paint's text size in pixel units. 651 */ setTextSize(float size)652 public void setTextSize(float size) { 653 int p = mPos; 654 mArray[mPos] = TEXT_SIZE; 655 mPos++; 656 mArray[mPos] = Float.floatToRawIntBits(size); 657 mPos++; 658 } 659 660 /** 661 * @param fontType 0 = default 1 = sans serif 2 = serif 3 = monospace 662 * @param weight 100-1000 663 * @param italic tur 664 */ setTextStyle(int fontType, int weight, boolean italic)665 public void setTextStyle(int fontType, int weight, boolean italic) { 666 int style = (weight & 0x3FF) | (italic ? 2048 : 0); // pack the weight and italic 667 mArray[mPos++] = TYPEFACE | (style << 16); 668 mArray[mPos++] = fontType; 669 } 670 671 /** 672 * Set the width for stroking. 673 * Pass 0 to stroke in hairline mode. 674 * Hairlines always draws a single pixel independent of the canvas's matrix. 675 * 676 * @param width set the paint's stroke width, used whenever the paint's 677 * style is Stroke or StrokeAndFill. 678 */ setStrokeWidth(float width)679 public void setStrokeWidth(float width) { 680 mArray[mPos] = STROKE_WIDTH; 681 mPos++; 682 mArray[mPos] = Float.floatToRawIntBits(width); 683 mPos++; 684 } 685 686 /** 687 * Set the Color based on Color 688 * @param color 689 */ setColor(int color)690 public void setColor(int color) { 691 mArray[mPos] = COLOR; 692 mPos++; 693 mArray[mPos] = color; 694 mPos++; 695 } 696 697 /** 698 * Set the Color based on ID 699 * @param color 700 */ setColorId(int color)701 public void setColorId(int color) { 702 mArray[mPos] = COLOR_ID; 703 mPos++; 704 mArray[mPos] = color; 705 mPos++; 706 } 707 708 709 /** 710 * Set the paint's Cap. 711 * 712 * @param cap set the paint's line cap style, used whenever the paint's 713 * style is Stroke or StrokeAndFill. 714 */ setStrokeCap(int cap)715 public void setStrokeCap(int cap) { 716 mArray[mPos] = STROKE_CAP | (cap << 16); 717 mPos++; 718 } 719 720 /** 721 * Set the style STROKE and/or FILL 722 * @param style 723 */ setStyle(int style)724 public void setStyle(int style) { 725 mArray[mPos] = STYLE | (style << 16); 726 mPos++; 727 } 728 729 /** 730 * Set the shader id to use 731 * @param shaderId 732 */ setShader(int shaderId)733 public void setShader(int shaderId) { 734 mArray[mPos] = SHADER; 735 mPos++; 736 mArray[mPos] = shaderId; 737 mPos++; 738 } 739 740 /** 741 * Set the Alpha value 742 */ setAlpha(float alpha)743 public void setAlpha(float alpha) { 744 mArray[mPos] = ALPHA; 745 mPos++; 746 mArray[mPos] = Float.floatToRawIntBits(alpha); 747 mPos++; 748 } 749 750 /** 751 * Set the paint's stroke miter value. This is used to control the behavior 752 * of miter joins when the joins angle is sharp. This value must be >= 0. 753 * 754 * @param miter set the miter limit on the paint, used whenever the paint's 755 * style is Stroke or StrokeAndFill. 756 */ setStrokeMiter(float miter)757 public void setStrokeMiter(float miter) { 758 mArray[mPos] = STROKE_MITER; 759 mPos++; 760 mArray[mPos] = Float.floatToRawIntBits(miter); 761 mPos++; 762 } 763 764 /** 765 * Set the paint's Join. 766 * 767 * @param join set the paint's Join, used whenever the paint's style is 768 * Stroke or StrokeAndFill. 769 */ setStrokeJoin(int join)770 public void setStrokeJoin(int join) { 771 mArray[mPos] = STROKE_JOIN | (join << 16); 772 mPos++; 773 } 774 setFilterBitmap(boolean filter)775 public void setFilterBitmap(boolean filter) { 776 mArray[mPos] = FILTER_BITMAP | (filter ? (1 << 16) : 0); 777 mPos++; 778 } 779 780 /** 781 * Set or clear the blend mode. A blend mode defines how source pixels 782 * (generated by a drawing command) are composited with the 783 * destination pixels 784 * (content of the render target). 785 * 786 * @param blendmode The blend mode to be installed in the paint 787 */ setBlendMode(int blendmode)788 public void setBlendMode(int blendmode) { 789 mArray[mPos] = BLEND_MODE | (blendmode << 16); 790 mPos++; 791 } 792 793 /** 794 * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit 795 * AntiAliasing smooths out the edges of what is being drawn, but is has 796 * no impact on the interior of the shape. See setDither() and 797 * setFilterBitmap() to affect how colors are treated. 798 * 799 * @param aa true to set the antialias bit in the flags, false to clear it 800 */ setAntiAlias(boolean aa)801 public void setAntiAlias(boolean aa) { 802 mArray[mPos] = ANTI_ALIAS | (((aa) ? 1 : 0) << 16); 803 mPos++; 804 } 805 clear(long mask)806 public void clear(long mask) { // unused for now 807 } 808 reset()809 public void reset() { 810 mPos = 0; 811 } 812 blendModeString(int mode)813 public static String blendModeString(int mode) { 814 switch (mode) { 815 case PaintBundle.BLEND_MODE_CLEAR: 816 return "CLEAR"; 817 case PaintBundle.BLEND_MODE_SRC: 818 return "SRC"; 819 case PaintBundle.BLEND_MODE_DST: 820 return "DST"; 821 case PaintBundle.BLEND_MODE_SRC_OVER: 822 return "SRC_OVER"; 823 case PaintBundle.BLEND_MODE_DST_OVER: 824 return "DST_OVER"; 825 case PaintBundle.BLEND_MODE_SRC_IN: 826 return "SRC_IN"; 827 case PaintBundle.BLEND_MODE_DST_IN: 828 return "DST_IN"; 829 case PaintBundle.BLEND_MODE_SRC_OUT: 830 return "SRC_OUT"; 831 case PaintBundle.BLEND_MODE_DST_OUT: 832 return "DST_OUT"; 833 case PaintBundle.BLEND_MODE_SRC_ATOP: 834 return "SRC_ATOP"; 835 case PaintBundle.BLEND_MODE_DST_ATOP: 836 return "DST_ATOP"; 837 case PaintBundle.BLEND_MODE_XOR: 838 return "XOR"; 839 case PaintBundle.BLEND_MODE_PLUS: 840 return "PLUS"; 841 case PaintBundle.BLEND_MODE_MODULATE: 842 return "MODULATE"; 843 case PaintBundle.BLEND_MODE_SCREEN: 844 return "SCREEN"; 845 case PaintBundle.BLEND_MODE_OVERLAY: 846 return "OVERLAY"; 847 case PaintBundle.BLEND_MODE_DARKEN: 848 return "DARKEN"; 849 case PaintBundle.BLEND_MODE_LIGHTEN: 850 return "LIGHTEN"; 851 case PaintBundle.BLEND_MODE_COLOR_DODGE: 852 return "COLOR_DODGE"; 853 case PaintBundle.BLEND_MODE_COLOR_BURN: 854 return "COLOR_BURN"; 855 case PaintBundle.BLEND_MODE_HARD_LIGHT: 856 return "HARD_LIGHT"; 857 case PaintBundle.BLEND_MODE_SOFT_LIGHT: 858 return "SOFT_LIGHT"; 859 case PaintBundle.BLEND_MODE_DIFFERENCE: 860 return "DIFFERENCE"; 861 case PaintBundle.BLEND_MODE_EXCLUSION: 862 return "EXCLUSION"; 863 case PaintBundle.BLEND_MODE_MULTIPLY: 864 return "MULTIPLY"; 865 case PaintBundle.BLEND_MODE_HUE: 866 return "HUE"; 867 case PaintBundle.BLEND_MODE_SATURATION: 868 return "SATURATION"; 869 case PaintBundle.BLEND_MODE_COLOR: 870 return "COLOR"; 871 case PaintBundle.BLEND_MODE_LUMINOSITY: 872 return "LUMINOSITY"; 873 case PaintBundle.BLEND_MODE_NULL: 874 return "null"; 875 case PaintBundle.PORTER_MODE_ADD: 876 return "ADD"; 877 } 878 return "null"; 879 } 880 881 /** 882 * Check all the floats for Nan(id) floats and call listenTo 883 * @param context 884 * @param support 885 */ registerVars(RemoteContext context, VariableSupport support)886 public void registerVars(RemoteContext context, VariableSupport support) { 887 int i = 0; 888 while (i < mPos) { 889 int cmd = mArray[i++]; 890 int type = cmd & 0xFFFF; 891 switch (type) { 892 case STROKE_MITER: 893 case STROKE_WIDTH: 894 case ALPHA: 895 case TEXT_SIZE: 896 float v = Float.intBitsToFloat(mArray[i++]); 897 if (Float.isNaN(v)) { 898 context.listensTo(Utils.idFromNan(v), support); 899 } 900 break; 901 case COLOR_ID: 902 context.listensTo(mArray[i++], support); 903 break; 904 case COLOR: 905 906 case TYPEFACE: 907 case SHADER: 908 case COLOR_FILTER: 909 i++; 910 break; 911 case STROKE_JOIN: 912 case FILTER_BITMAP: 913 case STROKE_CAP: 914 case STYLE: 915 case IMAGE_FILTER_QUALITY: 916 case BLEND_MODE: 917 case ANTI_ALIAS: 918 break; 919 920 case GRADIENT: { 921 // TODO gradients should be handled correctly 922 i = callPrintGradient(cmd, mArray, i, new StringBuilder()); 923 } 924 } 925 } 926 } 927 928 /** 929 * Update variables if any are float ids 930 * @param context 931 */ updateVariables(RemoteContext context)932 public void updateVariables(RemoteContext context) { 933 if (mOutArray == null) { 934 mOutArray = Arrays.copyOf(mArray, mArray.length); 935 } else { 936 System.arraycopy(mArray, 0, mOutArray, 0, mArray.length); 937 } 938 int i = 0; 939 while (i < mPos) { 940 int cmd = mArray[i++]; 941 int type = cmd & 0xFFFF; 942 switch (type) { 943 case STROKE_MITER: 944 case STROKE_WIDTH: 945 case ALPHA: 946 case TEXT_SIZE: 947 mOutArray[i] = fixFloatVar(mArray[i], context); 948 i++; 949 break; 950 case COLOR_ID: 951 mOutArray[i] = fixColor(mArray[i], context); 952 i++; 953 break; 954 case COLOR: 955 case TYPEFACE: 956 case SHADER: 957 case COLOR_FILTER: 958 i++; 959 break; 960 case STROKE_JOIN: 961 case FILTER_BITMAP: 962 case STROKE_CAP: 963 case STYLE: 964 case IMAGE_FILTER_QUALITY: 965 case BLEND_MODE: 966 case ANTI_ALIAS: 967 break; 968 969 case GRADIENT: { 970 // TODO gradients should be handled correctly 971 i = updateFloatsInGradient(cmd, mOutArray, mArray, i, context); 972 } 973 } 974 } 975 } 976 fixFloatVar(int val, RemoteContext context)977 private int fixFloatVar(int val, RemoteContext context) { 978 float v = Float.intBitsToFloat(val); 979 if (Float.isNaN(v)) { 980 int id = Utils.idFromNan(v); 981 return Float.floatToRawIntBits(context.getFloat(id)); 982 } 983 return val; 984 } 985 fixColor(int colorId, RemoteContext context)986 private int fixColor(int colorId, RemoteContext context) { 987 int n = context.getColor(colorId); 988 return n; 989 } 990 updateFloatsInGradient(int cmd, int[] out, int[] array, int i, RemoteContext context)991 int updateFloatsInGradient(int cmd, int[] out, int[] array, 992 int i, 993 RemoteContext context) { 994 int ret = i; 995 int type = (cmd >> 16); 996 switch (type) { 997 case 0: { 998 int len = array[ret++]; 999 if (len > 0) { 1000 for (int j = 0; j < len; j++) { 1001 ret++; 1002 } 1003 } 1004 len = array[ret++]; 1005 1006 if (len > 0) { 1007 for (int j = 0; j < len; j++) { 1008 out[ret] = fixFloatVar(array[ret], context); 1009 ret++; 1010 } 1011 } 1012 1013 out[ret] = fixFloatVar(array[ret], context); 1014 ret++; 1015 out[ret] = fixFloatVar(array[ret], context); 1016 ret++; 1017 1018 // end 1019 out[ret] = fixFloatVar(array[ret], context); 1020 ret++; 1021 out[ret] = fixFloatVar(array[ret], context); 1022 ret++; 1023 ret++; // tileMode 1024 } 1025 1026 break; 1027 case 1: { 1028 // RadialGradient 1029 int len = array[ret++]; 1030 if (len > 0) { 1031 for (int j = 0; j < len; j++) { 1032 ret++; 1033 } 1034 } 1035 len = array[ret++]; 1036 if (len > 0) { 1037 for (int j = 0; j < len; j++) { 1038 out[ret] = fixFloatVar(array[ret], context); 1039 ret++; 1040 } 1041 } 1042 1043 1044 // center 1045 out[ret] = fixFloatVar(array[ret], context); 1046 ret++; 1047 out[ret] = fixFloatVar(array[ret], context); 1048 ret++; 1049 // radius 1050 out[ret] = fixFloatVar(array[ret], context); 1051 ret++; 1052 ret++; // tileMode 1053 1054 } 1055 1056 break; 1057 case 2: { 1058 // SweepGradient 1059 int len = array[ret++]; 1060 int[] colors = null; 1061 if (len > 0) { 1062 colors = new int[len]; 1063 for (int j = 0; j < colors.length; j++) { 1064 colors[j] = array[ret++]; 1065 1066 } 1067 } 1068 len = array[ret++]; 1069 float[] stops = null; 1070 if (len > 0) { 1071 stops = new float[len]; 1072 for (int j = 0; j < stops.length; j++) { 1073 out[ret] = fixFloatVar(array[ret], context); 1074 ret++; 1075 } 1076 } 1077 1078 // center 1079 out[ret] = fixFloatVar(array[ret], context); 1080 ret++; 1081 out[ret] = fixFloatVar(array[ret], context); 1082 ret++; 1083 } 1084 break; 1085 default: { 1086 System.err.println("gradient type unknown"); 1087 } 1088 } 1089 1090 return ret; 1091 } 1092 1093 }