1 /* 2 * Copyright (c) 2011, 2016, 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.lang.annotation.Native; 29 import com.sun.javafx.logging.PlatformLogger; 30 import com.sun.javafx.logging.PlatformLogger.Level; 31 import com.sun.webkit.Invoker; 32 import java.nio.ByteBuffer; 33 import java.util.HashMap; 34 import java.util.LinkedList; 35 import java.util.concurrent.atomic.AtomicInteger; 36 37 public abstract class WCRenderQueue extends Ref { 38 private final static AtomicInteger idCountObj = new AtomicInteger(0); 39 private final static PlatformLogger log = 40 PlatformLogger.getLogger(WCRenderQueue.class.getName()); 41 @Native public final static int MAX_QUEUE_SIZE = 0x80000; 42 43 private final LinkedList<BufferData> buffers = new LinkedList<BufferData>(); 44 private BufferData currentBuffer = new BufferData(); 45 private final WCRectangle clip; 46 private int size = 0; 47 private final boolean opaque; 48 49 // Associated graphics context (currently used to draw to a buffered image). 50 protected final WCGraphicsContext gc; 51 52 protected WCRenderQueue(WCGraphicsContext gc) { 53 this.clip = null; 54 this.opaque = false; 55 this.gc = gc; 56 } 57 58 protected WCRenderQueue(WCRectangle clip, boolean opaque) { 59 this.clip = clip; 60 this.opaque = opaque; 61 this.gc = null; 62 } 63 64 public synchronized int getSize() { 65 return size; 66 } 67 68 public synchronized void addBuffer(ByteBuffer buffer) { 69 if (log.isLoggable(Level.FINE) && buffers.isEmpty()) { 70 log.fine("'{'WCRenderQueue{0}[{1}]", 71 new Object[]{hashCode(), idCountObj.incrementAndGet()}); 72 } 73 currentBuffer.setBuffer(buffer); 74 buffers.addLast(currentBuffer); 75 currentBuffer = new BufferData(); 76 size += buffer.capacity(); 77 if (size > MAX_QUEUE_SIZE && gc!=null) { 78 // It is isolated queue over the canvas image [image-gc!=null]. 79 // We need to flush the changes periodically 80 // by the same reason as in [WebPage.addLastRQ]. 81 flush(); 82 } 83 } 84 85 public synchronized boolean isEmpty() { 86 return buffers.isEmpty(); 87 } 88 89 public synchronized void decode(WCGraphicsContext gc) { 90 for (BufferData bdata : buffers) { 91 try { 92 GraphicsDecoder.decode( 93 WCGraphicsManager.getGraphicsManager(), gc, bdata); 94 } catch (RuntimeException e) { 95 e.printStackTrace(System.err); 96 } 97 } 98 dispose(); 99 } 100 101 public synchronized void decode() { 102 assert (gc != null); 103 decode(gc); 104 gc.flush(); 105 } 106 107 public synchronized void decode(int fontSmoothingType) { 108 assert (gc != null); 109 gc.setFontSmoothingType(fontSmoothingType); 110 decode(); 111 } 112 113 protected abstract void flush(); 114 115 private void fwkFlush() { 116 flush(); 117 } 118 119 private void fwkAddBuffer(ByteBuffer buffer) { 120 addBuffer(buffer); 121 } 122 123 public WCRectangle getClip() { 124 return clip; 125 } 126 127 public synchronized void dispose() { 128 int n = buffers.size(); 129 if (n > 0) { 130 int i = 0; 131 final Object[] arr = new Object[n]; 132 for (BufferData bdata: buffers) { 133 arr[i++] = bdata.getBuffer(); 134 } 135 buffers.clear(); 136 Invoker.getInvoker().invokeOnEventThread(() -> { 137 twkRelease(arr); 138 }); 139 size = 0; 140 if (log.isLoggable(Level.FINE)) { 141 log.fine("'}'WCRenderQueue{0}[{1}]", 142 new Object[]{hashCode(), idCountObj.decrementAndGet()}); 143 } 144 } 145 } 146 147 protected abstract void disposeGraphics(); 148 149 private void fwkDisposeGraphics() { 150 disposeGraphics(); 151 } 152 153 private native void twkRelease(Object[] bufs); 154 155 /*is called from native*/ 156 private int refString(String str) { 157 return currentBuffer.addString(str); 158 } 159 160 /*is called from native*/ 161 private int refIntArr(int[] arr) { 162 return currentBuffer.addIntArray(arr); 163 } 164 165 /*is called from native*/ 166 private int refFloatArr(float[] arr) { 167 return currentBuffer.addFloatArray(arr); 168 } 169 170 public boolean isOpaque() { 171 return opaque; 172 } 173 174 @Override public synchronized String toString() { 175 return "WCRenderQueue{" 176 + "clip=" + clip + ", " 177 + "size=" + size + ", " 178 + "opaque=" + opaque 179 + "}"; 180 } 181 } 182 183 final class BufferData { 184 /* For passing data that does not fit into the queue */ 185 private final AtomicInteger idCount = new AtomicInteger(0); 186 private final HashMap<Integer,String> strMap = 187 new HashMap<Integer,String>(); 188 private final HashMap<Integer,int[]> intArrMap = 189 new HashMap<Integer,int[]>(); 190 private final HashMap<Integer,float[]> floatArrMap = 191 new HashMap<Integer,float[]>(); 192 193 private ByteBuffer buffer; 194 195 private int createID() { 196 return idCount.incrementAndGet(); 197 } 198 199 int addIntArray(int[] a) { 200 int id = createID(); 201 intArrMap.put(id, a); 202 return id; 203 } 204 205 int[] getIntArray(int id) { 206 return intArrMap.get(id); 207 } 208 209 int addFloatArray(float[] a) { 210 int id = createID(); 211 floatArrMap.put(id, a); 212 return id; 213 } 214 215 float[] getFloatArray(int id) { 216 return floatArrMap.get(id); 217 } 218 219 int addString(String s) { 220 int id = createID(); 221 strMap.put(id, s); 222 return id; 223 } 224 225 String getString(int id) { 226 return strMap.get(id); 227 } 228 229 ByteBuffer getBuffer() { 230 return buffer; 231 } 232 233 void setBuffer(ByteBuffer buffer) { 234 this.buffer = buffer; 235 } 236 }