changeset 50695:0bb0e464ee76

8198991: Move Java2D demo to the open repository Reviewed-by: serb, jeff
author prr
date Mon, 14 May 2018 08:58:32 -0700
parents 752645a158ff
children 23a8ccafa7ba
files make/CompileDemos.gmk src/demo/share/jfc/J2Ddemo/README.txt src/demo/share/jfc/J2Ddemo/fonts/A.ttf src/demo/share/jfc/J2Ddemo/images/bld.jpg src/demo/share/jfc/J2Ddemo/images/bld@2x.jpg src/demo/share/jfc/J2Ddemo/images/boat.png src/demo/share/jfc/J2Ddemo/images/boat@2x.png src/demo/share/jfc/J2Ddemo/images/box.gif src/demo/share/jfc/J2Ddemo/images/box.png src/demo/share/jfc/J2Ddemo/images/box@2x.png src/demo/share/jfc/J2Ddemo/images/boxwave.gif src/demo/share/jfc/J2Ddemo/images/boxwave.png src/demo/share/jfc/J2Ddemo/images/boxwave@2x.png src/demo/share/jfc/J2Ddemo/images/clone.gif src/demo/share/jfc/J2Ddemo/images/clone@2x.gif src/demo/share/jfc/J2Ddemo/images/clouds.jpg src/demo/share/jfc/J2Ddemo/images/clouds@2x.jpg src/demo/share/jfc/J2Ddemo/images/duke.gif src/demo/share/jfc/J2Ddemo/images/duke.png src/demo/share/jfc/J2Ddemo/images/duke.running.gif src/demo/share/jfc/J2Ddemo/images/duke@2x.gif src/demo/share/jfc/J2Ddemo/images/duke@2x.png src/demo/share/jfc/J2Ddemo/images/dukeplug.gif src/demo/share/jfc/J2Ddemo/images/dukeplug.png src/demo/share/jfc/J2Ddemo/images/dukeplug@2x.png src/demo/share/jfc/J2Ddemo/images/fight.gif src/demo/share/jfc/J2Ddemo/images/fight.png src/demo/share/jfc/J2Ddemo/images/fight@2x.png src/demo/share/jfc/J2Ddemo/images/globe.gif src/demo/share/jfc/J2Ddemo/images/globe.png src/demo/share/jfc/J2Ddemo/images/globe@2x.png src/demo/share/jfc/J2Ddemo/images/jumptojavastrip.png src/demo/share/jfc/J2Ddemo/images/loop.gif src/demo/share/jfc/J2Ddemo/images/loop@2x.gif src/demo/share/jfc/J2Ddemo/images/looping.gif src/demo/share/jfc/J2Ddemo/images/looping@2x.gif src/demo/share/jfc/J2Ddemo/images/magnify.gif src/demo/share/jfc/J2Ddemo/images/magnify.png src/demo/share/jfc/J2Ddemo/images/magnify@2x.png src/demo/share/jfc/J2Ddemo/images/painting.gif src/demo/share/jfc/J2Ddemo/images/painting.png src/demo/share/jfc/J2Ddemo/images/painting@2x.png src/demo/share/jfc/J2Ddemo/images/print.gif src/demo/share/jfc/J2Ddemo/images/print@2x.gif src/demo/share/jfc/J2Ddemo/images/remove.gif src/demo/share/jfc/J2Ddemo/images/remove@2x.gif src/demo/share/jfc/J2Ddemo/images/snooze.gif src/demo/share/jfc/J2Ddemo/images/snooze.png src/demo/share/jfc/J2Ddemo/images/snooze@2x.png src/demo/share/jfc/J2Ddemo/images/star7.gif src/demo/share/jfc/J2Ddemo/images/star7.png src/demo/share/jfc/J2Ddemo/images/star7@2x.png src/demo/share/jfc/J2Ddemo/images/start.gif src/demo/share/jfc/J2Ddemo/images/start2.gif src/demo/share/jfc/J2Ddemo/images/start2@2x.gif src/demo/share/jfc/J2Ddemo/images/start@2x.gif src/demo/share/jfc/J2Ddemo/images/stop.gif src/demo/share/jfc/J2Ddemo/images/stop2.gif src/demo/share/jfc/J2Ddemo/images/stop2@2x.gif src/demo/share/jfc/J2Ddemo/images/stop@2x.gif src/demo/share/jfc/J2Ddemo/images/surfing.gif src/demo/share/jfc/J2Ddemo/images/surfing.png src/demo/share/jfc/J2Ddemo/images/surfing@2x.png src/demo/share/jfc/J2Ddemo/images/thumbsup.gif src/demo/share/jfc/J2Ddemo/images/thumbsup.png src/demo/share/jfc/J2Ddemo/images/thumbsup@2x.png src/demo/share/jfc/J2Ddemo/images/tip.gif src/demo/share/jfc/J2Ddemo/images/tip.png src/demo/share/jfc/J2Ddemo/images/tip@2x.png src/demo/share/jfc/J2Ddemo/java2d/AnimatingContext.java src/demo/share/jfc/J2Ddemo/java2d/AnimatingControlsSurface.java src/demo/share/jfc/J2Ddemo/java2d/AnimatingSurface.java src/demo/share/jfc/J2Ddemo/java2d/CloningFeature.java src/demo/share/jfc/J2Ddemo/java2d/ControlsSurface.java src/demo/share/jfc/J2Ddemo/java2d/CustomControls.java src/demo/share/jfc/J2Ddemo/java2d/CustomControlsContext.java src/demo/share/jfc/J2Ddemo/java2d/DemoFonts.java src/demo/share/jfc/J2Ddemo/java2d/DemoGroup.java src/demo/share/jfc/J2Ddemo/java2d/DemoImages.java src/demo/share/jfc/J2Ddemo/java2d/DemoInstVarsAccessor.java src/demo/share/jfc/J2Ddemo/java2d/DemoInstVarsAccessorImplBase.java src/demo/share/jfc/J2Ddemo/java2d/DemoPanel.java src/demo/share/jfc/J2Ddemo/java2d/GlobalControls.java src/demo/share/jfc/J2Ddemo/java2d/GlobalPanel.java src/demo/share/jfc/J2Ddemo/java2d/Intro.java src/demo/share/jfc/J2Ddemo/java2d/J2Ddemo.java src/demo/share/jfc/J2Ddemo/java2d/MemoryMonitor.java src/demo/share/jfc/J2Ddemo/java2d/PerformanceMonitor.java src/demo/share/jfc/J2Ddemo/java2d/RunWindow.java src/demo/share/jfc/J2Ddemo/java2d/Surface.java src/demo/share/jfc/J2Ddemo/java2d/TextureChooser.java src/demo/share/jfc/J2Ddemo/java2d/Tools.java src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/Arcs.java src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/BezierAnim.java src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/Curves.java src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/Ellipses.java src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/Areas.java src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/ClipAnim.java src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/Intersection.java src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/Text.java src/demo/share/jfc/J2Ddemo/java2d/demos/Colors/BullsEye.java src/demo/share/jfc/J2Ddemo/java2d/demos/Colors/ColorConvert.java src/demo/share/jfc/J2Ddemo/java2d/demos/Colors/Rotator3D.java src/demo/share/jfc/J2Ddemo/java2d/demos/Composite/ACimages.java src/demo/share/jfc/J2Ddemo/java2d/demos/Composite/ACrules.java src/demo/share/jfc/J2Ddemo/java2d/demos/Composite/FadeAnim.java src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/AllFonts.java src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/AttributedStr.java src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/Highlighting.java src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/Outline.java src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/Tree.java src/demo/share/jfc/J2Ddemo/java2d/demos/Images/DukeAnim.java src/demo/share/jfc/J2Ddemo/java2d/demos/Images/ImageOps.java src/demo/share/jfc/J2Ddemo/java2d/demos/Images/JPEGFlip.java src/demo/share/jfc/J2Ddemo/java2d/demos/Images/WarpImage.java src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/Caps.java src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/Dash.java src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/Joins.java src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/LineAnim.java src/demo/share/jfc/J2Ddemo/java2d/demos/Mix/Balls.java src/demo/share/jfc/J2Ddemo/java2d/demos/Mix/BezierScroller.java src/demo/share/jfc/J2Ddemo/java2d/demos/Mix/Stars3D.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/GradAnim.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/Gradient.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/Texture.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/TextureAnim.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/Append.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/CurveQuadTo.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/FillStroke.java src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/WindingRule.java src/demo/share/jfc/J2Ddemo/java2d/demos/Transforms/Rotate.java src/demo/share/jfc/J2Ddemo/java2d/demos/Transforms/SelectTx.java src/demo/share/jfc/J2Ddemo/java2d/demos/Transforms/TransformAnim.java test/jdk/TEST.ROOT test/jdk/TEST.groups test/jdk/demo/jfc/J2Ddemo/J2DdemoTest.java test/jdk/demo/jfc/TEST.properties
diffstat 137 files changed, 15701 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/make/CompileDemos.gmk	Fri May 11 20:59:21 2018 -0700
+++ b/make/CompileDemos.gmk	Mon May 14 08:58:32 2018 -0700
@@ -253,6 +253,12 @@
     DEMO_SUBDIR := jfc, \
 ))
 
+$(eval $(call SetupBuildDemo, J2Ddemo, \
+    DEMO_SUBDIR := jfc, \
+    MAIN_CLASS := java2d.J2Ddemo, \
+    JAR_NAME := J2Ddemo, \
+))
+
 $(eval $(call SetupBuildDemo, Metalworks, \
     DEMO_SUBDIR := jfc, \
 ))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/README.txt	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,96 @@
