Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/apple/laf/JRSUIControl.java
38829 views
/*1* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package apple.laf;2627import java.nio.*;28import java.util.*;2930import apple.laf.JRSUIConstants.*;3132public final class JRSUIControl {33private static native int initNativeJRSUI();3435private static native long getPtrOfBuffer(ByteBuffer byteBuffer);36private static native long getCFDictionary(boolean flipped);37private static native void disposeCFDictionary(long cfDictionaryPtr);3839private static native int syncChanges(long cfDictionaryPtr, long byteBufferPtr);4041// private static native int paint(long cfDictionaryPtr, long oldProperties, long newProperties, OSXSurfaceData osxsd, double x, double y, double w, double h);42// private static native int paintChanges(long cfDictionaryPtr, long byteBufferPtr, long oldProperties, long newProperties, OSXSurfaceData osxsd, double x, double y, double w, double h);4344private static native int paintToCGContext (long cgContext, long cfDictionaryPtr, long oldProperties, long newProperties, double x, double y, double w, double h);45private static native int paintChangesToCGContext (long cgContext, long cfDictionaryPtr, long oldProperties, long newProperties, double x, double y, double w, double h, long byteBufferPtr);4647private static native int paintImage (int[] data, int imgW, int imgH, long cfDictionaryPtr, long oldProperties, long newProperties, double x, double y, double w, double h);48private static native int paintChangesImage (int[] data, int imgW, int imgH, long cfDictionaryPtr, long oldProperties, long newProperties, double x, double y, double w, double h, long byteBufferPtr);4950private static native int getNativeHitPart( long cfDictionaryPtr, long oldProperties, long newProperties, double x, double y, double w, double h, double hitX, double hitY);51private static native void getNativePartBounds(final double[] rect, long cfDictionaryPtr, long oldProperties, long newProperties, double x, double y, double w, double h, int part);52private static native double getNativeScrollBarOffsetChange( long cfDictionaryPtr, long oldProperties, long newProperties, double x, double y, double w, double h, int offset, int visibleAmount, int extent);5354private static final int INCOHERENT = 2;55private static final int NOT_INIT = 1;56private static final int SUCCESS = 0;57private static final int NULL_PTR = -1;58private static final int NULL_CG_REF = -2;5960private static int nativeJRSInitialized = NOT_INIT;616263public static void initJRSUI() {64if (nativeJRSInitialized == SUCCESS) return;65nativeJRSInitialized = initNativeJRSUI();66if (nativeJRSInitialized != SUCCESS) throw new RuntimeException("JRSUI could not be initialized (" + nativeJRSInitialized + ").");67}6869private static final int NIO_BUFFER_SIZE = 128;70private static class ThreadLocalByteBuffer {71final ByteBuffer buffer;72final long ptr;7374public ThreadLocalByteBuffer() {75buffer = ByteBuffer.allocateDirect(NIO_BUFFER_SIZE);76buffer.order(ByteOrder.nativeOrder());77ptr = getPtrOfBuffer(buffer);78}79}8081private static final ThreadLocal<ThreadLocalByteBuffer> threadLocal = new ThreadLocal<ThreadLocalByteBuffer>();82private static ThreadLocalByteBuffer getThreadLocalBuffer() {83ThreadLocalByteBuffer byteBuffer = threadLocal.get();84if (byteBuffer != null) return byteBuffer;8586byteBuffer = new ThreadLocalByteBuffer();87threadLocal.set(byteBuffer);88return byteBuffer;89}9091private final HashMap<Key, DoubleValue> nativeMap;92private final HashMap<Key, DoubleValue> changes;93private long cfDictionaryPtr;9495private long priorEncodedProperties;96private long currentEncodedProperties;97private final boolean flipped;9899public JRSUIControl(final boolean flipped){100this.flipped = flipped;101cfDictionaryPtr = getCFDictionary(flipped);102if (cfDictionaryPtr == 0) throw new RuntimeException("Unable to create native representation");103nativeMap = new HashMap<Key, DoubleValue>();104changes = new HashMap<Key, DoubleValue>();105}106107JRSUIControl(final JRSUIControl other) {108flipped = other.flipped;109cfDictionaryPtr = getCFDictionary(flipped);110if (cfDictionaryPtr == 0) throw new RuntimeException("Unable to create native representation");111nativeMap = new HashMap<Key, DoubleValue>();112changes = new HashMap<Key, DoubleValue>(other.nativeMap);113changes.putAll(other.changes);114}115116protected synchronized final void finalize() throws Throwable {117if (cfDictionaryPtr == 0) return;118disposeCFDictionary(cfDictionaryPtr);119cfDictionaryPtr = 0;120}121122123enum BufferState {124NO_CHANGE,125ALL_CHANGES_IN_BUFFER,126SOME_CHANGES_IN_BUFFER,127CHANGE_WONT_FIT_IN_BUFFER;128}129130private BufferState loadBufferWithChanges(final ThreadLocalByteBuffer localByteBuffer) {131final ByteBuffer buffer = localByteBuffer.buffer;132buffer.rewind();133134for (final JRSUIConstants.Key key : new HashSet<JRSUIConstants.Key>(changes.keySet())) {135final int changeIndex = buffer.position();136final JRSUIConstants.DoubleValue value = changes.get(key);137138try {139buffer.putLong(key.getConstantPtr());140buffer.put(value.getTypeCode());141value.putValueInBuffer(buffer);142} catch (final BufferOverflowException e) {143return handleBufferOverflow(buffer, changeIndex);144} catch (final RuntimeException e) {145System.err.println(this);146throw e;147}148149if (buffer.position() >= NIO_BUFFER_SIZE - 8) {150return handleBufferOverflow(buffer, changeIndex);151}152153changes.remove(key);154nativeMap.put(key, value);155}156157buffer.putLong(0);158return BufferState.ALL_CHANGES_IN_BUFFER;159}160161private BufferState handleBufferOverflow(final ByteBuffer buffer, final int changeIndex) {162if (changeIndex == 0) {163buffer.putLong(0, 0);164return BufferState.CHANGE_WONT_FIT_IN_BUFFER;165}166167buffer.putLong(changeIndex, 0);168return BufferState.SOME_CHANGES_IN_BUFFER;169}170171private synchronized void set(final JRSUIConstants.Key key, final JRSUIConstants.DoubleValue value) {172final JRSUIConstants.DoubleValue existingValue = nativeMap.get(key);173174if (existingValue != null && existingValue.equals(value)) {175changes.remove(key);176return;177}178179changes.put(key, value);180}181182public void set(final JRSUIState state) {183state.apply(this);184}185186void setEncodedState(final long state) {187currentEncodedProperties = state;188}189190void set(final JRSUIConstants.Key key, final double value) {191set(key, new JRSUIConstants.DoubleValue(value));192}193194// private static final Color blue = new Color(0x00, 0x00, 0xFF, 0x40);195// private static void paintDebug(Graphics2D g, double x, double y, double w, double h) {196// final Color prev = g.getColor();197// g.setColor(blue);198// g.drawRect((int)x, (int)y, (int)w, (int)h);199// g.setColor(prev);200// }201202// private static int paintsWithNoChange = 0;203// private static int paintsWithChangesThatFit = 0;204// private static int paintsWithChangesThatOverflowed = 0;205206public void paint(final int[] data, final int imgW, final int imgH, final double x, final double y, final double w, final double h) {207paintImage(data, imgW, imgH, x, y, w, h);208priorEncodedProperties = currentEncodedProperties;209}210211private synchronized int paintImage(final int[] data, final int imgW, final int imgH, final double x, final double y, final double w, final double h) {212if (changes.isEmpty()) {213// paintsWithNoChange++;214return paintImage(data, imgW, imgH, cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h);215}216217final ThreadLocalByteBuffer localByteBuffer = getThreadLocalBuffer();218BufferState bufferState = loadBufferWithChanges(localByteBuffer);219220// fast tracking this, since it's the likely scenario221if (bufferState == BufferState.ALL_CHANGES_IN_BUFFER) {222// paintsWithChangesThatFit++;223return paintChangesImage(data, imgW, imgH, cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h, localByteBuffer.ptr);224}225226while (bufferState == BufferState.SOME_CHANGES_IN_BUFFER) {227final int status = syncChanges(cfDictionaryPtr, localByteBuffer.ptr);228if (status != SUCCESS) throw new RuntimeException("JRSUI failed to sync changes into the native buffer: " + this);229bufferState = loadBufferWithChanges(localByteBuffer);230}231232if (bufferState == BufferState.CHANGE_WONT_FIT_IN_BUFFER) {233throw new RuntimeException("JRSUI failed to sync changes to the native buffer, because some change was too big: " + this);234}235236// implicitly ALL_CHANGES_IN_BUFFER, now that we sync'd the buffer down to native a few times237// paintsWithChangesThatOverflowed++;238return paintChangesImage(data, imgW, imgH, cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h, localByteBuffer.ptr);239}240241public void paint(final long cgContext, final double x, final double y, final double w, final double h) {242paintToCGContext(cgContext, x, y, w, h);243priorEncodedProperties = currentEncodedProperties;244}245246private synchronized int paintToCGContext(final long cgContext, final double x, final double y, final double w, final double h) {247if (changes.isEmpty()) {248// paintsWithNoChange++;249return paintToCGContext(cgContext, cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h);250}251252final ThreadLocalByteBuffer localByteBuffer = getThreadLocalBuffer();253BufferState bufferState = loadBufferWithChanges(localByteBuffer);254255// fast tracking this, since it's the likely scenario256if (bufferState == BufferState.ALL_CHANGES_IN_BUFFER) {257// paintsWithChangesThatFit++;258return paintChangesToCGContext(cgContext, cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h, localByteBuffer.ptr);259}260261while (bufferState == BufferState.SOME_CHANGES_IN_BUFFER) {262final int status = syncChanges(cfDictionaryPtr, localByteBuffer.ptr);263if (status != SUCCESS) throw new RuntimeException("JRSUI failed to sync changes into the native buffer: " + this);264bufferState = loadBufferWithChanges(localByteBuffer);265}266267if (bufferState == BufferState.CHANGE_WONT_FIT_IN_BUFFER) {268throw new RuntimeException("JRSUI failed to sync changes to the native buffer, because some change was too big: " + this);269}270271// implicitly ALL_CHANGES_IN_BUFFER, now that we sync'd the buffer down to native a few times272// paintsWithChangesThatOverflowed++;273return paintChangesToCGContext(cgContext, cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h, localByteBuffer.ptr);274}275276277Hit getHitForPoint(final double x, final double y, final double w, final double h, final double hitX, final double hitY) {278sync();279// reflect hitY about the midline of the control before sending to native280final Hit hit = JRSUIConstants.getHit(getNativeHitPart(cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h, hitX, 2 * y + h - hitY));281priorEncodedProperties = currentEncodedProperties;282return hit;283}284285void getPartBounds(final double[] rect, final double x, final double y, final double w, final double h, final int part) {286if (rect == null) throw new NullPointerException("Cannot load null rect");287if (rect.length != 4) throw new IllegalArgumentException("Rect must have four elements");288289sync();290getNativePartBounds(rect, cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h, part);291priorEncodedProperties = currentEncodedProperties;292}293294double getScrollBarOffsetChange(final double x, final double y, final double w, final double h, final int offset, final int visibleAmount, final int extent) {295sync();296final double offsetChange = getNativeScrollBarOffsetChange(cfDictionaryPtr, priorEncodedProperties, currentEncodedProperties, x, y, w, h, offset, visibleAmount, extent);297priorEncodedProperties = currentEncodedProperties;298return offsetChange;299}300301private void sync() {302if (changes.isEmpty()) return;303304final ThreadLocalByteBuffer localByteBuffer = getThreadLocalBuffer();305BufferState bufferState = loadBufferWithChanges(localByteBuffer);306if (bufferState == BufferState.ALL_CHANGES_IN_BUFFER) {307final int status = syncChanges(cfDictionaryPtr, localByteBuffer.ptr);308if (status != SUCCESS) throw new RuntimeException("JRSUI failed to sync changes into the native buffer: " + this);309return;310}311312while (bufferState == BufferState.SOME_CHANGES_IN_BUFFER) {313final int status = syncChanges(cfDictionaryPtr, localByteBuffer.ptr);314if (status != SUCCESS) throw new RuntimeException("JRSUI failed to sync changes into the native buffer: " + this);315bufferState = loadBufferWithChanges(localByteBuffer);316}317318if (bufferState == BufferState.CHANGE_WONT_FIT_IN_BUFFER) {319throw new RuntimeException("JRSUI failed to sync changes to the native buffer, because some change was too big: " + this);320}321}322323@Override324public int hashCode() {325int bits = (int)(currentEncodedProperties ^ (currentEncodedProperties >>> 32));326bits ^= nativeMap.hashCode();327bits ^= changes.hashCode();328return bits;329}330331@Override332public boolean equals(final Object obj) {333if (!(obj instanceof JRSUIControl)) return false;334final JRSUIControl other = (JRSUIControl)obj;335if (currentEncodedProperties != other.currentEncodedProperties) return false;336if (!nativeMap.equals(other.nativeMap)) return false;337if (!changes.equals(other.changes)) return false;338return true;339}340341@Override342public String toString() {343final StringBuilder builder = new StringBuilder("JRSUIControl[inNative:");344builder.append(Arrays.toString(nativeMap.entrySet().toArray()));345builder.append(", changes:");346builder.append(Arrays.toString(changes.entrySet().toArray()));347builder.append("]");348return builder.toString();349}350}351352353