/* * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.webkit; import java.security.AccessController; import java.security.PrivilegedAction; public class Timer { private static Timer instance; private static Mode mode; long fireTime; Timer() { } public static enum Mode { PLATFORM_TICKS, SEPARATE_THREAD } public synchronized static Mode getMode() { if (mode == null) { mode = Boolean.valueOf(AccessController.doPrivileged( (PrivilegedAction) () -> System.getProperty( "com.sun.webkit.platformticks", "true"))) ? Mode.PLATFORM_TICKS : Mode.SEPARATE_THREAD; } return mode; } public synchronized static Timer getTimer() { if (instance == null) { instance = (getMode() == Mode.PLATFORM_TICKS) ? new Timer() : new SeparateThreadTimer(); } return instance; } public synchronized void notifyTick() { if (fireTime > 0 && fireTime <= System.currentTimeMillis()) { fireTimerEvent(fireTime); } } void fireTimerEvent(long time) { boolean needFire = false; synchronized (this) { // The event is not fired if either: // - webkit has stopped the timer; // - webkit has updated the timer. if (time == fireTime) { needFire = true; fireTime = 0; } } if (needFire) { WebPage.lockPage(); try { twkFireTimerEvent(); } finally { WebPage.unlockPage(); } } } synchronized void setFireTime(long time) { fireTime = time; } /** * @param fireTime time to wait in seconds */ private static void fwkSetFireTime(double fireTime) { getTimer().setFireTime((long)Math.ceil(fireTime * 1000)); } private static void fwkStopTimer() { getTimer().setFireTime(0); } private static native void twkFireTimerEvent(); } final class SeparateThreadTimer extends Timer implements Runnable { private final Invoker invoker; private final FireRunner fireRunner; private final Thread thread; SeparateThreadTimer() { invoker = Invoker.getInvoker(); fireRunner = new FireRunner(); thread = new Thread(this, "WebPane-Timer"); thread.setDaemon(true); } private final class FireRunner implements Runnable { private volatile long time; private Runnable forTime(long time) { this.time = time; return this; } @Override public void run() { fireTimerEvent(time); } } @Override synchronized void setFireTime(long time) { super.setFireTime(time); if (thread.getState() == Thread.State.NEW) { thread.start(); } notifyAll(); } @Override public synchronized void run() { while (true) { try { if (fireTime > 0) { long curTime = System.currentTimeMillis(); while (fireTime > curTime) { wait(fireTime - curTime); curTime = System.currentTimeMillis(); } if (fireTime > 0) { invoker.invokeOnEventThread(fireRunner.forTime(fireTime)); } } wait(); } catch (InterruptedException e) { break; } } } @Override public void notifyTick() { assert false; } }