+The classes for the Java2D(TM) demo are contained in the J2Ddemo.jar file.  
+To run the J2D demo:
+
+% java -jar J2Ddemo.jar
+
+-----------------------------------------------------------------------
+Introduction
+-----------------------------------------------------------------------
+
+This Java2D demo consists of a set of demos housed in one GUI 
+framework that uses a JTabbedPane.  You can access different groups of 
+demos by clicking the tabs at the top of the pane. There are demo 
+groups for Arcs_Curves, Clipping, Colors, Composite, Fonts, Images, 
+Lines, Mix, Paint, Paths and Transforms.  On the right-hand side of the 
+pane, the GUI framework features individual and global controls for 
+changing graphics attributes. There's also a memory-usage monitor, and 
+a monitor for tracking the performance, in frames per second, of 
+animation demos.
+
+
+-----------------------------------------------------------------------
+Tips on usage 
+----------------------------------------------------------------------- 
+
+Click on one of the tabs at the top of the pane to select a demo group.  
+When you select a group, a set of surfaces is displayed, each of which 
+contains one of the group's demos. At the bottom of each surface is 
+a set of tools for controlling the demo.  The tools can be displayed
+by selecting the Tools checkbox in the Global Controls panel or
+by clicking on the slim strip of gray bumps at the bottom of the demo
+panel.
+
+If you click on a demo surface, that demo is laid out by itself. A
+new icon button will appear in the demo's tools toolbar one that enables 
+you to create new instances of that demo's surface. 
+
+To run the demo continuously without user interaction, select the 
+Run Window item in the Options menu and press the run button in the 
+new window that's displayed.  To do this from the command line:
+
+    java -jar J2Ddemo.jar -runs=10
+
+To view all the command line options for customizing demo runs:
+
+    java -jar J2Ddemo.jar -help
+
+You can run the demos in stand-alone mode by issuing a command like this
+
+    java -cp J2Ddemo.jar java2d.demos.Clipping.ClipAnim
+
+You can run the demos in groups by issuing a command like this
+
+    java -cp J2Ddemo.jar java2d.DemoGroup Clipping    
+
+To increase or decrease the Memory Monitor sampling rate click on the
+Memory Monitor's title border, a panel with a TextField will appear.
+
+The J2Ddemo Intro (the 'J2D demo' tab) contains a scene table, click in 
+the gray border and a table will appear.
+
+Animated demos have a slider to control the animation rate.  Bring up
+the animated demo toolbar, then click in the gray area of the toolbar
+panel, the toolbar goes away and the slider appears.
+
+Demos that have Custom Controls can have their Custom Control Thread
+activated and stopped by clicking in the gray area of the demos Custom 
+Control panel.
+
+-----------------------------------------------------------------------
+NOTE about demo surfaces 
+----------------------------------------------------------------------- 
+
+The demo groups are in separate packages with their class files stored 
+in directories named according to the demo group name.  All drawing 
+demos extend either the Surface, AnimatingSurface, ControlsSurface or
+AnimatingControlsSurface classes.  Surface is the base class, demos
+must implement the Surface's render method.  All animated demos extend 
+either the AnimatingSurface or the AnimatingControlsSurface classes.  
+Animated demos must implement the reset and step methods.  The demos
+with gui controls extend either the ControlsSurface or the 
+AnimatingControlsSurface classes.  Demos with controls must implement
+the methods in the CustomControlsContext interface.
+
+
+======================================================================
+
+Here are some resources for learning about and using the Java2D(TM)
+
+OpenJDK group page: http://openjdk.java.net/groups/2d/
+
+Learning Java 2D: http://www.oracle.com/technetwork/articles/java/java2dpart1-137217.html
+
+Tutorial : http://download.oracle.com/javase/tutorial/2d/
+Specification: http://download.oracle.com/javase/8/docs/technotes/guides/2d/spec/j2d-bookTOC.html
+Java 2D (TM) API White Paper : http://www.oracle.com/technetwork/java/javase/tech/2d-142228.html
+2D FAQ: http://www.oracle.com/technetwork/java/index-137037.html
Binary file src/demo/share/jfc/J2Ddemo/fonts/A.ttf has changed
Binary file src/demo/share/jfc/J2Ddemo/images/bld.jpg has changed
Binary file src/demo/share/jfc/J2Ddemo/images/bld@2x.jpg has changed
Binary file src/demo/share/jfc/J2Ddemo/images/boat.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/boat@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/box.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/box.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/box@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/boxwave.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/boxwave.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/boxwave@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/clone.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/clone@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/clouds.jpg has changed
Binary file src/demo/share/jfc/J2Ddemo/images/clouds@2x.jpg has changed
Binary file src/demo/share/jfc/J2Ddemo/images/duke.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/duke.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/duke.running.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/duke@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/duke@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/dukeplug.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/dukeplug.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/dukeplug@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/fight.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/fight.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/fight@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/globe.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/globe.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/globe@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/jumptojavastrip.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/loop.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/loop@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/looping.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/looping@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/magnify.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/magnify.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/magnify@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/painting.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/painting.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/painting@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/print.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/print@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/remove.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/remove@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/snooze.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/snooze.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/snooze@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/star7.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/star7.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/star7@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/start.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/start2.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/start2@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/start@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/stop.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/stop2.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/stop2@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/stop@2x.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/surfing.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/surfing.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/surfing@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/thumbsup.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/thumbsup.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/thumbsup@2x.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/tip.gif has changed
Binary file src/demo/share/jfc/J2Ddemo/images/tip.png has changed
Binary file src/demo/share/jfc/J2Ddemo/images/tip@2x.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/AnimatingContext.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package java2d;
+
+
+/**
+ * The interface for a DemoSurface that animates.
+ */
+public interface AnimatingContext {
+        public void step(int w, int h);
+        public void reset(int newwidth, int newheight);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/AnimatingControlsSurface.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,81 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java2d.CustomControlsContext.State.START;
+import java.awt.Component;
+
+
+/**
+ * Demos that animate and have custom controls extend this class.
+ */
+@SuppressWarnings("serial")
+public abstract class AnimatingControlsSurface extends AnimatingSurface
+        implements CustomControlsContext {
+
+    @Override
+    public void setControls(Component[] controls) {
+        this.controls = controls;
+    }
+
+    @Override
+    public void setConstraints(String[] constraints) {
+        this.constraints = constraints;
+    }
+
+    @Override
+    public String[] getConstraints() {
+        return constraints;
+    }
+
+    @Override
+    public Component[] getControls() {
+        return controls;
+    }
+
+    @Override
+    public void handleThread(CustomControlsContext.State state) {
+        for (Component control : controls) {
+            if (control instanceof CustomControls) {
+                if (state == START) {
+                    ((CustomControls) control).start();
+                } else {
+                    ((CustomControls) control).stop();
+                }
+            }
+        }
+    }
+
+    private Component[] controls;
+    private String[] constraints = { java.awt.BorderLayout.NORTH };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/AnimatingSurface.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package java2d;
+
+
+/**
+ * Demos that animate extend this class.
+ */
+@SuppressWarnings("serial")
+public abstract class AnimatingSurface extends Surface implements Runnable {
+
+    private volatile boolean running = false;
+
+    private volatile Thread thread;
+
+    public abstract void step(int w, int h);
+
+    public abstract void reset(int newwidth, int newheight);
+
+
+    public synchronized void start() {
+        if (!running() && !dontThread) {
+            thread = new Thread(this);
+            thread.setPriority(Thread.MIN_PRIORITY);
+            thread.setName(name + " Demo");
+            thread.start();
+            running = true;
+        }
+    }
+
+
+    public synchronized void stop() {
+        if (thread != null) {
+            running = false;
+            thread.interrupt();
+        }
+        thread = null;
+        notifyAll();
+    }
+
+
+    @Override
+    @SuppressWarnings("SleepWhileHoldingLock")
+    public void run() {
+
+        while (running() && !isShowing() || getSize().width == 0) {
+            try {
+                Thread.sleep(200);
+            } catch (InterruptedException ignored) {
+            }
+        }
+
+        while (running()) {
+            repaint();
+            try {
+                Thread.sleep(sleepAmount);
+            } catch (InterruptedException ignored) {
+            }
+        }
+        synchronized (this) {
+            running = false;
+        }
+    }
+
+    /**
+     * @return the running
+     */
+    public synchronized boolean running() {
+        return running;
+    }
+
+    /**
+     * Causes surface to repaint immediately
+     */
+    public synchronized void doRepaint() {
+        if (running() && thread != null) {
+            thread.interrupt();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/CloningFeature.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,196 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.SoftBevelBorder;
+
+
+/**
+ * Illustration of how to use the clone feature of the demo.
+ */
+@SuppressWarnings("serial")
+public final class CloningFeature extends JPanel implements Runnable {
+
+    private final DemoInstVarsAccessor demoInstVars;
+    private Thread thread;
+    private JTextArea ta;
+
+    public CloningFeature(DemoInstVarsAccessor demoInstVars) {
+        this.demoInstVars = demoInstVars;
+
+        setLayout(new BorderLayout());
+        EmptyBorder eb = new EmptyBorder(5, 5, 5, 5);
+        SoftBevelBorder sbb = new SoftBevelBorder(BevelBorder.RAISED);
+        setBorder(new CompoundBorder(eb, sbb));
+
+        ta = new JTextArea("Cloning Demonstrated\n\nClicking once on a demo\n");
+        ta.setMinimumSize(new Dimension(300, 500));
+        JScrollPane scroller = new JScrollPane();
+        scroller.getViewport().add(ta);
+        ta.setFont(new Font("Dialog", Font.PLAIN, 14));
+        ta.setForeground(Color.black);
+        ta.setBackground(Color.lightGray);
+        ta.setEditable(false);
+
+        add("Center", scroller);
+
+        start();
+    }
+
+    public void start() {
+        thread = new Thread(this);
+        thread.setPriority(Thread.MAX_PRIORITY);
+        thread.setName("CloningFeature");
+        thread.start();
+    }
+
+    public void stop() {
+        if (thread != null) {
+            thread.interrupt();
+        }
+        thread = null;
+    }
+
+    @Override
+    @SuppressWarnings("SleepWhileHoldingLock")
+    public void run() {
+
+
+        int index = demoInstVars.getTabbedPane().getSelectedIndex();
+        if (index == 0) {
+            demoInstVars.getTabbedPane().setSelectedIndex(1);
+            try {
+                Thread.sleep(3333);
+            } catch (Exception e) {
+                return;
+            }
+        }
+
+        if (!demoInstVars.getControls().toolBarCB.isSelected()) {
+            demoInstVars.getControls().toolBarCB.setSelected(true);
+            try {
+                Thread.sleep(2222);
+            } catch (Exception e) {
+                return;
+            }
+        }
+
+        index = demoInstVars.getTabbedPane().getSelectedIndex() - 1;
+        DemoGroup dg = demoInstVars.getGroup()[index];
+        DemoPanel dp = (DemoPanel) dg.getPanel().getComponent(0);
+        if (dp.surface == null) {
+            ta.append("Sorry your zeroth component is not a Surface.");
+            return;
+        }
+
+        dg.mouseClicked(dp.surface);
+
+        try {
+            Thread.sleep(3333);
+        } catch (Exception e) {
+            return;
+        }
+
+        ta.append("Clicking the ToolBar double document button\n");
+        try {
+            Thread.sleep(3333);
+        } catch (Exception e) {
+            return;
+        }
+
+        dp = (DemoPanel) dg.clonePanels[0].getComponent(0);
+
+        if (dp.tools != null) {
+            for (int i = 0; i < 3 && thread != null; i++) {
+                ta.append("   Cloning\n");
+                dp.tools.cloneB.doClick();
+                try {
+                    Thread.sleep(3333);
+                } catch (Exception e) {
+                    return;
+                }
+            }
+        }
+
+        ta.append("Changing attributes \n");
+
+        try {
+            Thread.sleep(3333);
+        } catch (Exception e) {
+            return;
+        }
+
+        Component cmps[] = dg.clonePanels[0].getComponents();
+        for (int i = 0; i < cmps.length && thread != null; i++) {
+            if ((dp = (DemoPanel) cmps[i]).tools == null) {
+                continue;
+            }
+            switch (i) {
+                case 0:
+                    ta.append("   Changing AntiAliasing\n");
+                    dp.tools.aliasB.doClick();
+                    break;
+                case 1:
+                    ta.append("   Changing Composite & Texture\n");
+                    dp.tools.compositeB.doClick();
+                    dp.tools.textureB.doClick();
+                    break;
+                case 2:
+                    ta.append("   Changing Screen\n");
+                    dp.tools.screenCombo.setSelectedIndex(4);
+                    break;
+                case 3:
+                    ta.append("   Removing a clone\n");
+                    dp.tools.cloneB.doClick();
+            }
+            try {
+                Thread.sleep(3333);
+            } catch (Exception e) {
+                return;
+            }
+        }
+
+        ta.append("\nAll Done!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/ControlsSurface.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package java2d;
+
+
+import static java2d.CustomControlsContext.State.START;
+import java.awt.Component;
+
+
+/**
+ * The class to utilize custom controls for a Demo.
+ */
+@SuppressWarnings("serial")
+public abstract class ControlsSurface extends Surface implements CustomControlsContext {
+
+    @Override
+    public void setControls(Component[] controls) {
+        this.controls = controls;
+    }
+
+    @Override
+    public void setConstraints(String[] constraints) {
+        this.constraints = constraints;
+    }
+
+    @Override
+    public String[] getConstraints() {
+        return constraints;
+    }
+
+    @Override
+    public Component[] getControls() {
+        return controls;
+    }
+
+    @Override
+    public void handleThread(CustomControlsContext.State state) {
+        for (Component control : controls) {
+            if (control instanceof CustomControls) {
+                if (state == START) {
+                    ((CustomControls) control).start();
+                } else {
+                    ((CustomControls) control).stop();
+                }
+            }
+        }
+    }
+
+    private Component[] controls;
+    private String[] constraints = { java.awt.BorderLayout.NORTH };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/CustomControls.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,133 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package java2d;
+
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.JPanel;
+import javax.swing.border.EtchedBorder;
+
+
+/**
+ * A convenience class for demos that use Custom Controls.  This class
+ * sets up the thread for running the custom control.  A notifier thread
+ * is started as well, a flashing 2x2 rect is drawn in the upper right corner
+ * while the custom control thread continues to run.
+ */
+@SuppressWarnings("serial")
+public abstract class CustomControls extends JPanel implements Runnable {
+
+
+    protected Thread thread;
+    protected boolean doNotifier;
+    private CCNotifierThread ccnt;
+    private String name = "foo.bar Demo";
+    private static final Color blue = new Color(204, 204, 255);
+
+
+    public CustomControls() {
+        setBorder(new EtchedBorder());
+        addMouseListener(new MouseAdapter() {
+
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                if (thread == null) { start(); } else { stop(); }
+            }
+        });
+    }
+
+    public CustomControls(String name) {
+        this();
+        this.name = name + " Demo";
+    }
+
+    @Override
+    public void paintComponent(Graphics g) {
+        super.paintComponent(g);
+        g.setColor(doNotifier ? blue : Color.gray);
+        g.fillRect(getSize().width-2, 0, 2, 2);
+    }
+
+    public void start() {
+        if (thread == null) {
+            thread = new Thread(this);
+            thread.setPriority(Thread.MIN_PRIORITY);
+            thread.setName(name + " ccthread");
+            thread.start();
+            (ccnt = new CCNotifierThread()).start();
+            ccnt.setName(name + " ccthread notifier");
+        }
+    }
+
+    public synchronized void stop() {
+        if (thread != null) {
+            thread.interrupt();
+            if (ccnt != null) {
+                ccnt.interrupt();
+            }
+        }
+        thread = null;
+    }
+
+
+    // Custom Controls override the run method
+    @Override
+    public void run() {
+    }
+
+
+    /**
+     * Notifier that the custom control thread is running.
+     */
+    class CCNotifierThread extends Thread {
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            while (thread != null) {
+                doNotifier = !doNotifier;
+                repaint();
+                try {
+                    Thread.sleep(444);
+                } catch (Exception ex) {
+                    break;
+                }
+            }
+            doNotifier = false; repaint();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/CustomControlsContext.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package java2d;
+
+
+import java.awt.Component;
+
+
+/**
+ * ControlsSurface or AnimatingControlsSurface classes implement
+ * this interface.
+ */
+public interface CustomControlsContext {
+    public static enum State { START, STOP };
+    public String[] getConstraints();
+    public Component[] getControls();
+    public void setControls(Component[] controls);
+    public void setConstraints(String[] constraints);
+    public void handleThread(CustomControlsContext.State state);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/DemoFonts.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package java2d;
+
+
+import java.awt.Font;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * A cache of the dynamically loaded fonts found in the fonts directory.
+ */
+public class DemoFonts {
+
+    // Prepare a static "cache" mapping font names to Font objects.
+    private static final String[] names =  { "A.ttf" };
+    private static final Map<String,Font> cache =
+               new ConcurrentHashMap<String,Font>(names.length);
+    static {
+        for (String name : names) {
+            cache.put(name, getFont(name));
+        }
+    }
+
+    public static void newDemoFonts() {
+    }
+
+
+    public static Font getFont(String name) {
+        Font font = null;
+        if (cache != null) {
+            if ((font = cache.get(name)) != null) {
+                return font;
+            }
+        }
+        String fName = "/fonts/" + name;
+        try {
+            InputStream is = DemoFonts.class.getResourceAsStream(fName);
+            font = Font.createFont(Font.TRUETYPE_FONT, is);
+        } catch (Exception ex) {
+            Logger.getLogger(DemoFonts.class.getName()).log(Level.SEVERE,
+                    fName + " not loaded.  Using serif font.", ex);
+            font = new Font(Font.SERIF, Font.PLAIN, 24);
+        }
+        return font;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/DemoGroup.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,384 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.JToggleButton;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.SoftBevelBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * DemoGroup handles multiple demos inside of a panel.  Demos are loaded
+ * from the demos[][] string as listed in J2Ddemo.java.
+ * Demo groups can be loaded individually, for example :
+ *      java DemoGroup Fonts
+ * Loads all the demos found in the demos/Fonts directory.
+ */
+@SuppressWarnings("serial")
+public class DemoGroup extends JPanel
+        implements ChangeListener, ActionListener {
+    private final DemoInstVarsAccessor demoInstVars;
+    public int columns = 2;
+    private static final Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+    private final EmptyBorder emptyB = new EmptyBorder(5, 5, 5, 5);
+    private final BevelBorder bevelB = new BevelBorder(BevelBorder.LOWERED);
+    private String groupName;
+    public JPanel clonePanels[];
+    public JTabbedPane tabbedPane;
+
+    public DemoGroup(String name, DemoInstVarsAccessor demoInstVars) {
+
+        groupName = name;
+        this.demoInstVars = demoInstVars;
+
+        setLayout(new BorderLayout());
+
+        JPanel p = new JPanel(new GridLayout(0, 2));
+        p.setBorder(new CompoundBorder(emptyB, bevelB));
+
+        // Find the named demo group in J2Ddemo.demos[].
+        int ind = -1;
+        while (!name.equals(J2Ddemo.demos[++ind][0])) {
+        }
+        String[] demos = J2Ddemo.demos[ind];
+
+        // If there are an odd number of demos, use GridBagLayout.
+        // Note that we don't use the first entry.
+        int numDemos = demos.length - 1;
+        if (numDemos % 2 == 1) {
+            p.setLayout(new GridBagLayout());
+        }
+
+        MouseAdapter mouseListener = new MouseAdapter() {
+
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                DemoGroup.this.mouseClicked(e.getComponent());
+            }
+        };
+
+        // For each demo in the group, prepare a DemoPanel.
+        for (int i = 1; i <= numDemos; i++) {
+            DemoPanel dp =
+                    new DemoPanel("java2d.demos." + name + "." + demos[i], demoInstVars);
+            dp.setDemoBorder(p);
+            if (dp.surface != null) {
+                dp.surface.addMouseListener(mouseListener);
+                dp.surface.setMonitor(demoInstVars.getPerformanceMonitor() != null);
+            }
+            if (p.getLayout() instanceof GridBagLayout) {
+                int x = p.getComponentCount() % 2;
+                int y = p.getComponentCount() / 2;
+                int w = (i == numDemos) ? 2 : 1;
+                J2Ddemo.addToGridBag(p, dp, x, y, w, 1, 1, 1);
+            } else {
+                p.add(dp);
+            }
+        }
+
+        add(p);
+    }
+
+    public void mouseClicked(Component component) {
+        String className = component.toString();
+
+        if (tabbedPane == null) {
+            shutDown(getPanel());
+            JPanel p = new JPanel(new BorderLayout());
+            p.setBorder(new CompoundBorder(emptyB, bevelB));
+
+            tabbedPane = new JTabbedPane();
+            tabbedPane.setFont(font);
+
+            JPanel tmpP = (JPanel) getComponent(0);
+            tabbedPane.addTab(groupName, tmpP);
+
+            clonePanels = new JPanel[tmpP.getComponentCount()];
+            for (int i = 0; i < clonePanels.length; i++) {
+                clonePanels[i] = new JPanel(new BorderLayout());
+                DemoPanel dp = (DemoPanel) tmpP.getComponent(i);
+                DemoPanel c = new DemoPanel(dp.className, demoInstVars);
+                c.setDemoBorder(clonePanels[i]);
+                if (c.surface != null) {
+                    c.surface.setMonitor(demoInstVars.getPerformanceMonitor() != null);
+                    Image cloneImg = DemoImages.getImage("clone.gif", this);
+                    c.tools.cloneB = c.tools.addTool(cloneImg,
+                            "Clone the Surface", this);
+                    Dimension d = c.tools.toolbar.getPreferredSize();
+                    c.tools.toolbar.setPreferredSize(
+                            new Dimension(d.width + 27, d.height));
+                    if (demoInstVars.getBackgroundColor() != null) {
+                        c.surface.setBackground(demoInstVars.getBackgroundColor());
+                    }
+                }
+                clonePanels[i].add(c);
+                String s = dp.className.substring(dp.className.indexOf('.') + 1);
+                tabbedPane.addTab(s, clonePanels[i]);
+            }
+            p.add(tabbedPane);
+            remove(tmpP);
+            add(p);
+
+            tabbedPane.addChangeListener(this);
+            revalidate();
+        }
+
+        className = className.substring(0, className.indexOf('['));
+
+        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
+            String s1 = className.substring(className.indexOf('.') + 1);
+            if (tabbedPane.getTitleAt(i).equals(s1)) {
+                tabbedPane.setSelectedIndex(i);
+                break;
+            }
+        }
+
+        revalidate();
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        JButton b = (JButton) e.getSource();
+        if (b.getToolTipText().startsWith("Clone")) {
+            cloneDemo();
+        } else {
+            removeClone(b.getParent().getParent().getParent().getParent());
+        }
+    }
+    private int index;
+
+    @Override
+    public void stateChanged(ChangeEvent e) {
+        shutDown((JPanel) tabbedPane.getComponentAt(index));
+        index = tabbedPane.getSelectedIndex();
+        setup(false);
+    }
+
+    public JPanel getPanel() {
+        if (tabbedPane != null) {
+            return (JPanel) tabbedPane.getSelectedComponent();
+        } else {
+            return (JPanel) getComponent(0);
+        }
+    }
+
+    public void setup(boolean issueRepaint) {
+
+        JPanel p = getPanel();
+
+        // Let PerformanceMonitor know which demos are running
+        if (demoInstVars.getPerformanceMonitor() != null) {
+            demoInstVars.getPerformanceMonitor().surf.setPanel(p);
+            demoInstVars.getPerformanceMonitor().surf.setSurfaceState();
+        }
+
+        GlobalControls c = demoInstVars.getControls();
+        // .. tools check against global controls settings ..
+        // .. & start demo & custom control thread if need be ..
+        for (int i = 0; i < p.getComponentCount(); i++) {
+            DemoPanel dp = (DemoPanel) p.getComponent(i);
+            if (dp.surface != null && c != null) {
+                Tools t = dp.tools;
+                t.setVisible(isValid());
+                t.issueRepaint = issueRepaint;
+                JToggleButton b[] = { t.toggleB, t.aliasB, t.renderB,
+                    t.textureB, t.compositeB };
+                JCheckBox cb[] = { c.toolBarCB, c.aliasCB, c.renderCB,
+                    c.textureCB, c.compositeCB };
+                for (int j = 0; j < b.length; j++) {
+                    if (c.obj != null && c.obj.equals(cb[j])) {
+                        if (b[j].isSelected() != cb[j].isSelected()) {
+                            b[j].doClick();
+                        }
+                    } else if (c.obj == null) {
+                        if (b[j].isSelected() != cb[j].isSelected()) {
+                            b[j].doClick();
+                        }
+                    }
+                }
+                t.setVisible(true);
+                if (c.screenCombo.getSelectedIndex()
+                        != t.screenCombo.getSelectedIndex()) {
+                    t.screenCombo.setSelectedIndex(c.screenCombo.
+                            getSelectedIndex());
+                }
+                if (demoInstVars.getVerboseCB().isSelected()) {
+                    dp.surface.verbose(c);
+                }
+                dp.surface.setSleepAmount(c.slider.getValue());
+                if (demoInstVars.getBackgroundColor() != null) {
+                    dp.surface.setBackground(demoInstVars.getBackgroundColor());
+                }
+                t.issueRepaint = true;
+            }
+            dp.start();
+        }
+        revalidate();
+    }
+
+    public void shutDown(JPanel p) {
+        for (int i = 0; i < p.getComponentCount(); i++) {
+            ((DemoPanel) p.getComponent(i)).stop();
+        }
+        System.gc();
+    }
+
+    public void cloneDemo() {
+        JPanel panel = clonePanels[tabbedPane.getSelectedIndex() - 1];
+        if (panel.getComponentCount() == 1) {
+            panel.invalidate();
+            panel.setLayout(new GridLayout(0, columns, 5, 5));
+            panel.revalidate();
+        }
+        DemoPanel original = (DemoPanel) getPanel().getComponent(0);
+        DemoPanel clone = new DemoPanel(original.className, demoInstVars);
+        if (columns == 2) {
+            clone.setDemoBorder(panel);
+        }
+        Image removeImg = DemoImages.getImage("remove.gif", this);
+        clone.tools.cloneB =
+                clone.tools.addTool(removeImg, "Remove the Surface", this);
+        Dimension d = clone.tools.toolbar.getPreferredSize();
+        clone.tools.toolbar.setPreferredSize(
+                new Dimension(d.width + 27, d.height));
+        if (demoInstVars.getBackgroundColor() != null) {
+            clone.surface.setBackground(demoInstVars.getBackgroundColor());
+        }
+        if (demoInstVars.getControls() != null) {
+            if (clone.tools.isExpanded
+                    != demoInstVars.getControls().toolBarCB.isSelected()) {
+                clone.tools.toggleB.doClick();
+            }
+        }
+        clone.start();
+        clone.surface.setMonitor(demoInstVars.getPerformanceMonitor() != null);
+        panel.add(clone);
+        panel.repaint();
+        panel.revalidate();
+    }
+
+    public void removeClone(Component theClone) {
+        JPanel panel = clonePanels[tabbedPane.getSelectedIndex() - 1];
+        if (panel.getComponentCount() == 2) {
+            Component cmp = panel.getComponent(0);
+            panel.removeAll();
+            panel.setLayout(new BorderLayout());
+            panel.revalidate();
+            panel.add(cmp);
+        } else {
+            panel.remove(theClone);
+            int cmpCount = panel.getComponentCount();
+            for (int j = 1; j < cmpCount; j++) {
+                int top = (j + 1 >= 3) ? 0 : 5;
+                int left = ((j + 1) % 2) == 0 ? 0 : 5;
+                EmptyBorder eb = new EmptyBorder(top, left, 5, 5);
+                SoftBevelBorder sbb = new SoftBevelBorder(BevelBorder.RAISED);
+                JPanel p = (JPanel) panel.getComponent(j);
+                p.setBorder(new CompoundBorder(eb, sbb));
+            }
+        }
+        panel.repaint();
+        panel.revalidate();
+    }
+
+    public static void main(String args[]) {
+        class DemoInstVarsAccessorImpl extends DemoInstVarsAccessorImplBase {
+            private volatile JCheckBoxMenuItem ccthreadCB;
+
+            public void setCcthreadCB(JCheckBoxMenuItem ccthreadCB) {
+                this.ccthreadCB = ccthreadCB;
+            }
+
+            @Override
+            public JCheckBoxMenuItem getCcthreadCB() {
+                return ccthreadCB;
+            }
+        }
+        DemoInstVarsAccessorImpl demoInstVars = new DemoInstVarsAccessorImpl();
+        final DemoGroup group = new DemoGroup(args[0], demoInstVars);
+        JFrame f = new JFrame("Java2D(TM) Demo - DemoGroup");
+        f.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+
+            @Override
+            public void windowDeiconified(WindowEvent e) {
+                group.setup(false);
+            }
+
+            @Override
+            public void windowIconified(WindowEvent e) {
+                group.shutDown(group.getPanel());
+            }
+        });
+        f.getContentPane().add("Center", group);
+        f.pack();
+        int FRAME_WIDTH = 620;
+        int FRAME_HEIGHT = 530;
+        f.setSize(FRAME_WIDTH, FRAME_HEIGHT);
+        f.setLocationRelativeTo(null);  // centers f on screen
+        f.setVisible(true);
+        for (String arg : args) {
+            if (arg.startsWith("-ccthread")) {
+                demoInstVars.setCcthreadCB(new JCheckBoxMenuItem("CCThread", true));
+            }
+        }
+        group.setup(false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/DemoImages.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import java.awt.Component;
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.net.URL;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * A collection of all the demo images found in the images directory.
+ * Certain classes are preloaded; the rest are loaded lazily.
+ */
+@SuppressWarnings("serial")
+public class DemoImages extends Component {
+
+    private static final String[] names = {
+        "bld.jpg", "boat.png", "box.png",
+        "boxwave.png", "clouds.jpg", "duke.gif", "duke.running.gif",
+        "dukeplug.png", "fight.png", "globe.png",
+        "jumptojavastrip.png", "magnify.png", "painting.png",
+        "remove.gif", "snooze.png", "star7.gif", "surfing.png",
+        "thumbsup.png", "tip.png", "duke.png", "print.gif",
+        "loop.gif", "looping.gif", "start.gif", "start2.gif",
+        "stop.gif", "stop2.gif", "clone.gif"
+    };
+    private static final Map<String, Image> cache =
+            new ConcurrentHashMap<String, Image>(names.length);
+
+    private DemoImages() {
+    }
+
+    public static void newDemoImages() {
+        DemoImages demoImages = new DemoImages();
+        for (String name : names) {
+            cache.put(name, getImage(name, demoImages));
+        }
+    }
+
+
+    /*
+     * Gets the named image using the toolkit of the specified component.
+     * Note that this has to work even before we have had a chance to
+     * instantiate DemoImages and preload the cache.
+     */
+    public static Image getImage(String name, Component cmp) {
+        Image img = null;
+        if (cache != null) {
+            if ((img = cache.get(name)) != null) {
+                return img;
+            }
+        }
+
+        ClassLoader cl = cmp.getClass().getClassLoader();
+        URL fileLoc = cl.getResource("images/" + name);
+        img = cmp.getToolkit().getImage(fileLoc);
+
+        MediaTracker tracker = new MediaTracker(cmp);
+        tracker.addImage(img, 0);
+        try {
+            tracker.waitForID(0);
+            if (tracker.isErrorAny()) {
+                System.out.println("Error loading image " + name);
+            }
+        } catch (Exception ex) {
+            Logger.getLogger(DemoImages.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        return img;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/DemoInstVarsAccessor.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,27 @@
+package java2d;
+
+import java.awt.Color;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JTabbedPane;
+
+/**
+ * The interface provides access to instance variables of 'J2Ddemo' object, which
+ * were static variables of 'J2Ddemo' class read/written from various parts of the
+ * demo classes. The interface is a part of the fix which changed static variables
+ * for instance variables in certain demo classes.
+ */
+public interface DemoInstVarsAccessor {
+    public GlobalControls getControls();
+    public MemoryMonitor getMemoryMonitor();
+    public PerformanceMonitor getPerformanceMonitor();
+    public JTabbedPane getTabbedPane();
+    public DemoGroup[] getGroup();
+    public void setGroupColumns(int columns);
+    public JCheckBoxMenuItem getVerboseCB();
+    public JCheckBoxMenuItem getCcthreadCB();
+    public JCheckBoxMenuItem getPrintCB();
+    public Color getBackgroundColor();
+    public JCheckBoxMenuItem getMemoryCB();
+    public JCheckBoxMenuItem getPerfCB();
+    public Intro getIntro();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/DemoInstVarsAccessorImplBase.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,79 @@
+package java2d;
+
+import java.awt.Color;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JTabbedPane;
+
+/**
+ * The implementation of 'DemoInstVarsAccessor' interface with empty methods.
+ * It is used, when some parts of the demo are executed as standalone applications
+ * not creating 'J2Ddemo' instances, for example in 'TextureChooser.main',
+ * 'DemoGroup.main', 'Surface.createDemoFrame'.
+ */
+public class DemoInstVarsAccessorImplBase implements DemoInstVarsAccessor {
+    private JCheckBoxMenuItem printCB = new JCheckBoxMenuItem("Default Printer");
+
+    @Override
+    public GlobalControls getControls() {
+        return null;
+    }
+
+    @Override
+    public MemoryMonitor getMemoryMonitor() {
+        return null;
+    }
+
+    @Override
+    public PerformanceMonitor getPerformanceMonitor() {
+        return null;
+    }
+
+    @Override
+    public JTabbedPane getTabbedPane() {
+        return null;
+    }
+
+    @Override
+    public DemoGroup[] getGroup() {
+        return null;
+    }
+
+    @Override
+    public void setGroupColumns(int columns) {
+    }
+
+    @Override
+    public JCheckBoxMenuItem getVerboseCB() {
+        return null;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getCcthreadCB() {
+        return null;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getPrintCB() {
+        return printCB;
+    }
+
+    @Override
+    public Color getBackgroundColor() {
+        return null;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getMemoryCB() {
+        return null;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getPerfCB() {
+        return null;
+    }
+
+    @Override
+    public Intro getIntro() {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/DemoPanel.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,124 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java2d.CustomControlsContext.State.START;
+import static java2d.CustomControlsContext.State.STOP;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JPanel;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.SoftBevelBorder;
+
+
+/**
+ * The panel for the Surface, Custom Controls & Tools.
+ * Other component types welcome.
+ */
+@SuppressWarnings("serial")
+public class DemoPanel extends JPanel {
+    private final DemoInstVarsAccessor demoInstVars;
+    public Surface surface;
+    public CustomControlsContext ccc;
+    public Tools tools;
+    public String className;
+
+    public DemoPanel(Object obj, DemoInstVarsAccessor demoInstVars) {
+        this.demoInstVars = demoInstVars;
+
+        setLayout(new BorderLayout());
+        try {
+            if (obj instanceof String) {
+                className = (String) obj;
+                obj = Class.forName(className).newInstance();
+            }
+            if (obj instanceof Component) {
+                add((Component) obj);
+            }
+            if (obj instanceof Surface) {
+                add("South", tools = new Tools(surface = (Surface) obj, demoInstVars));
+            }
+            if (obj instanceof CustomControlsContext) {
+                ccc = (CustomControlsContext) obj;
+                Component cmps[] = ccc.getControls();
+                String cons[] = ccc.getConstraints();
+                for (int i = 0; i < cmps.length; i++) {
+                    add(cmps[i], cons[i]);
+                }
+            }
+        } catch (Exception e) {
+            Logger.getLogger(DemoPanel.class.getName()).log(Level.SEVERE, null,
+                    e);
+        }
+    }
+
+    public void start() {
+        if (surface != null) {
+            surface.startClock();
+        }
+        if (tools != null && surface != null) {
+            if (tools.startStopB != null && tools.startStopB.isSelected()) {
+                surface.animating.start();
+            }
+        }
+        if (ccc != null
+                && demoInstVars.getCcthreadCB() != null
+                && demoInstVars.getCcthreadCB().isSelected()) {
+            ccc.handleThread(START);
+        }
+    }
+
+    public void stop() {
+        if (surface != null) {
+            if (surface.animating != null) {
+                surface.animating.stop();
+            }
+            surface.bimg = null;
+        }
+        if (ccc != null) {
+            ccc.handleThread(STOP);
+        }
+    }
+
+    public void setDemoBorder(JPanel p) {
+        int top = (p.getComponentCount() + 1 >= 3) ? 0 : 5;
+        int left = ((p.getComponentCount() + 1) % 2) == 0 ? 0 : 5;
+        EmptyBorder eb = new EmptyBorder(top, left, 5, 5);
+        SoftBevelBorder sbb = new SoftBevelBorder(BevelBorder.RAISED);
+        setBorder(new CompoundBorder(eb, sbb));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/GlobalControls.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,151 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.SwingConstants;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * Global Controls panel for changing graphic attributes of
+ * the demo surface.
+ */
+@SuppressWarnings("serial")
+public class GlobalControls extends JPanel implements ItemListener,
+        ChangeListener {
+    private final DemoInstVarsAccessor demoInstVars;
+    public static final String[] screenNames = {
+        "Auto Screen", "On Screen", "Off Screen",
+        "INT_xRGB", "INT_ARGB", "INT_ARGB_PRE", "INT_BGR",
+        "3BYTE_BGR", "4BYTE_ABGR", "4BYTE_ABGR_PRE", "USHORT_565_RGB",
+        "USHORT_x555_RGB", "BYTE_GRAY", "USHORT_GRAY",
+        "BYTE_BINARY", "BYTE_INDEXED", "BYTE_BINARY 2 bit", "BYTE_BINARY 4 bit",
+        "INT_RGBx", "USHORT_555x_RGB" };
+    public final JComboBox screenCombo;
+    public TextureChooser texturechooser;
+    public JCheckBox aliasCB, renderCB, toolBarCB;
+    public JCheckBox compositeCB, textureCB;
+    public JSlider slider;
+    public Object obj;
+    private Font font = new Font(Font.SERIF, Font.PLAIN, 12);
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public GlobalControls(DemoInstVarsAccessor demoInstVars) {
+        this.demoInstVars = demoInstVars;
+
+        setLayout(new GridBagLayout());
+        setBorder(new TitledBorder(new EtchedBorder(), "Global Controls"));
+
+        aliasCB = createCheckBox("Anti-Aliasing", true, 0);
+        renderCB = createCheckBox("Rendering Quality", false, 1);
+        textureCB = createCheckBox("Texture", false, 2);
+        compositeCB = createCheckBox("AlphaComposite", false, 3);
+
+        screenCombo = new JComboBox();
+        screenCombo.setPreferredSize(new Dimension(120, 18));
+        screenCombo.setLightWeightPopupEnabled(true);
+        screenCombo.setFont(font);
+        for (int i = 0; i < screenNames.length; i++) {
+            screenCombo.addItem(screenNames[i]);
+        }
+        screenCombo.addItemListener(this);
+        J2Ddemo.addToGridBag(this, screenCombo, 0, 4, 1, 1, 0.0, 0.0);
+
+        toolBarCB = createCheckBox("Tools", false, 5);
+
+        slider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 30);
+        slider.addChangeListener(this);
+        TitledBorder tb = new TitledBorder(new EtchedBorder());
+        tb.setTitleFont(font);
+        tb.setTitle("Anim delay = 30 ms");
+        slider.setBorder(tb);
+        slider.setMinimumSize(new Dimension(80, 46));
+        J2Ddemo.addToGridBag(this, slider, 0, 6, 1, 1, 1.0, 1.0);
+
+        texturechooser = new TextureChooser(0, demoInstVars);
+        J2Ddemo.addToGridBag(this, texturechooser, 0, 7, 1, 1, 1.0, 1.0);
+    }
+
+    private JCheckBox createCheckBox(String s, boolean b, int y) {
+        JCheckBox cb = new JCheckBox(s, b);
+        cb.setFont(font);
+        cb.setHorizontalAlignment(SwingConstants.LEFT);
+        cb.addItemListener(this);
+        J2Ddemo.addToGridBag(this, cb, 0, y, 1, 1, 1.0, 1.0);
+        return cb;
+    }
+
+    @Override
+    public void stateChanged(ChangeEvent e) {
+        int value = slider.getValue();
+        TitledBorder tb = (TitledBorder) slider.getBorder();
+        tb.setTitle("Anim delay = " + String.valueOf(value) + " ms");
+        int index = demoInstVars.getTabbedPane().getSelectedIndex() - 1;
+        DemoGroup dg = demoInstVars.getGroup()[index];
+        JPanel p = dg.getPanel();
+        for (int i = 0; i < p.getComponentCount(); i++) {
+            DemoPanel dp = (DemoPanel) p.getComponent(i);
+            if (dp.tools != null && dp.tools.slider != null) {
+                dp.tools.slider.setValue(value);
+            }
+        }
+        slider.repaint();
+    }
+
+    @Override
+    public void itemStateChanged(ItemEvent e) {
+        if (demoInstVars.getTabbedPane().getSelectedIndex() != 0) {
+            obj = e.getSource();
+            int index = demoInstVars.getTabbedPane().getSelectedIndex() - 1;
+            demoInstVars.getGroup()[index].setup(true);
+            obj = null;
+        }
+    }
+
+    @Override
+    public Dimension getPreferredSize() {
+        return new Dimension(135, 260);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/GlobalPanel.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import java.awt.BorderLayout;
+import java.awt.GridBagLayout;
+import javax.swing.JPanel;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * Panel that holds the Demo groups, Controls and Monitors for each tab.
+ * It's a special "always visible" panel for the Controls, MemoryMonitor &
+ * PerformanceMonitor.
+ */
+@SuppressWarnings("serial")
+public class GlobalPanel extends JPanel implements ChangeListener {
+    private final DemoInstVarsAccessor demoInstVars;
+    private JPanel p;
+    private int index;
+
+    public GlobalPanel(DemoInstVarsAccessor demoInstVars) {
+        this.demoInstVars = demoInstVars;
+
+        setLayout(new BorderLayout());
+        p = new JPanel(new GridBagLayout());
+        EmptyBorder eb = new EmptyBorder(5, 0, 5, 5);
+        BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
+        p.setBorder(new CompoundBorder(eb, bb));
+        J2Ddemo.addToGridBag(p, demoInstVars.getControls(), 0, 0, 1, 1, 0, 0);
+        J2Ddemo.addToGridBag(p, demoInstVars.getMemoryMonitor(), 0, 1, 1, 1, 0, 0);
+        J2Ddemo.addToGridBag(p, demoInstVars.getPerformanceMonitor(), 0, 2, 1, 1, 0, 0);
+        add(demoInstVars.getIntro());
+    }
+
+    @Override
+    public void stateChanged(ChangeEvent e) {
+
+        demoInstVars.getGroup()[index].shutDown(demoInstVars.getGroup()[index].getPanel());
+        if (demoInstVars.getTabbedPane().getSelectedIndex() == 0) {
+            demoInstVars.getMemoryMonitor().surf.stop();
+            demoInstVars.getPerformanceMonitor().surf.stop();
+            removeAll();
+            add(demoInstVars.getIntro());
+            demoInstVars.getIntro().start();
+        } else {
+            if (getComponentCount() == 1) {
+                demoInstVars.getIntro().stop();
+                remove(demoInstVars.getIntro());
+                add(p, BorderLayout.EAST);
+                if (demoInstVars.getMemoryCB().getState()) {
+                    demoInstVars.getMemoryMonitor().surf.start();
+                }
+                if (demoInstVars.getPerfCB().getState()) {
+                    demoInstVars.getPerformanceMonitor().surf.start();
+                }
+            } else {
+                remove(demoInstVars.getGroup()[index]);
+            }
+            index = demoInstVars.getTabbedPane().getSelectedIndex() - 1;
+            add(demoInstVars.getGroup()[index]);
+            demoInstVars.getGroup()[index].setup(false);
+        }
+        revalidate();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/Intro.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,1784 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import static java.awt.Color.YELLOW;
+import java.awt.AlphaComposite;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.TexturePaint;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.FlatteningPathIterator;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSlider;
+import javax.swing.JTable;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+
+
+/**
+ * Introduction to the J2Ddemo.
+ *
+ * @author Brian Lichtenwalter
+ * @author Alexander Kouznetsov
+ */
+@SuppressWarnings("serial")
+public class Intro extends JPanel {
+
+    private static final Color myBlack = new Color(20, 20, 20);
+    private static final Color myWhite = new Color(240, 240, 255);
+    private static final Color myRed = new Color(149, 43, 42);
+    private static final Color myBlue = new Color(94, 105, 176);
+    private static final Color myYellow = new Color(255, 255, 140);
+    private ScenesTable scenesTable;
+    private boolean doTable;
+    private final Surface surface;
+
+    public Intro() {
+        EmptyBorder eb = new EmptyBorder(80, 110, 80, 110);
+        BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
+        setBorder(new CompoundBorder(eb, bb));
+        setLayout(new BorderLayout());
+        setBackground(GRAY);
+        setToolTipText("click for scene table");
+        add(surface = new Surface());
+        addMouseListener(new MouseAdapter() {
+
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                removeAll();
+                if ((doTable = !doTable)) {
+                    setToolTipText("click for animation");
+                    surface.stop();
+                    if (scenesTable == null) {
+                        scenesTable = new ScenesTable(Intro.this);
+                    }
+                    add(scenesTable);
+                } else {
+                    setToolTipText("click for scene table");
+                    surface.start();
+                    add(surface);
+                }
+                revalidate();
+                repaint();
+            }
+        });
+    }
+
+    public void start() {
+        if (!doTable) {
+            surface.start();
+        }
+    }
+
+    public void stop() {
+        if (!doTable) {
+            surface.stop();
+        }
+    }
+
+    public static void main(String argv[]) {
+        final Intro intro = new Intro();
+        WindowListener l = new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+
+            @Override
+            public void windowDeiconified(WindowEvent e) {
+                intro.start();
+            }
+
+            @Override
+            public void windowIconified(WindowEvent e) {
+                intro.stop();
+            }
+        };
+        JFrame f = new JFrame("Java2D(TM) Demo - Intro");
+        f.addWindowListener(l);
+        f.getContentPane().add("Center", intro);
+        f.pack();
+        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+        int w = 720;
+        int h = 510;
+        f.setLocation(screenSize.width / 2 - w / 2, screenSize.height / 2 - h
+                / 2);
+        f.setSize(w, h);
+        f.setVisible(true);
+        intro.start();
+    }
+
+
+    /**
+     * ScenesTable is the list of scenes known to the Director.
+     * Scene participation, scene name and scene pause amount columns.
+     * Global animation delay for scene's steps.
+     */
+    static class ScenesTable extends JPanel implements ActionListener,
+            ChangeListener {
+        private final Intro intro;
+        private JTable table;
+        private TableModel dataModel;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public ScenesTable(final Intro intro) {
+            this.intro = intro;
+
+            setBackground(WHITE);
+            setLayout(new BorderLayout());
+            final String[] names = { "", "Scenes", "Pause" };
+
+            dataModel = new AbstractTableModel() {
+
+                @Override
+                public int getColumnCount() {
+                    return names.length;
+                }
+
+                @Override
+                public int getRowCount() {
+                    return intro.surface.director.size();
+                }
+
+                @Override
+                public Object getValueAt(int row, int col) {
+                    Surface.Scene scene = intro.surface.director.get(row);
+                    if (col == 0) {
+                        return scene.participate;
+                    } else if (col == 1) {
+                        return scene.name;
+                    } else {
+                        return scene.pauseAmt;
+                    }
+                }
+
+                @Override
+                public String getColumnName(int col) {
+                    return names[col];
+                }
+
+                @Override
+                public Class<?> getColumnClass(int c) {
+                    return getValueAt(0, c).getClass();
+                }
+
+                @Override
+                public boolean isCellEditable(int row, int col) {
+                    return col != 1 ? true : false;
+                }
+
+                @Override
+                public void setValueAt(Object aValue, int row, int col) {
+                    Surface.Scene scene = intro.surface.director.get(row);
+                    if (col == 0) {
+                        scene.participate = aValue;
+                    } else if (col == 1) {
+                        scene.name = aValue;
+                    } else {
+                        scene.pauseAmt = aValue;
+                    }
+                }
+            };
+
+            table = new JTable(dataModel);
+            TableColumn col = table.getColumn("");
+            col.setWidth(16);
+            col.setMinWidth(16);
+            col.setMaxWidth(20);
+            col = table.getColumn("Pause");
+            col.setWidth(60);
+            col.setMinWidth(60);
+            col.setMaxWidth(60);
+            table.sizeColumnsToFit(0);
+
+            JScrollPane scrollpane = new JScrollPane(table);
+            add(scrollpane);
+
+            JPanel panel = new JPanel(new BorderLayout());
+            JButton b = new JButton("Unselect All");
+            b.setHorizontalAlignment(JButton.LEFT);
+            Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+            b.setFont(font);
+            b.addActionListener(this);
+            panel.add("West", b);
+
+            JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 200,
+                    (int) intro.surface.sleepAmt);
+            slider.addChangeListener(this);
+            TitledBorder tb = new TitledBorder(new EtchedBorder());
+            tb.setTitleFont(font);
+            tb.setTitle("Anim delay = " + String.valueOf(intro.surface.sleepAmt)
+                    + " ms");
+            slider.setBorder(tb);
+            slider.setPreferredSize(new Dimension(140, 40));
+            slider.setMinimumSize(new Dimension(100, 40));
+            slider.setMaximumSize(new Dimension(180, 40));
+            panel.add("East", slider);
+
+            add("South", panel);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JButton b = (JButton) e.getSource();
+            b.setSelected(!b.isSelected());
+            b.setText(b.isSelected() ? "Select All" : "Unselect All");
+            for (int i = 0; i < intro.surface.director.size(); i++) {
+                Surface.Scene scene = intro.surface.director.get(i);
+                scene.participate = Boolean.valueOf(!b.isSelected());
+            }
+            table.tableChanged(new TableModelEvent(dataModel));
+        }
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            JSlider slider = (JSlider) e.getSource();
+            int value = slider.getValue();
+            TitledBorder tb = (TitledBorder) slider.getBorder();
+            tb.setTitle("Anim delay = " + String.valueOf(value) + " ms");
+            intro.surface.sleepAmt = (long) value;
+            slider.repaint();
+        }
+    }  // End ScenesTable class
+
+
+    /**
+     * Surface is the stage where the Director plays its scenes.
+     */
+    static class Surface extends JPanel implements Runnable {
+
+        private final Image dukeanim, duke;
+        private BufferedImage bimg;
+        public Director director;
+        public int index;
+        public long sleepAmt = 30;
+        private Thread thread;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public Surface() {
+            setBackground(myBlack);
+            setLayout(new BorderLayout());
+            addMouseListener(new MouseAdapter() {
+
+                @Override
+                public void mouseClicked(MouseEvent e) {
+                    if (thread == null) {
+                        start();
+                    } else {
+                        stop();
+                    }
+                }
+            });
+            dukeanim = DemoImages.getImage("duke.running.gif", this);
+            duke = DemoImages.getImage("duke.png", this);
+            director = new Director(this);
+        }
+
+        public FontMetrics getMetrics(Font font) {
+            return getFontMetrics(font);
+        }
+
+        @Override
+        public void paint(Graphics g) {
+            Dimension d = getSize();
+            if (d.width <= 0 || d.height <= 0) {
+                return;
+            }
+            if (bimg == null || bimg.getWidth() != d.width || bimg.getHeight()
+                    != d.height) {
+                bimg = getGraphicsConfiguration().createCompatibleImage(d.width,
+                        d.height);
+                // reset future scenes
+                for (int i = index + 1; i < director.size(); i++) {
+                    (director.get(i)).reset(d.width, d.height);
+                }
+            }
+
+            Scene scene = director.get(index);
+            if (scene.index <= scene.length) {
+                if (thread != null) {
+                    scene.step(d.width, d.height);
+                }
+
+                Graphics2D g2 = bimg.createGraphics();
+                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                        RenderingHints.VALUE_ANTIALIAS_ON);
+                g2.setBackground(getBackground());
+                g2.clearRect(0, 0, d.width, d.height);
+
+                scene.render(d.width, d.height, g2);
+
+                if (thread != null) {
+                    // increment scene.index after scene.render
+                    scene.index++;
+                }
+                g2.dispose();
+            }
+            g.drawImage(bimg, 0, 0, this);
+        }
+
+        public void start() {
+            if (thread == null) {
+                thread = new Thread(this);
+                thread.setPriority(Thread.MIN_PRIORITY);
+                thread.setName("Intro");
+                thread.start();
+            }
+        }
+
+        public synchronized void stop() {
+            if (thread != null) {
+                thread.interrupt();
+            }
+            thread = null;
+            notifyAll();
+        }
+
+        public void reset() {
+            index = 0;
+            Dimension d = getSize();
+            for (Scene scene : director) {
+                scene.reset(d.width, d.height);
+            }
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+
+            Thread me = Thread.currentThread();
+
+            while (thread == me && !isShowing() || getSize().width <= 0) {
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                    return;
+                }
+            }
+
+            if (index == 0) {
+                reset();
+            }
+
+            while (thread == me) {
+                Scene scene = director.get(index);
+                if (((Boolean) scene.participate).booleanValue()) {
+                    repaint();
+                    try {
+                        Thread.sleep(sleepAmt);
+                    } catch (InterruptedException e) {
+                        break;
+                    }
+                    if (scene.index > scene.length) {
+                        scene.pause();
+                        if (++index >= director.size()) {
+                            reset();
+                        }
+                    }
+                } else {
+                    if (++index >= director.size()) {
+                        reset();
+                    }
+                }
+            }
+            thread = null;
+        }
+
+
+        /**
+         * Part is a piece of the scene.  Classes must implement Part
+         * in order to participate in a scene.
+         */
+        interface Part {
+
+            public void reset(int newwidth, int newheight);
+
+            public void step(int w, int h);
+
+            public void render(int w, int h, Graphics2D g2);
+
+            public int getBegin();
+
+            public int getEnd();
+        }
+
+
+        /**
+         * Director is the holder of the scenes, their names & pause amounts
+         * between scenes.
+         */
+        static class Director extends ArrayList<Scene> {
+
+            GradientPaint gp = new GradientPaint(0, 40, myBlue, 38, 2, myBlack);
+            Font f1 = new Font(Font.SERIF, Font.PLAIN, 200);
+            Font f2 = new Font(Font.SERIF, Font.PLAIN, 120);
+            Font f3 = new Font(Font.SERIF, Font.PLAIN, 72);
+
+            public Director(Surface surf) {
+                Object partsInfo[][][] = {
+                { { "J  -  scale text on gradient", "0" },
+                    { new GpE(GpE.BURI, myBlack, myBlue, 0, 20),
+                        new TxE("J", f1, TxE.SCI, myYellow, 2, 20) } },
+                { { "2  -  scale & rotate text on gradient", "0" },
+                    { new GpE(GpE.BURI, myBlue, myBlack, 0, 22),
+                        new TxE("2", f1, TxE.RI | TxE.SCI, myYellow, 2, 22) } },
+                { { "D  -  scale text on gradient", "0" },
+                    { new GpE(GpE.BURI, myBlack, myBlue, 0, 20),
+                        new TxE("D", f1, TxE.SCI, myYellow, 2, 20) } },
+                { { "J2D demo  -  scale & rotate text on gradient", "1000" },
+                    { new GpE(GpE.SIH, myBlue, myBlack, 0, 40),
+                        new TxE("J2D demo", f2, TxE.RI | TxE.SCI, myYellow, 0, 40) } },
+                { { "Previous scene dither dissolve out", "0" },
+                    { new DdE(0, 20, 1, surf) } },
+                { { "Graphics Features", "999" },
+                    { new Temp(Temp.RECT, null, 0, 15),
+                        new Temp(Temp.IMG, surf.duke, 2, 15),
+                        new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130),
+                        new Features(Features.GRAPHICS, 16, 130, surf) } },
+                { { "J2D demo  -  texture text on gradient", "1000" },
+                    { new GpE(GpE.WI, myBlue, myBlack, 0, 20),
+                        new GpE(GpE.WD, myBlue, myBlack, 21, 40),
+                        new TpE(TpE.OI | TpE.NF, myBlack, myYellow, 4, 0, 10),
+                        new TpE(TpE.OD | TpE.NF, myBlack, myYellow, 4, 11, 20),
+                        new TpE(TpE.OI | TpE.NF | TpE.HAF, myBlack, myYellow, 5,
+                        21, 40),
+                        new TxE("J2D demo", f2, 0, null, 0, 40) } },
+                { { "Previous scene random close out", "0" },
+                    { new CoE(CoE.RAND, 0, 20, surf) } },
+                { { "Text Features", "999" },
+                    { new Temp(Temp.RECT, null, 0, 15),
+                        new Temp(Temp.IMG, surf.duke, 2, 15),
+                        new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130),
+                        new Features(Features.TEXT, 16, 130, surf) } },
+                { { "J2D demo  -  composite text on texture", "1000" },
+                    { new TpE(TpE.RI, myBlack, gp, 40, 0, 20),
+                        new TpE(TpE.RD, myBlack, gp, 40, 21, 40),
+                        new TpE(TpE.RI, myBlack, gp, 40, 41, 60),
+                        new TxE("J2D demo", f2, TxE.AC, myYellow, 0, 60) } },
+                { { "Previous scene dither dissolve out", "0" },
+                    { new DdE(0, 20, 4, surf) } },
+                { { "Imaging Features", "999" },
+                    { new Temp(Temp.RECT, null, 0, 15),
+                        new Temp(Temp.IMG, surf.duke, 2, 15),
+                        new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130),
+                        new Features(Features.IMAGES, 16, 130, surf) } },
+                { { "J2D demo  -  text on gradient", "1000" },
+                    { new GpE(GpE.SDH, myBlue, myBlack, 0, 20),
+                        new GpE(GpE.SIH, myBlue, myBlack, 21, 40),
+                        new GpE(GpE.SDH, myBlue, myBlack, 41, 50),
+                        new GpE(GpE.INC | GpE.NF, myRed, myYellow, 0, 50),
+                        new TxE("J2D demo", f2, TxE.NOP, null, 0, 50) } },
+                { { "Previous scene ellipse close out", "0" },
+                    { new CoE(CoE.OVAL, 0, 20, surf) } },
+                { { "Color Features", "999" },
+                    { new Temp(Temp.RECT, null, 0, 15),
+                        new Temp(Temp.IMG, surf.duke, 2, 15),
+                        new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 99),
+                        new Features(Features.COLOR, 16, 99, surf) } },
+                { { "J2D demo  -  composite and rotate text on paints", "2000" },
+                    { new GpE(GpE.BURI, myBlack, myBlue, 0, 20),
+                        new GpE(GpE.BURD, myBlack, myBlue, 21, 30),
+                        new TpE(TpE.OI | TpE.HAF, myBlack, myBlue, 10, 31, 40),
+                        new TxE("J2D demo", f2, TxE.AC | TxE.RI, myYellow, 0, 40) } },
+                { { "Previous scene subimage transform out", "0" },
+                    { new SiE(60, 60, 0, 40, surf) } },
+                { { "CREDITS  -  transform in", "1000" },
+                    { new LnE(LnE.ACI | LnE.ZOOMI | LnE.RI, 0, 60),
+                        new TxE("CREDITS", f3, TxE.AC | TxE.SCI, RED, 20, 30),
+                        new TxE("CREDITS", f3, TxE.SCXD, RED, 31, 38),
+                        new TxE("CREDITS", f3, TxE.SCXI, RED, 39, 48),
+                        new TxE("CREDITS", f3, TxE.SCXD, RED, 49, 54),
+                        new TxE("CREDITS", f3, TxE.SCXI, RED, 55, 60) } },
+                { { "CREDITS  -  transform out", "0" },
+                    { new LnE(LnE.ACD | LnE.ZOOMD | LnE.RD, 0, 45),
+                        new TxE("CREDITS", f3, 0, RED, 0, 9),
+                        new TxE("CREDITS", f3, TxE.SCD | TxE.RD, RED, 10, 30) } },
+                { { "Contributors", "1000" },
+                    { new Temp(Temp.RECT, null, 0, 30),
+                        new Temp(Temp.IMG, surf.dukeanim, 4, 30),
+                        new Temp(Temp.RNA | Temp.INA, surf.dukeanim, 31, 200),
+                        new Contributors(34, 200, surf) } }, };
+
+                for (Object[][] partInfo : partsInfo) {
+                    List<Part> parts = new ArrayList<Part>();
+                    for (Object part : partInfo[1]) {
+                        parts.add((Part) part);
+                    }
+                    add(new Scene(parts, partInfo[0][0], partInfo[0][1]));
+                }
+            }
+        }
+
+
+        /**
+         * Scene is the manager of the parts.
+         */
+        static class Scene extends Object {
+
+            public Object name;
+            public Object participate = Boolean.TRUE;
+            public Object pauseAmt;
+            public List<Part> parts;
+            public int index;
+            public int length;
+
+            public Scene(List<Part> parts, Object name, Object pauseAmt) {
+                this.name = name;
+                this.parts = parts;
+                this.pauseAmt = pauseAmt;
+                for (Part part : parts) {
+                    int partLength = part.getEnd();
+                    if (partLength > length) {
+                        length = partLength;
+                    }
+                }
+            }
+
+            public void reset(int w, int h) {
+                index = 0;
+                for (int i = 0; i < parts.size(); i++) {
+                    (parts.get(i)).reset(w, h);
+                }
+            }
+
+            public void step(int w, int h) {
+                for (int i = 0; i < parts.size(); i++) {
+                    Part part = parts.get(i);
+                    if (index >= part.getBegin() && index <= part.getEnd()) {
+                        part.step(w, h);
+                    }
+                }
+            }
+
+            public void render(int w, int h, Graphics2D g2) {
+                for (int i = 0; i < parts.size(); i++) {
+                    Part part = parts.get(i);
+                    if (index >= part.getBegin() && index <= part.getEnd()) {
+                        part.render(w, h, g2);
+                    }
+                }
+            }
+
+            public void pause() {
+                try {
+                    Thread.sleep(Long.parseLong((String) pauseAmt));
+                } catch (Exception ignored) {
+                }
+                System.gc();
+            }
+        } // End Scene class
+
+
+        /**
+         * Text Effect.  Transformation of characters.  Clip or fill.
+         */
+        static final class TxE implements Part {
+
+            static final int INC = 1;
+            static final int DEC = 2;
+            static final int R = 4;            // rotate
+            static final int RI = R | INC;
+            static final int RD = R | DEC;
+            static final int SC = 8;            // scale
+            static final int SCI = SC | INC;
+            static final int SCD = SC | DEC;
+            static final int SCX = 16;           // scale invert x
+            static final int SCXI = SCX | SC | INC;
+            static final int SCXD = SCX | SC | DEC;
+            static final int SCY = 32;           // scale invert y
+            static final int SCYI = SCY | SC | INC;
+            static final int SCYD = SCY | SC | DEC;
+            static final int AC = 64;           // AlphaComposite
+            static final int CLIP = 128;          // Clipping
+            static final int NOP = 512;          // No Paint
+            private int beginning, ending;
+            private int type;
+            private double rIncr, sIncr;
+            private double sx, sy, rotate;
+            private Shape shapes[], txShapes[];
+            private int sw;
+            private int numRev;
+            private Paint paint;
+
+            public TxE(String text,
+                    Font font,
+                    int type,
+                    Paint paint,
+                    int beg,
+                    int end) {
+                this.type = type;
+                this.paint = paint;
+                this.beginning = beg;
+                this.ending = end;
+
+                setIncrements(2);
+
+                char[] chars = text.toCharArray();
+                shapes = new Shape[chars.length];
+                txShapes = new Shape[chars.length];
+                FontRenderContext frc = new FontRenderContext(null, true, true);
+                TextLayout tl = new TextLayout(text, font, frc);
+                sw = (int) tl.getOutline(null).getBounds().getWidth();
+                for (int j = 0; j < chars.length; j++) {
+                    String s = String.valueOf(chars[j]);
+                    shapes[j] = new TextLayout(s, font, frc).getOutline(null);
+                }
+            }
+
+            public void setIncrements(double numRevolutions) {
+                this.numRev = (int) numRevolutions;
+                rIncr = 360.0 / ((ending - beginning) / numRevolutions);
+                sIncr = 1.0 / (ending - beginning);
+                if ((type & SCX) != 0 || (type & SCY) != 0) {
+                    sIncr *= 2;
+                }
+                if ((type & DEC) != 0) {
+                    rIncr = -rIncr;
+                    sIncr = -sIncr;
+                }
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                if (type == SCXI) {
+                    sx = -1.0;
+                    sy = 1.0;
+                } else if (type == SCYI) {
+                    sx = 1.0;
+                    sy = -1.0;
+                } else {
+                    sx = sy = (type & DEC) != 0 ? 1.0 : 0.0;
+                }
+                rotate = 0;
+            }
+
+            @Override
+            public void step(int w, int h) {
+
+                float charWidth = w / 2 - sw / 2;
+
+                for (int i = 0; i < shapes.length; i++) {
+                    AffineTransform at = new AffineTransform();
+                    Rectangle2D maxBounds = shapes[i].getBounds();
+                    at.translate(charWidth, h / 2 + maxBounds.getHeight() / 2);
+                    charWidth += (float) maxBounds.getWidth() + 1;
+                    Shape shape = at.createTransformedShape(shapes[i]);
+                    Rectangle2D b1 = shape.getBounds2D();
+
+                    if ((type & R) != 0) {
+                        at.rotate(Math.toRadians(rotate));
+                    }
+                    if ((type & SC) != 0) {
+                        at.scale(sx, sy);
+                    }
+                    shape = at.createTransformedShape(shapes[i]);
+                    Rectangle2D b2 = shape.getBounds2D();
+
+                    double xx = (b1.getX() + b1.getWidth() / 2)
+                            - (b2.getX() + b2.getWidth() / 2);
+                    double yy = (b1.getY() + b1.getHeight() / 2)
+                            - (b2.getY() + b2.getHeight() / 2);
+                    AffineTransform toCenterAT = new AffineTransform();
+                    toCenterAT.translate(xx, yy);
+                    toCenterAT.concatenate(at);
+                    txShapes[i] = toCenterAT.createTransformedShape(shapes[i]);
+                }
+                // avoid over rotation
+                if (Math.abs(rotate) <= numRev * 360) {
+                    rotate += rIncr;
+                    if ((type & SCX) != 0) {
+                        sx += sIncr;
+                    } else if ((type & SCY) != 0) {
+                        sy += sIncr;
+                    } else {
+                        sx += sIncr;
+                        sy += sIncr;
+                    }
+                }
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                Composite saveAC = null;
+                if ((type & AC) != 0 && sx > 0 && sx < 1) {
+                    saveAC = g2.getComposite();
+                    g2.setComposite(AlphaComposite.getInstance(
+                            AlphaComposite.SRC_OVER, (float) sx));
+                }
+                GeneralPath path = null;
+                if ((type & CLIP) != 0) {
+                    path = new GeneralPath();
+                }
+                if (paint != null) {
+                    g2.setPaint(paint);
+                }
+                for (int i = 0; i < txShapes.length; i++) {
+                    if ((type & CLIP) != 0) {
+                        path.append(txShapes[i], false);
+                    } else {
+                        g2.fill(txShapes[i]);
+                    }
+                }
+                if ((type & CLIP) != 0) {
+                    g2.clip(path);
+                }
+                if (saveAC != null) {
+                    g2.setComposite(saveAC);
+                }
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End TxE class
+
+
+        /**
+         * GradientPaint Effect.  Burst, split, horizontal and
+         * vertical gradient fill effects.
+         */
+        static class GpE implements Part {
+
+            static final int INC = 1;               // increasing
+            static final int DEC = 2;               // decreasing
+            static final int CNT = 4;               // center
+            static final int WID = 8;               // width
+            static final int WI = WID | INC;
+            static final int WD = WID | DEC;
+            static final int HEI = 16;              // height
+            static final int HI = HEI | INC;
+            static final int HD = HEI | DEC;
+            static final int SPL = 32 | CNT;        // split
+            static final int SIW = SPL | INC | WID;
+            static final int SDW = SPL | DEC | WID;
+            static final int SIH = SPL | INC | HEI;
+            static final int SDH = SPL | DEC | HEI;
+            static final int BUR = 64 | CNT;        // burst
+            static final int BURI = BUR | INC;
+            static final int BURD = BUR | DEC;
+            static final int NF = 128;             // no fill
+            private Color c1, c2;
+            private int beginning, ending;
+            private float incr, index;
+            private List<Rectangle2D> rect = new ArrayList<Rectangle2D>();
+            private List<GradientPaint> grad = new ArrayList<GradientPaint>();
+            private int type;
+
+            public GpE(int type, Color c1, Color c2, int beg, int end) {
+                this.type = type;
+                this.c1 = c1;
+                this.c2 = c2;
+                this.beginning = beg;
+                this.ending = end;
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                incr = 1.0f / (ending - beginning);
+                if ((type & CNT) != 0) {
+                    incr /= 2.3f;
+                }
+                if ((type & CNT) != 0 && (type & INC) != 0) {
+                    index = 0.5f;
+                } else if ((type & DEC) != 0) {
+                    index = 1.0f;
+                    incr = -incr;
+                } else {
+                    index = 0.0f;
+                }
+                index += incr;
+            }
+
+            @Override
+            public void step(int w, int h) {
+                rect.clear();
+                grad.clear();
+
+                if ((type & WID) != 0) {
+                    float w2 = 0, x1 = 0, x2 = 0;
+                    if ((type & SPL) != 0) {
+                        w2 = w * 0.5f;
+                        x1 = w * (1.0f - index);
+                        x2 = w * index;
+                    } else {
+                        w2 = w * index;
+                        x1 = x2 = w2;
+                    }
+                    rect.add(new Rectangle2D.Float(0, 0, w2, h));
+                    rect.add(new Rectangle2D.Float(w2, 0, w - w2, h));
+                    grad.add(new GradientPaint(0, 0, c1, x1, 0, c2));
+                    grad.add(new GradientPaint(x2, 0, c2, w, 0, c1));
+                } else if ((type & HEI) != 0) {
+                    float h2 = 0, y1 = 0, y2 = 0;
+                    if ((type & SPL) != 0) {
+                        h2 = h * 0.5f;
+                        y1 = h * (1.0f - index);
+                        y2 = h * index;
+                    } else {
+                        h2 = h * index;
+                        y1 = y2 = h2;
+                    }
+                    rect.add(new Rectangle2D.Float(0, 0, w, h2));
+                    rect.add(new Rectangle2D.Float(0, h2, w, h - h2));
+                    grad.add(new GradientPaint(0, 0, c1, 0, y1, c2));
+                    grad.add(new GradientPaint(0, y2, c2, 0, h, c1));
+                } else if ((type & BUR) != 0) {
+
+                    float w2 = w / 2;
+                    float h2 = h / 2;
+
+                    rect.add(new Rectangle2D.Float(0, 0, w2, h2));
+                    rect.add(new Rectangle2D.Float(w2, 0, w2, h2));
+                    rect.add(new Rectangle2D.Float(0, h2, w2, h2));
+                    rect.add(new Rectangle2D.Float(w2, h2, w2, h2));
+
+                    float x1 = w * (1.0f - index);
+                    float x2 = w * index;
+                    float y1 = h * (1.0f - index);
+                    float y2 = h * index;
+
+                    grad.add(new GradientPaint(0, 0, c1, x1, y1, c2));
+                    grad.add(new GradientPaint(w, 0, c1, x2, y1, c2));
+                    grad.add(new GradientPaint(0, h, c1, x1, y2, c2));
+                    grad.add(new GradientPaint(w, h, c1, x2, y2, c2));
+                } else if ((type & NF) != 0) {
+                    float y = h * index;
+                    grad.add(new GradientPaint(0, 0, c1, 0, y, c2));
+                }
+
+                if ((type & INC) != 0 || (type & DEC) != 0) {
+                    index += incr;
+                }
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                        RenderingHints.VALUE_ANTIALIAS_OFF);
+                for (int i = 0; i < grad.size(); i++) {
+                    g2.setPaint(grad.get(i));
+                    if ((type & NF) == 0) {
+                        g2.fill(rect.get(i));
+                    }
+                }
+                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                        RenderingHints.VALUE_ANTIALIAS_ON);
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End GpE class
+
+
+        /**
+         * TexturePaint Effect.  Expand and collapse a texture.
+         */
+        static final class TpE implements Part {
+
+            static final int INC = 1;             // increasing
+            static final int DEC = 2;             // decreasing
+            static final int OVAL = 4;             // oval
+            static final int RECT = 8;             // rectangle
+            static final int HAF = 16;             // half oval or rect size
+            static final int NF = 32;             // no fill
+            static final int OI = OVAL | INC;
+            static final int OD = OVAL | DEC;
+            static final int RI = RECT | INC;
+            static final int RD = RECT | DEC;
+            private Paint p1, p2;
+            private int beginning, ending;
+            private float incr, index;
+            private TexturePaint texture;
+            private int type;
+            private int size;
+            private BufferedImage bimg;
+            private Rectangle rect;
+
+            public TpE(int type, Paint p1, Paint p2, int size,
+                    int beg, int end) {
+                this.type = type;
+                this.p1 = p1;
+                this.p2 = p2;
+                this.beginning = beg;
+                this.ending = end;
+                setTextureSize(size);
+            }
+
+            public void setTextureSize(int size) {
+                this.size = size;
+                bimg = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
+                rect = new Rectangle(0, 0, size, size);
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                incr = (float) (size) / (float) (ending - beginning);
+                if ((type & HAF) != 0) {
+                    incr /= 2;
+                }
+                if ((type & DEC) != 0) {
+                    index = size;
+                    if ((type & HAF) != 0) {
+                        index /= 2;
+                    }
+                    incr = -incr;
+                } else {
+                    index = 0.0f;
+                }
+                index += incr;
+            }
+
+            @Override
+            public void step(int w, int h) {
+                Graphics2D g2 = bimg.createGraphics();
+                g2.setPaint(p1);
+                g2.fillRect(0, 0, size, size);
+                g2.setPaint(p2);
+                if ((type & OVAL) != 0) {
+                    g2.fill(new Ellipse2D.Float(0, 0, index, index));
+                } else if ((type & RECT) != 0) {
+                    g2.fill(new Rectangle2D.Float(0, 0, index, index));
+                }
+                texture = new TexturePaint(bimg, rect);
+                g2.dispose();
+                index += incr;
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                g2.setPaint(texture);
+                if ((type & NF) == 0) {
+                    g2.fillRect(0, 0, w, h);
+                }
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End TpE class
+
+
+        /**
+         * Close out effect.  Close out the buffered image with different
+         * geometry shapes.
+         */
+        static class CoE implements Part {
+            private final Surface surf;
+            static final int WID = 1;
+            static final int HEI = 2;
+            static final int OVAL = 4;
+            static final int RECT = 8;
+            static final int RAND = 16;
+            static final int ARC = 32;
+            private int type;
+            private int beginning, ending;
+            private BufferedImage bimg;
+            private Shape shape;
+            private double zoom, extent;
+            private double zIncr, eIncr;
+            private boolean doRandom;
+
+            public CoE(int type, int beg, int end, Surface surf) {
+                this.type = type;
+                this.beginning = beg;
+                this.ending = end;
+                this.surf = surf;
+                zIncr = -(2.0 / (ending - beginning));
+                eIncr = 360.0 / (ending - beginning);
+                doRandom = (type & RAND) != 0;
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                if (doRandom) {
+                    int num = (int) (Math.random() * 5.0);
+                    switch (num) {
+                        case 0:
+                            type = OVAL;
+                            break;
+                        case 1:
+                            type = RECT;
+                            break;
+                        case 2:
+                            type = RECT | WID;
+                            break;
+                        case 3:
+                            type = RECT | HEI;
+                            break;
+                        case 4:
+                            type = ARC;
+                            break;
+                        default:
+                            type = OVAL;
+                    }
+                }
+                shape = null;
+                bimg = null;
+                extent = 360.0;
+                zoom = 2.0;
+            }
+
+            @Override
+            public void step(int w, int h) {
+                if (bimg == null) {
+                    int biw = surf.bimg.getWidth();
+                    int bih = surf.bimg.getHeight();
+                    bimg = new BufferedImage(biw, bih,
+                            BufferedImage.TYPE_INT_RGB);
+                    Graphics2D big = bimg.createGraphics();
+                    big.drawImage(surf.bimg, 0, 0, null);
+                }
+                double z = Math.min(w, h) * zoom;
+                if ((type & OVAL) != 0) {
+                    shape = new Ellipse2D.Double(w / 2 - z / 2, h / 2 - z / 2, z,
+                            z);
+                } else if ((type & ARC) != 0) {
+                    shape = new Arc2D.Double(-100, -100, w + 200, h + 200, 90,
+                            extent, Arc2D.PIE);
+                    extent -= eIncr;
+                } else if ((type & RECT) != 0) {
+                    if ((type & WID) != 0) {
+                        shape = new Rectangle2D.Double(w / 2 - z / 2, 0, z, h);
+                    } else if ((type & HEI) != 0) {
+                        shape = new Rectangle2D.Double(0, h / 2 - z / 2, w, z);
+                    } else {
+                        shape = new Rectangle2D.Double(w / 2 - z / 2, h / 2 - z
+                                / 2, z, z);
+                    }
+                }
+                zoom += zIncr;
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                g2.clip(shape);
+                g2.drawImage(bimg, 0, 0, null);
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End CoE class
+
+
+        /**
+         * Dither Dissolve Effect. For each successive step in the animation,
+         * a pseudo-random starting horizontal position is chosen using list,
+         * and then the corresponding points created from xlist and ylist are
+         * blacked out for the current "chunk".  The x and y chunk starting
+         * positions are each incremented by the associated chunk size, and
+         * this process is repeated for the number of "steps" in the
+         * animation, causing an equal number of pseudo-randomly picked
+         * "blocks" to be blacked out during each step of the animation.
+         */
+        static class DdE implements Part {
+            private final Surface surf;
+            private int beginning, ending;
+            private BufferedImage bimg;
+            private Graphics2D big;
+            private List<Integer> list, xlist, ylist;
+            private int xeNum, yeNum;    // element number
+            private int xcSize, ycSize;  // chunk size
+            private int inc;
+            private int blocksize;
+
+            public DdE(int beg, int end, int blocksize, Surface surf) {
+                this.beginning = beg;
+                this.ending = end;
+                this.blocksize = blocksize;
+                this.surf = surf;
+            }
+
+            private void createShuffledLists() {
+                int width = bimg.getWidth();
+                int height = bimg.getHeight();
+                xlist = new ArrayList<Integer>(width);
+                ylist = new ArrayList<Integer>(height);
+                list = new ArrayList<Integer>(ending - beginning + 1);
+                for (int i = 0; i < width; i++) {
+                    xlist.add(i, i);
+                }
+                for (int i = 0; i < height; i++) {
+                    ylist.add(i, i);
+                }
+                for (int i = 0; i < (ending - beginning + 1); i++) {
+                    list.add(i, i);
+                }
+                java.util.Collections.shuffle(xlist);
+                java.util.Collections.shuffle(ylist);
+                java.util.Collections.shuffle(list);
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                bimg = null;
+            }
+
+            @Override
+            public void step(int w, int h) {
+                if (inc > ending) {
+                    bimg = null;
+                }
+                if (bimg == null) {
+                    int biw = surf.bimg.getWidth();
+                    int bih = surf.bimg.getHeight();
+                    bimg = new BufferedImage(biw, bih,
+                            BufferedImage.TYPE_INT_RGB);
+                    createShuffledLists();
+                    big = bimg.createGraphics();
+                    big.drawImage(surf.bimg, 0, 0, null);
+                    xcSize = (xlist.size() / (ending - beginning)) + 1;
+                    ycSize = (ylist.size() / (ending - beginning)) + 1;
+                    xeNum = 0;
+                    inc = 0;
+                }
+                xeNum = xcSize * (list.get(inc)).intValue();
+                yeNum = -ycSize;
+                inc++;
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                big.setColor(myBlack);
+
+                for (int k = 0; k <= (ending - beginning); k++) {
+                    if ((xeNum + xcSize) > xlist.size()) {
+                        xeNum = 0;
+                    } else {
+                        xeNum += xcSize;
+                    }
+                    yeNum += ycSize;
+
+                    for (int i = xeNum; i < xeNum + xcSize && i < xlist.size();
+                            i++) {
+                        for (int j = yeNum; j < yeNum + ycSize && j
+                                < ylist.size(); j++) {
+                            int xval = (xlist.get(i)).intValue();
+                            int yval = (ylist.get(j)).intValue();
+                            if (((xval % blocksize) == 0) && ((yval % blocksize)
+                                    == 0)) {
+                                big.fillRect(xval, yval, blocksize, blocksize);
+                            }
+                        }
+                    }
+                }
+
+                g2.drawImage(bimg, 0, 0, null);
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End DdE class
+
+
+        /**
+         * Subimage effect.  Subimage the scene's buffered
+         * image then rotate and scale down the subimages.
+         */
+        static class SiE implements Part {
+            private final Surface surf;
+            private int beginning, ending;
+            private BufferedImage bimg;
+            private double rIncr, sIncr;
+            private double scale, rotate;
+            private int siw, sih;
+            private List<BufferedImage> subs = new ArrayList<BufferedImage>(20);
+            private List<Point> pts = new ArrayList<Point>(20);
+
+            public SiE(int siw, int sih, int beg, int end, Surface surf) {
+                this.siw = siw;
+                this.sih = sih;
+                this.beginning = beg;
+                this.ending = end;
+                this.surf = surf;
+                rIncr = 360.0 / (ending - beginning);
+                sIncr = 1.0 / (ending - beginning);
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                scale = 1.0;
+                rotate = 0.0;
+                bimg = null;
+                subs.clear();
+                pts.clear();
+            }
+
+            @Override
+            public void step(int w, int h) {
+                if (bimg == null) {
+                    int biw = surf.bimg.getWidth();
+                    int bih = surf.bimg.getHeight();
+                    bimg = new BufferedImage(biw, bih,
+                            BufferedImage.TYPE_INT_RGB);
+                    Graphics2D big = bimg.createGraphics();
+                    big.drawImage(surf.bimg, 0, 0, null);
+                    for (int x = 0; x < w && scale > 0.0; x += siw) {
+                        int ww = x + siw < w ? siw : w - x;
+                        for (int y = 0; y < h; y += sih) {
+                            int hh = y + sih < h ? sih : h - y;
+                            subs.add(bimg.getSubimage(x, y, ww, hh));
+                            pts.add(new Point(x, y));
+                        }
+                    }
+                }
+
+                rotate += rIncr;
+                scale -= sIncr;
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                AffineTransform saveTx = g2.getTransform();
+                g2.setColor(myBlue);
+                for (int i = 0; i < subs.size() && scale > 0.0; i++) {
+                    BufferedImage bi = subs.get(i);
+                    Point p = pts.get(i);
+                    int ww = bi.getWidth();
+                    int hh = bi.getHeight();
+                    AffineTransform at = new AffineTransform();
+                    at.rotate(Math.toRadians(rotate), p.x + ww / 2, p.y + hh / 2);
+                    at.translate(p.x, p.y);
+                    at.scale(scale, scale);
+
+                    Rectangle b1 = new Rectangle(0, 0, ww, hh);
+                    Shape shape = at.createTransformedShape(b1);
+                    Rectangle2D b2 = shape.getBounds2D();
+                    double xx = (p.x + ww / 2) - (b2.getX() + b2.getWidth() / 2);
+                    double yy = (p.y + hh / 2)
+                            - (b2.getY() + b2.getHeight() / 2);
+                    AffineTransform toCenterAT = new AffineTransform();
+                    toCenterAT.translate(xx, yy);
+                    toCenterAT.concatenate(at);
+
+                    g2.setTransform(toCenterAT);
+                    g2.drawImage(bi, 0, 0, null);
+                    g2.draw(b1);
+                }
+                g2.setTransform(saveTx);
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End SiE class
+
+
+        /**
+         * Line Effect.  Flattened ellipse with lines from the center
+         * to the edge.  Expand or collapse the ellipse.  Fade in or out
+         * the lines.
+         */
+        static class LnE implements Part {
+
+            static final int INC = 1;
+            static final int DEC = 2;
+            static final int R = 4;             // rotate
+            static final int ZOOM = 8;             // zoom
+            static final int AC = 32;             // AlphaComposite
+            static final int RI = R | INC;
+            static final int RD = R | DEC;
+            static final int ZOOMI = ZOOM | INC;
+            static final int ZOOMD = ZOOM | DEC;
+            static final int ACI = AC | INC;
+            static final int ACD = AC | DEC;
+            private int beginning, ending;
+            private double rIncr, rotate;
+            private double zIncr, zoom;
+            private List<Point2D.Double> pts = new ArrayList<Point2D.Double>();
+            private float alpha, aIncr;
+            private int type;
+
+            public LnE(int type, int beg, int end) {
+                this.type = type;
+                this.beginning = beg;
+                this.ending = end;
+                float range = ending - beginning;
+                rIncr = 360.0f / range;
+                aIncr = 0.9f / range;
+                zIncr = 2.0f / range;
+                if ((type & DEC) != 0) {
+                    rIncr = -rIncr;
+                    aIncr = -aIncr;
+                    zIncr = -zIncr;
+                }
+            }
+
+            public void generatePts(int w, int h, double sizeF) {
+                pts.clear();
+                double size = Math.min(w, h) * sizeF;
+                Ellipse2D ellipse = new Ellipse2D.Double(w / 2 - size / 2, h / 2 - size
+                        / 2, size, size);
+                PathIterator pi = ellipse.getPathIterator(null, 0.8);
+                while (!pi.isDone()) {
+                    double[] pt = new double[6];
+                    switch (pi.currentSegment(pt)) {
+                        case FlatteningPathIterator.SEG_MOVETO:
+                        case FlatteningPathIterator.SEG_LINETO:
+                            pts.add(new Point2D.Double(pt[0], pt[1]));
+                    }
+                    pi.next();
+                }
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                if ((type & DEC) != 0) {
+                    rotate = 360;
+                    alpha = 1.0f;
+                    zoom = 2.0;
+                } else {
+                    rotate = alpha = 0;
+                    zoom = 0;
+                }
+                if ((type & ZOOM) == 0) {
+                    generatePts(w, h, 0.5);
+                }
+            }
+
+            @Override
+            public void step(int w, int h) {
+                if ((type & ZOOM) != 0) {
+                    generatePts(w, h, zoom += zIncr);
+                }
+                if ((type & RI) != 0 || (type & RI) != 0) {
+                    rotate += rIncr;
+                }
+                if ((type & ACI) != 0 || (type & ACD) != 0) {
+                    alpha += aIncr;
+                }
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                Composite saveAC = null;
+                if ((type & AC) != 0 && alpha >= 0 && alpha <= 1) {
+                    saveAC = g2.getComposite();
+                    g2.setComposite(AlphaComposite.getInstance(
+                            AlphaComposite.SRC_OVER, alpha));
+                }
+                AffineTransform saveTx = null;
+                if ((type & R) != 0) {
+                    saveTx = g2.getTransform();
+                    AffineTransform at = new AffineTransform();
+                    at.rotate(Math.toRadians(rotate), w / 2, h / 2);
+                    g2.setTransform(at);
+                }
+                Point2D p1 = new Point2D.Double(w / 2, h / 2);
+                g2.setColor(YELLOW);
+                for (Point2D pt : pts) {
+                    g2.draw(new Line2D.Float(p1, pt));
+                }
+                if (saveTx != null) {
+                    g2.setTransform(saveTx);
+                }
+                if (saveAC != null) {
+                    g2.setComposite(saveAC);
+                }
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End LnE class
+
+
+        /**
+         * Template for Features & Contributors consisting of translating
+         * blue and red rectangles and an image going from transparent to
+         * opaque.
+         */
+        static class Temp implements Part {
+
+            static final int NOANIM = 1;
+            static final int RECT = 2;
+            static final int IMG = 4;
+            static final int RNA = RECT | NOANIM;
+            static final int INA = IMG | NOANIM;
+            private int beginning, ending;
+            private float alpha, aIncr;
+            private int type;
+            private Rectangle rect1, rect2;
+            private int x, y, xIncr, yIncr;
+            private Image img;
+
+            public Temp(int type, Image img, int beg, int end) {
+                this.type = type;
+                this.img = img;
+                this.beginning = beg;
+                this.ending = end;
+                aIncr = 0.9f / (ending - beginning);
+                if ((type & NOANIM) != 0) {
+                    alpha = 1.0f;
+                }
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                rect1 = new Rectangle(8, 20, w - 20, 30);
+                rect2 = new Rectangle(20, 8, 30, h - 20);
+                if ((type & NOANIM) == 0) {
+                    alpha = 0.0f;
+                    xIncr = w / (ending - beginning);
+                    yIncr = h / (ending - beginning);
+                    x = w + (int) (xIncr * 1.4);
+                    y = h + (int) (yIncr * 1.4);
+                }
+            }
+
+            @Override
+            public void step(int w, int h) {
+                if ((type & NOANIM) != 0) {
+                    return;
+                }
+                if ((type & RECT) != 0) {
+                    rect1.setLocation(x -= xIncr, 20);
+                    rect2.setLocation(20, y -= yIncr);
+                }
+                if ((type & IMG) != 0) {
+                    alpha += aIncr;
+                }
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                if ((type & RECT) != 0) {
+                    g2.setColor(myBlue);
+                    g2.fill(rect1);
+                    g2.setColor(myRed);
+                    g2.fill(rect2);
+                }
+                if ((type & IMG) != 0) {
+                    Composite saveAC = g2.getComposite();
+                    if (alpha >= 0 && alpha <= 1) {
+                        g2.setComposite(AlphaComposite.getInstance(
+                                AlphaComposite.SRC_OVER, alpha));
+                    }
+                    g2.drawImage(img, 30, 30, null);
+                    g2.setComposite(saveAC);
+                }
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End Temp class
+
+
+        /**
+         * Features of Java2D(TM).  Single character advancement effect.
+         */
+        static class Features implements Part {
+
+            static final int GRAPHICS = 0;
+            static final int TEXT = 1;
+            static final int IMAGES = 2;
+            static final int COLOR = 3;
+            static final Font font1 = new Font(Font.SERIF, Font.BOLD, 38);
+            static final Font font2 = new Font(Font.SERIF, Font.PLAIN, 24);
+            private final FontMetrics fm1;
+            private final FontMetrics fm2;
+            private static final String table[][] = { { "Graphics", "Antialiased rendering",
+                    "Bezier paths",
+                    "Transforms", "Compositing", "Stroking parameters" },
+                { "Text", "Extended font support",
+                    "Advanced text layout", "Dynamic font loading",
+                    "AttributeSets for font customization" },
+                { "Images", "Flexible image layouts",
+                    "Extended imaging operations",
+                    "   Convolutions, Lookup Tables",
+                    "RenderableImage interface" },
+                { "Color", "ICC profile support", "Color conversion",
+                    "Arbitrary color spaces" } };
+            private String list[];
+            private int beginning, ending;
+            private int strH;
+            private int endIndex, listIndex;
+            private List<String> v = new ArrayList<String>();
+
+            public Features(int type, int beg, int end, Surface surf) {
+                list = table[type];
+                this.beginning = beg;
+                this.ending = end;
+                fm1 = surf.getMetrics(font1);
+                fm2 = surf.getMetrics(font2);
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                strH = (fm2.getAscent() + fm2.getDescent());
+                endIndex = 1;
+                listIndex = 0;
+                v.clear();
+                v.add(list[listIndex].substring(0, endIndex));
+            }
+
+            @Override
+            public void step(int w, int h) {
+                if (listIndex < list.length) {
+                    if (++endIndex > list[listIndex].length()) {
+                        if (++listIndex < list.length) {
+                            endIndex = 1;
+                            v.add(list[listIndex].substring(0, endIndex));
+                        }
+                    } else {
+                        v.set(listIndex, list[listIndex].substring(0, endIndex));
+                    }
+                }
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                g2.setColor(myWhite);
+                g2.setFont(font1);
+                g2.drawString(v.get(0), 90, 85);
+                g2.setFont(font2);
+                for (int i = 1, y = 90; i < v.size(); i++) {
+                    g2.drawString(v.get(i), 120, y += strH);
+                }
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End Features class
+
+
+        /**
+         * Scrolling text of Java2D(TM) contributors.
+         */
+        static class Contributors implements Part {
+
+            private static final String members[] = {
+                "Brian Lichtenwalter", "Jeannette Hung",
+                "Thanh Nguyen", "Jim Graham", "Jerry Evans",
+                "John Raley", "Michael Peirce", "Robert Kim",
+                "Jennifer Ball", "Deborah Adair", "Paul Charlton",
+                "Dmitry Feld", "Gregory Stone", "Richard Blanchard",
+                "Link Perry", "Phil Race", "Vincent Hardy",
+                "Parry Kejriwal", "Doug Felt", "Rekha Rangarajan",
+                "Paula Patel", "Michael Bundschuh", "Joe Warzecha",
+                "Joey Beheler", "Aastha Bhardwaj", "Daniel Rice",
+                "Chris Campbell", "Shinsuke Fukuda", "Dmitri Trembovetski",
+                "Chet Haase", "Jennifer Godinez", "Nicholas Talian",
+                "Raul Vera", "Ankit Patel", "Ilya Bagrak",
+                "Praveen Mohan", "Rakesh Menon"
+            };
+            private static final Font font = new Font(Font.SERIF, Font.PLAIN, 26);
+            private final FontMetrics fm;
+            private int beginning, ending;
+            private int nStrs, strH, index, yh, height;
+            private List<String> v = new ArrayList<String>();
+            private List<String> cast =
+                    new ArrayList<String>(members.length + 3);
+            private int counter, cntMod;
+            private GradientPaint gp;
+
+            public Contributors(int beg, int end, Surface surf) {
+                this.beginning = beg;
+                this.ending = end;
+                fm = surf.getMetrics(font);
+                java.util.Arrays.sort(members);
+                cast.add("CONTRIBUTORS");
+                cast.add(" ");
+                cast.addAll(Arrays.asList(members));
+                cast.add(" ");
+                cast.add(" ");
+                cntMod = (ending - beginning) / cast.size() - 1;
+            }
+
+            @Override
+            public void reset(int w, int h) {
+                v.clear();
+                strH = (fm.getAscent() + fm.getDescent());
+                nStrs = (h - 40) / strH + 1;
+                height = strH * (nStrs - 1) + 48;
+                index = 0;
+                gp = new GradientPaint(0, h / 2, WHITE, 0, h + 20, BLACK);
+                counter = 0;
+            }
+
+            @Override
+            public void step(int w, int h) {
+                if (counter++ % cntMod == 0) {
+                    if (index < cast.size()) {
+                        v.add(cast.get(index));
+                    }
+                    if ((v.size() == nStrs || index >= cast.size()) && !v.
+                            isEmpty()) {
+                        v.remove(0);
+                    }
+                    ++index;
+                }
+            }
+
+            @Override
+            public void render(int w, int h, Graphics2D g2) {
+                g2.setPaint(gp);
+                g2.setFont(font);
+                double remainder = counter % cntMod;
+                double incr = 1.0 - remainder / cntMod;
+                incr = incr == 1.0 ? 0 : incr;
+                int y = (int) (incr * strH);
+
+                if (index >= cast.size()) {
+                    y = yh + y;
+                } else {
+                    y = yh = height - v.size() * strH + y;
+                }
+                for (String s : v) {
+                    g2.drawString(s, w / 2 - fm.stringWidth(s) / 2, y += strH);
+                }
+            }
+
+            @Override
+            public int getBegin() {
+                return beginning;
+            }
+
+            @Override
+            public int getEnd() {
+                return ending;
+            }
+        } // End Contributors class
+    } // End Surface class
+} // End Intro class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/J2Ddemo.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,728 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java2d.CustomControlsContext.State.START;
+import static java2d.CustomControlsContext.State.STOP;
+import static java2d.DemoImages.newDemoImages;
+import static java2d.DemoFonts.newDemoFonts;
+import static java2d.RunWindow.RunWindowSettings;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.Icon;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JColorChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JProgressBar;
+import javax.swing.JSeparator;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.EtchedBorder;
+
+
+/**
+ * A demo that shows Java 2D(TM) API features.
+ */
+@SuppressWarnings("serial")
+public class J2Ddemo extends JPanel implements ItemListener, ActionListener, DemoInstVarsAccessor {
+    private final GlobalControls controls;
+    private final MemoryMonitor memorymonitor;
+    private final PerformanceMonitor performancemonitor;
+    private final JTabbedPane tabbedPane;
+    private final DemoGroup[] group;
+    private JCheckBoxMenuItem verboseCB;
+    private JCheckBoxMenuItem ccthreadCB;
+    private JCheckBoxMenuItem printCB = new JCheckBoxMenuItem("Default Printer");
+    private Color backgroundColor;
+    private JCheckBoxMenuItem memoryCB, perfCB;
+    private final Intro intro;
+    public static final String[][] demos = {
+        { "Arcs_Curves", "Arcs", "BezierAnim", "Curves", "Ellipses" },
+        { "Clipping", "Areas", "ClipAnim", "Intersection", "Text" },
+        { "Colors", "BullsEye", "ColorConvert", "Rotator3D" },
+        { "Composite", "ACimages", "ACrules", "FadeAnim" },
+        { "Fonts", "AttributedStr", "Highlighting", "Outline", "Tree" },
+        { "Images", "DukeAnim", "ImageOps", "JPEGFlip", "WarpImage" },
+        { "Lines", "Caps", "Dash", "Joins", "LineAnim" },
+        { "Mix", "Balls", "BezierScroller", "Stars3D" },
+        { "Paint", "GradAnim", "Gradient", "Texture", "TextureAnim" },
+        { "Paths", "Append", "CurveQuadTo", "FillStroke", "WindingRule" },
+        { "Transforms", "Rotate", "SelectTx", "TransformAnim" }
+    };
+    private final boolean demoIsInApplet;
+    private JCheckBoxMenuItem controlsCB;
+    private JMenuItem runMI, cloneMI, fileMI, backgMI;
+//    private JMenuItem ccthreadMI, verboseMI;
+    private RunWindow runwindow;
+    private RunWindowSettings runWndSetts;
+    private CloningFeature cloningfeature;
+    private JFrame rf, cf;
+//    private GlobalPanel gp;
+
+    /**
+     * Construct the J2D Demo.
+     */
+    public J2Ddemo(boolean demoIsInApplet, DemoProgress progress, RunWindowSettings runWndSetts) {
+        this.demoIsInApplet = demoIsInApplet;
+        this.runWndSetts = runWndSetts;
+
+        setLayout(new BorderLayout());
+        setBorder(new EtchedBorder());
+
+        add(createMenuBar(), BorderLayout.NORTH);
+
+        // hard coding 14 = 11 demo dirs + images + fonts + Intro
+        progress.setMaximum(13);
+        progress.setText("Loading images");
+        newDemoImages();
+        progress.setValue(progress.getValue() + 1);
+        progress.setText("Loading fonts");
+        newDemoFonts();
+        progress.setValue(progress.getValue() + 1);
+        progress.setText("Loading Intro");
+        intro = new Intro();
+        progress.setValue(progress.getValue() + 1);
+        UIManager.put("Button.margin", new Insets(0, 0, 0, 0));
+
+        controls = new GlobalControls(this);
+        memorymonitor = new MemoryMonitor();
+        performancemonitor = new PerformanceMonitor();
+
+        GlobalPanel gp = new GlobalPanel(this);
+
+        tabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);
+        tabbedPane.setFont(new Font(Font.SERIF, Font.PLAIN, 12));
+        tabbedPane.addTab("", new J2DIcon(this), gp);
+        tabbedPane.addChangeListener(gp);
+
+        group = new DemoGroup[demos.length];
+        for (int i = 0; i < demos.length; i++) {
+            progress.setText("Loading demos." + demos[i][0]);
+            group[i] = new DemoGroup(demos[i][0], this);
+            tabbedPane.addTab(demos[i][0], null);
+            progress.setValue(progress.getValue() + 1);
+        }
+
+        add(tabbedPane, BorderLayout.CENTER);
+    }
+
+    private JMenuBar createMenuBar() {
+
+        JPopupMenu.setDefaultLightWeightPopupEnabled(false);
+        JMenuBar menuBar = new JMenuBar();
+
+        if (!demoIsInApplet) {
+            JMenu file = menuBar.add(new JMenu("File"));
+            fileMI = file.add(new JMenuItem("Exit"));
+            fileMI.addActionListener(this);
+        }
+
+        JMenu options = menuBar.add(new JMenu("Options"));
+
+        controlsCB = (JCheckBoxMenuItem) options.add(
+                new JCheckBoxMenuItem("Global Controls", true));
+        controlsCB.addItemListener(this);
+
+        memoryCB = (JCheckBoxMenuItem) options.add(
+                new JCheckBoxMenuItem("Memory Monitor", true));
+        memoryCB.addItemListener(this);
+
+        perfCB = (JCheckBoxMenuItem) options.add(
+                new JCheckBoxMenuItem("Performance Monitor", true));
+        perfCB.addItemListener(this);
+
+        options.add(new JSeparator());
+
+        ccthreadCB = (JCheckBoxMenuItem) options.add(
+                new JCheckBoxMenuItem("Custom Controls Thread"));
+        ccthreadCB.addItemListener(this);
+
+        printCB = (JCheckBoxMenuItem) options.add(printCB);
+
+        verboseCB = (JCheckBoxMenuItem) options.add(
+                new JCheckBoxMenuItem("Verbose"));
+
+        options.add(new JSeparator());
+
+        backgMI = options.add(new JMenuItem("Background Color"));
+        backgMI.addActionListener(this);
+
+        runMI = options.add(new JMenuItem("Run Window"));
+        runMI.addActionListener(this);
+
+        cloneMI = options.add(new JMenuItem("Cloning Feature"));
+        cloneMI.addActionListener(this);
+
+        return menuBar;
+    }
+
+    public void createRunWindow() {
+        if (rf != null) {
+            rf.toFront();
+            return;
+        }
+        runwindow = new RunWindow(this, runWndSetts);
+        WindowListener l = new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                runwindow.stop();
+                rf.dispose();
+            }
+
+            @Override
+            public void windowClosed(WindowEvent e) {
+                rf = null;
+            }
+        };
+        rf = new JFrame("Run");
+        rf.addWindowListener(l);
+        rf.getContentPane().add("Center", runwindow);
+        rf.pack();
+        if (!demoIsInApplet) {
+            rf.setSize(new Dimension(200, 125));
+        } else {
+            rf.setSize(new Dimension(200, 150));
+        }
+        rf.setVisible(true);
+    }
+
+    public void startRunWindow() {
+        SwingUtilities.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+                runwindow.doRunAction();
+            }
+        });
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (e.getSource().equals(fileMI)) {
+            System.exit(0);
+        } else if (e.getSource().equals(runMI)) {
+            createRunWindow();
+        } else if (e.getSource().equals(cloneMI)) {
+            if (cloningfeature == null) {
+                cloningfeature = new CloningFeature(this);
+                WindowListener l = new WindowAdapter() {
+
+                    @Override
+                    public void windowClosing(WindowEvent e) {
+                        cloningfeature.stop();
+                        cf.dispose();
+                    }
+
+                    @Override
+                    public void windowClosed(WindowEvent e) {
+                        cloningfeature = null;
+                    }
+                };
+                cf = new JFrame("Cloning Demo");
+                cf.addWindowListener(l);
+                cf.getContentPane().add("Center", cloningfeature);
+                cf.pack();
+                cf.setSize(new Dimension(320, 330));
+                cf.setVisible(true);
+            } else {
+                cf.toFront();
+            }
+        } else if (e.getSource().equals(backgMI)) {
+            backgroundColor =
+                    JColorChooser.showDialog(this, "Background Color",
+                    Color.white);
+            for (int i = 1; i < tabbedPane.getTabCount(); i++) {
+                JPanel p = group[i - 1].getPanel();
+                for (int j = 0; j < p.getComponentCount(); j++) {
+                    DemoPanel dp = (DemoPanel) p.getComponent(j);
+                    if (dp.surface != null) {
+                        dp.surface.setBackground(backgroundColor);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void itemStateChanged(ItemEvent e) {
+        if (e.getSource().equals(controlsCB)) {
+            boolean newVisibility = !controls.isVisible();
+            controls.setVisible(newVisibility);
+            for (Component cmp : controls.texturechooser.getComponents()) {
+                cmp.setVisible(newVisibility);
+            }
+        } else if (e.getSource().equals(memoryCB)) {
+            if (memorymonitor.isVisible()) {
+                memorymonitor.setVisible(false);
+                memorymonitor.surf.setVisible(false);
+                memorymonitor.surf.stop();
+            } else {
+                memorymonitor.setVisible(true);
+                memorymonitor.surf.setVisible(true);
+                memorymonitor.surf.start();
+            }
+        } else if (e.getSource().equals(perfCB)) {
+            if (performancemonitor.isVisible()) {
+                performancemonitor.setVisible(false);
+                performancemonitor.surf.setVisible(false);
+                performancemonitor.surf.stop();
+            } else {
+                performancemonitor.setVisible(true);
+                performancemonitor.surf.setVisible(true);
+                performancemonitor.surf.start();
+            }
+        } else if (e.getSource().equals(ccthreadCB)) {
+            CustomControlsContext.State state =
+                    ccthreadCB.isSelected() ? START : STOP;
+            if (tabbedPane.getSelectedIndex() != 0) {
+                JPanel p = group[tabbedPane.getSelectedIndex() - 1].getPanel();
+                for (int i = 0; i < p.getComponentCount(); i++) {
+                    DemoPanel dp = (DemoPanel) p.getComponent(i);
+                    if (dp.ccc != null) {
+                        dp.ccc.handleThread(state);
+                    }
+                }
+            }
+        }
+        revalidate();
+    }
+
+    public void start() {
+        if (tabbedPane.getSelectedIndex() == 0) {
+            intro.start();
+        } else {
+            group[tabbedPane.getSelectedIndex() - 1].setup(false);
+            if (memorymonitor.surf.thread == null && memoryCB.getState()) {
+                memorymonitor.surf.start();
+            }
+            if (performancemonitor.surf.thread == null && perfCB.getState()) {
+                performancemonitor.surf.start();
+            }
+        }
+    }
+
+    public void stop() {
+        if (tabbedPane.getSelectedIndex() == 0) {
+            intro.stop();
+        } else {
+            memorymonitor.surf.stop();
+            performancemonitor.surf.stop();
+            int i = tabbedPane.getSelectedIndex() - 1;
+            group[i].shutDown(group[i].getPanel());
+        }
+    }
+
+    /**
+     * Start of 'DemoInstVarsAccessor' implementation.
+     */
+    @Override
+    public GlobalControls getControls() {
+        return controls;
+    }
+
+    @Override
+    public MemoryMonitor getMemoryMonitor() {
+        return memorymonitor;
+    }
+
+    @Override
+    public PerformanceMonitor getPerformanceMonitor() {
+        return performancemonitor;
+    }
+
+    @Override
+    public JTabbedPane getTabbedPane() {
+        return tabbedPane;
+    }
+
+    @Override
+    public DemoGroup[] getGroup() {
+        return group;
+    }
+
+    @Override
+    public void setGroupColumns(int columns) {
+        for (DemoGroup dg : group) {
+            if (dg != null) {
+                dg.columns = columns;
+            }
+        }
+    }
+
+    @Override
+    public JCheckBoxMenuItem getVerboseCB() {
+        return verboseCB;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getCcthreadCB() {
+        return ccthreadCB;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getPrintCB() {
+        return printCB;
+    }
+
+    @Override
+    public Color getBackgroundColor() {
+        return backgroundColor;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getMemoryCB() {
+        return memoryCB;
+    }
+
+    @Override
+    public JCheckBoxMenuItem getPerfCB() {
+        return perfCB;
+    }
+
+    @Override
+    public Intro getIntro() {
+        return intro;
+    }
+    /**
+     * End of 'DemoInstVarsAccessor' implementation.
+     */
+
+    static void addToGridBag(JPanel panel, Component comp,
+            int x, int y, int w, int h, double weightx, double weighty) {
+
+        GridBagLayout gbl = (GridBagLayout) panel.getLayout();
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.BOTH;
+        c.gridx = x;
+        c.gridy = y;
+        c.gridwidth = w;
+        c.gridheight = h;
+        c.weightx = weightx;
+        c.weighty = weighty;
+        panel.add(comp);
+        gbl.setConstraints(comp, c);
+    }
+
+
+    /**
+     * The Icon for the Intro tab.
+     */
+    static class J2DIcon implements Icon {
+        private final DemoInstVarsAccessor demoInstVars;
+        private static final Color myBlue = new Color(94, 105, 176);
+        private static final Color myBlack = new Color(20, 20, 20);
+        private static final Font font = new Font(Font.SERIF, Font.BOLD, 12);
+        private FontRenderContext frc = new FontRenderContext(null, true, true);
+        private TextLayout tl = new TextLayout("J2D demo", font, frc);
+
+        public J2DIcon(DemoInstVarsAccessor demoInstVars) {
+            this.demoInstVars = demoInstVars;
+        }
+
+        @Override
+        public void paintIcon(Component c, Graphics g, int x, int y) {
+            Graphics2D g2 = (Graphics2D) g;
+            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                    RenderingHints.VALUE_ANTIALIAS_ON);
+            g2.setFont(font);
+            if (demoInstVars.getTabbedPane().getSelectedIndex() == 0) {
+                g2.setColor(myBlue);
+            } else {
+                g2.setColor(myBlack);
+            }
+            tl.draw(g2, x, y + (float)(tl.getBounds().getHeight()));
+        }
+
+        @Override
+        public int getIconWidth() {
+            return (int)(tl.getAdvance())+5;
+        }
+
+        @Override
+        public int getIconHeight() {
+            return (int)(tl.getBounds().getHeight());
+        }
+    }
+
+    /**
+     * This class eliminates the need in presence of static 'JLabel', 'JProgressBar'
+     * variables in 'J2Ddemo' class. It is a part of the fix which changed static
+     * variables for instance variables in certain demo classes.
+     */
+    public static class DemoProgress {
+        private final JLabel progressLabel;
+        private final JProgressBar progressBar;
+
+        public DemoProgress(JLabel progressLabel, JProgressBar progressBar) {
+            if (progressLabel == null) {
+                throw new IllegalArgumentException("null was transferred as 'progressLabel' argument");
+            }
+            if (progressBar == null) {
+                throw new IllegalArgumentException("null was transferred as 'progressBar' argument");
+            }
+
+            this.progressLabel = progressLabel;
+            this.progressBar = progressBar;
+        }
+
+        public void setText(String text) {
+            progressLabel.setText(text);
+        }
+
+        public void setMaximum(int n) {
+            progressBar.setMaximum(n);
+        }
+
+        public int getValue() {
+            return progressBar.getValue();
+        }
+
+        public void setValue(int n) {
+            progressBar.setValue(n);
+        }
+    }
+
+    private static void initFrame(String[] args, RunWindowSettings runWndSetts) {
+        final J2Ddemo[] demoOneInstArr = new J2Ddemo[1];
+
+        JFrame frame = new JFrame("Java 2D(TM) Demo");
+        frame.getAccessibleContext().setAccessibleDescription(
+                "A sample application to demonstrate Java2D(TM) features");
+        int FRAME_WIDTH = 400, FRAME_HEIGHT = 200;
+        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
+        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+        frame.setLocation(d.width / 2 - FRAME_WIDTH / 2, d.height / 2 - FRAME_HEIGHT
+                / 2);
+        frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+        frame.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+
+            @Override
+            public void windowDeiconified(WindowEvent e) {
+                J2Ddemo demo = demoOneInstArr[0];
+                if (demo != null) {
+                    demo.start();
+                }
+            }
+
+            @Override
+            public void windowIconified(WindowEvent e) {
+                J2Ddemo demo = demoOneInstArr[0];
+                if (demo != null) {
+                    demo.stop();
+                }
+            }
+        });
+        JOptionPane.setRootFrame(frame);
+
+        JPanel progressPanel = new JPanel() {
+
+            @Override
+            public Insets getInsets() {
+                return new Insets(40, 30, 20, 30);
+            }
+        };
+        progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS));
+        frame.getContentPane().add(progressPanel, BorderLayout.CENTER);
+
+        Dimension labelSize = new Dimension(400, 20);
+        JLabel progressLabel = new JLabel("Loading, please wait...");
+        progressLabel.setAlignmentX(CENTER_ALIGNMENT);
+        progressLabel.setMaximumSize(labelSize);
+        progressLabel.setPreferredSize(labelSize);
+        progressPanel.add(progressLabel);
+        progressPanel.add(Box.createRigidArea(new Dimension(1, 20)));
+
+        JProgressBar progressBar = new JProgressBar();
+        progressBar.setStringPainted(true);
+        progressLabel.setLabelFor(progressBar);
+        progressBar.setAlignmentX(CENTER_ALIGNMENT);
+        progressBar.setMinimum(0);
+        progressBar.setValue(0);
+        progressBar.getAccessibleContext().setAccessibleName(
+                                  "J2D demo loading progress");
+        progressPanel.add(progressBar);
+        DemoProgress demoProgress = new DemoProgress(progressLabel, progressBar);
+
+        frame.setVisible(true);
+
+        J2Ddemo demo = new J2Ddemo(false, demoProgress, runWndSetts);
+        demoOneInstArr[0] = demo;
+
+        frame.getContentPane().removeAll();
+        frame.getContentPane().setLayout(new BorderLayout());
+        frame.getContentPane().add(demo, BorderLayout.CENTER);
+        FRAME_WIDTH = 850;
+        FRAME_HEIGHT = 600;
+        frame.setLocation(d.width / 2 - FRAME_WIDTH / 2, d.height / 2 - FRAME_HEIGHT
+                / 2);
+        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
+        frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            String s = arg.substring(arg.indexOf('=') + 1);
+            if (arg.startsWith("-runs=")) {
+                runWndSetts.setNumRuns(Integer.parseInt(s));
+                runWndSetts.setExit(true);
+                demo.createRunWindow();
+            } else if (arg.startsWith("-screen=")) {
+                demo.getControls().screenCombo.setSelectedIndex(Integer.parseInt(s));
+            } else if (arg.startsWith("-antialias=")) {
+                demo.controls.aliasCB.setSelected(s.endsWith("true"));
+            } else if (arg.startsWith("-rendering=")) {
+                demo.controls.renderCB.setSelected(s.endsWith("true"));
+            } else if (arg.startsWith("-texture=")) {
+                demo.controls.textureCB.setSelected(s.endsWith("true"));
+            } else if (arg.startsWith("-composite=")) {
+                demo.controls.compositeCB.setSelected(s.endsWith("true"));
+            } else if (arg.startsWith("-verbose")) {
+                demo.verboseCB.setSelected(true);
+            } else if (arg.startsWith("-print")) {
+                demo.printCB.setSelected(true);
+                runWndSetts.setPrintCBIsSelected(true);
+            } else if (arg.startsWith("-columns=")) {
+                demo.setGroupColumns(Integer.parseInt(s));
+            } else if (arg.startsWith("-buffers=")) {
+                // usage -buffers=3,10
+                runWndSetts.setBuffersFlag(true);
+                int i1 = arg.indexOf('=') + 1;
+                int i2 = arg.indexOf(',');
+                String s1 = arg.substring(i1, i2);
+                runWndSetts.setBufBeg(Integer.parseInt(s1));
+                s1 = arg.substring(i2 + 1, arg.length());
+                runWndSetts.setBufEnd(Integer.parseInt(s1));
+            } else if (arg.startsWith("-ccthread")) {
+                demo.ccthreadCB.setSelected(true);
+            } else if (arg.startsWith("-zoom")) {
+                runWndSetts.setZoomCBSelected(true);
+            } else if (arg.startsWith("-maxscreen")) {
+                frame.setLocation(0, 0);
+                frame.setSize(d.width, d.height);
+            }
+        }
+
+        frame.validate();
+        frame.repaint();
+        frame.getFocusTraversalPolicy().getDefaultComponent(frame).requestFocus();
+        demo.start();
+
+        if (runWndSetts.getExit()) {
+            demo.startRunWindow();
+        }
+
+    }
+
+    public static void main(final String args[]) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                RunWindowSettings runWndSetts = new RunWindowSettings();
+                for (int i = 0; i < args.length; i++) {
+                    if (args[i].startsWith("-h") || args[i].startsWith("-help")) {
+                        String s = "\njava -jar J2Ddemo.jar -runs=5 -delay=5 -screen=5 "
+                                + "-antialias=true -rendering=true -texture=true "
+                                + "-composite=true -verbose -print -columns=3 "
+                                + "-buffers=5,10 -ccthread -zoom -maxscreen \n";
+                        System.out.println(s);
+                        s =
+                                "    -runs=5       Number of runs to execute\n"
+                                + "    -delay=5      Sleep amount between tabs\n"
+                                + "    -antialias=   true or false for antialiasing\n"
+                                + "    -rendering=   true or false for quality or speed\n"
+                                + "    -texture=     true or false for texturing\n"
+                                + "    -composite=   true or false for compositing\n"
+                                + "    -verbose      output Surface graphic states \n"
+                                + "    -print        during run print the Surface, "
+                                + "use the Default Printer\n"
+                                + "    -columns=3    # of columns to use in clone layout \n"
+                                + "    -screen=3     demos all use this screen type \n"
+                                + "    -buffers=5,10 during run - clone to see screens "
+                                + "five through ten\n"
+                                + "    -ccthread     Invoke the Custom Controls Thread \n"
+                                + "    -zoom         mouseClick on surface for zoom in  \n"
+                                + "    -maxscreen    take up the entire monitor screen \n";
+                        System.out.println(s);
+                        s =
+                                "Examples : \n" + "    Print all of the demos : \n"
+                                + "        java -jar J2Ddemo.jar -runs=1 -delay=60 -print \n"
+                                + "    Run zoomed in with custom control thread \n"
+                                + "        java -jar J2Ddemo.jar -runs=10 -zoom -ccthread\n";
+                        System.out.println(s);
+                        System.exit(0);
+                    } else if (args[i].startsWith("-delay=")) {
+                        String s = args[i].substring(args[i].indexOf('=') + 1);
+                        runWndSetts.setDelay(Integer.parseInt(s));
+                    }
+                }
+
+                initFrame(args, runWndSetts);
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/MemoryMonitor.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,367 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.YELLOW;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.Date;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+
+
+/**
+ * Tracks Memory allocated & used, displayed in graph form.
+ */
+@SuppressWarnings("serial")
+public class MemoryMonitor extends JPanel {
+
+    private final JCheckBox dateStampCB = new JCheckBox("Output Date Stamp");
+    public Surface surf;
+    JPanel controls;
+    boolean doControls;
+    JTextField tf;
+
+    public MemoryMonitor() {
+        setLayout(new BorderLayout());
+        setBorder(new TitledBorder(new EtchedBorder(), "Memory Monitor"));
+        add(surf = new Surface());
+        controls = new JPanel();
+        controls.setPreferredSize(new Dimension(135, 80));
+        Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+        JLabel label = new JLabel("Sample Rate");
+        label.setFont(font);
+        label.setForeground(BLACK);
+        controls.add(label);
+        tf = new JTextField("1000");
+        tf.setPreferredSize(new Dimension(45, 20));
+        controls.add(tf);
+        controls.add(label = new JLabel("ms"));
+        label.setFont(font);
+        label.setForeground(BLACK);
+        controls.add(dateStampCB);
+        dateStampCB.setFont(font);
+        addMouseListener(new MouseAdapter() {
+
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                removeAll();
+                if ((doControls = !doControls)) {
+                    surf.stop();
+                    add(controls);
+                } else {
+                    try {
+                        surf.sleepAmount = Long.parseLong(tf.getText().trim());
+                    } catch (Exception ex) {
+                    }
+                    surf.start();
+                    add(surf);
+                }
+                revalidate();
+                repaint();
+            }
+        });
+    }
+
+
+    public class Surface extends JPanel implements Runnable {
+
+        public Thread thread;
+        public long sleepAmount = 1000;
+        private int w, h;
+        private BufferedImage bimg;
+        private Graphics2D big;
+        private Font font = new Font(Font.SERIF, Font.PLAIN, 11);
+        private Runtime r = Runtime.getRuntime();
+        private int columnInc;
+        private int pts[];
+        private int ptNum;
+        private int ascent, descent;
+        private Rectangle graphOutlineRect = new Rectangle();
+        private Rectangle2D mfRect = new Rectangle2D.Float();
+        private Rectangle2D muRect = new Rectangle2D.Float();
+        private Line2D graphLine = new Line2D.Float();
+        private Color graphColor = new Color(46, 139, 87);
+        private Color mfColor = new Color(0, 100, 0);
+        private String usedStr;
+
+        public Surface() {
+            setBackground(BLACK);
+            addMouseListener(new MouseAdapter() {
+
+                @Override
+                public void mouseClicked(MouseEvent e) {
+                    if (thread == null) {
+                        start();
+                    } else {
+                        stop();
+                    }
+                }
+            });
+        }
+
+        @Override
+        public Dimension getMinimumSize() {
+            return getPreferredSize();
+        }
+
+        @Override
+        public Dimension getMaximumSize() {
+            return getPreferredSize();
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(135, 80);
+        }
+
+        @Override
+        public void paint(Graphics g) {
+
+            if (big == null) {
+                return;
+            }
+
+            big.setBackground(getBackground());
+            big.clearRect(0, 0, w, h);
+
+            float freeMemory = r.freeMemory();
+            float totalMemory = r.totalMemory();
+
+            // .. Draw allocated and used strings ..
+            big.setColor(GREEN);
+            big.drawString(String.valueOf((int) totalMemory / 1024)
+                    + "K allocated", 4.0f, ascent + 0.5f);
+            usedStr = String.valueOf(((int) (totalMemory - freeMemory)) / 1024)
+                    + "K used";
+            big.drawString(usedStr, 4, h - descent);
+
+            // Calculate remaining size
+            float ssH = ascent + descent;
+            float remainingHeight = (h - (ssH * 2) - 0.5f);
+            float blockHeight = remainingHeight / 10;
+            float blockWidth = 20.0f;
+
+            // .. Memory Free ..
+            big.setColor(mfColor);
+            int MemUsage = (int) ((freeMemory / totalMemory) * 10);
+            int i = 0;
+            for (; i < MemUsage; i++) {
+                mfRect.setRect(5, ssH + i * blockHeight,
+                        blockWidth, blockHeight - 1);
+                big.fill(mfRect);
+            }
+
+            // .. Memory Used ..
+            big.setColor(GREEN);
+            for (; i < 10; i++) {
+                muRect.setRect(5, ssH + i * blockHeight,
+                        blockWidth, blockHeight - 1);
+                big.fill(muRect);
+            }
+
+            // .. Draw History Graph ..
+            big.setColor(graphColor);
+            int graphX = 30;
+            int graphY = (int) ssH;
+            int graphW = w - graphX - 5;
+            int graphH = (int) remainingHeight;
+            graphOutlineRect.setRect(graphX, graphY, graphW, graphH);
+            big.draw(graphOutlineRect);
+
+            int graphRow = graphH / 10;
+
+            // .. Draw row ..
+            for (int j = graphY; j <= graphH + graphY; j += graphRow) {
+                graphLine.setLine(graphX, j, graphX + graphW, j);
+                big.draw(graphLine);
+            }
+
+            // .. Draw animated column movement ..
+            int graphColumn = graphW / 15;
+
+            if (columnInc == 0) {
+                columnInc = graphColumn;
+            }
+
+            for (int j = graphX + columnInc; j < graphW + graphX; j +=
+                            graphColumn) {
+                graphLine.setLine(j, graphY, j, graphY + graphH);
+                big.draw(graphLine);
+            }
+
+            --columnInc;
+
+            if (pts == null) {
+                pts = new int[graphW];
+                ptNum = 0;
+            } else if (pts.length != graphW) {
+                int tmp[] = null;
+                if (ptNum < graphW) {
+                    tmp = new int[ptNum];
+                    System.arraycopy(pts, 0, tmp, 0, tmp.length);
+                } else {
+                    tmp = new int[graphW];
+                    System.arraycopy(pts, pts.length - tmp.length, tmp, 0,
+                            tmp.length);
+                    ptNum = tmp.length - 2;
+                }
+                pts = new int[graphW];
+                System.arraycopy(tmp, 0, pts, 0, tmp.length);
+            } else {
+                big.setColor(YELLOW);
+                pts[ptNum] =
+                        (int) (graphY + graphH * (freeMemory / totalMemory));
+                for (int j = graphX + graphW - ptNum, k = 0; k < ptNum; k++, j++) {
+                    if (k != 0) {
+                        if (pts[k] != pts[k - 1]) {
+                            big.drawLine(j - 1, pts[k - 1], j, pts[k]);
+                        } else {
+                            big.fillRect(j, pts[k], 1, 1);
+                        }
+                    }
+                }
+                if (ptNum + 2 == pts.length) {
+                    // throw out oldest point
+                    for (int j = 1; j < ptNum; j++) {
+                        pts[j - 1] = pts[j];
+                    }
+                    --ptNum;
+                } else {
+                    ptNum++;
+                }
+            }
+            g.drawImage(bimg, 0, 0, this);
+        }
+
+        public void start() {
+            thread = new Thread(this);
+            thread.setPriority(Thread.MIN_PRIORITY);
+            thread.setName("MemoryMonitor");
+            thread.start();
+        }
+
+        public synchronized void stop() {
+            thread = null;
+            notify();
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+
+            Thread me = Thread.currentThread();
+
+            while (thread == me && !isShowing() || getSize().width == 0) {
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                    return;
+                }
+            }
+
+            while (thread == me && isShowing()) {
+                Dimension d = getSize();
+                if (d.width != w || d.height != h) {
+                    w = d.width;
+                    h = d.height;
+                    bimg = (BufferedImage) createImage(w, h);
+                    big = bimg.createGraphics();
+                    big.setFont(font);
+                    FontMetrics fm = big.getFontMetrics(font);
+                    ascent = fm.getAscent();
+                    descent = fm.getDescent();
+                }
+                repaint();
+                try {
+                    Thread.sleep(sleepAmount);
+                } catch (InterruptedException e) {
+                    break;
+                }
+                if (dateStampCB.isSelected()) {
+                    System.out.println(new Date().toString() + " " + usedStr);
+                }
+            }
+            thread = null;
+        }
+    }
+
+    public static void main(String s[]) {
+        final MemoryMonitor demo = new MemoryMonitor();
+        WindowListener l = new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+
+            @Override
+            public void windowDeiconified(WindowEvent e) {
+                demo.surf.start();
+            }
+
+            @Override
+            public void windowIconified(WindowEvent e) {
+                demo.surf.stop();
+            }
+        };
+        JFrame f = new JFrame("J2D Demo - MemoryMonitor");
+        f.addWindowListener(l);
+        f.getContentPane().add("Center", demo);
+        f.pack();
+        f.setSize(new Dimension(200, 200));
+        f.setVisible(true);
+        demo.surf.start();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/PerformanceMonitor.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,202 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import javax.swing.JPanel;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+
+
+/**
+ * Displays the time for a Surface to paint. Displays the number
+ * of frames per second on animated demos.  Up to four surfaces fit
+ * in the display area.
+ */
+@SuppressWarnings("serial")
+public class PerformanceMonitor extends JPanel {
+
+    Surface surf;
+
+    public PerformanceMonitor() {
+        setLayout(new BorderLayout());
+        setBorder(new TitledBorder(new EtchedBorder(), "Performance"));
+        add(surf = new Surface());
+    }
+
+
+    public class Surface extends JPanel implements Runnable {
+
+        public Thread thread;
+        private BufferedImage bimg;
+        private Font font = new Font(Font.SERIF, Font.PLAIN, 12);
+        private JPanel panel;
+
+        public Surface() {
+            setBackground(Color.black);
+            addMouseListener(new MouseAdapter() {
+
+                @Override
+                public void mouseClicked(MouseEvent e) {
+                    if (thread == null) {
+                        start();
+                    } else {
+                        stop();
+                    }
+                }
+            });
+        }
+
+        @Override
+        public Dimension getMinimumSize() {
+            return getPreferredSize();
+        }
+
+        @Override
+        public Dimension getMaximumSize() {
+            return getPreferredSize();
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            int textH = getFontMetrics(font).getHeight();
+            return new Dimension(135, 2 + textH * 4);
+        }
+
+        @Override
+        public void paint(Graphics g) {
+            if (bimg != null) {
+                g.drawImage(bimg, 0, 0, this);
+            }
+        }
+
+        public void start() {
+            thread = new Thread(this);
+            thread.setPriority(Thread.MIN_PRIORITY);
+            thread.setName("PerformanceMonitor");
+            thread.start();
+        }
+
+        public synchronized void stop() {
+            thread = null;
+            setSurfaceState();
+            notify();
+        }
+
+        public void setSurfaceState() {
+            if (panel != null) {
+                for (Component comp : panel.getComponents()) {
+                    if (((DemoPanel) comp).surface != null) {
+                        ((DemoPanel) comp).surface.setMonitor(thread != null);
+                    }
+                }
+            }
+        }
+
+        public void setPanel(JPanel panel) {
+            this.panel = panel;
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+
+            Thread me = Thread.currentThread();
+
+            while (thread == me && !isShowing() || getSize().width == 0) {
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                    return;
+                }
+            }
+
+            Dimension d = new Dimension(0, 0);
+            Graphics2D big = null;
+            FontMetrics fm = null;
+            int ascent = 0;
+            int descent = 0;
+
+            while (thread == me && isShowing()) {
+
+                if (getWidth() != d.width || getHeight() != d.height) {
+                    d = getSize();
+                    bimg = (BufferedImage) createImage(d.width, d.height);
+                    big = bimg.createGraphics();
+                    big.setFont(font);
+                    fm = big.getFontMetrics();
+                    ascent = fm.getAscent();
+                    descent = fm.getDescent();
+                    setSurfaceState();
+                }
+
+                big.setBackground(getBackground());
+                big.clearRect(0, 0, d.width, d.height);
+                if (panel == null) {
+                    continue;
+                }
+                big.setColor(Color.green);
+                int ssH = 1;
+                for (Component comp : panel.getComponents()) {
+                    if (((DemoPanel) comp).surface != null) {
+                        String pStr = ((DemoPanel) comp).surface.perfStr;
+                        if (pStr != null) {
+                            ssH += ascent;
+                            big.drawString(pStr, 4, ssH + 1);
+                            ssH += descent;
+                        }
+                    }
+                }
+                repaint();
+
+                try {
+                    Thread.sleep(999);
+                } catch (InterruptedException e) {
+                    break;
+                }
+            }
+            thread = null;
+        }
+    } // End Surface
+} // End PeformanceMonitor
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/RunWindow.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,444 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.RED;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+
+
+/**
+ * A separate window for running the J2Ddemo.  Go from tab to tab or demo to
+ * demo.
+ */
+@SuppressWarnings("serial")
+public class RunWindow extends JPanel implements Runnable, ActionListener {
+    private final DemoInstVarsAccessor demoInstVars;
+    private final JButton runB;
+    private int delay = 10;
+    private int numRuns = 20;
+    private boolean exit;
+    private final JCheckBox zoomCB = new JCheckBox("Zoom");
+    private final JCheckBox printCB = new JCheckBox("Print");
+    private boolean buffersFlag;
+    private int bufBeg, bufEnd;
+    private JTextField delayTextField, runsTextField;
+    private Thread thread;
+    private JProgressBar pb;
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public RunWindow(DemoInstVarsAccessor demoInstVars, RunWindowSettings runWndSetts) {
+        this.demoInstVars = demoInstVars;
+
+        delay = runWndSetts.getDelay();
+        numRuns = runWndSetts.getNumRuns();
+        exit = runWndSetts.getExit();
+        zoomCB.setSelected(runWndSetts.isZoomCBSelected());
+        printCB.setSelected(runWndSetts.isPrintCBSelected());
+        buffersFlag = runWndSetts.getBuffersFlag();
+        bufBeg = runWndSetts.getBufBeg();
+        bufEnd = runWndSetts.getBufEnd();
+
+        setLayout(new GridBagLayout());
+        EmptyBorder eb = new EmptyBorder(5, 5, 5, 5);
+        setBorder(new CompoundBorder(eb, new BevelBorder(BevelBorder.LOWERED)));
+
+        Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+
+        runB = new JButton("Run");
+        runB.setBackground(GREEN);
+        runB.addActionListener(this);
+        runB.setMinimumSize(new Dimension(70, 30));
+        J2Ddemo.addToGridBag(this, runB, 0, 0, 1, 1, 0.0, 0.0);
+
+        pb = new JProgressBar();
+        pb.setPreferredSize(new Dimension(100, 30));
+        pb.setMinimum(0);
+        J2Ddemo.addToGridBag(this, pb, 1, 0, 2, 1, 1.0, 0.0);
+
+        JPanel p1 = new JPanel(new GridLayout(2, 2));
+        JPanel p2 = new JPanel();
+        JLabel l = new JLabel("Runs:");
+        l.setFont(font);
+        l.setForeground(BLACK);
+        p2.add(l);
+        p2.add(runsTextField = new JTextField(String.valueOf(numRuns)));
+        runsTextField.setPreferredSize(new Dimension(30, 20));
+        runsTextField.addActionListener(this);
+        p1.add(p2);
+        p2 = new JPanel();
+        l = new JLabel("Delay:");
+        l.setFont(font);
+        l.setForeground(BLACK);
+        p2.add(l);
+        p2.add(delayTextField = new JTextField(String.valueOf(delay)));
+        delayTextField.setPreferredSize(new Dimension(30, 20));
+        delayTextField.addActionListener(this);
+        p1.add(p2);
+
+        zoomCB.setHorizontalAlignment(SwingConstants.CENTER);
+        zoomCB.setFont(font);
+        printCB.setFont(font);
+        p1.add(zoomCB);
+        p1.add(printCB);
+        printCB.addActionListener(this);
+        J2Ddemo.addToGridBag(this, p1, 0, 1, 3, 1, 1.0, 1.0);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (e.getSource().equals(printCB)) {
+            demoInstVars.getPrintCB().setSelected(printCB.isSelected());
+        } else if (e.getSource().equals(delayTextField)) {
+            delay = Integer.parseInt(delayTextField.getText().trim());
+        } else if (e.getSource().equals(runsTextField)) {
+            numRuns = Integer.parseInt(runsTextField.getText().trim());
+        } else if ("Run".equals(e.getActionCommand())) {
+            doRunAction();
+        } else if ("Stop".equals(e.getActionCommand())) {
+            stop();
+        }
+    }
+
+    public void doRunAction() {
+        runB.setText("Stop");
+        runB.setBackground(RED);
+        start();
+    }
+
+    public void start() {
+        thread = new Thread(this);
+        thread.setPriority(Thread.NORM_PRIORITY + 1);
+        thread.setName("RunWindow");
+        thread.start();
+    }
+
+    public synchronized void stop() {
+        if (thread != null) {
+            thread.interrupt();
+        }
+        thread = null;
+        notifyAll();
+    }
+
+    @SuppressWarnings("SleepWhileHoldingLock")
+    public void sleepPerTab() {
+        for (int j = 0; j < delay + 1 && thread != null; j++) {
+            for (int k = 0; k < 10 && thread != null; k++) {
+                try {
+                    Thread.sleep(100);
+                } catch (Exception e) {
+                }
+            }
+            Runnable pbUpdateRunnable = new Runnable() {
+
+                @Override
+                public void run() {
+                    pb.setValue(pb.getValue() + 1);
+                }
+            };
+            SwingUtilities.invokeLater(pbUpdateRunnable);
+        }
+    }
+
+    private void printDemo(final DemoGroup dg) {
+        Runnable printDemoRunnable = new Runnable() {
+
+            @Override
+            public void run() {
+                if (!demoInstVars.getControls().toolBarCB.isSelected()) {
+                    demoInstVars.getControls().toolBarCB.setSelected(true);
+                    dg.invalidate();
+                }
+                for (Component comp : dg.getPanel().getComponents()) {
+                    DemoPanel dp = (DemoPanel) comp;
+                    if (dp.tools != null) {
+                        if (dp.surface.animating != null) {
+                            if (dp.surface.animating.running()) {
+                                dp.tools.startStopB.doClick();
+                            }
+                        }
+                        dp.tools.printB.doClick();
+                    }
+                }
+            }
+        };
+        invokeAndWait(printDemoRunnable);
+    }
+    private DemoGroup dg = null;
+    private DemoPanel dp = null;
+
+    @Override
+    public void run() {
+
+        System.out.println("\nJ2D Demo RunWindow : " + numRuns + " Runs, "
+                + delay + " second delay between tabs\n" + "java version: " + System.
+                getProperty("java.version") + "\n" + System.getProperty(
+                "os.name") + " " + System.getProperty("os.version") + "\n");
+        Runtime r = Runtime.getRuntime();
+
+        for (int runNum = 0; runNum < numRuns && thread != null; runNum++) {
+
+            Date d = new Date();
+            System.out.print("#" + runNum + " " + d.toString() + ", ");
+            r.gc();
+            float freeMemory = r.freeMemory();
+            float totalMemory = r.totalMemory();
+            System.out.println(((totalMemory - freeMemory) / 1024) + "K used");
+
+            for (int i = 0; i < demoInstVars.getTabbedPane().getTabCount() && thread
+                    != null; i++) {
+
+                final int mainTabIndex = i;
+                Runnable initDemoRunnable = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        pb.setValue(0);
+                        pb.setMaximum(delay);
+                        if (mainTabIndex != 0) {
+                            dg = demoInstVars.getGroup()[mainTabIndex - 1];
+                            dg.invalidate();
+                        }
+                        demoInstVars.getTabbedPane().setSelectedIndex(mainTabIndex);
+                    }
+                };
+                invokeAndWait(initDemoRunnable);
+
+                if (i != 0 && (zoomCB.isSelected() || buffersFlag)) {
+                    dp = (DemoPanel) dg.getPanel().getComponent(0);
+                    if (dg.tabbedPane == null && dp.surface != null) {
+                        Runnable mouseClickedRunnable = new Runnable() {
+
+                            @Override
+                            public void run() {
+                                dg.mouseClicked(dp.surface);
+                            }
+                        };
+                        invokeAndWait(mouseClickedRunnable);
+                    }
+                    for (int j = 1; j < dg.tabbedPane.getTabCount() && thread
+                            != null; j++) {
+
+                        final int subTabIndex = j;
+
+                        Runnable initPanelRunnable = new Runnable() {
+
+                            @Override
+                            public void run() {
+                                pb.setValue(0);
+                                pb.setMaximum(delay);
+                                dg.tabbedPane.setSelectedIndex(subTabIndex);
+                            }
+                        };
+                        invokeAndWait(initPanelRunnable);
+
+                        final JPanel p = dg.getPanel();
+                        if (buffersFlag && p.getComponentCount() == 1) {
+                            dp = (DemoPanel) p.getComponent(0);
+                            if (dp.surface.animating != null) {
+                                dp.surface.animating.stop();
+                            }
+                            for (int k = bufBeg; k <= bufEnd && thread != null;
+                                    k++) {
+
+                                final int cloneIndex = k;
+                                Runnable cloneRunnable = new Runnable() {
+
+                                    @Override
+                                    public void run() {
+                                        dp.tools.cloneB.doClick();
+                                        int n = p.getComponentCount();
+                                        DemoPanel clone = (DemoPanel) p.
+                                                getComponent(n - 1);
+                                        if (clone.surface.animating != null) {
+                                            clone.surface.animating.stop();
+                                        }
+                                        clone.tools.issueRepaint = true;
+                                        clone.tools.screenCombo.setSelectedIndex(
+                                                cloneIndex);
+                                        clone.tools.issueRepaint = false;
+                                    }
+                                };
+                                invokeAndWait(cloneRunnable);
+                            }
+                        }
+                        if (printCB.isSelected()) {
+                            printDemo(dg);
+                        }
+                        sleepPerTab();
+                    }
+                } else if (i != 0 && printCB.isSelected()) {
+                    printDemo(dg);
+                    sleepPerTab();
+                } else {
+                    sleepPerTab();
+                }
+            }
+            if (runNum + 1 == numRuns) {
+                System.out.println("Finished.");
+                if (exit && thread != null) {
+                    System.out.println("System.exit(0).");
+                    System.exit(0);
+                }
+            }
+        }
+        Runnable resetRunnable = new Runnable() {
+
+            @Override
+            public void run() {
+                runB.setText("Run");
+                runB.setBackground(GREEN);
+                pb.setValue(0);
+            }
+        };
+        invokeAndWait(resetRunnable);
+
+        thread = null;
+        dg = null;
+        dp = null;
+    }
+
+    private static void invokeAndWait(Runnable run) {
+        try {
+            SwingUtilities.invokeAndWait(run);
+        } catch (Exception e) {
+            Logger.getLogger(RunWindow.class.getName()).log(Level.SEVERE,
+                    "ERROR in invokeAndWait", e);
+        }
+    }
+
+    /**
+     * This class contains initial values for instance variables of 'RunWindow' class,
+     * and its instance is used in creation of 'RunWindow' object. Values parsed from
+     * certain command line options of the demo or from the demo applet parameters are
+     * set to the fields of this class instance. It is a part of the fix which changed
+     * static variables for instance variables in certain demo classes.
+     *
+     * This class is not thread safe, its instances must be accessed only from EDT.
+     */
+    public static class RunWindowSettings {
+        private int delay = 10;
+        private int numRuns = 20;
+        private boolean exit;
+        private boolean zoomCBIsSelected;
+        private boolean printCBIsSelected;
+        private boolean buffersFlag;
+        private int bufBeg, bufEnd;
+
+        public int getDelay() {
+            return delay;
+        }
+
+        public void setDelay(int delay) {
+            this.delay = delay;
+        }
+
+        public int getNumRuns() {
+            return numRuns;
+        }
+
+        public void setNumRuns(int numRuns) {
+            this.numRuns = numRuns;
+        }
+
+        public boolean getExit() {
+            return exit;
+        }
+
+        public void setExit(boolean exit) {
+            this.exit = exit;
+        }
+
+        public boolean isZoomCBSelected() {
+            return zoomCBIsSelected;
+        }
+
+        public void setZoomCBSelected(boolean b) {
+            zoomCBIsSelected = b;
+        }
+
+        public boolean isPrintCBSelected() {
+            return printCBIsSelected;
+        }
+
+        public void setPrintCBIsSelected(boolean b) {
+            printCBIsSelected = b;
+        }
+
+        public boolean getBuffersFlag() {
+            return buffersFlag;
+        }
+
+        public void setBuffersFlag(boolean buffersFlag) {
+            this.buffersFlag = buffersFlag;
+        }
+
+        public int getBufBeg() {
+            return bufBeg;
+        }
+
+        public void setBufBeg(int bufBeg) {
+            this.bufBeg = bufBeg;
+        }
+
+        public int getBufEnd() {
+            return bufEnd;
+        }
+
+        public void setBufEnd(int bufEnd) {
+            this.bufEnd = bufEnd;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/Surface.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,504 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java.awt.RenderingHints.KEY_ANTIALIASING;
+import static java.awt.RenderingHints.KEY_RENDERING;
+import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF;
+import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;
+import static java.awt.RenderingHints.VALUE_RENDER_QUALITY;
+import static java.awt.RenderingHints.VALUE_RENDER_SPEED;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DataBufferUShort;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JPanel;
+import javax.swing.RepaintManager;
+
+
+/**
+ * Surface is the base class for the 2d rendering demos.  Demos must
+ * implement the render() method. Subclasses for Surface are
+ * AnimatingSurface, ControlsSurface and AnimatingControlsSurface.
+ */
+@SuppressWarnings("serial")
+public abstract class Surface extends JPanel implements Printable {
+
+    public Object AntiAlias = VALUE_ANTIALIAS_ON;
+    public Object Rendering = VALUE_RENDER_SPEED;
+    public AlphaComposite composite;
+    public Paint texture;
+    public String perfStr;            // PerformanceMonitor
+    public BufferedImage bimg;
+    public int imageType;
+    public String name;
+    public boolean clearSurface = true;
+    // Demos using animated gif's that implement ImageObserver set dontThread.
+    public boolean dontThread;
+    public AnimatingSurface animating;
+    protected long sleepAmount = 50;
+    private long orig, start, frame;
+    private Toolkit toolkit;
+    private boolean perfMonitor, outputPerf;
+    private int biw, bih;
+    private boolean clearOnce;
+    private boolean toBeInitialized = true;
+
+    public Surface() {
+        setDoubleBuffered(this instanceof AnimatingSurface);
+        toolkit = getToolkit();
+        name = this.getClass().getSimpleName();
+        setImageType(0);
+
+        // To launch an individual demo with the performance str output  :
+        //    java -Dj2ddemo.perf= -cp J2Ddemo.jar demos.Clipping.ClipAnim
+        try {
+            if (System.getProperty("j2ddemo.perf") != null) {
+                perfMonitor = outputPerf = true;
+            }
+        } catch (Exception ex) {
+        }
+        if (this instanceof AnimatingSurface) {
+            animating = (AnimatingSurface) this;
+        }
+    }
+
+    protected Image getImage(String name) {
+        return DemoImages.getImage(name, this);
+    }
+
+    protected Font getFont(String name) {
+        return DemoFonts.getFont(name);
+    }
+
+    public int getImageType() {
+        return imageType;
+    }
+
+    public final void setImageType(int imgType) {
+        if (imgType == 0) {
+            imageType = 1;
+        } else {
+            imageType = imgType;
+        }
+        bimg = null;
+    }
+
+    public void setAntiAlias(boolean aa) {
+        AntiAlias = aa ? VALUE_ANTIALIAS_ON : VALUE_ANTIALIAS_OFF;
+    }
+
+    public void setRendering(boolean rd) {
+        Rendering = rd ? VALUE_RENDER_QUALITY : VALUE_RENDER_SPEED;
+    }
+
+    public void setTexture(Object obj) {
+        if (obj instanceof GradientPaint) {
+            texture = new GradientPaint(0, 0, Color.white,
+                    getSize().width * 2, 0, Color.green);
+        } else {
+            texture = (Paint) obj;
+        }
+    }
+
+    public void setComposite(boolean cp) {
+        composite = cp
+                ? AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)
+                : null;
+    }
+
+    public void setMonitor(boolean pm) {
+        perfMonitor = pm;
+    }
+
+    public void setSleepAmount(long amount) {
+        sleepAmount = amount;
+    }
+
+    public long getSleepAmount() {
+        return sleepAmount;
+    }
+
+    public BufferedImage createBufferedImage(Graphics2D g2,
+            int w,
+            int h,
+            int imgType) {
+        BufferedImage bi = null;
+        if (imgType == 0) {
+            bi = g2.getDeviceConfiguration().
+                    createCompatibleImage(w, h);
+        } else if (imgType > 0 && imgType < 14) {
+            bi = new BufferedImage(w, h, imgType);
+        } else if (imgType == 14) {
+            bi = createBinaryImage(w, h, 2);
+        } else if (imgType == 15) {
+            bi = createBinaryImage(w, h, 4);
+        } else if (imgType == 16) {
+            bi = createSGISurface(w, h, 32);
+        } else if (imgType == 17) {
+            bi = createSGISurface(w, h, 16);
+        }
+        return bi;
+    }
+    // Lookup tables for BYTE_BINARY 1, 2 and 4 bits.
+    private static final byte[] lut1Arr = new byte[] { 0, (byte) 255 };
+    private static final byte[] lut2Arr = new byte[] { 0, (byte) 85, (byte) 170, (byte) 255 };
+    private static final byte[] lut4Arr = new byte[] { 0, (byte) 17, (byte) 34, (byte) 51,
+        (byte) 68, (byte) 85, (byte) 102, (byte) 119,
+        (byte) 136, (byte) 153, (byte) 170, (byte) 187,
+        (byte) 204, (byte) 221, (byte) 238, (byte) 255 };
+
+    private BufferedImage createBinaryImage(int w, int h, int pixelBits) {
+        int bytesPerRow = w * pixelBits / 8;
+        if (w * pixelBits % 8 != 0) {
+            bytesPerRow++;
+        }
+        byte[] imageData = new byte[h * bytesPerRow];
+        IndexColorModel cm = null;
+        switch (pixelBits) {
+            case 1:
+                cm = new IndexColorModel(pixelBits, lut1Arr.length,
+                        lut1Arr, lut1Arr, lut1Arr);
+                break;
+            case 2:
+                cm = new IndexColorModel(pixelBits, lut2Arr.length,
+                        lut2Arr, lut2Arr, lut2Arr);
+                break;
+            case 4:
+                cm = new IndexColorModel(pixelBits, lut4Arr.length,
+                        lut4Arr, lut4Arr, lut4Arr);
+                break;
+            default:
+                Logger.getLogger(Surface.class.getName()).log(Level.SEVERE,
+                        null, new Exception("Invalid # of bit per pixel"));
+        }
+
+        DataBuffer db = new DataBufferByte(imageData, imageData.length);
+        WritableRaster r = Raster.createPackedRaster(db, w, h, pixelBits, null);
+        return new BufferedImage(cm, r, false, null);
+    }
+
+    private BufferedImage createSGISurface(int w, int h, int pixelBits) {
+        int rMask32 = 0xFF000000;
+        int rMask16 = 0xF800;
+        int gMask32 = 0x00FF0000;
+        int gMask16 = 0x07C0;
+        int bMask32 = 0x0000FF00;
+        int bMask16 = 0x003E;
+
+        DirectColorModel dcm = null;
+        DataBuffer db = null;
+        WritableRaster wr = null;
+        switch (pixelBits) {
+            case 16:
+                short[] imageDataUShort = new short[w * h];
+                dcm = new DirectColorModel(16, rMask16, gMask16, bMask16);
+                db = new DataBufferUShort(imageDataUShort,
+                        imageDataUShort.length);
+                wr = Raster.createPackedRaster(db, w, h, w,
+                        new int[] { rMask16, gMask16, bMask16 },
+                        null);
+                break;
+            case 32:
+                int[] imageDataInt = new int[w * h];
+                dcm = new DirectColorModel(32, rMask32, gMask32, bMask32);
+                db = new DataBufferInt(imageDataInt, imageDataInt.length);
+                wr = Raster.createPackedRaster(db, w, h, w,
+                        new int[] { rMask32, gMask32, bMask32 },
+                        null);
+                break;
+            default:
+                Logger.getLogger(Surface.class.getName()).log(Level.SEVERE,
+                        null, new Exception("Invalid # of bit per pixel"));
+        }
+
+        return new BufferedImage(dcm, wr, false, null);
+    }
+
+    public Graphics2D createGraphics2D(int width,
+            int height,
+            BufferedImage bi,
+            Graphics g) {
+
+        Graphics2D g2 = null;
+
+        if (bi != null) {
+            g2 = bi.createGraphics();
+        } else {
+            g2 = (Graphics2D) g;
+        }
+
+        g2.setBackground(getBackground());
+        g2.setRenderingHint(KEY_ANTIALIASING, AntiAlias);
+        g2.setRenderingHint(KEY_RENDERING, Rendering);
+
+        if (clearSurface || clearOnce) {
+            g2.clearRect(0, 0, width, height);
+            clearOnce = false;
+        }
+
+        if (texture != null) {
+            // set composite to opaque for texture fills
+            g2.setComposite(AlphaComposite.SrcOver);
+            g2.setPaint(texture);
+            g2.fillRect(0, 0, width, height);
+        }
+
+        if (composite != null) {
+            g2.setComposite(composite);
+        }
+
+        return g2;
+    }
+
+    // ...demos that extend Surface must implement this routine...
+    public abstract void render(int w, int h, Graphics2D g2);
+
+    /**
+     * It's possible to turn off double-buffering for just the repaint
+     * calls invoked directly on the non double buffered component.
+     * This can be done by overriding paintImmediately() (which is called
+     * as a result of repaint) and getting the current RepaintManager and
+     * turning off double buffering in the RepaintManager before calling
+     * super.paintImmediately(g).
+     */
+    @Override
+    public void paintImmediately(int x, int y, int w, int h) {
+        RepaintManager repaintManager = null;
+        boolean save = true;
+        if (!isDoubleBuffered()) {
+            repaintManager = RepaintManager.currentManager(this);
+            save = repaintManager.isDoubleBufferingEnabled();
+            repaintManager.setDoubleBufferingEnabled(false);
+        }
+        super.paintImmediately(x, y, w, h);
+
+        if (repaintManager != null) {
+            repaintManager.setDoubleBufferingEnabled(save);
+        }
+    }
+
+    @Override
+    public void paint(Graphics g) {
+
+        super.paint(g);
+
+        Dimension d = getSize();
+
+        if (biw != d.width || bih != d.height) {
+            toBeInitialized = true;
+            biw = d.width;
+            bih = d.height;
+        }
+
+        if (imageType == 1) {
+            bimg = null;
+        } else if (bimg == null || toBeInitialized) {
+            bimg = createBufferedImage((Graphics2D) g,
+                    d.width, d.height, imageType - 2);
+            clearOnce = true;
+        }
+
+        if (toBeInitialized) {
+            if (animating != null) {
+                animating.reset(d.width, d.height);
+            }
+            toBeInitialized = false;
+            startClock();
+        }
+
+        if (animating != null && animating.running()) {
+            animating.step(d.width, d.height);
+        }
+        Graphics2D g2 = createGraphics2D(d.width, d.height, bimg, g);
+        render(d.width, d.height, g2);
+        g2.dispose();
+
+        if (bimg != null) {
+            g.drawImage(bimg, 0, 0, null);
+            toolkit.sync();
+        }
+
+        if (perfMonitor) {
+            LogPerformance();
+        }
+    }
+
+    @Override
+    public int print(Graphics g, PageFormat pf, int pi) throws PrinterException {
+        if (pi >= 1) {
+            return Printable.NO_SUCH_PAGE;
+        }
+
+        Graphics2D g2d = (Graphics2D) g;
+        g2d.translate(pf.getImageableX(), pf.getImageableY());
+        g2d.translate(pf.getImageableWidth() / 2,
+                pf.getImageableHeight() / 2);
+
+        Dimension d = getSize();
+
+        double scale = Math.min(pf.getImageableWidth() / d.width,
+                pf.getImageableHeight() / d.height);
+        if (scale < 1.0) {
+            g2d.scale(scale, scale);
+        }
+
+        g2d.translate(-d.width / 2.0, -d.height / 2.0);
+
+        if (bimg == null) {
+            Graphics2D g2 = createGraphics2D(d.width, d.height, null, g2d);
+            render(d.width, d.height, g2);
+            g2.dispose();
+        } else {
+            g2d.drawImage(bimg, 0, 0, this);
+        }
+
+        return Printable.PAGE_EXISTS;
+    }
+
+    public void startClock() {
+        orig = System.currentTimeMillis();
+        start = orig;
+        frame = 0;
+    }
+    private static final int REPORTFRAMES = 30;
+
+    private void LogPerformance() {
+        if ((frame % REPORTFRAMES) == 0) {
+            long end = System.currentTimeMillis();
+            long rel = (end - start);
+            if (frame == 0) {
+                perfStr = name + " " + rel + " ms";
+                if (animating == null || !animating.running()) {
+                    frame = -1;
+                }
+            } else {
+                String s1 = Float.toString((REPORTFRAMES / (rel / 1000.0f)));
+                s1 = (s1.length() < 4) ? s1.substring(0, s1.length()) : s1.
+                        substring(0, 4);
+                perfStr = name + " " + s1 + " fps";
+            }
+            if (outputPerf) {
+                System.out.println(perfStr);
+            }
+            start = end;
+        }
+        ++frame;
+    }
+
+    // System.out graphics state information.
+    public void verbose(GlobalControls controls) {
+        String str = "  " + name + " ";
+        if (animating != null && animating.running()) {
+            str = str.concat(" Running");
+        } else if (this instanceof AnimatingSurface) {
+            str = str.concat(" Stopped");
+        }
+
+        if (controls != null) {
+            str = str.concat(" " + controls.screenCombo.getSelectedItem());
+        }
+
+        str.concat((AntiAlias == VALUE_ANTIALIAS_ON) ? " ANTIALIAS_ON "
+                : " ANTIALIAS_OFF ");
+        str.concat((Rendering == VALUE_RENDER_QUALITY) ? "RENDER_QUALITY "
+                : "RENDER_SPEED ");
+
+        if (texture != null) {
+            str = str.concat("Texture ");
+        }
+
+        if (composite != null) {
+            str = str.concat("Composite=" + composite.getAlpha() + " ");
+        }
+
+        Runtime r = Runtime.getRuntime();
+        r.gc();
+        float freeMemory = r.freeMemory();
+        float totalMemory = r.totalMemory();
+        str = str.concat(((totalMemory - freeMemory) / 1024) + "K used");
+        System.out.println(str);
+    }
+
+    public static void createDemoFrame(Surface surface) {
+        final DemoPanel dp = new DemoPanel(surface, new DemoInstVarsAccessorImplBase());
+        Frame f = new Frame("J2D Demo - " + surface.name);
+        f.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+
+            @Override
+            public void windowDeiconified(WindowEvent e) {
+                dp.start();
+            }
+
+            @Override
+            public void windowIconified(WindowEvent e) {
+                dp.stop();
+            }
+        });
+        f.add("Center", dp);
+        f.pack();
+        f.setSize(new Dimension(500, 300));
+        f.setVisible(true);
+        if (surface.animating != null) {
+            surface.animating.start();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/TextureChooser.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,241 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java.awt.Color.GRAY;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.TexturePaint;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.Ellipse2D;
+import java.awt.image.BufferedImage;
+import javax.swing.JPanel;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+
+
+/**
+ * Four types of Paint displayed: Geometry, Text & Image Textures and
+ * a Gradient Paint.  Paints can be selected with the Mouse.
+ */
+@SuppressWarnings("serial")
+public final class TextureChooser extends JPanel {
+    private final DemoInstVarsAccessor demoInstVars;
+    public Object texture = getGeomTexture();
+    public int num;
+
+    public TextureChooser(int num, DemoInstVarsAccessor demoInstVars) {
+        this.num = num;
+        this.demoInstVars = demoInstVars;
+
+        setLayout(new GridLayout(0, 2, 5, 5));
+        setBorder(new TitledBorder(new EtchedBorder(), "Texture Chooser"));
+
+        add(new Surface(getGeomTexture(), this, 0));
+        add(new Surface(getImageTexture(), this, 1));
+        add(new Surface(getTextTexture(), this, 2));
+        add(new Surface(getGradientPaint(), this, 3));
+    }
+
+    public static TexturePaint getGeomTexture() {
+        BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
+        Graphics2D tG2 = bi.createGraphics();
+        tG2.setBackground(WHITE);
+        tG2.clearRect(0, 0, 5, 5);
+        tG2.setColor(new Color(211, 211, 211, 200));
+        tG2.fill(new Ellipse2D.Float(0, 0, 5, 5));
+        Rectangle r = new Rectangle(0, 0, 5, 5);
+        return new TexturePaint(bi, r);
+    }
+
+    public TexturePaint getImageTexture() {
+        Image img = DemoImages.getImage("globe.png", this);
+        int sw = img.getWidth(this);
+        int sh = img.getHeight(this);
+        int iw = sw/5;
+        int ih = sh/5;
+        BufferedImage bi =
+             new BufferedImage(iw, ih, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D tG2 = bi.createGraphics();
+        tG2.drawImage(img, 0, 0, iw, ih, 0, 0, sw, sh, this);
+        Rectangle r = new Rectangle(0, 0, iw, ih);
+        return new TexturePaint(bi, r);
+    }
+
+    public TexturePaint getTextTexture() {
+        Font f = new Font(Font.SERIF, Font.BOLD, 10);
+        TextLayout tl = new TextLayout("OpenJDK", f, new FontRenderContext(null,
+                false, false));
+        int sw = (int) tl.getBounds().getWidth();
+        int sh = (int) (tl.getAscent() + tl.getDescent());
+        BufferedImage bi = new BufferedImage(sw, sh, BufferedImage.TYPE_INT_RGB);
+        Graphics2D tG2 = bi.createGraphics();
+        tG2.setBackground(WHITE);
+        tG2.clearRect(0, 0, sw, sh);
+        tG2.setColor(LIGHT_GRAY);
+        tl.draw(tG2, 0, tl.getAscent());
+        Rectangle r = new Rectangle(0, 0, sw, sh);
+        return new TexturePaint(bi, r);
+    }
+
+    public GradientPaint getGradientPaint() {
+        return new GradientPaint(0, 0, WHITE, 80, 0, GREEN);
+    }
+
+
+    public class Surface extends JPanel {
+
+        public boolean clickedFrame;
+        private int num;
+        private TextureChooser tc;
+        private boolean enterExitFrame = false;
+        private Object t;
+
+        public Surface(final Object t, final TextureChooser tc, int num) {
+            setBackground(WHITE);
+            this.t = t;
+            this.tc = tc;
+            this.clickedFrame = (num == tc.num);
+            this.num = num;
+            if (num == tc.num) {
+                tc.texture = t;
+            }
+            addMouseListener(new MouseAdapter() {
+
+                @Override
+                public void mouseClicked(MouseEvent e) {
+                    tc.texture = t;
+                    clickedFrame = true;
+
+                    for (Component comp : tc.getComponents()) {
+                        if (comp instanceof Surface) {
+                            Surface surf = (Surface) comp;
+                            if (!surf.equals(Surface.this) && surf.clickedFrame) {
+                                surf.clickedFrame = false;
+                                surf.repaint();
+                            }
+                        }
+                    }
+
+                    // ABP
+                    if (demoInstVars.getControls().textureCB.isSelected()) {
+                        demoInstVars.getControls().textureCB.doClick();
+                        demoInstVars.getControls().textureCB.doClick();
+                    }
+                }
+
+                @Override
+                public void mouseEntered(MouseEvent e) {
+                    enterExitFrame = true;
+                    repaint();
+                }
+
+                @Override
+                public void mouseExited(MouseEvent e) {
+                    enterExitFrame = false;
+                    repaint();
+                }
+            });
+        }
+
+        @Override
+        public void paintComponent(Graphics g) {
+            super.paintComponent(g);
+            Graphics2D g2 = (Graphics2D) g;
+            int w = getSize().width;
+            int h = getSize().height;
+            if (t instanceof TexturePaint) {
+                g2.setPaint((TexturePaint) t);
+            } else {
+                g2.setPaint((GradientPaint) t);
+            }
+            g2.fill(new Rectangle(0, 0, w, h));
+            if (clickedFrame || enterExitFrame) {
+                g2.setColor(GRAY);
+                BasicStroke bs = new BasicStroke(3, BasicStroke.CAP_BUTT,
+                        BasicStroke.JOIN_MITER);
+                g2.setStroke(bs);
+                g2.drawRect(0, 0, w - 1, h - 1);
+                tc.num = num;
+            }
+        }
+
+        @Override
+        public Dimension getMinimumSize() {
+            return getPreferredSize();
+        }
+
+        @Override
+        public Dimension getMaximumSize() {
+            return getPreferredSize();
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(30, 30);
+        }
+    }
+
+    public static void main(String s[]) {
+        Frame f = new Frame("J2D Demo - TextureChooser");
+        f.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                System.exit(0);
+            }
+        });
+        f.add("Center", new TextureChooser(0, new DemoInstVarsAccessorImplBase()));
+        f.pack();
+        f.setSize(new Dimension(400, 400));
+        f.setVisible(true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/Tools.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,496 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.print.PrinterJob;
+import java.text.DecimalFormat;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.print.attribute.HashPrintRequestAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.border.EtchedBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * Tools to control individual demo graphic attributes.  Also, control for
+ * start & stop on animated demos; control for cloning the demo; control for
+ * printing the demo.  Expand and collapse the Tools panel with ToggleIcon.
+ */
+@SuppressWarnings("serial")
+public final class Tools extends JPanel implements ActionListener,
+        ChangeListener, Runnable {
+    private final DemoInstVarsAccessor demoInstVars;
+    private ImageIcon stopIcon, startIcon;
+    private Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+    private Color roColor = new Color(187, 213, 238);
+    private Surface surface;
+    private Thread thread;
+    private JPanel toolbarPanel;
+    private JPanel sliderPanel;
+    private JLabel label;
+    private ToggleIcon bumpyIcon, rolloverIcon;
+    private DecimalFormat decimalFormat = new DecimalFormat("000");
+    protected boolean focus;
+    public JToggleButton toggleB;
+    public JButton printB;
+    public JComboBox screenCombo;
+    public JToggleButton renderB, aliasB;
+    public JToggleButton textureB, compositeB;
+    public JButton startStopB;
+    public JButton cloneB;
+    public boolean issueRepaint = true;
+    public JToolBar toolbar;
+    public JSlider slider;
+    public boolean doSlider;
+    public boolean isExpanded;
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public Tools(Surface surface, DemoInstVarsAccessor demoInstVars) {
+        this.surface = surface;
+        this.demoInstVars = demoInstVars;
+
+        setLayout(new BorderLayout());
+
+        stopIcon = new ImageIcon(DemoImages.getImage("stop.gif", this));
+        startIcon = new ImageIcon(DemoImages.getImage("start.gif", this));
+        bumpyIcon = new ToggleIcon(this, LIGHT_GRAY);
+        rolloverIcon = new ToggleIcon(this, roColor);
+        toggleB = new JToggleButton(bumpyIcon);
+        toggleB.addMouseListener(new MouseAdapter() {
+
+            @Override
+            public void mouseEntered(MouseEvent e) {
+                focus = true;
+                bumpyIcon.start();
+            }
+
+            @Override
+            public void mouseExited(MouseEvent e) {
+                focus = false;
+                bumpyIcon.stop();
+            }
+        });
+        isExpanded = false;
+        toggleB.addActionListener(this);
+        toggleB.setMargin(new Insets(0, 0, -4, 0));
+        toggleB.setBorderPainted(false);
+        toggleB.setFocusPainted(false);
+        toggleB.setContentAreaFilled(false);
+        toggleB.setRolloverIcon(rolloverIcon);
+        add("North", toggleB);
+
+        toolbar = new JToolBar();
+        toolbar.setPreferredSize(new Dimension(5*25, 26));
+        toolbar.setFloatable(false);
+
+        String s = surface.AntiAlias == RenderingHints.VALUE_ANTIALIAS_ON
+                ? "On" : "Off";
+        aliasB = addTool("A", "Antialiasing " + s, this);
+
+        s = surface.Rendering == RenderingHints.VALUE_RENDER_SPEED
+                ? "Speed" : "Quality";
+        renderB = addTool("R", "Rendering " + s, this);
+
+        s = surface.texture != null ? "On" : "Off";
+        textureB = addTool("T", "Texture " + s, this);
+
+        s = surface.composite != null ? "On" : "Off";
+        compositeB = addTool("C", "Composite " + s, this);
+
+        Image printBImg = DemoImages.getImage("print.gif", this);
+        printB = addTool(printBImg, "Print the Surface", this);
+
+        if (surface instanceof AnimatingSurface) {
+            Image stopImg = DemoImages.getImage("stop.gif", this);
+            startStopB = addTool(stopImg, "Stop Animation", this);
+            toolbar.setPreferredSize(new Dimension(6*25, 26));
+        }
+
+        screenCombo = new JComboBox();
+        screenCombo.setPreferredSize(new Dimension(100, 18));
+        screenCombo.setFont(font);
+        for (String name : GlobalControls.screenNames) {
+            screenCombo.addItem(name);
+        }
+        screenCombo.addActionListener(this);
+        toolbarPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
+        toolbarPanel.setLocation(0, 6);
+        toolbarPanel.setVisible(false);
+        toolbarPanel.add(toolbar);
+        toolbarPanel.add(screenCombo);
+        toolbarPanel.setBorder(new EtchedBorder());
+        add(toolbarPanel);
+
+        setPreferredSize(new Dimension(200, 8));
+
+        if (surface instanceof AnimatingSurface) {
+            sliderPanel = new JPanel(new BorderLayout());
+            label = new JLabel(" Sleep = 030 ms");
+            label.setForeground(BLACK);
+            sliderPanel.add(label, BorderLayout.WEST);
+            slider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 30);
+            slider.addChangeListener(this);
+            sliderPanel.setBorder(new EtchedBorder());
+            sliderPanel.add(slider);
+
+            addMouseListener(new MouseAdapter() {
+
+                @Override
+                public void mouseClicked(MouseEvent e) {
+                    if (toolbarPanel.isVisible()) {
+                        invalidate();
+                        if ((doSlider = !doSlider)) {
+                            remove(toolbarPanel);
+                            add(sliderPanel);
+                        } else {
+                            remove(sliderPanel);
+                            add(toolbarPanel);
+                        }
+                        validate();
+                        repaint();
+                    }
+                }
+            });
+        }
+    }
+
+    public JButton addTool(Image img,
+            String toolTip,
+            ActionListener al) {
+        JButton b = new JButton(new ImageIcon(img)) {
+
+            Dimension prefSize = new Dimension(25, 22);
+
+            @Override
+            public Dimension getPreferredSize() {
+                return prefSize;
+            }
+
+            @Override
+            public Dimension getMaximumSize() {
+                return prefSize;
+            }
+
+            @Override
+            public Dimension getMinimumSize() {
+                return prefSize;
+            }
+        };
+        toolbar.add(b);
+        b.setFocusPainted(false);
+        b.setSelected(true);
+        b.setToolTipText(toolTip);
+        b.addActionListener(al);
+        return b;
+    }
+
+    public JToggleButton addTool(String name,
+            String toolTip,
+            ActionListener al) {
+        JToggleButton b = new JToggleButton(name) {
+
+            Dimension prefSize = new Dimension(25, 22);
+
+            @Override
+            public Dimension getPreferredSize() {
+                return prefSize;
+            }
+
+            @Override
+            public Dimension getMaximumSize() {
+                return prefSize;
+            }
+
+            @Override
+            public Dimension getMinimumSize() {
+                return prefSize;
+            }
+        };
+        toolbar.add(b);
+        b.setFocusPainted(false);
+        if (toolTip.equals("Rendering Quality") || toolTip.equals(
+                "Antialiasing On") || toolTip.equals("Texture On") || toolTip.
+                equals("Composite On")) {
+            b.setSelected(true);
+        } else {
+            b.setSelected(false);
+        }
+        b.setToolTipText(toolTip);
+        b.addActionListener(al);
+        return b;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        Object obj = e.getSource();
+        if (obj instanceof JButton) {
+            JButton b = (JButton) obj;
+            b.setSelected(!b.isSelected());
+            if (b.getIcon() == null) {
+                b.setBackground(b.isSelected() ? GREEN : LIGHT_GRAY);
+            }
+        }
+        if (obj.equals(toggleB)) {
+            isExpanded = !isExpanded;
+            if (isExpanded) {
+                setPreferredSize(new Dimension(200, 38));
+            } else {
+                setPreferredSize(new Dimension(200, 6));
+            }
+            toolbarPanel.setVisible(isExpanded);
+            if (sliderPanel != null) {
+                sliderPanel.setVisible(isExpanded);
+            }
+            getParent().validate();
+            toggleB.getModel().setRollover(false);
+            return;
+        }
+        if (obj.equals(printB)) {
+            start();
+            return;
+        }
+
+        if (obj.equals(startStopB)) {
+            if (startStopB.getToolTipText().equals("Stop Animation")) {
+                startStopB.setIcon(startIcon);
+                startStopB.setToolTipText("Start Animation");
+                surface.animating.stop();
+            } else {
+                startStopB.setIcon(stopIcon);
+                startStopB.setToolTipText("Stop Animation");
+                surface.animating.start();
+            }
+        } else if (obj.equals(aliasB)) {
+            if (aliasB.getToolTipText().equals("Antialiasing On")) {
+                aliasB.setToolTipText("Antialiasing Off");
+            } else {
+                aliasB.setToolTipText("Antialiasing On");
+            }
+            surface.setAntiAlias(aliasB.isSelected());
+        } else if (obj.equals(renderB)) {
+            if (renderB.getToolTipText().equals("Rendering Quality")) {
+                renderB.setToolTipText("Rendering Speed");
+            } else {
+                renderB.setToolTipText("Rendering Quality");
+            }
+            surface.setRendering(renderB.isSelected());
+        } else if (obj.equals(textureB)) {
+            if (textureB.getToolTipText().equals("Texture On")) {
+                textureB.setToolTipText("Texture Off");
+                surface.setTexture(null);
+                surface.clearSurface = true;
+            } else {
+                textureB.setToolTipText("Texture On");
+                surface.setTexture(demoInstVars.getControls().texturechooser.texture);
+            }
+        } else if (obj.equals(compositeB)) {
+            if (compositeB.getToolTipText().equals("Composite On")) {
+                compositeB.setToolTipText("Composite Off");
+            } else {
+                compositeB.setToolTipText("Composite On");
+            }
+            surface.setComposite(compositeB.isSelected());
+        } else if (obj.equals(screenCombo)) {
+            surface.setImageType(screenCombo.getSelectedIndex());
+        }
+
+        if (issueRepaint && surface.animating != null) {
+            if (surface.getSleepAmount() != 0) {
+                if (surface.animating.running()) {
+                    surface.animating.doRepaint();
+                }
+            }
+        } else if (issueRepaint) {
+            surface.repaint();
+        }
+    }
+
+    @Override
+    public void stateChanged(ChangeEvent e) {
+        int value = slider.getValue();
+        label.setText(" Sleep = " + decimalFormat.format(value) + " ms");
+        label.repaint();
+        surface.setSleepAmount(value);
+    }
+
+    public void start() {
+        thread = new Thread(this);
+        thread.setPriority(Thread.MAX_PRIORITY);
+        thread.setName("Printing " + surface.name);
+        thread.start();
+    }
+
+    public synchronized void stop() {
+        thread = null;
+        notifyAll();
+    }
+
+    @Override
+    public void run() {
+        boolean stopped = false;
+        if (surface.animating != null && surface.animating.running()) {
+            stopped = true;
+            startStopB.doClick();
+        }
+
+        try {
+            PrinterJob printJob = PrinterJob.getPrinterJob();
+            printJob.setPrintable(surface);
+            boolean pDialogState = true;
+            PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
+
+            if (!demoInstVars.getPrintCB().isSelected()) {
+                pDialogState = printJob.printDialog(aset);
+            }
+            if (pDialogState) {
+                printJob.print(aset);
+            }
+        } catch (java.security.AccessControlException ace) {
+            String errmsg = "Applet access control exception; to allow "
+                    + "access to printer, set\n"
+                    + "permission for \"queuePrintJob\" in "
+                    + "RuntimePermission.";
+            JOptionPane.showMessageDialog(this, errmsg, "Printer Access Error",
+                    JOptionPane.ERROR_MESSAGE);
+        } catch (Exception ex) {
+            Logger.getLogger(Tools.class.getName()).log(Level.SEVERE,
+                    null, ex);
+        }
+
+        if (stopped) {
+            startStopB.doClick();
+        }
+        thread = null;
+    }
+
+
+    /**
+     * Expand and Collapse the Tools Panel with this bumpy button.
+     */
+    static class ToggleIcon implements Icon, Runnable {
+
+        private Color shadowColor = new Color(102, 102, 153);
+        private Color fillColor;
+        private Tools tools;
+        private Thread thread;
+
+        public ToggleIcon(Tools tools, Color fillColor) {
+            this.tools = tools;
+            this.fillColor = fillColor;
+        }
+
+        @Override
+        public void paintIcon(Component c, Graphics g, int x, int y) {
+            int w = getIconWidth();
+            int h = getIconHeight();
+            g.setColor(fillColor);
+            g.fillRect(0, 0, w, h);
+            for (; x < w - 2; x += 4) {
+                g.setColor(WHITE);
+                g.fillRect(x, 1, 1, 1);
+                g.fillRect(x + 2, 3, 1, 1);
+                g.setColor(shadowColor);
+                g.fillRect(x + 1, 2, 1, 1);
+                g.fillRect(x + 3, 4, 1, 1);
+            }
+        }
+
+        @Override
+        public int getIconWidth() {
+            return tools.getSize().width;
+        }
+
+        @Override
+        public int getIconHeight() {
+            return 6;
+        }
+
+        public void start() {
+            thread = new Thread(this);
+            thread.setPriority(Thread.MIN_PRIORITY);
+            thread.setName("ToggleIcon");
+            thread.start();
+        }
+
+        public synchronized void stop() {
+            if (thread != null) {
+                thread.interrupt();
+            }
+            thread = null;
+        }
+
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(400);
+            } catch (InterruptedException e) {
+            }
+            if (tools.focus && thread != null) {
+                tools.toggleB.doClick();
+            }
+            thread = null;
+        }
+    }
+} // End Tools class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/Arcs.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,165 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Arcs_Curves;
+
+
+import java.awt.*;
+import java.awt.geom.Arc2D;
+import java.awt.geom.AffineTransform;
+import java2d.AnimatingSurface;
+import static java.awt.Color.*;
+
+
+/**
+ * Arc2D Open, Chord & Pie arcs; Animated Pie Arc.
+ */
+@SuppressWarnings("serial")
+public class Arcs extends AnimatingSurface {
+
+    private static String types[] = { "Arc2D.OPEN", "Arc2D.CHORD", "Arc2D.PIE" };
+    private static final int CLOSE = 0;
+    private static final int OPEN = 1;
+    private static final int FORWARD = 0;
+    private static final int BACKWARD = 1;
+    private static final int DOWN = 2;
+    private static final int UP = 3;
+    private int aw, ah; // animated arc width & height
+    private int x, y;
+    private int angleStart = 45;
+    private int angleExtent = 270;
+    private int mouth = CLOSE;
+    private int direction = FORWARD;
+
+    public Arcs() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        x = 0;
+        y = 0;
+        aw = w / 12;
+        ah = h / 12;
+    }
+
+    @Override
+    public void step(int w, int h) {
+        // Compute direction
+        if (x + aw >= w - 5 && direction == FORWARD) {
+            direction = DOWN;
+        }
+        if (y + ah >= h - 5 && direction == DOWN) {
+            direction = BACKWARD;
+        }
+        if (x - aw <= 5 && direction == BACKWARD) {
+            direction = UP;
+        }
+        if (y - ah <= 5 && direction == UP) {
+            direction = FORWARD;
+        }
+
+        // compute angle start & extent
+        if (mouth == CLOSE) {
+            angleStart -= 5;
+            angleExtent += 10;
+        }
+        if (mouth == OPEN) {
+            angleStart += 5;
+            angleExtent -= 10;
+        }
+        if (direction == FORWARD) {
+            x += 5;
+            y = 0;
+        }
+        if (direction == DOWN) {
+            x = w;
+            y += 5;
+        }
+        if (direction == BACKWARD) {
+            x -= 5;
+            y = h;
+        }
+        if (direction == UP) {
+            x = 0;
+            y -= 5;
+        }
+        if (angleStart == 0) {
+            mouth = OPEN;
+        }
+        if (angleStart > 45) {
+            mouth = CLOSE;
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        // Draw Arcs
+        g2.setStroke(new BasicStroke(5.0f));
+        for (int i = 0; i < types.length; i++) {
+            Arc2D arc = new Arc2D.Float(i);
+            arc.setFrame((i + 1) * w * .2, (i + 1) * h * .2, w * .17, h * .17);
+            arc.setAngleStart(45);
+            arc.setAngleExtent(270);
+            g2.setColor(BLUE);
+            g2.draw(arc);
+            g2.setColor(GRAY);
+            g2.fill(arc);
+            g2.setColor(BLACK);
+            g2.drawString(types[i], (int) ((i + 1) * w * .2), (int) ((i + 1) * h
+                    * .2 - 3));
+        }
+
+        // Draw Animated Pie Arc
+        Arc2D pieArc = new Arc2D.Float(Arc2D.PIE);
+        pieArc.setFrame(0, 0, aw, ah);
+        pieArc.setAngleStart(angleStart);
+        pieArc.setAngleExtent(angleExtent);
+        AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+        switch (direction) {
+            case DOWN:
+                at.rotate(Math.toRadians(90));
+                break;
+            case BACKWARD:
+                at.rotate(Math.toRadians(180));
+                break;
+            case UP:
+                at.rotate(Math.toRadians(270));
+        }
+        g2.setColor(BLUE);
+        g2.fill(at.createTransformedShape(pieArc));
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Arcs());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/BezierAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,339 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Arcs_Curves;
+
+
+import static java.awt.Color.BLUE;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import static java.awt.Color.YELLOW;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.TexturePaint;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.image.BufferedImage;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.Icon;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+
+
+/**
+ * Animated Bezier Curve with controls for different draw & fill paints.
+ */
+@SuppressWarnings("serial")
+public class BezierAnim extends AnimatingControlsSurface {
+
+    private static final int NUMPTS = 6;
+    protected BasicStroke solid = new BasicStroke(10.0f,
+            BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
+    protected BasicStroke dashed = new BasicStroke(10.0f,
+            BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10, new float[] { 5 },
+            0);
+    private float animpts[] = new float[NUMPTS * 2];
+    private float deltas[] = new float[NUMPTS * 2];
+    protected Paint fillPaint, drawPaint;
+    protected boolean doFill = true;
+    protected boolean doDraw = true;
+    protected GradientPaint gradient;
+    protected BasicStroke stroke;
+
+    public BezierAnim() {
+        setBackground(WHITE);
+        gradient = new GradientPaint(0, 0, RED, 200, 200, YELLOW);
+        fillPaint = gradient;
+        drawPaint = BLUE;
+        stroke = solid;
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    public void animate(float[] pts, float[] deltas, int index, int limit) {
+        float newpt = pts[index] + deltas[index];
+        if (newpt <= 0) {
+            newpt = -newpt;
+            deltas[index] = (float) (Math.random() * 4.0 + 2.0);
+        } else if (newpt >= limit) {
+            newpt = 2.0f * limit - newpt;
+            deltas[index] = -(float) (Math.random() * 4.0 + 2.0);
+        }
+        pts[index] = newpt;
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        for (int i = 0; i < animpts.length; i += 2) {
+            animpts[i + 0] = (float) (Math.random() * w);
+            animpts[i + 1] = (float) (Math.random() * h);
+            deltas[i + 0] = (float) (Math.random() * 6.0 + 4.0);
+            deltas[i + 1] = (float) (Math.random() * 6.0 + 4.0);
+            if (animpts[i + 0] > w / 2.0f) {
+                deltas[i + 0] = -deltas[i + 0];
+            }
+            if (animpts[i + 1] > h / 2.0f) {
+                deltas[i + 1] = -deltas[i + 1];
+            }
+        }
+        gradient = new GradientPaint(0, 0, RED, w * .7f, h * .7f, YELLOW);
+    }
+
+    @Override
+    public void step(int w, int h) {
+        for (int i = 0; i < animpts.length; i += 2) {
+            animate(animpts, deltas, i + 0, w);
+            animate(animpts, deltas, i + 1, h);
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        float[] ctrlpts = animpts;
+        int len = ctrlpts.length;
+        float prevx = ctrlpts[len - 2];
+        float prevy = ctrlpts[len - 1];
+        float curx = ctrlpts[0];
+        float cury = ctrlpts[1];
+        float midx = (curx + prevx) / 2.0f;
+        float midy = (cury + prevy) / 2.0f;
+        GeneralPath gp = new GeneralPath(Path2D.WIND_NON_ZERO);
+        gp.moveTo(midx, midy);
+        for (int i = 2; i <= ctrlpts.length; i += 2) {
+            float x1 = (midx + curx) / 2.0f;
+            float y1 = (midy + cury) / 2.0f;
+            prevx = curx;
+            prevy = cury;
+            if (i < ctrlpts.length) {
+                curx = ctrlpts[i + 0];
+                cury = ctrlpts[i + 1];
+            } else {
+                curx = ctrlpts[0];
+                cury = ctrlpts[1];
+            }
+            midx = (curx + prevx) / 2.0f;
+            midy = (cury + prevy) / 2.0f;
+            float x2 = (prevx + midx) / 2.0f;
+            float y2 = (prevy + midy) / 2.0f;
+            gp.curveTo(x1, y1, x2, y2, midx, midy);
+        }
+        gp.closePath();
+        if (doDraw) {
+            g2.setPaint(drawPaint);
+            g2.setStroke(stroke);
+            g2.draw(gp);
+        }
+        if (doFill) {
+            if (fillPaint instanceof GradientPaint) {
+                fillPaint = gradient;
+            }
+            g2.setPaint(fillPaint);
+            g2.fill(gp);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new BezierAnim());
+    }
+
+
+    static class DemoControls extends CustomControls implements ActionListener {
+
+        static final TexturePaint tp1, tp2;
+
+        static {
+            BufferedImage bi = new BufferedImage(2, 1,
+                    BufferedImage.TYPE_INT_RGB);
+            bi.setRGB(0, 0, 0xff00ff00);
+            bi.setRGB(1, 0, 0xffff0000);
+            tp1 = new TexturePaint(bi, new Rectangle(0, 0, 2, 1));
+            bi = new BufferedImage(2, 1, BufferedImage.TYPE_INT_RGB);
+            bi.setRGB(0, 0, 0xff0000ff);
+            bi.setRGB(1, 0, 0xffff0000);
+            tp2 = new TexturePaint(bi, new Rectangle(0, 0, 2, 1));
+        }
+        BezierAnim demo;
+        static Paint drawPaints[] = { new Color(0, 0, 0, 0), BLUE, new Color(0,
+            0, 255, 126),
+            BLUE, tp2 };
+        static String drawName[] = { "No Draw", "Blue", "Blue w/ Alpha",
+            "Blue Dash", "Texture" };
+        static Paint fillPaints[] = { new Color(0, 0, 0, 0), GREEN, new Color(0,
+            255, 0, 126),
+            tp1, new GradientPaint(0, 0, RED, 30, 30, YELLOW) };
+        String fillName[] = { "No Fill", "Green", "Green w/ Alpha", "Texture",
+            "Gradient" };
+        JMenu fillMenu, drawMenu;
+        JMenuItem fillMI[] = new JMenuItem[fillPaints.length];
+        JMenuItem drawMI[] = new JMenuItem[drawPaints.length];
+        PaintedIcon fillIcons[] = new PaintedIcon[fillPaints.length];
+        PaintedIcon drawIcons[] = new PaintedIcon[drawPaints.length];
+        Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(BezierAnim demo) {
+            super(demo.name);
+            this.demo = demo;
+
+            JMenuBar drawMenuBar = new JMenuBar();
+            add(drawMenuBar);
+
+            JMenuBar fillMenuBar = new JMenuBar();
+            add(fillMenuBar);
+
+            drawMenu = drawMenuBar.add(new JMenu("Draw Choice"));
+            drawMenu.setFont(font);
+
+            for (int i = 0; i < drawPaints.length; i++) {
+                drawIcons[i] = new PaintedIcon(drawPaints[i]);
+                drawMI[i] = drawMenu.add(new JMenuItem(drawName[i]));
+                drawMI[i].setFont(font);
+                drawMI[i].setIcon(drawIcons[i]);
+                drawMI[i].addActionListener(this);
+            }
+            drawMenu.setIcon(drawIcons[1]);
+
+            fillMenu = fillMenuBar.add(new JMenu("Fill Choice"));
+            fillMenu.setFont(font);
+            for (int i = 0; i < fillPaints.length; i++) {
+                fillIcons[i] = new PaintedIcon(fillPaints[i]);
+                fillMI[i] = fillMenu.add(new JMenuItem(fillName[i]));
+                fillMI[i].setFont(font);
+                fillMI[i].setIcon(fillIcons[i]);
+                fillMI[i].addActionListener(this);
+            }
+            fillMenu.setIcon(fillIcons[fillPaints.length - 1]);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            Object obj = e.getSource();
+            for (int i = 0; i < fillPaints.length; i++) {
+                if (obj.equals(fillMI[i])) {
+                    demo.doFill = true;
+                    demo.fillPaint = fillPaints[i];
+                    fillMenu.setIcon(fillIcons[i]);
+                    break;
+                }
+            }
+            for (int i = 0; i < drawPaints.length; i++) {
+                if (obj.equals(drawMI[i])) {
+                    demo.doDraw = true;
+                    demo.drawPaint = drawPaints[i];
+                    if (((JMenuItem) obj).getText().endsWith("Dash")) {
+                        demo.stroke = demo.dashed;
+                    } else {
+                        demo.stroke = demo.solid;
+                    }
+                    drawMenu.setIcon(drawIcons[i]);
+                    break;
+                }
+            }
+            if (obj.equals(fillMI[0])) {
+                demo.doFill = false;
+            } else if (obj.equals(drawMI[0])) {
+                demo.doDraw = false;
+            }
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 36);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (JMenuItem dmi : drawMI) {
+                    dmi.doClick();
+                    for (JMenuItem fmi : fillMI) {
+                        fmi.doClick();
+                        try {
+                            Thread.sleep(3000 + (long) (Math.random() * 3000));
+                        } catch (InterruptedException e) {
+                            break;
+                        }
+                    }
+                }
+            }
+            thread = null;
+        }
+
+
+        static class PaintedIcon implements Icon {
+
+            Paint paint;
+
+            public PaintedIcon(Paint p) {
+                this.paint = p;
+            }
+
+            @Override
+            public void paintIcon(Component c, Graphics g, int x, int y) {
+                Graphics2D g2 = (Graphics2D) g;
+                g2.setPaint(paint);
+                g2.fillRect(x, y, getIconWidth(), getIconHeight());
+                g2.setColor(GRAY);
+                g2.draw3DRect(x, y, getIconWidth() - 1, getIconHeight() - 1,
+                        true);
+            }
+
+            @Override
+            public int getIconWidth() {
+                return 12;
+            }
+
+            @Override
+            public int getIconHeight() {
+                return 12;
+            }
+        } // End PaintedIcon class
+    } // End DemoControls class
+} // End BezierAnim class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/Curves.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,142 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Arcs_Curves;
+
+
+import java.awt.*;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.FlatteningPathIterator;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java2d.Surface;
+import static java.awt.Color.*;
+import static java.awt.geom.PathIterator.*;
+
+
+/**
+ * CubicCurve2D & QuadCurve2D curves includes FlattenPathIterator example.
+ */
+@SuppressWarnings("serial")
+public class Curves extends Surface {
+
+    private static Color colors[] = { BLUE, GREEN, RED };
+
+    public Curves() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        g2.setColor(BLACK);
+        FontRenderContext frc = g2.getFontRenderContext();
+        TextLayout tl = new TextLayout("QuadCurve2D", g2.getFont(), frc);
+        float xx = (float) (w * .5 - tl.getBounds().getWidth() / 2);
+        tl.draw(g2, xx, tl.getAscent());
+
+        tl = new TextLayout("CubicCurve2D", g2.getFont(), frc);
+        xx = (float) (w * .5 - tl.getBounds().getWidth() / 2);
+        tl.draw(g2, xx, h * .5f);
+        g2.setStroke(new BasicStroke(5.0f));
+
+        float yy = 20;
+
+        for (int i = 0; i < 2; i++) {
+            for (int j = 0; j < 3; j++) {
+                Shape shape = null;
+
+                if (i == 0) {
+                    shape = new QuadCurve2D.Float(w * .1f, yy, w * .5f, 50, w
+                            * .9f, yy);
+                } else {
+                    shape = new CubicCurve2D.Float(w * .1f, yy, w * .4f, yy - 15,
+                            w * .6f, yy + 15, w * .9f, yy);
+                }
+                g2.setColor(colors[j]);
+                if (j != 2) {
+                    g2.draw(shape);
+                }
+
+                if (j == 1) {
+                    g2.setColor(LIGHT_GRAY);
+                    PathIterator f = shape.getPathIterator(null);
+                    while (!f.isDone()) {
+                        float[] pts = new float[6];
+                        switch (f.currentSegment(pts)) {
+                            case SEG_MOVETO:
+                            case SEG_LINETO:
+                                g2.fill(new Rectangle2D.Float(pts[0], pts[1], 5,
+                                        5));
+                                break;
+                            case SEG_CUBICTO:
+                            case SEG_QUADTO:
+                                g2.fill(new Rectangle2D.Float(pts[0], pts[1], 5,
+                                        5));
+                                if (pts[2] != 0) {
+                                    g2.fill(new Rectangle2D.Float(pts[2], pts[3],
+                                            5, 5));
+                                }
+                                if (pts[4] != 0) {
+                                    g2.fill(new Rectangle2D.Float(pts[4], pts[5],
+                                            5, 5));
+                                }
+                        }
+                        f.next();
+                    }
+                } else if (j == 2) {
+                    PathIterator p = shape.getPathIterator(null);
+                    FlatteningPathIterator f =
+                            new FlatteningPathIterator(p, 0.1);
+                    while (!f.isDone()) {
+                        float[] pts = new float[6];
+                        switch (f.currentSegment(pts)) {
+                            case SEG_MOVETO:
+                            case SEG_LINETO:
+                                g2.fill(new Ellipse2D.Float(pts[0], pts[1], 3, 3));
+                        }
+                        f.next();
+                    }
+                }
+                yy += h / 6;
+            }
+            yy = h / 2 + 15;
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Curves());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Arcs_Curves/Ellipses.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Arcs_Curves;
+
+
+import java.awt.*;
+import java.awt.geom.Ellipse2D;
+import java2d.AnimatingSurface;
+import static java.awt.Color.*;
+
+
+/**
+ * Ellipse2D 25 animated expanding ellipses.
+ */
+@SuppressWarnings("serial")
+public final class Ellipses extends AnimatingSurface {
+
+    private static Color colors[] = {
+        BLUE, CYAN, GREEN, MAGENTA, ORANGE, PINK, RED,
+        YELLOW, LIGHT_GRAY, WHITE };
+    private Ellipse2D.Float[] ellipses;
+    private double esize[];
+    private float estroke[];
+    private double maxSize;
+
+    public Ellipses() {
+        setBackground(BLACK);
+        ellipses = new Ellipse2D.Float[25];
+        esize = new double[ellipses.length];
+        estroke = new float[ellipses.length];
+        for (int i = 0; i < ellipses.length; i++) {
+            ellipses[i] = new Ellipse2D.Float();
+            getRandomXY(i, 20 * Math.random(), 200, 200);
+        }
+    }
+
+    public void getRandomXY(int i, double size, int w, int h) {
+        esize[i] = size;
+        estroke[i] = 1.0f;
+        double x = Math.random() * (w - (maxSize / 2));
+        double y = Math.random() * (h - (maxSize / 2));
+        ellipses[i].setFrame(x, y, size, size);
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        maxSize = w / 10;
+        for (int i = 0; i < ellipses.length; i++) {
+            getRandomXY(i, maxSize * Math.random(), w, h);
+        }
+    }
+
+    @Override
+    public void step(int w, int h) {
+        for (int i = 0; i < ellipses.length; i++) {
+            estroke[i] += 0.025f;
+            esize[i]++;
+            if (esize[i] > maxSize) {
+                getRandomXY(i, 1, w, h);
+            } else {
+                ellipses[i].setFrame(ellipses[i].getX(), ellipses[i].getY(),
+                        esize[i], esize[i]);
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        for (int i = 0; i < ellipses.length; i++) {
+            g2.setColor(colors[i % colors.length]);
+            g2.setStroke(new BasicStroke(estroke[i]));
+            g2.draw(ellipses[i]);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Ellipses());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/Areas.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,222 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Clipping;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import javax.swing.*;
+import java2d.ControlsSurface;
+import java2d.CustomControls;
+import static java.awt.Color.*;
+
+
+/**
+ * The Areas class demonstrates the CAG (Constructive Area Geometry)
+ * operations: Add(union), Subtract, Intersect, and ExclusiveOR.
+ */
+@SuppressWarnings("serial")
+public class Areas extends ControlsSurface {
+
+    protected String areaType = "nop";
+
+    public Areas() {
+        setBackground(WHITE);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        GeneralPath p1 = new GeneralPath();
+        p1.moveTo(w * .25f, 0.0f);
+        p1.lineTo(w * .75f, h * .5f);
+        p1.lineTo(w * .25f, h);
+        p1.lineTo(0.0f, h * .5f);
+        p1.closePath();
+
+        GeneralPath p2 = new GeneralPath();
+        p2.moveTo(w * .75f, 0.0f);
+        p2.lineTo(w, h * .5f);
+        p2.lineTo(w * .75f, h);
+        p2.lineTo(w * .25f, h * .5f);
+        p2.closePath();
+
+
+        Area area = new Area(p1);
+        g2.setColor(YELLOW);
+        if (areaType.equals("nop")) {
+            g2.fill(p1);
+            g2.fill(p2);
+            g2.setColor(RED);
+            g2.draw(p1);
+            g2.draw(p2);
+            return;
+        } else if (areaType.equals("add")) {
+            area.add(new Area(p2));
+        } else if (areaType.equals("sub")) {
+            area.subtract(new Area(p2));
+        } else if (areaType.equals("xor")) {
+            area.exclusiveOr(new Area(p2));
+        } else if (areaType.equals("int")) {
+            area.intersect(new Area(p2));
+        } else if (areaType.equals("pear")) {
+
+            double sx = w / 100;
+            double sy = h / 140;
+            g2.scale(sx, sy);
+            double x = w / sx / 2;
+            double y = h / sy / 2;
+
+            // Creates the first leaf by filling the intersection of two Area
+            // objects created from an ellipse.
+            Ellipse2D leaf = new Ellipse2D.Double(x - 16, y - 29, 15.0, 15.0);
+            Area leaf1 = new Area(leaf);
+            leaf.setFrame(x - 14, y - 47, 30.0, 30.0);
+            Area leaf2 = new Area(leaf);
+            leaf1.intersect(leaf2);
+            g2.setColor(GREEN);
+            g2.fill(leaf1);
+
+            // Creates the second leaf.
+            leaf.setFrame(x + 1, y - 29, 15.0, 15.0);
+            leaf1 = new Area(leaf);
+            leaf2.intersect(leaf1);
+            g2.fill(leaf2);
+
+            // Creates the stem by filling the Area resulting from the
+            // subtraction of two Area objects created from an ellipse.
+            Ellipse2D stem = new Ellipse2D.Double(x, y - 42, 40.0, 40.0);
+            Area st1 = new Area(stem);
+            stem.setFrame(x + 3, y - 47, 50.0, 50.0);
+            st1.subtract(new Area(stem));
+            g2.setColor(BLACK);
+            g2.fill(st1);
+
+            // Creates the pear itself by filling the Area resulting from the
+            // union of two Area objects created by two different ellipses.
+            Ellipse2D circle = new Ellipse2D.Double(x - 25, y, 50.0, 50.0);
+            Ellipse2D oval = new Ellipse2D.Double(x - 19, y - 20, 40.0, 70.0);
+            Area circ = new Area(circle);
+            circ.add(new Area(oval));
+
+            g2.setColor(YELLOW);
+            g2.fill(circ);
+            return;
+        }
+
+        g2.fill(area);
+        g2.setColor(RED);
+        g2.draw(area);
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Areas());
+    }
+
+
+    static final class DemoControls extends CustomControls implements
+            ActionListener {
+
+        Areas demo;
+        JToolBar toolbar;
+        JComboBox combo;
+
+        public DemoControls(Areas demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("nop", "no area operation", true);
+            addTool("add", "add", false);
+            addTool("sub", "subtract", false);
+            addTool("xor", "exclusiveOr", false);
+            addTool("int", "intersection", false);
+            addTool("pear", "pear", false);
+        }
+
+        public void addTool(String str, String tooltip, boolean state) {
+            JToggleButton b =
+                    (JToggleButton) toolbar.add(new JToggleButton(str));
+            b.setFocusPainted(false);
+            b.setToolTipText(tooltip);
+            b.setSelected(state);
+            b.addActionListener(this);
+            int width = b.getPreferredSize().width;
+            Dimension prefSize = new Dimension(width, 21);
+            b.setPreferredSize(prefSize);
+            b.setMaximumSize(prefSize);
+            b.setMinimumSize(prefSize);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            for (Component comp : toolbar.getComponents()) {
+                ((JToggleButton) comp).setSelected(false);
+            }
+            JToggleButton b = (JToggleButton) e.getSource();
+            b.setSelected(true);
+            demo.areaType = b.getText();
+            demo.repaint();
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 40);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            try {
+                Thread.sleep(1111);
+            } catch (Exception e) {
+                return;
+            }
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (Component comp : toolbar.getComponents()) {
+                    ((AbstractButton) comp).doClick();
+                    try {
+                        Thread.sleep(4444);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End Areas
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/ClipAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,302 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Clipping;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.awt.image.BufferedImage;
+import javax.swing.*;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import static java.lang.Math.random;
+import static java.awt.Color.*;
+
+
+/**
+ * Animated clipping of an image & composited shapes.
+ */
+@SuppressWarnings("serial")
+public class ClipAnim extends AnimatingControlsSurface {
+
+    private static Image dimg, cimg;
+    static TexturePaint texturePaint;
+
+    static {
+        BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
+        Graphics2D big = bi.createGraphics();
+        big.setBackground(YELLOW);
+        big.clearRect(0, 0, 5, 5);
+        big.setColor(RED);
+        big.fillRect(0, 0, 3, 3);
+        texturePaint = new TexturePaint(bi, new Rectangle(0, 0, 5, 5));
+    }
+    private AnimVal animval[] = new AnimVal[3];
+    protected boolean doObjects = true;
+    private Font originalFont = new Font(Font.SERIF, Font.PLAIN, 12);
+    private Font font;
+    private GradientPaint gradient;
+    private int strX, strY;
+    private int dukeX, dukeY, dukeWidth, dukeHeight;
+
+    public ClipAnim() {
+        cimg = getImage("clouds.jpg");
+        dimg = getImage("duke.png");
+        setBackground(WHITE);
+        animval[0] = new AnimVal(true);
+        animval[1] = new AnimVal(false);
+        animval[2] = new AnimVal(false);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        for (AnimVal a : animval) {
+            a.reset(w, h);
+        }
+        gradient = new GradientPaint(0, h / 2, RED, w * .4f, h * .9f, YELLOW);
+        double scale = 0.4;
+        dukeHeight = (int) (scale * h);
+        dukeWidth = (int) (dimg.getWidth(this) * scale * h / dimg.getHeight(this));
+        dukeX = (int) (w * .25 - dukeWidth / 2);
+        dukeY = (int) (h * .25 - dukeHeight / 2);
+        FontMetrics fm = getFontMetrics(originalFont);
+        double sw = fm.stringWidth("CLIPPING");
+        double sh = fm.getAscent() + fm.getDescent();
+        double sx = (w / 2 - 30) / sw;
+        double sy = (h / 2 - 30) / sh;
+        AffineTransform Tx = AffineTransform.getScaleInstance(sx, sy);
+        font = originalFont.deriveFont(Tx);
+        fm = getFontMetrics(font);
+        strX = (int) (w * .75 - fm.stringWidth("CLIPPING") / 2);
+        strY = (int) (h * .72 + fm.getAscent() / 2);
+    }
+
+    @Override
+    public void step(int w, int h) {
+        for (AnimVal a : animval) {
+            if (a.isSelected) {
+                a.step(w, h);
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        GeneralPath p1 = new GeneralPath();
+        GeneralPath p2 = new GeneralPath();
+
+        for (AnimVal a : animval) {
+            if (a.isSelected) {
+                double x = a.x;
+                double y = a.y;
+                double ew = a.ew;
+                double eh = a.eh;
+                p1.append(new Ellipse2D.Double(x, y, ew, eh), false);
+                p2.append(new Rectangle2D.Double(x + 5, y + 5, ew - 10, eh - 10),
+                        false);
+            }
+        }
+        if (animval[0].isSelected || animval[1].isSelected
+                || animval[2].isSelected) {
+            g2.setClip(p1);
+            g2.clip(p2);
+        }
+
+        if (doObjects) {
+            int w2 = w / 2;
+            int h2 = h / 2;
+            g2.drawImage(cimg, 0, 0, w2, h2, null);
+            g2.drawImage(dimg, dukeX, dukeY, dukeWidth, dukeHeight, null);
+
+            g2.setPaint(texturePaint);
+            g2.fillRect(w2, 0, w2, h2);
+
+            g2.setPaint(gradient);
+            g2.fillRect(0, h2, w2, h2);
+
+            g2.setColor(LIGHT_GRAY);
+            g2.fillRect(w2, h2, w2, h2);
+            g2.setColor(RED);
+            g2.drawOval(w2, h2, w2 - 1, h2 - 1);
+            g2.setFont(font);
+            g2.drawString("CLIPPING", strX, strY);
+        } else {
+            g2.setColor(LIGHT_GRAY);
+            g2.fillRect(0, 0, w, h);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new ClipAnim());
+    }
+
+
+    public class AnimVal {
+
+        double ix = 5.0;
+        double iy = 3.0;
+        double iw = 5.0;
+        double ih = 3.0;
+        double x, y;
+        double ew, eh;   // ellipse width & height
+        boolean isSelected;
+
+        public AnimVal(boolean isSelected) {
+            this.isSelected = isSelected;
+        }
+
+        public void step(int w, int h) {
+            x += ix;
+            y += iy;
+            ew += iw;
+            eh += ih;
+
+            if (ew > w / 2) {
+                ew = w / 2;
+                iw = random() * -w / 16 - 1;
+            }
+            if (ew < w / 8) {
+                ew = w / 8;
+                iw = random() * w / 16 + 1;
+            }
+            if (eh > h / 2) {
+                eh = h / 2;
+                ih = random() * -h / 16 - 1;
+            }
+            if (eh < h / 8) {
+                eh = h / 8;
+                ih = random() * h / 16 + 1;
+            }
+
+            if ((x + ew) > w) {
+                x = (w - ew) - 1;
+                ix = random() * -w / 32 - 1;
+            }
+            if ((y + eh) > h) {
+                y = (h - eh) - 2;
+                iy = random() * -h / 32 - 1;
+            }
+            if (x < 0) {
+                x = 2;
+                ix = random() * w / 32 + 1;
+            }
+            if (y < 0) {
+                y = 2;
+                iy = random() * h / 32 + 1;
+            }
+        }
+
+        public void reset(int w, int h) {
+            x = random() * w;
+            y = random() * h;
+            ew = (random() * w) / 2;
+            eh = (random() * h) / 2;
+        }
+    }
+
+
+    static final class DemoControls extends CustomControls implements
+            ActionListener {
+
+        ClipAnim demo;
+        JToolBar toolbar;
+
+        public DemoControls(ClipAnim demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("Objects", true);
+            addTool("Clip1", true);
+            addTool("Clip2", false);
+            addTool("Clip3", false);
+        }
+
+        public void addTool(String str, boolean state) {
+            JToggleButton b =
+                    (JToggleButton) toolbar.add(new JToggleButton(str));
+            b.setFocusPainted(false);
+            b.setSelected(state);
+            b.addActionListener(this);
+            int width = b.getPreferredSize().width;
+            Dimension prefSize = new Dimension(width, 21);
+            b.setPreferredSize(prefSize);
+            b.setMaximumSize(prefSize);
+            b.setMinimumSize(prefSize);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JToggleButton b = (JToggleButton) e.getSource();
+            if (b.getText().equals("Objects")) {
+                demo.doObjects = b.isSelected();
+            } else if (b.getText().equals("Clip1")) {
+                demo.animval[0].isSelected = b.isSelected();
+            } else if (b.getText().equals("Clip2")) {
+                demo.animval[1].isSelected = b.isSelected();
+            } else if (b.getText().equals("Clip3")) {
+                demo.animval[2].isSelected = b.isSelected();
+            }
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 40);
+        }
+
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(5000);
+            } catch (InterruptedException e) {
+                return;
+            }
+            ((AbstractButton) toolbar.getComponentAtIndex(2)).doClick();
+            try {
+                Thread.sleep(5000);
+            } catch (InterruptedException e) {
+                return;
+            }
+            if (getSize().width > 400) {
+                ((AbstractButton) toolbar.getComponentAtIndex(3)).doClick();
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End ClipAnim
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/Intersection.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,245 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package java2d.demos.Clipping;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import javax.swing.*;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import static java.awt.Color.*;
+
+
+/**
+ * Animated intersection clipping of lines, an image and a textured rectangle.
+ */
+@SuppressWarnings("serial")
+public class Intersection extends AnimatingControlsSurface {
+
+    private static final int HEIGHT_DECREASE = 0;
+    private static final int HEIGHT_INCREASE = 1;
+    private static final int  WIDTH_DECREASE = 2;
+    private static final int  WIDTH_INCREASE = 3;
+
+    private int xx, yy, ww, hh;
+    private int direction = HEIGHT_DECREASE;
+    private int angdeg;
+    private Shape textshape;
+    private double sw, sh;
+    private GeneralPath ovals;
+    private Rectangle2D rectshape;
+    protected boolean doIntersection = true;
+    protected boolean doOvals = true;
+    protected boolean doText;
+    protected boolean threeSixty;
+
+
+    public Intersection() {
+        setBackground(WHITE);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+
+    @Override
+    public void reset(int w, int h) {
+        xx = yy = 0;
+        ww = w-1; hh = h;
+        direction = HEIGHT_DECREASE;
+        angdeg = 0;
+        FontRenderContext frc = new FontRenderContext(null, true, false);
+        Font f = new Font(Font.SERIF, Font.BOLD,32);
+        TextLayout tl = new TextLayout("J2D", f, frc);
+        sw = tl.getBounds().getWidth();
+        sh = tl.getBounds().getHeight();
+        int size = Math.min(w, h);
+        double sx = (size-40)/sw;
+        double sy = (size-100)/sh;
+        AffineTransform Tx = AffineTransform.getScaleInstance(sx, sy);
+        textshape = tl.getOutline(Tx);
+        rectshape = textshape.getBounds();
+        sw = rectshape.getWidth();
+        sh = rectshape.getHeight();
+        ovals = new GeneralPath();
+        ovals.append(new Ellipse2D.Double(  10,   10, 20, 20), false);
+        ovals.append(new Ellipse2D.Double(w-30,   10, 20, 20), false);
+        ovals.append(new Ellipse2D.Double(  10, h-30, 20, 20), false);
+        ovals.append(new Ellipse2D.Double(w-30, h-30, 20, 20), false);
+    }
+
+
+    @Override
+    public void step(int w, int h) {
+        if (direction == HEIGHT_DECREASE) {
+            yy+=2; hh-=4;
+            if (yy >= h/2) {
+                direction = HEIGHT_INCREASE;
+            }
+        } else if (direction == HEIGHT_INCREASE) {
+            yy-=2; hh+=4;
+            if (yy <= 0) {
+                direction = WIDTH_DECREASE;
+                hh = h-1; yy = 0;
+            }
+        }
+        if (direction == WIDTH_DECREASE) {
+            xx+=2; ww-=4;
+            if (xx >= w/2) {
+                direction = WIDTH_INCREASE;
+            }
+        } else if (direction == WIDTH_INCREASE) {
+            xx-=2; ww+=4;
+            if (xx <= 0) {
+                direction = HEIGHT_DECREASE;
+                ww = w-1; xx = 0;
+            }
+        }
+        if ((angdeg += 5) == 360) {
+            angdeg = 0;
+            threeSixty = true;
+        }
+    }
+
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        Rectangle rect = new Rectangle(xx, yy, ww, hh);
+
+        AffineTransform Tx = new AffineTransform();
+        Tx.rotate(Math.toRadians(angdeg),w/2,h/2);
+        Tx.translate(w/2-sw/2, sh+(h-sh)/2);
+
+        GeneralPath path = new GeneralPath();
+        if (doOvals) {
+            path.append(ovals, false);
+        }
+        if (doText) {
+            path.append(Tx.createTransformedShape(textshape), false);
+        } else {
+            path.append(Tx.createTransformedShape(rectshape), false);
+        }
+
+        if (doIntersection) {
+            g2.clip(rect);
+            g2.clip(path);
+        }
+
+        g2.setColor(GREEN);
+        g2.fill(rect);
+
+        g2.setClip(new Rectangle(0, 0, w, h));
+
+        g2.setColor(LIGHT_GRAY);
+        g2.draw(rect);
+        g2.setColor(BLACK);
+        g2.draw(path);
+    }
+
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Intersection());
+    }
+
+
+    static final class DemoControls extends CustomControls implements ActionListener {
+
+        Intersection demo;
+        JToolBar toolbar;
+
+        public DemoControls(Intersection demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("Intersect", true );
+            addTool("Text",      false);
+            addTool("Ovals",     true );
+        }
+
+
+        public void addTool(String str, boolean state) {
+            JToggleButton b = (JToggleButton) toolbar.add(new JToggleButton(str));
+            b.setFocusPainted(false);
+            b.setSelected(state);
+            b.addActionListener(this);
+            int width = b.getPreferredSize().width;
+            Dimension prefSize = new Dimension(width, 21);
+            b.setPreferredSize(prefSize);
+            b.setMaximumSize(  prefSize);
+            b.setMinimumSize(  prefSize);
+        }
+
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JToggleButton b = (JToggleButton) e.getSource();
+            if (b.getText().equals("Intersect")) {
+                demo.doIntersection = b.isSelected();
+            } else if (b.getText().equals("Ovals")) {
+                demo.doOvals = b.isSelected();
+            } else if (b.getText().equals("Text")) {
+                demo.doText = b.isSelected();
+            }
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200,40);
+        }
+
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                if (demo.threeSixty) {
+                    ((AbstractButton) toolbar.getComponentAtIndex(1)).doClick();
+                    demo.threeSixty = false;
+                }
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) { return; }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End Intersection
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Clipping/Text.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,246 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Clipping;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.BLUE;
+import static java.awt.Color.CYAN;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import static java.awt.Color.YELLOW;
+import java.awt.BasicStroke;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.TexturePaint;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+import java.awt.image.BufferedImage;
+import java2d.ControlsSurface;
+import java2d.CustomControls;
+import javax.swing.AbstractButton;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+
+
+/**
+ * Clipping an image, lines, text, texture and gradient with text.
+ */
+@SuppressWarnings("serial")
+public class Text extends ControlsSurface {
+
+    /**
+     *
+     */
+    static Image img;
+    static TexturePaint texturePaint;
+
+    static {
+        BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
+        Graphics2D big = bi.createGraphics();
+        big.setBackground(YELLOW);
+        big.clearRect(0, 0, 5, 5);
+        big.setColor(RED);
+        big.fillRect(0, 0, 3, 3);
+        texturePaint = new TexturePaint(bi, new Rectangle(0, 0, 5, 5));
+    }
+    private String clipType = "Lines";
+    protected boolean doClip = true;
+
+    public Text() {
+        setBackground(WHITE);
+        img = getImage("clouds.jpg");
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        FontRenderContext frc = g2.getFontRenderContext();
+        Font f = new Font(Font.SANS_SERIF, Font.BOLD, 32);
+        String s = "JDK";
+        TextLayout tl = new TextLayout(s, f, frc);
+        double sw = tl.getBounds().getWidth();
+        double sh = tl.getBounds().getHeight();
+        double sx = (w - 40) / sw;
+        double sy = (h - 40) / sh;
+        AffineTransform Tx = AffineTransform.getScaleInstance(sx, sy);
+        Shape shape = tl.getOutline(Tx);
+        sw = shape.getBounds().getWidth();
+        sh = shape.getBounds().getHeight();
+        Tx =
+                AffineTransform.getTranslateInstance(w / 2 - sw / 2, h / 2 + sh
+                / 2);
+        shape = Tx.createTransformedShape(shape);
+        Rectangle r = shape.getBounds();
+
+        if (doClip) {
+            g2.clip(shape);
+        }
+
+        if (clipType.equals("Lines")) {
+            g2.setColor(BLACK);
+            g2.fill(r);
+            g2.setColor(YELLOW);
+            g2.setStroke(new BasicStroke(1.5f));
+            for (int j = r.y; j < r.y + r.height; j = j + 3) {
+                Line2D line = new Line2D.Float(r.x, j,
+                        (r.x + r.width), j);
+                g2.draw(line);
+            }
+        } else if (clipType.equals("Image")) {
+            g2.drawImage(img, r.x, r.y, r.width, r.height, null);
+        } else if (clipType.equals("TP")) {
+            g2.setPaint(texturePaint);
+            g2.fill(r);
+        } else if (clipType.equals("GP")) {
+            g2.setPaint(new GradientPaint(0, 0, BLUE, w, h, YELLOW));
+            g2.fill(r);
+        } else if (clipType.equals("Text")) {
+            g2.setColor(BLACK);
+            g2.fill(shape.getBounds());
+            g2.setColor(CYAN);
+            f = new Font(Font.SERIF, Font.BOLD, 10);
+            tl = new TextLayout("OpenJDK", f, frc);
+            sw = tl.getBounds().getWidth();
+
+            int x = r.x;
+            int y = (int) (r.y + tl.getAscent());
+            sh = r.y + r.height;
+            while (y < sh) {
+                tl.draw(g2, x, y);
+                if ((x += (int) sw) > (r.x + r.width)) {
+                    x = r.x;
+                    y += (int) tl.getAscent();
+                }
+            }
+        }
+        g2.setClip(new Rectangle(0, 0, w, h));
+
+        g2.setColor(GRAY);
+        g2.draw(shape);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Text());
+    }
+
+
+    @SuppressWarnings("serial")
+    static final class DemoControls extends CustomControls implements
+            ActionListener {
+
+        Text demo;
+        JToolBar toolbar;
+
+        public DemoControls(Text demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("Clip", true);
+            addTool("Lines", true);
+            addTool("Image", false);
+            addTool("TP", false);
+            addTool("GP", false);
+            addTool("Text", false);
+        }
+
+        public void addTool(String str, boolean state) {
+            JToggleButton b =
+                    (JToggleButton) toolbar.add(new JToggleButton(str));
+            b.setFocusPainted(false);
+            b.setSelected(state);
+            b.addActionListener(this);
+            int width = b.getPreferredSize().width;
+            Dimension prefSize = new Dimension(width, 21);
+            b.setPreferredSize(prefSize);
+            b.setMaximumSize(prefSize);
+            b.setMinimumSize(prefSize);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            if (e.getSource().equals(toolbar.getComponentAtIndex(0))) {
+                JToggleButton b = (JToggleButton) e.getSource();
+                demo.doClip = b.isSelected();
+            } else {
+                for (Component comp : toolbar.getComponents()) {
+                    ((JToggleButton) comp).setSelected(false);
+                }
+                JToggleButton b = (JToggleButton) e.getSource();
+                b.setSelected(true);
+                demo.clipType = b.getText();
+            }
+            demo.repaint();
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 40);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            try {
+                Thread.sleep(1111);
+            } catch (Exception e) {
+                return;
+            }
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 1; i < toolbar.getComponentCount() - 1; i++) {
+                    ((AbstractButton) toolbar.getComponentAtIndex(i)).doClick();
+                    try {
+                        Thread.sleep(4444);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End Text
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Colors/BullsEye.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Colors;
+
+
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.geom.Ellipse2D;
+import java2d.Surface;
+
+
+/**
+ * Creating colors with an alpha value.
+ */
+@SuppressWarnings("serial")
+public class BullsEye extends Surface {
+
+    public BullsEye() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        Color reds[] = { RED.darker(), RED };
+        for (int N = 0; N < 18; N++) {
+            float i = (N + 2) / 2.0f;
+            float x = (5 + i * (w / 2 / 10));
+            float y = (5 + i * (h / 2 / 10));
+            float ew = (w - 10) - (i * w / 10);
+            float eh = (h - 10) - (i * h / 10);
+            float alpha = (N == 0) ? 0.1f : 1.0f / (19.0f - N);
+            if (N >= 16) {
+                g2.setColor(reds[N - 16]);
+            } else {
+                g2.setColor(new Color(0f, 0f, 0f, alpha));
+            }
+            g2.fill(new Ellipse2D.Float(x, y, ew, eh));
+        }
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new BullsEye());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Colors/ColorConvert.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,129 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Colors;
+
+
+import static java.awt.Color.black;
+import static java.awt.Color.blue;
+import static java.awt.Color.cyan;
+import static java.awt.Color.green;
+import static java.awt.Color.magenta;
+import static java.awt.Color.orange;
+import static java.awt.Color.pink;
+import static java.awt.Color.red;
+import static java.awt.Color.white;
+import static java.awt.Color.yellow;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.color.ColorSpace;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java2d.Surface;
+
+
+/**
+ * ColorConvertOp a ColorSpace.TYPE_RGB BufferedImage to a ColorSpace.CS_GRAY
+ * BufferedImage.
+ */
+@SuppressWarnings("serial")
+public class ColorConvert extends Surface {
+
+    private static Image img;
+    private static Color colors[] = { red, pink, orange,
+        yellow, green, magenta, cyan, blue };
+
+    public ColorConvert() {
+        setBackground(white);
+        img = getImage("clouds.jpg");
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        int iw = img.getWidth(this);
+        int ih = img.getHeight(this);
+        FontRenderContext frc = g2.getFontRenderContext();
+        Font font = g2.getFont();
+        g2.setColor(black);
+        TextLayout tl = new TextLayout("ColorConvertOp RGB->GRAY", font, frc);
+        tl.draw(g2, (float) (w / 2 - tl.getBounds().getWidth() / 2),
+                tl.getAscent() + tl.getLeading());
+
+        BufferedImage srcImg =
+                new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
+        Graphics2D srcG = srcImg.createGraphics();
+        RenderingHints rhs = g2.getRenderingHints();
+        srcG.setRenderingHints(rhs);
+        srcG.drawImage(img, 0, 0, null);
+
+        String s = "OpenJDK";
+        Font f = new Font(Font.SERIF, Font.BOLD, iw / 6);
+        tl = new TextLayout(s, f, frc);
+        Rectangle2D tlb = tl.getBounds();
+        char[] chars = s.toCharArray();
+        float charWidth = 0.0f;
+        int rw = iw / chars.length;
+        int rh = ih / chars.length;
+        for (int i = 0; i < chars.length; i++) {
+            tl = new TextLayout(String.valueOf(chars[i]), f, frc);
+            Shape shape = tl.getOutline(null);
+            srcG.setColor(colors[i % colors.length]);
+            tl.draw(srcG, (float) (iw / 2 - tlb.getWidth() / 2 + charWidth),
+                    (float) (ih / 2 + tlb.getHeight() / 2));
+            charWidth += (float) shape.getBounds().getWidth();
+            srcG.fillRect(i * rw, ih - rh, rw, rh);
+            srcG.setColor(colors[colors.length - 1 - i % colors.length]);
+            srcG.fillRect(i * rw, 0, rw, rh);
+        }
+
+        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
+        ColorConvertOp theOp = new ColorConvertOp(cs, rhs);
+
+        BufferedImage dstImg =
+                new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
+        theOp.filter(srcImg, dstImg);
+
+        g2.drawImage(srcImg, 10, 20, w / 2 - 20, h - 30, null);
+        g2.drawImage(dstImg, w / 2 + 10, 20, w / 2 - 20, h - 30, null);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new ColorConvert());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Colors/Rotator3D.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,397 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Colors;
+
+
+import static java.lang.Math.PI;
+import static java.lang.Math.abs;
+import static java.lang.Math.cos;
+import static java.lang.Math.min;
+import static java.lang.Math.random;
+import static java.lang.Math.sin;
+import static java.lang.Math.sqrt;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java2d.AnimatingSurface;
+
+
+/**
+ * 3D objects with color & lighting translated, rotated and scaled.
+ */
+@SuppressWarnings("serial")
+public class Rotator3D extends AnimatingSurface {
+
+    private Objects3D objs[] = new Objects3D[3];
+    private static final int[][][] polygons = {
+        // Solid cube
+        { { 5, 1, 15, 13, 21, 23, 15 },
+            { 5, 2, 21, 13, 19, 27, 21 },
+            { 5, 3, 23, 15, 17, 25, 23 },
+            { 5, 4, 19, 13, 15, 17, 19 },
+            { 5, 5, 27, 21, 23, 25, 27 },
+            { 5, 6, 27, 19, 17, 25, 27 } },
+        // Polygonal faces cube
+        { { 5, 1, 21, 13, 19, 27, 21 },
+            { 5, 5, 23, 15, 17, 25, 23 },
+            { 4, 0, 15, 14, 16, 15 }, { 7, 6, 16, 14, 13, 12, 18, 17, 16 }, { 4,
+                0, 12, 19, 18, 12 },
+            { 4, 2, 22, 21, 20, 22 }, { 7, 0, 24, 23, 22, 20, 27, 26, 24 }, { 4,
+                2, 24, 26, 25, 24 },
+            { 4, 3, 15, 13, 23, 15 }, { 4, 0, 23, 13, 21, 23 },
+            { 5, 0, 27, 26, 18, 19, 27 }, { 5, 4, 25, 17, 18, 26, 25 } },
+        // Octahedron
+        { { 4, 3, 18, 21, 16, 18 }, { 4, 1, 20, 16, 18, 20 },
+            { 4, 1, 18, 21, 16, 18 }, { 4, 3, 20, 17, 19, 20 },
+            { 4, 2, 20, 26, 27, 20 }, { 5, 3, 26, 18, 16, 27, 26 },
+            { 5, 0, 17, 24, 25, 19, 17 }, { 4, 3, 21, 25, 24, 21 },
+            { 4, 4, 18, 21, 22, 18 }, { 4, 2, 22, 21, 17, 22 },
+            { 4, 5, 20, 23, 16, 20 }, { 4, 1, 20, 23, 19, 20 },
+            { 4, 6, 21, 23, 16, 21 }, { 4, 4, 21, 23, 19, 21 },
+            { 4, 5, 20, 18, 22, 20 }, { 4, 6, 20, 22, 17, 20 } }
+    };
+    private static final double[][][] points = {
+        // Points for solid cube & polygonal faces cube
+        { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 },
+            { 0, 0, -1 }, { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 },
+            { 0, 0, 1 }, { 0, 0, -1 }, { 1, 1, 0 }, { 1, 1, 1 }, { 0, 1, 1 },
+            { -1, 1, 1 }, { -1, 1, 0 }, { -1, 1, -1 }, { 0, 1, -1 },
+            { 1, 1, -1 },
+            { 1, -1, 0 }, { 1, -1, 1 }, { 0, -1, 1 }, { -1, -1, 1 },
+            { -1, -1, 0 },
+            { -1, -1, -1 }, { 0, -1, -1 }, { 1, -1, -1 } },
+        // Points for octahedron
+        { { 0, 0, 1 }, { 0, 0, -1 }, { -0.8165, 0.4714, 0.33333 },
+            { 0.8165, -0.4714, -0.33333 }, { 0.8165, 0.4714, 0.33333 },
+            { -0.8165, -0.4714, -0.33333 }, { 0, -0.9428, 0.3333 },
+            { 0, 0.9428, -0.33333 }, { 0, 0, 1 }, { 0, 0, -1 },
+            { -0.8165, 0.4714, 0.33333 }, { 0.8165, -0.4714, -0.33333 },
+            { 0.8165, 0.4714, 0.33333 }, { -0.8165, -0.4714, -0.33333 },
+            { 0, -0.9428, 0.33333 }, { 0, 0.9428, -0.33333 },
+            { -1.2247, -0.7071, 1 }, { 1.2247, 0.7071, -1 },
+            { 0, 1.4142, 1 }, { 0, -1.4142, -1 }, { -1.2247, 0.7071, -1 },
+            { 1.2247, -0.7071, 1 }, { 0.61237, 1.06066, 0 },
+            { -0.61237, -1.06066, 0 }, { 1.2247, 0, 0 },
+            { 0.61237, -1.06066, 0 }, { -0.61237, 1.06066, 0 },
+            { -1.2247, 0, 0 } }
+    };
+    private static final int[][][] faces = {
+        // Solid cube
+        { { 1, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 0 }, { 1, 5 } },
+        // Polygonal faces cube
+        { { 1, 0 }, { 1, 1 }, { 3, 2, 3, 4 }, { 3, 5, 6, 7 }, { 2, 8, 9 }, { 2,
+                10, 11 } },
+        // Octahedron
+        { { 1, 2 }, { 1, 3 }, { 2, 4, 5 }, { 2, 6, 7 }, { 2, 8, 9 },
+            { 2, 10, 11 }, { 2, 12, 13 }, { 2, 14, 15 } }, };
+
+    public Rotator3D() {
+        setBackground(Color.white);
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        objs[0] = new Objects3D(polygons[0], points[0], faces[0], w, h);
+        objs[1] = new Objects3D(polygons[1], points[0], faces[1], w, h);
+        objs[2] = new Objects3D(polygons[2], points[1], faces[2], w, h);
+    }
+
+    @Override
+    public void step(int w, int h) {
+        for (Objects3D obj : objs) {
+            if (obj != null) {
+                obj.step(w, h);
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        for (Objects3D obj : objs) {
+            if (obj != null) {
+                obj.render(g2);
+            }
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Rotator3D());
+    }
+
+
+    /**
+     * 3D Objects : Solid Cube, Cube & Octahedron with polygonal faces.
+     */
+    public class Objects3D {
+
+        private final int UP = 0;
+        private final int DOWN = 1;
+        private int[][] polygons;
+        private double[][] points;
+        private int npoint;
+        private int[][] faces;
+        private int nface;
+        private int ncolour = 10;
+        private Color[][] colours = new Color[ncolour][7];
+        private double[] lightvec = { 0, 1, 1 };
+        private double Zeye = 10;
+        private double angle;
+        private Matrix3D orient, tmp, tmp2, tmp3;
+        private int scaleDirection;
+        private double scale, scaleAmt;
+        private double ix = 3.0, iy = 3.0;
+        private double[][] rotPts;
+        private int[][] scrPts;
+        private int xx[] = new int[20];
+        private int yy[] = new int[20];
+        private double x, y;
+        private int p, j;
+        private int colour;
+        private double bounce, persp;
+
+        public Objects3D(int[][] polygons,
+                double[][] points,
+                int[][] faces,
+                int w,
+                int h) {
+
+            this.polygons = polygons;
+            this.points = points;
+            this.faces = faces;
+            npoint = points.length;
+            nface = faces.length;
+
+            x = w * random();
+            y = h * random();
+
+            ix = random() > 0.5 ? ix : -ix;
+            iy = random() > 0.5 ? iy : -iy;
+
+            rotPts = new double[npoint][3];
+            scrPts = new int[npoint][2];
+
+            for (int i = 0; i < ncolour; i++) {
+                int val = 255 - (ncolour - i - 1) * 100 / ncolour;
+                Color[] c = {
+                    new Color(val, val, val), // white
+                    new Color(val, 0, 0), // red
+                    new Color(0, val, 0), // green
+                    new Color(0, 0, val), // blue
+                    new Color(val, val, 0), // yellow
+                    new Color(0, val, val), // cyan
+                    new Color(val, 0, val) // magenta
+                };
+                colours[i] = c;
+            }
+
+            double len = sqrt(lightvec[0] * lightvec[0] + lightvec[1]
+                    * lightvec[1] + lightvec[2] * lightvec[2]);
+            lightvec[0] = lightvec[0] / len;
+            lightvec[1] = lightvec[1] / len;
+            lightvec[2] = lightvec[2] / len;
+
+            double max = 0;
+            for (int i = 0; i < npoint; i++) {
+                len = sqrt(points[i][0] * points[i][0] + points[i][1]
+                        * points[i][1] + points[i][2] * points[i][2]);
+                if (len > max) {
+                    max = len;
+                }
+            }
+
+            for (int i = 0; i < nface; i++) {
+                len = sqrt(points[i][0] * points[i][0] + points[i][1]
+                        * points[i][1] + points[i][2] * points[i][2]);
+                points[i][0] = points[i][0] / len;
+                points[i][1] = points[i][1] / len;
+                points[i][2] = points[i][2] / len;
+            }
+
+            orient = new Matrix3D();
+            tmp = new Matrix3D();
+            tmp2 = new Matrix3D();
+            tmp3 = new Matrix3D();
+            tmp.Rotation(2, 0, PI / 50);
+            CalcScrPts((double) w / 3, (double) h / 3, 0);
+
+            scale = min(w / 3 / max / 1.2, h / 3 / max / 1.2);
+            scaleAmt = scale;
+            scale *= random() * 1.5;
+            scaleDirection = scaleAmt < scale ? DOWN : UP;
+        }
+
+        private Color getColour(int f, int index) {
+            colour = (int) ((rotPts[f][0] * lightvec[0] + rotPts[f][1]
+                    * lightvec[1] + rotPts[f][2] * lightvec[2]) * ncolour);
+            if (colour < 0) {
+                colour = 0;
+            }
+            if (colour > ncolour - 1) {
+                colour = ncolour - 1;
+            }
+            return colours[colour][polygons[faces[f][index]][1]];
+        }
+
+        private void CalcScrPts(double x, double y, double z) {
+            for (p = 0; p < npoint; p++) {
+
+                rotPts[p][2] = points[p][0] * orient.M[2][0]
+                        + points[p][1] * orient.M[2][1]
+                        + points[p][2] * orient.M[2][2];
+
+                rotPts[p][0] = points[p][0] * orient.M[0][0]
+                        + points[p][1] * orient.M[0][1]
+                        + points[p][2] * orient.M[0][2];
+
+                rotPts[p][1] = -points[p][0] * orient.M[1][0]
+                        - points[p][1] * orient.M[1][1]
+                        - points[p][2] * orient.M[1][2];
+            }
+            for (p = nface; p < npoint; p++) {
+                rotPts[p][2] += z;
+                persp = (Zeye - rotPts[p][2]) / (scale * Zeye);
+                scrPts[p][0] = (int) (rotPts[p][0] / persp + x);
+                scrPts[p][1] = (int) (rotPts[p][1] / persp + y);
+            }
+        }
+
+        private boolean faceUp(int f) {
+            return (rotPts[f][0] * rotPts[nface + f][0] + rotPts[f][1] * rotPts[nface
+                    + f][1] + rotPts[f][2] * (rotPts[nface + f][2] - Zeye) < 0);
+        }
+
+        public void step(int w, int h) {
+            x += ix;
+            y += iy;
+            if (x > w - scale) {
+                x = w - scale - 1;
+                ix = -w / 100 - 1;
+            }
+            if (x - scale < 0) {
+                x = 2 + scale;
+                ix = w / 100 + random() * 3;
+            }
+            if (y > h - scale) {
+                y = h - scale - 2;
+                iy = -h / 100 - 1;
+            }
+            if (y - scale < 0) {
+                y = 2 + scale;
+                iy = h / 100 + random() * 3;
+            }
+
+            angle += random() * 0.15;
+            tmp3.Rotation(1, 2, angle);
+            tmp2.Rotation(1, 0, angle * sqrt(2) / 2);
+            tmp.Rotation(0, 2, angle * PI / 4);
+            orient.M = tmp3.Times(tmp2.Times(tmp.M));
+            bounce = abs(cos(0.5 * (angle))) * 2 - 1;
+
+            if (scale > scaleAmt * 1.4) {
+                scaleDirection = DOWN;
+            }
+            if (scale < scaleAmt * 0.4) {
+                scaleDirection = UP;
+            }
+            if (scaleDirection == UP) {
+                scale += random();
+            }
+            if (scaleDirection == DOWN) {
+                scale -= random();
+            }
+
+            CalcScrPts(x, y, bounce);
+        }
+
+        public void render(Graphics2D g2) {
+            for (int f = 0; f < nface; f++) {
+                if (faceUp(f)) {
+                    for (j = 1; j < faces[f][0] + 1; j++) {
+                        DrawPoly(g2, faces[f][j], getColour(f, j));
+                    }
+                }
+            }
+        }
+
+        private void DrawPoly(Graphics2D g2, int poly, Color colour) {
+            for (int point = 2; point < polygons[poly][0] + 2; point++) {
+                xx[point - 2] = scrPts[polygons[poly][point]][0];
+                yy[point - 2] = scrPts[polygons[poly][point]][1];
+            }
+            g2.setColor(colour);
+            g2.fillPolygon(xx, yy, polygons[poly][0]);
+            g2.setColor(Color.black);
+            g2.drawPolygon(xx, yy, polygons[poly][0]);
+        }
+
+
+        /**
+         * A 3D matrix object.
+         */
+        public class Matrix3D {
+
+            public double[][] M = { { 1, 0, 0 },
+                { 0, 1, 0 },
+                { 0, 0, 1 } };
+            private double[][] tmp = new double[3][3];
+            private int row, col, k;
+
+            public void Rotation(int i, int j, double angle) {
+                for (row = 0; row < 3; row++) {
+                    for (col = 0; col < 3; col++) {
+                        if (row != col) {
+                            M[row][col] = 0.0;
+                        } else {
+                            M[row][col] = 1.0;
+                        }
+                    }
+                }
+                M[i][i] = cos(angle);
+                M[j][j] = cos(angle);
+                M[i][j] = sin(angle);
+                M[j][i] = -sin(angle);
+            }
+
+            public double[][] Times(double[][] N) {
+                for (row = 0; row < 3; row++) {
+                    for (col = 0; col < 3; col++) {
+                        tmp[row][col] = 0.0;
+                        for (k = 0; k < 3; k++) {
+                            tmp[row][col] += M[row][k] * N[k][col];
+                        }
+                    }
+                }
+                return tmp;
+            }
+        } // End Matrix3D
+    } // End Objects3D
+} // End Rotator3D
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Composite/ACimages.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,127 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Composite;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.BLUE;
+import static java.awt.Color.CYAN;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.MAGENTA;
+import static java.awt.Color.ORANGE;
+import static java.awt.Color.PINK;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import static java.awt.Color.YELLOW;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Shape;
+import java.awt.font.TextLayout;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java2d.Surface;
+
+
+/**
+ * Compositing shapes on images.
+ */
+@SuppressWarnings("serial")
+public class ACimages extends Surface {
+
+    private static final String s[] = { "box", "fight", "magnify",
+        "boxwave", "globe", "snooze",
+        "tip", "thumbsup", "dukeplug" };
+    private static Image imgs[] = new Image[s.length];
+    private static Color colors[] = { BLUE, CYAN, GREEN,
+        MAGENTA, ORANGE, PINK, RED, YELLOW, LIGHT_GRAY };
+
+    public ACimages() {
+        setBackground(WHITE);
+        for (int i = 0; i < imgs.length; i++) {
+            imgs[i] = getImage(s[i] + ".png");
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        float alpha = 0.0f;
+        int iw = w / 3;
+        int ih = (h - 45) / 3;
+        float xx = 0, yy = 15;
+
+        for (int i = 0; i < imgs.length; i++) {
+
+            xx = (i % 3 == 0) ? 0 : xx + w / 3;
+            switch (i) {
+                case 3:
+                    yy = h / 3 + 15;
+                    break;
+                case 6:
+                    yy = h / 3 * 2 + 15;
+            }
+
+            g2.setComposite(AlphaComposite.SrcOver);
+            g2.setColor(BLACK);
+            AlphaComposite ac = AlphaComposite.SrcOver.derive(alpha += .1f);
+            String str = "a=" + Float.toString(alpha).substring(0, 3);
+            new TextLayout(str, g2.getFont(), g2.getFontRenderContext()).draw(g2, xx
+                    + 3, yy - 2);
+
+            Shape shape = null;
+
+            switch (i % 3) {
+                case 0:
+                    shape = new Ellipse2D.Float(xx, yy, iw, ih);
+                    break;
+                case 1:
+                    shape = new RoundRectangle2D.Float(xx, yy, iw, ih, 25, 25);
+                    break;
+                case 2:
+                    shape = new Rectangle2D.Float(xx, yy, iw, ih);
+                    break;
+            }
+            g2.setColor(colors[i]);
+            g2.setComposite(ac);
+            g2.fill(shape);
+            g2.drawImage(imgs[i], (int) xx, (int) yy, iw, ih, null);
+        }
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new ACimages());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Composite/ACrules.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,263 @@
+/*
+ *
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java2d.demos.Composite;
+
+
+import static java.awt.AlphaComposite.Clear;
+import static java.awt.AlphaComposite.Dst;
+import static java.awt.AlphaComposite.DstAtop;
+import static java.awt.AlphaComposite.DstIn;
+import static java.awt.AlphaComposite.DstOut;
+import static java.awt.AlphaComposite.DstOver;
+import static java.awt.AlphaComposite.Src;
+import static java.awt.AlphaComposite.SrcAtop;
+import static java.awt.AlphaComposite.SrcIn;
+import static java.awt.AlphaComposite.SrcOut;
+import static java.awt.AlphaComposite.SrcOver;
+import static java.awt.AlphaComposite.Xor;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.font.TextLayout;
+import java.awt.geom.GeneralPath;<