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