1 /*
   2  * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.webkit.graphics;
  27 
  28 import com.sun.javafx.logging.PlatformLogger;
  29 
  30 import java.lang.annotation.Native;
  31 import java.nio.ByteBuffer;
  32 import java.nio.ByteOrder;
  33 
  34 public final class GraphicsDecoder  {
  35     @Native public final static int FILLRECT_FFFFI         = 0;
  36     @Native public final static int SETFILLCOLOR           = 1;
  37     @Native public final static int SETSTROKESTYLE         = 2;
  38     @Native public final static int SETSTROKECOLOR         = 3;
  39     @Native public final static int SETSTROKEWIDTH         = 4;
  40     @Native public final static int DRAWPOLYGON            = 6;
  41     @Native public final static int DRAWLINE               = 7;
  42     @Native public final static int DRAWIMAGE              = 8;
  43     @Native public final static int DRAWICON               = 9;
  44     @Native public final static int DRAWPATTERN            = 10;
  45     @Native public final static int TRANSLATE              = 11;
  46     @Native public final static int SAVESTATE              = 12;
  47     @Native public final static int RESTORESTATE           = 13;
  48     @Native public final static int CLIP_PATH              = 14;
  49     @Native public final static int SETCLIP_IIII           = 15;
  50     @Native public final static int DRAWRECT               = 16;
  51     @Native public final static int SETCOMPOSITE           = 17;
  52     @Native public final static int STROKEARC              = 18;
  53     @Native public final static int DRAWELLIPSE            = 19;
  54     @Native public final static int DRAWFOCUSRING          = 20;
  55     @Native public final static int SETALPHA               = 21;
  56     @Native public final static int BEGINTRANSPARENCYLAYER = 22;
  57     @Native public final static int ENDTRANSPARENCYLAYER   = 23;
  58     @Native public final static int STROKE_PATH            = 24;
  59     @Native public final static int FILL_PATH              = 25;
  60     @Native public final static int GETIMAGE               = 26;
  61     @Native public final static int SCALE                  = 27;
  62     @Native public final static int SETSHADOW              = 28;
  63     @Native public final static int DRAWSTRING             = 29;
  64     @Native public final static int DRAWSTRING_FAST        = 31;
  65     @Native public final static int DRAWWIDGET             = 33;
  66     @Native public final static int DRAWSCROLLBAR          = 34;
  67     @Native public final static int CLEARRECT_FFFF         = 36;
  68     @Native public final static int STROKERECT_FFFFF       = 37;
  69     @Native public final static int RENDERMEDIAPLAYER      = 38;
  70     @Native public final static int CONCATTRANSFORM_FFFFFF = 39;
  71     @Native public final static int COPYREGION             = 40;
  72     @Native public final static int DECODERQ               = 41;
  73     @Native public final static int SET_TRANSFORM          = 42;
  74     @Native public final static int ROTATE                 = 43;
  75     @Native public final static int RENDERMEDIACONTROL     = 44;
  76     @Native public final static int RENDERMEDIA_TIMETRACK  = 45;
  77     @Native public final static int RENDERMEDIA_VOLUMETRACK = 46;
  78     @Native public final static int FILLRECT_FFFF          = 47;
  79     @Native public final static int FILL_ROUNDED_RECT      = 48;
  80     @Native public final static int SET_FILL_GRADIENT      = 49;
  81     @Native public final static int SET_STROKE_GRADIENT    = 50;
  82     @Native public final static int SET_LINE_DASH          = 51;
  83     @Native public final static int SET_LINE_CAP           = 52;
  84     @Native public final static int SET_LINE_JOIN          = 53;
  85     @Native public final static int SET_MITER_LIMIT        = 54;
  86     @Native public final static int SET_TEXT_MODE          = 55;
  87 
  88     private final static PlatformLogger log =
  89             PlatformLogger.getLogger(GraphicsDecoder.class.getName());
  90 
  91     static void decode(WCGraphicsManager gm, WCGraphicsContext gc, BufferData bdata) {
  92         if (gc == null) {
  93             return;
  94         }
  95         ByteBuffer buf = bdata.getBuffer();
  96         buf.order(ByteOrder.nativeOrder());
  97         while (buf.remaining() > 0) {
  98             int op = buf.getInt();
  99             switch(op) {
 100                 case FILLRECT_FFFF:
 101                     gc.fillRect(
 102                         buf.getFloat(),
 103                         buf.getFloat(),
 104                         buf.getFloat(),
 105                         buf.getFloat(),
 106                         null);
 107                     break;
 108                 case FILLRECT_FFFFI:
 109                     gc.fillRect(
 110                         buf.getFloat(),
 111                         buf.getFloat(),
 112                         buf.getFloat(),
 113                         buf.getFloat(),
 114                         buf.getInt());
 115                     break;
 116                 case FILL_ROUNDED_RECT:
 117                     gc.fillRoundedRect(
 118                         // base rectangle
 119                         buf.getFloat(), buf.getFloat(), buf.getFloat(), buf.getFloat(),
 120                         // top corners w/h
 121                         buf.getFloat(), buf.getFloat(), buf.getFloat(), buf.getFloat(),
 122                         // bottom corners w/h
 123                         buf.getFloat(), buf.getFloat(), buf.getFloat(), buf.getFloat(),
 124                         buf.getInt());
 125                     break;
 126                 case CLEARRECT_FFFF:
 127                     gc.clearRect(
 128                         buf.getFloat(),
 129                         buf.getFloat(),
 130                         buf.getFloat(),
 131                         buf.getFloat());
 132                     break;
 133                 case STROKERECT_FFFFF:
 134                     gc.strokeRect(
 135                         buf.getFloat(),
 136                         buf.getFloat(),
 137                         buf.getFloat(),
 138                         buf.getFloat(),
 139                         buf.getFloat());
 140                     break;
 141                 case SETFILLCOLOR:
 142                     gc.setFillColor(buf.getInt());
 143                     break;
 144                 case SET_TEXT_MODE:
 145                     gc.setTextMode(getBoolean(buf), getBoolean(buf), getBoolean(buf));
 146                     break;
 147                 case SETSTROKESTYLE:
 148                     gc.setStrokeStyle(buf.getInt());
 149                     break;
 150                 case SETSTROKECOLOR:
 151                     gc.setStrokeColor(buf.getInt());
 152                     break;
 153                 case SETSTROKEWIDTH:
 154                     gc.setStrokeWidth(buf.getFloat());
 155                     break;
 156                 case SET_FILL_GRADIENT:
 157                     gc.setFillGradient(getGradient(gc, buf));
 158                     break;
 159                 case SET_STROKE_GRADIENT:
 160                     gc.setStrokeGradient(getGradient(gc, buf));
 161                     break;
 162                 case SET_LINE_DASH:
 163                     gc.setLineDash(buf.getFloat(), getFloatArray(buf));
 164                     break;
 165                 case SET_LINE_CAP:
 166                     gc.setLineCap(buf.getInt());
 167                     break;
 168                 case SET_LINE_JOIN:
 169                     gc.setLineJoin(buf.getInt());
 170                     break;
 171                 case SET_MITER_LIMIT:
 172                     gc.setMiterLimit(buf.getFloat());
 173                     break;
 174                 case DRAWPOLYGON:
 175                     gc.drawPolygon(getPath(gm, buf), buf.getInt() == -1);
 176                     break;
 177                 case DRAWLINE:
 178                     gc.drawLine(
 179                         buf.getInt(),
 180                         buf.getInt(),
 181                         buf.getInt(),
 182                         buf.getInt());
 183                     break;
 184                 case DRAWIMAGE:
 185                     drawImage(gc,
 186                         gm.getRef(buf.getInt()),
 187                         //dest React
 188                         buf.getFloat(),
 189                         buf.getFloat(),
 190                         buf.getFloat(),
 191                         buf.getFloat(),
 192                         //src Rect
 193                         buf.getFloat(),
 194                         buf.getFloat(),
 195                         buf.getFloat(),
 196                         buf.getFloat());
 197                     break;
 198                 case DRAWICON:
 199                     gc.drawIcon((WCIcon)gm.getRef(buf.getInt()),
 200                         buf.getInt(),
 201                         buf.getInt());
 202                     break;
 203                 case DRAWPATTERN:
 204                     drawPattern(gc,
 205                         gm.getRef(buf.getInt()),
 206                         getRectangle(buf),
 207                         (WCTransform)gm.getRef(buf.getInt()),
 208                         getPoint(buf),
 209                         getRectangle(buf));
 210                     break;
 211                 case TRANSLATE:
 212                     gc.translate(buf.getFloat(), buf.getFloat());
 213                     break;
 214                 case SCALE:
 215                     gc.scale(buf.getFloat(), buf.getFloat());
 216                     break;
 217                 case SAVESTATE:
 218                     gc.saveState();
 219                     break;
 220                 case RESTORESTATE:
 221                     gc.restoreState();
 222                     break;
 223                 case CLIP_PATH:
 224                     gc.setClip(
 225                         getPath(gm, buf),
 226                         buf.getInt()>0);
 227                     break;
 228                 case SETCLIP_IIII:
 229                     gc.setClip(
 230                         buf.getInt(),
 231                         buf.getInt(),
 232                         buf.getInt(),
 233                         buf.getInt());
 234                     break;
 235                 case DRAWRECT:
 236                     gc.drawRect(
 237                         buf.getInt(),
 238                         buf.getInt(),
 239                         buf.getInt(),
 240                         buf.getInt());
 241                     break;
 242                 case SETCOMPOSITE:
 243                     gc.setComposite(buf.getInt());
 244                     break;
 245                 case STROKEARC:
 246                     gc.strokeArc(
 247                         buf.getInt(),
 248                         buf.getInt(),
 249                         buf.getInt(),
 250                         buf.getInt(),
 251                         buf.getInt(),
 252                         buf.getInt());
 253                     break;
 254                 case DRAWELLIPSE:
 255                     gc.drawEllipse(
 256                         buf.getInt(),
 257                         buf.getInt(),
 258                         buf.getInt(),
 259                         buf.getInt());
 260                     break;
 261                 case DRAWFOCUSRING:
 262                     gc.drawFocusRing(
 263                         buf.getInt(),
 264                         buf.getInt(),
 265                         buf.getInt(),
 266                         buf.getInt(),
 267                         buf.getInt());
 268                     break;
 269                 case SETALPHA:
 270                     gc.setAlpha(buf.getFloat());
 271                     break;
 272                 case BEGINTRANSPARENCYLAYER:
 273                     gc.beginTransparencyLayer(buf.getFloat());
 274                     break;
 275                 case ENDTRANSPARENCYLAYER:
 276                     gc.endTransparencyLayer();
 277                     break;
 278                 case STROKE_PATH:
 279                     gc.strokePath(getPath(gm, buf));
 280                     break;
 281                 case FILL_PATH:
 282                     gc.fillPath(getPath(gm, buf));
 283                     break;
 284                 case SETSHADOW:
 285                     gc.setShadow(
 286                         buf.getFloat(),
 287                         buf.getFloat(),
 288                         buf.getFloat(),
 289                         buf.getInt());
 290                     break;
 291                 case DRAWSTRING:
 292                     gc.drawString(
 293                         (WCFont) gm.getRef(buf.getInt()),
 294                         bdata.getString(buf.getInt()),
 295                         (buf.getInt() == -1),           // rtl flag
 296                         buf.getInt(), buf.getInt(),     // from and to positions
 297                         buf.getFloat(), buf.getFloat());// (x,y) position
 298                     break;
 299                 case DRAWSTRING_FAST:
 300                     gc.drawString(
 301                         (WCFont) gm.getRef(buf.getInt()),
 302                         bdata.getIntArray(buf.getInt()), //glyphs
 303                         bdata.getFloatArray(buf.getInt()), //offsets
 304                         buf.getFloat(),
 305                         buf.getFloat());
 306                     break;
 307                 case DRAWWIDGET:
 308                     gc.drawWidget((RenderTheme)(gm.getRef(buf.getInt())),
 309                         gm.getRef(buf.getInt()), buf.getInt(), buf.getInt());
 310                     break;
 311                 case DRAWSCROLLBAR:
 312                     gc.drawScrollbar((ScrollBarTheme)(gm.getRef(buf.getInt())),
 313                         gm.getRef(buf.getInt()), buf.getInt(), buf.getInt(),
 314                         buf.getInt(), buf.getInt());
 315                     break;
 316                 case RENDERMEDIAPLAYER:
 317                     WCMediaPlayer mp = (WCMediaPlayer)gm.getRef(buf.getInt());
 318                     mp.render(gc,
 319                             buf.getInt(),   // x
 320                             buf.getInt(),   // y
 321                             buf.getInt(),   // width
 322                             buf.getInt());  // height
 323                     break;
 324                 case CONCATTRANSFORM_FFFFFF:
 325                     gc.concatTransform(new WCTransform(
 326                             buf.getFloat(), buf.getFloat(), buf.getFloat(),
 327                             buf.getFloat(), buf.getFloat(), buf.getFloat()));
 328                     break;
 329                 case SET_TRANSFORM:
 330                     gc.setTransform(new WCTransform(
 331                             buf.getFloat(), buf.getFloat(), buf.getFloat(),
 332                             buf.getFloat(), buf.getFloat(), buf.getFloat()));
 333                     break;
 334                 case COPYREGION:
 335                     WCPageBackBuffer buffer = (WCPageBackBuffer)gm.getRef(buf.getInt());
 336                     buffer.copyArea(buf.getInt(), buf.getInt(), buf.getInt(), buf.getInt(),
 337                                     buf.getInt(), buf.getInt());
 338                     break;
 339                 case DECODERQ:
 340                     WCRenderQueue _rq = (WCRenderQueue)gm.getRef(buf.getInt());
 341                     _rq.decode(gc.getFontSmoothingType());
 342                     break;
 343                 case ROTATE:
 344                     gc.rotate(buf.getFloat());
 345                     break;
 346                 case RENDERMEDIACONTROL:
 347                     RenderMediaControls.paintControl(gc,
 348                             buf.getInt(),   // control type
 349                             buf.getInt(),   // x
 350                             buf.getInt(),   // y
 351                             buf.getInt(),   // width
 352                             buf.getInt());  // height
 353                     break;
 354                 case RENDERMEDIA_TIMETRACK: {
 355                     int n = buf.getInt();   // number of timeRange pairs
 356                     float[] buffered = new float[n*2];
 357                     buf.asFloatBuffer().get(buffered);
 358                     buf.position(buf.position() + n*4 *2);
 359                     RenderMediaControls.paintTimeSliderTrack(gc,
 360                             buf.getFloat(), // duration
 361                             buf.getFloat(), // currentTime
 362                             buffered,       // buffered() timeRanges
 363                             buf.getInt(),   // x
 364                             buf.getInt(),   // y
 365                             buf.getInt(),   // width
 366                             buf.getInt());  // height
 367                      break;
 368                 }
 369                 case RENDERMEDIA_VOLUMETRACK:
 370                     RenderMediaControls.paintVolumeTrack(gc,
 371                             buf.getFloat(), // curVolume
 372                             buf.getInt() != 0,  // muted
 373                             buf.getInt(),   // x
 374                             buf.getInt(),   // y
 375                             buf.getInt(),   // width
 376                             buf.getInt());  // height
 377                     break;
 378                 default:
 379                     log.fine("ERROR. Unknown primitive found");
 380                     break;
 381             }
 382         }
 383     }
 384 
 385 
 386     private static void drawPattern(
 387             WCGraphicsContext gc,
 388             Object imgFrame,
 389             WCRectangle srcRect,
 390             WCTransform patternTransform,
 391             WCPoint phase,
 392             WCRectangle destRect)
 393     {
 394         WCImage img = WCImage.getImage(imgFrame);
 395         if (img != null) {
 396             // RT-10059: drawImage() may have to create the texture
 397             // lazily, and may fail with an OutOfMemory error
 398             // if the texture is too large. This is a legitimate
 399             // situation that should be handled gracefully. It should
 400             // not cause us to quit painting other page components.
 401             try {
 402                 gc.drawPattern(
 403                     img,
 404                     srcRect,
 405                     patternTransform,
 406                     phase,
 407                     destRect);
 408             } catch (OutOfMemoryError error) {
 409                 error.printStackTrace();
 410             }
 411         }
 412     }
 413 
 414     private static void drawImage(
 415             WCGraphicsContext gc,
 416             Object imgFrame,
 417             float dstx, float dsty, float dstw, float dsth,
 418             float srcx, float srcy, float srcw, float srch)
 419     {
 420         WCImage img = WCImage.getImage(imgFrame);
 421         if (img != null) {
 422             // RT-10059: drawImage() may have to create the texture
 423             // lazily, and may fail with an OutOfMemory error
 424             // if the texture is too large. This is a legitimate
 425             // situation that should be handled gracefully. It should
 426             // not cause us to quit painting other page components.
 427             try {
 428                 gc.drawImage(
 429                     img,
 430                     dstx, dsty, dstw, dsth,
 431                     srcx, srcy, srcw, srch);
 432             } catch (OutOfMemoryError error) {
 433                 error.printStackTrace();
 434             }
 435         }
 436     }
 437 
 438     private static boolean getBoolean(ByteBuffer buf) {
 439         return 0 != buf.getInt();
 440     }
 441 
 442     private static float[] getFloatArray(ByteBuffer buf) {
 443         float[] array = new float[buf.getInt()];
 444         for (int i = 0; i < array.length; i++) {
 445             array[i] = buf.getFloat();
 446         }
 447         return array;
 448     }
 449 
 450     private static WCPath getPath(WCGraphicsManager gm, ByteBuffer buf) {
 451         WCPath path = (WCPath) gm.getRef(buf.getInt());
 452         path.setWindingRule(buf.getInt());
 453         return path;
 454     }
 455 
 456     private static WCPoint getPoint(ByteBuffer buf) {
 457         return new WCPoint(buf.getFloat(),
 458                            buf.getFloat());
 459     }
 460 
 461     private static WCRectangle getRectangle(ByteBuffer buf) {
 462         return new WCRectangle(buf.getFloat(),
 463                                buf.getFloat(),
 464                                buf.getFloat(),
 465                                buf.getFloat());
 466     }
 467 
 468     private static WCGradient getGradient(WCGraphicsContext gc, ByteBuffer buf) {
 469         WCPoint p1 = getPoint(buf);
 470         WCPoint p2 = getPoint(buf);
 471         WCGradient gradient = getBoolean(buf)
 472                 ? gc.createRadialGradient(p1, buf.getFloat(), p2, buf.getFloat())
 473                 : gc.createLinearGradient(p1, p2);
 474 
 475         boolean proportional = getBoolean(buf);
 476         int spreadMethod = buf.getInt();
 477         if (gradient != null) {
 478             gradient.setProportional(proportional);
 479             gradient.setSpreadMethod(spreadMethod);
 480         }
 481         int count = buf.getInt();
 482         for (int i = 0; i < count; i++) {
 483             int color = buf.getInt();
 484             float offset = buf.getFloat();
 485             if (gradient != null) {
 486                 gradient.addStop(color, offset);
 487             }
 488         }
 489         return gradient;
 490     }
 491 }