8198991: Move Java2D demo to the open repository
authorprr
Mon, 14 May 2018 08:58:32 -0700
changeset 50146 0bb0e464ee76
parent 50145 752645a158ff
child 50147 23a8ccafa7ba
8198991: Move Java2D demo to the open repository Reviewed-by: serb, jeff
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
--- 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;
+import java.awt.image.BufferedImage;
+import java2d.AnimatingSurface;
+
+
+/**
+ * All the AlphaCompositing Rules demonstrated.
+ */
+@SuppressWarnings("serial")
+public class ACrules extends AnimatingSurface {
+
+    private static String compNames[] = {
+        "Src",
+        "SrcOver",
+        "SrcIn",
+        "SrcOut",
+        "SrcAtop",
+        "Clear",
+        "Dst",
+        "DstOver",
+        "DstIn",
+        "DstOut",
+        "DstAtop",
+        "Xor", };
+    private static final AlphaComposite compObjs[] = {
+        Src, SrcOver, SrcIn, SrcOut, SrcAtop, Clear,
+        Dst, DstOver, DstIn, DstOut, DstAtop, Xor, };
+    private static final int NUM_RULES = compObjs.length;
+    private static final int HALF_NUM_RULES = NUM_RULES / 2;
+    private int fadeIndex;
+    private static float fadeValues[][] = {
+        { 1.0f, -0.1f, 0.0f, 1.0f, 0.0f, 1.0f },
+        { 0.0f, 0.1f, 1.0f, 1.0f, -0.1f, 0.0f },
+        { 1.0f, 0.0f, 1.0f, 0.0f, 0.1f, 1.0f }, };
+    private static String fadeNames[] = {
+        "Src => transparent, Dest opaque",
+        "Src => opaque, Dest => transparent",
+        "Src opaque, Dest => opaque", };
+    private static Font f = new Font("serif", Font.PLAIN, 10);
+    private float srca = fadeValues[fadeIndex][0];
+    private float dsta = fadeValues[fadeIndex][3];
+    private String fadeLabel = fadeNames[0];
+    private BufferedImage statBI, animBI;
+    private int PADLEFT, PADRIGHT, HPAD;
+    private int PADABOVE, PADBELOW, VPAD;
+    private int RECTWIDTH, RECTHEIGHT;
+    private int PADDEDHEIGHT;
+    private GeneralPath srcpath = new GeneralPath();
+    private GeneralPath dstpath = new GeneralPath();
+    private LineMetrics lm;
+    private BufferedImage dBI, sBI;
+    private GradientPaint gradientDst, gradientSrc;
+
+    public ACrules() {
+        setBackground(Color.white);
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        setSleepAmount(400);
+        FontRenderContext frc = new FontRenderContext(null, false, false);
+        lm = f.getLineMetrics(compNames[0], frc);
+
+        PADLEFT = (w < 150) ? 10 : 15;
+        PADRIGHT = (w < 150) ? 10 : 15;
+        HPAD = (PADLEFT + PADRIGHT);
+        PADBELOW = (h < 250) ? 1 : 2;
+        PADABOVE = PADBELOW + (int) lm.getHeight();
+        VPAD = (PADABOVE + PADBELOW);
+        RECTWIDTH = w / 4 - HPAD;
+        RECTWIDTH = (RECTWIDTH < 6) ? 6 : RECTWIDTH;
+        RECTHEIGHT = (h - VPAD) / HALF_NUM_RULES - VPAD;
+        RECTHEIGHT = (RECTHEIGHT < 6) ? 6 : RECTHEIGHT;
+        PADDEDHEIGHT = (RECTHEIGHT + VPAD);
+
+        srcpath.reset();
+        srcpath.moveTo(0, 0);
+        srcpath.lineTo(RECTWIDTH, 0);
+        srcpath.lineTo(0, RECTHEIGHT);
+        srcpath.closePath();
+
+        dstpath.reset();
+        dstpath.moveTo(0, 0);
+        dstpath.lineTo(RECTWIDTH, RECTHEIGHT);
+        dstpath.lineTo(RECTWIDTH, 0);
+        dstpath.closePath();
+
+        dBI = new BufferedImage(RECTWIDTH, RECTHEIGHT,
+                BufferedImage.TYPE_INT_ARGB);
+        sBI = new BufferedImage(RECTWIDTH, RECTHEIGHT,
+                BufferedImage.TYPE_INT_ARGB);
+        gradientDst = new GradientPaint(0, 0,
+                new Color(1.0f, 0.0f, 0.0f, 1.0f),
+                0, RECTHEIGHT,
+                new Color(1.0f, 0.0f, 0.0f, 0.0f));
+        gradientSrc = new GradientPaint(0, 0,
+                new Color(0.0f, 0.0f, 1.0f, 1.0f),
+                RECTWIDTH, 0,
+                new Color(0.0f, 0.0f, 1.0f, 0.0f));
+        statBI = new BufferedImage(w / 2, h, BufferedImage.TYPE_INT_RGB);
+        statBI = drawCompBI(statBI, true);
+        animBI = new BufferedImage(w / 2, h, BufferedImage.TYPE_INT_RGB);
+    }
+
+    @Override
+    public void step(int w, int h) {
+        if (getSleepAmount() == 5000) {
+            setSleepAmount(200);
+        }
+
+        srca = srca + fadeValues[fadeIndex][1];
+        dsta = dsta + fadeValues[fadeIndex][4];
+        fadeLabel = fadeNames[fadeIndex];
+        if (srca < 0 || srca > 1.0 || dsta < 0 || dsta > 1.0) {
+            setSleepAmount(5000);
+            srca = fadeValues[fadeIndex][2];
+            dsta = fadeValues[fadeIndex][5];
+            if (fadeIndex++ == fadeValues.length - 1) {
+                fadeIndex = 0;
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        if (statBI == null || animBI == null) {
+            return;
+        }
+        g2.drawImage(statBI, 0, 0, null);
+        g2.drawImage(drawCompBI(animBI, false), w / 2, 0, null);
+
+        g2.setColor(Color.black);
+        FontRenderContext frc = g2.getFontRenderContext();
+        TextLayout tl = new TextLayout("AC Rules", g2.getFont(), frc);
+        tl.draw(g2, 15.0f, (float) tl.getBounds().getHeight() + 3.0f);
+
+        tl = new TextLayout(fadeLabel, f, frc);
+        float x = (float) (w * 0.75 - tl.getBounds().getWidth() / 2);
+        if ((x + tl.getBounds().getWidth()) > w) {
+            x = (float) (w - tl.getBounds().getWidth());
+        }
+        tl.draw(g2, x, (float) tl.getBounds().getHeight() + 3.0f);
+    }
+
+    private BufferedImage drawCompBI(BufferedImage bi, boolean doGradient) {
+        Graphics2D big = bi.createGraphics();
+        big.setColor(getBackground());
+        big.fillRect(0, 0, bi.getWidth(), bi.getHeight());
+        big.setRenderingHint(RenderingHints.KEY_ANTIALIASING, AntiAlias);
+        big.setFont(f);
+
+        Graphics2D gD = dBI.createGraphics();
+        gD.setRenderingHint(RenderingHints.KEY_ANTIALIASING, AntiAlias);
+        Graphics2D gS = sBI.createGraphics();
+        gS.setRenderingHint(RenderingHints.KEY_ANTIALIASING, AntiAlias);
+
+        int x = 0, y = 0;
+        int yy = (int) lm.getHeight() + VPAD;
+
+        for (int i = 0; i < compNames.length; i++) {
+            y = (i == 0 || i == HALF_NUM_RULES) ? yy : y + PADDEDHEIGHT;
+            x = (i >= HALF_NUM_RULES) ? bi.getWidth() / 2 + PADLEFT : PADLEFT;
+            big.translate(x, y);
+
+            gD.setComposite(Clear);
+            gD.fillRect(0, 0, RECTWIDTH, RECTHEIGHT);
+            gD.setComposite(Src);
+            if (doGradient) {
+                gD.setPaint(gradientDst);
+                gD.fillRect(0, 0, RECTWIDTH, RECTHEIGHT);
+            } else {
+                gD.setPaint(new Color(1.0f, 0.0f, 0.0f, dsta));
+                gD.fill(dstpath);
+            }
+
+            gS.setComposite(Clear);
+            gS.fillRect(0, 0, RECTWIDTH, RECTHEIGHT);
+            gS.setComposite(Src);
+            if (doGradient) {
+                gS.setPaint(gradientSrc);
+                gS.fillRect(0, 0, RECTWIDTH, RECTHEIGHT);
+            } else {
+                gS.setPaint(new Color(0.0f, 0.0f, 1.0f, srca));
+                gS.fill(srcpath);
+            }
+
+            gD.setComposite(compObjs[i]);
+            gD.drawImage(sBI, 0, 0, null);
+
+            big.drawImage(dBI, 0, 0, null);
+            big.setColor(Color.black);
+            big.drawString(compNames[i], 0, -lm.getDescent());
+            big.drawRect(0, 0, RECTWIDTH, RECTHEIGHT);
+            big.translate(-x, -y);
+        }
+
+        gD.dispose();
+        gS.dispose();
+        big.dispose();
+
+        return bi;
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new ACrules());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Composite/FadeAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,486 @@
+/*
+ *
+ * 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.BasicStroke;
+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.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.TexturePaint;
+import java.awt.geom.Arc2D;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.List;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JSlider;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * Animation of compositing shapes, text and images fading in and out.
+ */
+@SuppressWarnings("serial")
+public final class FadeAnim extends AnimatingControlsSurface {
+
+    private static final TexturePaint texturePaint;
+
+    static {
+        int w = 10;
+        int h = 10;
+        BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        Graphics2D gi = bi.createGraphics();
+        Color oc = BLUE;
+        Color ic = GREEN;
+        gi.setPaint(new GradientPaint(0, 0, oc, w * .35f, h * .35f, ic));
+        gi.fillRect(0, 0, w / 2, h / 2);
+        gi.setPaint(new GradientPaint(w, 0, oc, w * .65f, h * .35f, ic));
+        gi.fillRect(w / 2, 0, w / 2, h / 2);
+        gi.setPaint(new GradientPaint(0, h, oc, w * .35f, h * .65f, ic));
+        gi.fillRect(0, h / 2, w / 2, h / 2);
+        gi.setPaint(new GradientPaint(w, h, oc, w * .65f, h * .65f, ic));
+        gi.fillRect(w / 2, h / 2, w / 2, h / 2);
+        texturePaint = new TexturePaint(bi, new Rectangle(0, 0, w, h));
+    }
+    private static BasicStroke bs = new BasicStroke(6);
+    private static Font fonts[] = {
+        new Font(Font.SERIF, Font.PLAIN, 64),
+        new Font(Font.SERIF, Font.BOLD | Font.ITALIC, 24),
+        new Font(Font.MONOSPACED, Font.BOLD, 36),
+        new Font(Font.SANS_SERIF, Font.BOLD | Font.ITALIC, 48),
+        new Font(Font.SANS_SERIF, Font.PLAIN, 52) };
+    private static String strings[] = {
+        "Alpha", "Composite", "Src", "SrcOver",
+        "SrcIn", "SrcOut", "Clear", "DstOver", "DstIn" };
+    private static String imgs[] = {
+        "jumptojavastrip.png", "duke.png", "star7.png" };
+    private static Paint paints[] = {
+        RED, BLUE, GREEN, MAGENTA,
+        ORANGE, PINK, CYAN, texturePaint,
+        YELLOW, LIGHT_GRAY, WHITE };
+    private List<ObjectData> objects = new ArrayList<ObjectData>(20);
+    private int numShapes, numStrings, numImages;
+
+    public FadeAnim() {
+        setBackground(BLACK);
+        setStrings(2);
+        setImages(3);
+        setShapes(8);
+        setControls(new Component[] { new DemoControls(this) });
+        setConstraints(new String[] { BorderLayout.EAST });
+    }
+
+    public void setImages(int num) {
+
+        if (num < numImages) {
+            List<ObjectData> images = new ArrayList<ObjectData>(objects.size());
+            for (ObjectData obj : objects) {
+                if (obj.object instanceof Image) {
+                    images.add(obj);
+                }
+            }
+            objects.removeAll(images.subList(num, images.size()));
+        } else {
+            Dimension d = getSize();
+            for (int i = numImages; i < num; i++) {
+                Object obj = getImage(imgs[i % imgs.length]);
+                if (imgs[i % imgs.length].equals("jumptojavastrip.png")) {
+                    int iw = ((Image) obj).getWidth(null);
+                    int ih = ((Image) obj).getHeight(null);
+                    BufferedImage bimage = new BufferedImage(iw, ih,
+                            BufferedImage.TYPE_INT_RGB);
+                    bimage.createGraphics().drawImage((Image) obj, 0, 0, null);
+                    obj = bimage;
+                }
+                ObjectData od = new ObjectData(obj, BLACK);
+                od.reset(d.width, d.height);
+                objects.add(od);
+            }
+        }
+        numImages = num;
+    }
+
+    public void setStrings(int num) {
+
+        if (num < numStrings) {
+            List<ObjectData> textDatas = new ArrayList<ObjectData>(
+                    objects.size());
+            //for (int i = 0; i < objects.size(); i++) {
+            for (ObjectData obj : objects) {
+                if (obj.object instanceof TextData) {
+                    textDatas.add(obj);
+                }
+            }
+            objects.removeAll(textDatas.subList(num, textDatas.size()));
+        } else {
+            Dimension d = getSize();
+            for (int i = numStrings; i < num; i++) {
+                int j = i % fonts.length;
+                int k = i % strings.length;
+                Object obj = new TextData(strings[k], fonts[j], this);
+                ObjectData od = new ObjectData(obj, paints[i % paints.length]);
+                od.reset(d.width, d.height);
+                objects.add(od);
+            }
+        }
+        numStrings = num;
+    }
+
+    public void setShapes(int num) {
+
+        if (num < numShapes) {
+            List<ObjectData> shapes = new ArrayList<ObjectData>(objects.size());
+            //for (int i = 0; i < objects.size(); i++) {
+            for (ObjectData obj : objects) {
+                if (obj.object instanceof Shape) {
+                    shapes.add(obj);
+                }
+            }
+            objects.removeAll(shapes.subList(num, shapes.size()));
+        } else {
+            Dimension d = getSize();
+            for (int i = numShapes; i < num; i++) {
+                Object obj = null;
+                switch (i % 7) {
+                    case 0:
+                        obj = new GeneralPath();
+                        break;
+                    case 1:
+                        obj = new Rectangle2D.Double();
+                        break;
+                    case 2:
+                        obj = new Ellipse2D.Double();
+                        break;
+                    case 3:
+                        obj = new Arc2D.Double();
+                        break;
+                    case 4:
+                        obj = new RoundRectangle2D.Double();
+                        break;
+                    case 5:
+                        obj = new CubicCurve2D.Double();
+                        break;
+                    case 6:
+                        obj = new QuadCurve2D.Double();
+                        break;
+                }
+                ObjectData od = new ObjectData(obj, paints[i % paints.length]);
+                od.reset(d.width, d.height);
+                objects.add(od);
+            }
+        }
+        numShapes = num;
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        for (int i = 0; i < objects.size(); i++) {
+            objects.get(i).reset(w, h);
+        }
+    }
+
+    @Override
+    public void step(int w, int h) {
+        for (int i = 0; i < objects.size(); i++) {
+            objects.get(i).step(w, h);
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        for (int i = 0; i < objects.size(); i++) {
+            ObjectData od = objects.get(i);
+            AlphaComposite ac = AlphaComposite.getInstance(
+                    AlphaComposite.SRC_OVER, od.alpha);
+            g2.setComposite(ac);
+            g2.setPaint(od.paint);
+            g2.translate(od.x, od.y);
+
+            if (od.object instanceof Image) {
+                g2.drawImage((Image) od.object, 0, 0, this);
+            } else if (od.object instanceof TextData) {
+                g2.setFont(((TextData) od.object).font);
+                g2.drawString(((TextData) od.object).string, 0, 0);
+            } else if (od.object instanceof QuadCurve2D
+                    || od.object instanceof CubicCurve2D) {
+                g2.setStroke(bs);
+                g2.draw((Shape) od.object);
+            } else if (od.object instanceof Shape) {
+                g2.fill((Shape) od.object);
+            }
+            g2.translate(-od.x, -od.y);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new FadeAnim());
+    }
+
+
+    static class TextData extends Object {
+
+        public String string;
+        public Font font;
+        public int width, height;
+
+        public TextData(String str, Font font, Component cmp) {
+            string = str;
+            this.font = font;
+            FontMetrics fm = cmp.getFontMetrics(font);
+            width = fm.stringWidth(str);
+            height = fm.getHeight();
+        }
+    }
+
+
+    static class ObjectData extends Object {
+
+        final int UP = 0;
+        final int DOWN = 1;
+        Object object;
+        BufferedImage bimg;
+        Paint paint;
+        double x, y;
+        float alpha;
+        int alphaDirection;
+        int imgX;
+
+        public ObjectData(Object object, Paint paint) {
+            this.object = object;
+            this.paint = paint;
+            if (object instanceof BufferedImage) {
+                bimg = (BufferedImage) object;
+                this.object = bimg.getSubimage(0, 0, 80, 80);
+            }
+            getRandomXY(300, 250);
+            alpha = (float) Math.random();
+            alphaDirection = Math.random() > 0.5 ? UP : DOWN;
+        }
+
+        private void getRandomXY(int w, int h) {
+            if (object instanceof TextData) {
+                x = Math.random() * (w - ((TextData) object).width);
+                y = Math.random() * h;
+                y = y < ((TextData) object).height ? ((TextData) object).height
+                        : y;
+            } else if (object instanceof Image) {
+                x = Math.random() * (w - ((Image) object).getWidth(null));
+                y = Math.random() * (h - ((Image) object).getHeight(null));
+            } else if (object instanceof Shape) {
+                Rectangle bounds = ((Shape) object).getBounds();
+                x = Math.random() * (w - bounds.width);
+                y = Math.random() * (h - bounds.height);
+            }
+        }
+
+        public void reset(int w, int h) {
+            getRandomXY(w, h);
+            double ww = 20 + Math.random() * ((w == 0 ? 400 : w) / 4);
+            double hh = 20 + Math.random() * ((h == 0 ? 300 : h) / 4);
+            if (object instanceof Ellipse2D) {
+                ((Ellipse2D) object).setFrame(0, 0, ww, hh);
+            } else if (object instanceof Rectangle2D) {
+                ((Rectangle2D) object).setRect(0, 0, ww, ww);
+            } else if (object instanceof RoundRectangle2D) {
+                ((RoundRectangle2D) object).setRoundRect(0, 0, hh, hh, 20, 20);
+            } else if (object instanceof Arc2D) {
+                ((Arc2D) object).setArc(0, 0, hh, hh, 45, 270, Arc2D.PIE);
+            } else if (object instanceof QuadCurve2D) {
+                ((QuadCurve2D) object).setCurve(0, 0, w * .2, h * .4, w * .4, 0);
+            } else if (object instanceof CubicCurve2D) {
+                ((CubicCurve2D) object).setCurve(0, 0, 30, -60, 60, 60, 90, 0);
+            } else if (object instanceof GeneralPath) {
+                GeneralPath p = new GeneralPath();
+                float size = (float) ww;
+                p.moveTo(-size / 2.0f, -size / 8.0f);
+                p.lineTo(+size / 2.0f, -size / 8.0f);
+                p.lineTo(-size / 4.0f, +size / 2.0f);
+                p.lineTo(+0.0f, -size / 2.0f);
+                p.lineTo(+size / 4.0f, +size / 2.0f);
+                p.closePath();
+                object = p;
+            }
+        }
+
+        public void step(int w, int h) {
+            if (object instanceof BufferedImage) {
+                if ((imgX += 80) == 800) {
+                    imgX = 0;
+                }
+                object = bimg.getSubimage(imgX, 0, 80, 80);
+            }
+            if (alphaDirection == UP) {
+                if ((alpha += 0.05) > .99) {
+                    alphaDirection = DOWN;
+                    alpha = 1.0f;
+                }
+            } else if (alphaDirection == DOWN) {
+                if ((alpha -= .05) < 0.01) {
+                    alphaDirection = UP;
+                    alpha = 0;
+                    getRandomXY(w, h);
+                }
+            }
+        }
+    }
+
+
+    static class DemoControls extends CustomControls implements ChangeListener {
+
+        FadeAnim demo;
+        JSlider shapeSlider, stringSlider, imageSlider;
+        Font font = new Font(Font.SERIF, Font.BOLD, 10);
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(FadeAnim demo) {
+            super(demo.name);
+            this.demo = demo;
+            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+            add(Box.createVerticalStrut(5));
+
+            JToolBar toolbar = new JToolBar(SwingConstants.VERTICAL);
+            toolbar.setFloatable(false);
+            shapeSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 20,
+                    demo.numShapes);
+            shapeSlider.addChangeListener(this);
+            TitledBorder tb = new TitledBorder(new EtchedBorder());
+            tb.setTitleFont(font);
+            tb.setTitle(String.valueOf(demo.numShapes) + " Shapes");
+            shapeSlider.setBorder(tb);
+            shapeSlider.setPreferredSize(new Dimension(80, 45));
+            shapeSlider.setOpaque(true);
+            toolbar.addSeparator();
+            toolbar.add(shapeSlider);
+            toolbar.addSeparator();
+
+            stringSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 10,
+                    demo.numStrings);
+            stringSlider.addChangeListener(this);
+            tb = new TitledBorder(new EtchedBorder());
+            tb.setTitleFont(font);
+            tb.setTitle(String.valueOf(demo.numStrings) + " Strings");
+            stringSlider.setBorder(tb);
+            stringSlider.setPreferredSize(new Dimension(80, 45));
+            stringSlider.setOpaque(true);
+            toolbar.add(stringSlider);
+            toolbar.addSeparator();
+
+            imageSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 10,
+                    demo.numImages);
+            imageSlider.addChangeListener(this);
+            tb = new TitledBorder(new EtchedBorder());
+            tb.setTitleFont(font);
+            tb.setTitle(String.valueOf(demo.numImages) + " Images");
+            imageSlider.setBorder(tb);
+            imageSlider.setPreferredSize(new Dimension(80, 45));
+            imageSlider.setOpaque(true);
+            toolbar.add(imageSlider);
+            toolbar.addSeparator();
+
+            add(toolbar);
+        }
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            JSlider slider = (JSlider) e.getSource();
+            int value = slider.getValue();
+            TitledBorder tb = (TitledBorder) slider.getBorder();
+            if (slider.equals(shapeSlider)) {
+                tb.setTitle(String.valueOf(value) + " Shapes");
+                demo.setShapes(value);
+            } else if (slider.equals(stringSlider)) {
+                tb.setTitle(String.valueOf(value) + " Strings");
+                demo.setStrings(value);
+            } else if (slider.equals(imageSlider)) {
+                tb.setTitle(String.valueOf(value) + " Images");
+                demo.setImages(value);
+            }
+            slider.repaint();
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(80, 0);
+        }
+
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(999);
+            } catch (InterruptedException e) {
+                return;
+            }
+            shapeSlider.setValue((int) (Math.random() * 5));
+            stringSlider.setValue(10);
+            thread = null;
+        }
+    } // End DemoControls
+} // End FadeAnim
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/AllFonts.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,181 @@
+/*
+ *
+ * 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.Fonts;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JSlider;
+import javax.swing.SwingConstants;
+import javax.swing.border.EtchedBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * Scrolling text of fonts returned from GraphicsEnvironment.getAllFonts().
+ */
+@SuppressWarnings("serial")
+public class AllFonts extends AnimatingControlsSurface {
+
+    private static final List<Font> fonts = new ArrayList<Font>();
+
+    static {
+        GraphicsEnvironment ge =
+                GraphicsEnvironment.getLocalGraphicsEnvironment();
+        for (Font font : ge.getAllFonts()) {
+            if (font.canDisplayUpTo(font.getName()) != 0) {
+                fonts.add(font);
+            }
+        }
+    }
+    private int nStrs;
+    private int strH;
+    private int fi;
+    protected int fsize = 14;
+    protected List<Font> v = new ArrayList<Font>();
+
+    public AllFonts() {
+        setBackground(WHITE);
+        setSleepAmount(500);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    public void handleThread(int state) {
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        v.clear();
+        Font f = fonts.get(0).deriveFont(Font.PLAIN, fsize);
+        FontMetrics fm = getFontMetrics(f);
+        strH = (fm.getAscent() + fm.getDescent());
+        nStrs = h / strH + 1;
+        fi = 0;
+    }
+
+    @Override
+    public void step(int w, int h) {
+        if (fi < fonts.size()) {
+            v.add(fonts.get(fi).deriveFont(Font.PLAIN, fsize));
+        }
+        if (v.size() == nStrs && !v.isEmpty() || fi > fonts.size()) {
+            v.remove(0);
+        }
+        fi = v.isEmpty() ? 0 : ++fi;
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        g2.setColor(BLACK);
+
+        int yy = (fi >= fonts.size()) ? 0 : h - v.size() * strH - strH / 2;
+
+        for (int i = 0; i < v.size(); i++) {
+            Font f = v.get(i);
+            int sw = getFontMetrics(f).stringWidth(f.getName());
+            g2.setFont(f);
+            g2.drawString(f.getName(), (w / 2 - sw / 2), yy += strH);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new AllFonts());
+    }
+
+
+    static class DemoControls extends CustomControls implements ActionListener,
+            ChangeListener {
+
+        AllFonts demo;
+        JSlider slider;
+        int fsize[] = { 8, 14, 18, 24 };
+        JMenuItem menuitem[] = new JMenuItem[fsize.length];
+        Font font[] = new Font[fsize.length];
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(AllFonts demo) {
+            this.demo = demo;
+            setBackground(GRAY);
+
+            int sleepAmount = (int) demo.getSleepAmount();
+            slider = new JSlider(SwingConstants.HORIZONTAL, 0, 999, sleepAmount);
+            slider.setBorder(new EtchedBorder());
+            slider.setPreferredSize(new Dimension(90, 22));
+            slider.addChangeListener(this);
+            add(slider);
+            JMenuBar menubar = new JMenuBar();
+            add(menubar);
+            JMenu menu = menubar.add(new JMenu("Font Size"));
+            for (int i = 0; i < fsize.length; i++) {
+                font[i] = new Font(Font.SERIF, Font.PLAIN, fsize[i]);
+                menuitem[i] = menu.add(new JMenuItem(String.valueOf(fsize[i])));
+                menuitem[i].setFont(font[i]);
+                menuitem[i].addActionListener(this);
+            }
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            for (int i = 0; i < fsize.length; i++) {
+                if (e.getSource().equals(menuitem[i])) {
+                    demo.fsize = fsize[i];
+                    Dimension d = demo.getSize();
+                    demo.reset(d.width, d.height);
+                    break;
+                }
+            }
+        }
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            demo.setSleepAmount(slider.getValue());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/AttributedStr.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,190 @@
+/*
+ *
+ * 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.Fonts;
+
+
+import static java.awt.Font.BOLD;
+import static java.awt.Font.ITALIC;
+import static java.awt.Font.PLAIN;
+import static java.awt.font.TextAttribute.BACKGROUND;
+import static java.awt.font.TextAttribute.CHAR_REPLACEMENT;
+import static java.awt.font.TextAttribute.FONT;
+import static java.awt.font.TextAttribute.FOREGROUND;
+import static java.awt.font.TextAttribute.UNDERLINE;
+import static java.awt.font.TextAttribute.UNDERLINE_ON;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.TexturePaint;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GraphicAttribute;
+import java.awt.font.ImageGraphicAttribute;
+import java.awt.font.LineBreakMeasurer;
+import java.awt.font.ShapeGraphicAttribute;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java.awt.image.BufferedImage;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java2d.Surface;
+
+
+/**
+ * Demonstrates how to build an AttributedString and then render the
+ * string broken over lines.
+ */
+@SuppressWarnings("serial")
+public class AttributedStr extends Surface {
+
+    static final Color black = new Color(20, 20, 20);
+    static final Color blue = new Color(94, 105, 176);
+    static final Color yellow = new Color(255, 255, 140);
+    static final Color red = new Color(149, 43, 42);
+    static final Color white = new Color(240, 240, 255);
+    static final String text =
+            "  A quick brown  fox  jumped  over the lazy duke  ";
+    static final AttributedString as = new AttributedString(text);
+    static AttributedCharacterIterator aci;
+
+    static {
+        Shape shape = new Ellipse2D.Double(0, 25, 12, 12);
+        ShapeGraphicAttribute sga = new ShapeGraphicAttribute(shape,
+                GraphicAttribute.TOP_ALIGNMENT, false);
+        as.addAttribute(CHAR_REPLACEMENT, sga, 0, 1);
+
+
+        Font font = new Font("sanserif", BOLD | ITALIC, 20);
+        int index = text.indexOf("quick");
+        as.addAttribute(FONT, font, index, index + 5);
+
+        index = text.indexOf("brown");
+        font = new Font(Font.SERIF, BOLD, 20);
+        as.addAttribute(FONT, font, index, index + 5);
+        as.addAttribute(FOREGROUND, red, index, index + 5);
+
+        index = text.indexOf("fox");
+        AffineTransform fontAT = new AffineTransform();
+        fontAT.rotate(Math.toRadians(10));
+        Font fx = new Font(Font.SERIF, BOLD, 30).deriveFont(fontAT);
+        as.addAttribute(FONT, fx, index, index + 1);
+        as.addAttribute(FONT, fx, index + 1, index + 2);
+        as.addAttribute(FONT, fx, index + 2, index + 3);
+
+        fontAT.setToRotation(Math.toRadians(-4));
+        fx = font.deriveFont(fontAT);
+        index = text.indexOf("jumped");
+        as.addAttribute(FONT, fx, index, index + 6);
+
+        font = new Font(Font.SERIF, BOLD | ITALIC, 30);
+        index = text.indexOf("over");
+        as.addAttribute(UNDERLINE, UNDERLINE_ON, index, index + 4);
+        as.addAttribute(FOREGROUND, white, index, index + 4);
+        as.addAttribute(FONT, font, index, text.length());
+
+        font = new Font(Font.DIALOG, PLAIN, 20);
+        int i = text.indexOf("duke");
+        as.addAttribute(FONT, font, index, i - 1);
+
+        BufferedImage bi = new BufferedImage(4, 4, BufferedImage.TYPE_INT_ARGB);
+        bi.setRGB(0, 0, 0xffffffff);
+        TexturePaint tp = new TexturePaint(bi, new Rectangle(0, 0, 4, 4));
+        as.addAttribute(BACKGROUND, tp, i, i + 4);
+        font = new Font(Font.SERIF, BOLD, 40);
+        as.addAttribute(FONT, font, i, i + 4);
+    }
+
+    public AttributedStr() {
+        setBackground(Color.white);
+
+        Font font = getFont("A.ttf");
+        if (font != null) {
+            font = font.deriveFont(PLAIN, 70);
+        } else {
+            font = new Font(Font.SERIF, PLAIN, 50);
+        }
+        int index = text.indexOf("A") + 1;
+        as.addAttribute(FONT, font, 0, index);
+        as.addAttribute(FOREGROUND, white, 0, index);
+
+        font = new Font(Font.DIALOG, PLAIN, 40);
+        int size = getFontMetrics(font).getHeight();
+        BufferedImage bi =
+                new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D big = bi.createGraphics();
+        big.drawImage(getImage("snooze.png"), 0, 0, size, size, null);
+        ImageGraphicAttribute iga =
+                new ImageGraphicAttribute(bi, GraphicAttribute.TOP_ALIGNMENT);
+        as.addAttribute(CHAR_REPLACEMENT, iga, text.length() - 1, text.length());
+
+        aci = as.getIterator();
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        float x = 5, y = 0;
+        FontRenderContext frc = g2.getFontRenderContext();
+        LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
+
+        g2.setPaint(new GradientPaint(0, h, blue, w, 0, black));
+        g2.fillRect(0, 0, w, h);
+
+        g2.setColor(white);
+        String s = "AttributedString LineBreakMeasurer";
+        Font font = new Font(Font.SERIF, PLAIN, 12);
+        TextLayout tl = new TextLayout(s, font, frc);
+
+        tl.draw(g2, 5, y += (float) tl.getBounds().getHeight());
+
+        g2.setColor(yellow);
+
+        while (y < h - tl.getAscent()) {
+            lbm.setPosition(0);
+            while (lbm.getPosition() < text.length()) {
+                tl = lbm.nextLayout(w - x);
+                if (!tl.isLeftToRight()) {
+                    x = w - tl.getAdvance();
+                }
+                tl.draw(g2, x, y += tl.getAscent());
+                y += tl.getDescent() + tl.getLeading();
+            }
+        }
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new AttributedStr());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/Highlighting.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,135 @@
+/*
+ *
+ * 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.Fonts;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.CYAN;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextHitInfo;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java2d.AnimatingSurface;
+
+
+/**
+ * Highlighting of text showing the caret, the highlight & the character
+ * advances.
+ */
+@SuppressWarnings("serial")
+public class Highlighting extends AnimatingSurface {
+
+    private static String text[] = { "HIGHLIGHTING", "OpenJDK" };
+    private static Color colors[] = { CYAN, LIGHT_GRAY };
+    private static Font smallF = new Font("Monospaced", Font.PLAIN, 8);
+    private int[] curPos;
+    private TextLayout[] layouts;
+    private Font[] fonts;
+
+    public Highlighting() {
+        setBackground(WHITE);
+        fonts = new Font[2];
+        layouts = new TextLayout[fonts.length];
+        curPos = new int[fonts.length];
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        fonts[0] = new Font("Monospaced", Font.PLAIN, w / text[0].length() + 8);
+        fonts[1] = new Font("Serif", Font.BOLD, w / text[1].length());
+        for (int i = 0; i < layouts.length; i++) {
+            curPos[i] = 0;
+        }
+    }
+
+    @Override
+    public void step(int w, int h) {
+        setSleepAmount(900);
+        for (int i = 0; i < 2; i++) {
+            if (layouts[i] == null) {
+                continue;
+            }
+            if (curPos[i]++ == layouts[i].getCharacterCount()) {
+                curPos[i] = 0;
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        FontRenderContext frc = g2.getFontRenderContext();
+        for (int i = 0; i < 2; i++) {
+            layouts[i] = new TextLayout(text[i], fonts[i], frc);
+            float rw = layouts[i].getAdvance();
+            float rx = ((w - rw) / 2);
+            float ry = ((i == 0) ? h / 3 : h * 0.75f);
+
+            // draw highlighted shape
+            Shape hilite = layouts[i].getLogicalHighlightShape(0, curPos[i]);
+            AffineTransform at = AffineTransform.getTranslateInstance(rx, ry);
+            hilite = at.createTransformedShape(hilite);
+            float hy = (float) hilite.getBounds2D().getY();
+            float hh = (float) hilite.getBounds2D().getHeight();
+            g2.setColor(colors[i]);
+            g2.fill(hilite);
+
+            // get caret shape
+            Shape[] shapes = layouts[i].getCaretShapes(curPos[i]);
+            Shape caret = at.createTransformedShape(shapes[0]);
+
+            g2.setColor(BLACK);
+            layouts[i].draw(g2, rx, ry);
+            g2.draw(caret);
+            g2.draw(new Rectangle2D.Float(rx, hy, rw, hh));
+
+            // Display character advances.
+            for (int j = 0; j <= layouts[i].getCharacterCount(); j++) {
+                float[] cInfo = layouts[i].getCaretInfo(TextHitInfo.leading(j));
+                String str = String.valueOf((int) cInfo[0]);
+                TextLayout tl = new TextLayout(str, smallF, frc);
+                tl.draw(g2, rx + cInfo[0] - tl.getAdvance() / 2, hy + hh + tl.
+                        getAscent() + 1.0f);
+            }
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Highlighting());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/Outline.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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.Fonts;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.BLUE;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.MAGENTA;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import java.awt.BasicStroke;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextAttribute;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java2d.Surface;
+
+
+/**
+ * Rendering text as an outline shape.
+ */
+@SuppressWarnings("serial")
+public class Outline extends Surface {
+
+    public Outline() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        FontRenderContext frc = g2.getFontRenderContext();
+        Font f = new Font(Font.SANS_SERIF, Font.PLAIN, w / 8);
+        Font f1 = new Font(Font.SANS_SERIF, Font.ITALIC, w / 8);
+        String s = "AttributedString";
+        AttributedString as = new AttributedString(s);
+        as.addAttribute(TextAttribute.FONT, f, 0, 10);
+        as.addAttribute(TextAttribute.FONT, f1, 10, s.length());
+        AttributedCharacterIterator aci = as.getIterator();
+        TextLayout tl = new TextLayout(aci, frc);
+        float sw = (float) tl.getBounds().getWidth();
+        float sh = (float) tl.getBounds().getHeight();
+        Shape sha = tl.getOutline(AffineTransform.getTranslateInstance(w / 2 - sw
+                / 2, h * 0.2 + sh / 2));
+        g2.setColor(BLUE);
+        g2.setStroke(new BasicStroke(1.5f));
+        g2.draw(sha);
+        g2.setColor(MAGENTA);
+        g2.fill(sha);
+
+        f = new Font(Font.SERIF, Font.BOLD, w / 6);
+        tl = new TextLayout("Outline", f, frc);
+        sw = (float) tl.getBounds().getWidth();
+        sh = (float) tl.getBounds().getHeight();
+        sha = tl.getOutline(AffineTransform.getTranslateInstance(w / 2 - sw / 2, h
+                * 0.5 + sh / 2));
+        g2.setColor(BLACK);
+        g2.draw(sha);
+        g2.setColor(RED);
+        g2.fill(sha);
+
+        f = new Font(Font.SANS_SERIF, Font.ITALIC, w / 8);
+        AffineTransform fontAT = new AffineTransform();
+        fontAT.shear(-0.2, 0.0);
+        Font derivedFont = f.deriveFont(fontAT);
+        tl = new TextLayout("Italic-Shear", derivedFont, frc);
+        sw = (float) tl.getBounds().getWidth();
+        sh = (float) tl.getBounds().getHeight();
+        sha = tl.getOutline(AffineTransform.getTranslateInstance(w / 2 - sw / 2, h
+                * 0.80f + sh / 2));
+        g2.setColor(GREEN);
+        g2.draw(sha);
+        g2.setColor(BLACK);
+        g2.fill(sha);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Outline());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Fonts/Tree.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.Fonts;
+
+
+import static java.awt.Color.BLUE;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java2d.AnimatingSurface;
+
+
+/**
+ * Transformation of characters.
+ */
+@SuppressWarnings("serial")
+public class Tree extends AnimatingSurface {
+
+    private char theC = 'A';
+    private Character theT = new Character(theC);
+    private Character theR = new Character((char) (theC + 1));
+
+    public Tree() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void reset(int w, int h) {
+    }
+
+    @Override
+    public void step(int w, int h) {
+        setSleepAmount(4000);
+        theT = new Character(theC = ((char) (theC + 1)));
+        theR = new Character((char) (theC + 1));
+        if (theR.compareTo(new Character('z')) == 0) {
+            theC = 'A';
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        int mindim = Math.min(w, h);
+        AffineTransform at = new AffineTransform();
+        at.translate((w - mindim) / 2.0,
+                (h - mindim) / 2.0);
+        at.scale(mindim, mindim);
+        at.translate(0.5, 0.5);
+        at.scale(0.3, 0.3);
+        at.translate(-(Twidth + Rwidth), FontHeight / 4.0);
+        g2.transform(at);
+        tree(g2, mindim * 0.3, 0);
+
+    }
+    static Font theFont = new Font(Font.SERIF, Font.PLAIN, 1);
+    static double Twidth = 0.6;
+    static double Rwidth = 0.6;
+    static double FontHeight = 0.75;
+    static Color colors[] = { BLUE,
+        RED.darker(),
+        GREEN.darker() };
+
+    public void tree(Graphics2D g2d, double size, int phase) {
+        g2d.setColor(colors[phase % 3]);
+        new TextLayout(theT.toString(), theFont, g2d.getFontRenderContext()).
+                draw(g2d, 0.0f, 0.0f);
+        if (size > 10.0) {
+            AffineTransform at = new AffineTransform();
+            at.setToTranslation(Twidth, -0.1);
+            at.scale(0.6, 0.6);
+            g2d.transform(at);
+            size *= 0.6;
+            new TextLayout(theR.toString(), theFont, g2d.getFontRenderContext()).
+                    draw(g2d, 0.0f, 0.0f);
+            at.setToTranslation(Rwidth + 0.75, 0);
+            g2d.transform(at);
+            Graphics2D g2dt = (Graphics2D) g2d.create();
+            at.setToRotation(-Math.PI / 2.0);
+            g2dt.transform(at);
+            tree(g2dt, size, phase + 1);
+            g2dt.dispose();
+            at.setToTranslation(.75, 0);
+            at.rotate(-Math.PI / 2.0);
+            at.scale(-1.0, 1.0);
+            at.translate(-Twidth, 0);
+            g2d.transform(at);
+            tree(g2d, size, phase);
+        }
+        g2d.setTransform(new AffineTransform());
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Tree());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Images/DukeAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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.Images;
+
+
+import java.awt.*;
+import javax.swing.JButton;
+import java.awt.image.ImageObserver;
+import java2d.AnimatingSurface;
+import java2d.DemoPanel;
+
+
+/**
+ * Animated gif with a transparent background.
+ */
+@SuppressWarnings("serial")
+public class DukeAnim extends AnimatingSurface implements ImageObserver {
+
+    private static Image agif, clouds;
+    private static int aw, ah, cw;
+    private int x;
+    private JButton b;
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public DukeAnim() {
+        setBackground(Color.white);
+        clouds = getImage("clouds.jpg");
+        agif = getImage("duke.running.gif");
+        aw = agif.getWidth(this) / 2;
+        ah = agif.getHeight(this) / 2;
+        cw = clouds.getWidth(this);
+        dontThread = true;
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        b = ((DemoPanel) getParent()).tools.startStopB;
+    }
+
+    @Override
+    public void step(int w, int h) {
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        if ((x -= 3) <= -cw) {
+            x = w;
+        }
+        g2.drawImage(clouds, x, 10, cw, h - 20, this);
+        g2.drawImage(agif, w / 2 - aw, h / 2 - ah, this);
+    }
+
+    @Override
+    public boolean imageUpdate(Image img, int infoflags,
+            int x, int y, int width, int height) {
+        if (b.isSelected() && (infoflags & ALLBITS) != 0) {
+            repaint();
+        }
+        if (b.isSelected() && (infoflags & FRAMEBITS) != 0) {
+            repaint();
+        }
+        return isShowing();
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new DukeAnim());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Images/ImageOps.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,277 @@
+/*
+ *
+ * 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.Images;
+
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ByteLookupTable;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+import java.awt.image.LookupOp;
+import java.awt.image.RescaleOp;
+import java2d.ControlsSurface;
+import java2d.CustomControls;
+import javax.swing.JComboBox;
+import javax.swing.JSlider;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * Images drawn using operators such as ConvolveOp LowPass & Sharpen,
+ * LookupOp and RescaleOp.
+ */
+@SuppressWarnings("serial")
+public class ImageOps extends ControlsSurface implements ChangeListener {
+
+    protected JSlider slider1, slider2;
+    private static final String imgName[] = { "bld.jpg", "boat.png" };
+    private static final BufferedImage img[] = new BufferedImage[imgName.length];
+    private static final String opsName[] = {
+        "Threshold", "RescaleOp", "Invert", "Yellow Invert", "3x3 Blur",
+        "3x3 Sharpen", "3x3 Edge", "5x5 Edge" };
+    private static final BufferedImageOp biop[] =
+            new BufferedImageOp[opsName.length];
+    private static int rescaleFactor = 128;
+    private static float rescaleOffset = 0;
+    private static final int low = 100, high = 200;
+    private int opsIndex, imgIndex;
+
+    static {
+        thresholdOp(low, high);
+        int i = 1;
+        biop[i++] = new RescaleOp(1.0f, 0, null);
+        byte invert[] = new byte[256];
+        byte ordered[] = new byte[256];
+        for (int j = 0; j < 256; j++) {
+            invert[j] = (byte) (256 - j);
+            ordered[j] = (byte) j;
+        }
+        biop[i++] = new LookupOp(new ByteLookupTable(0, invert), null);
+        byte[][] yellowInvert = new byte[][] { invert, invert, ordered };
+        biop[i++] = new LookupOp(new ByteLookupTable(0, yellowInvert), null);
+        int dim[][] = { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 5, 5 } };
+        float data[][] = { { 0.1f, 0.1f, 0.1f, // 3x3 blur
+                0.1f, 0.2f, 0.1f,
+                0.1f, 0.1f, 0.1f },
+            { -1.0f, -1.0f, -1.0f, // 3x3 sharpen
+                -1.0f, 9.0f, -1.0f,
+                -1.0f, -1.0f, -1.0f },
+            { 0.f, -1.f, 0.f, // 3x3 edge
+                -1.f, 5.f, -1.f,
+                0.f, -1.f, 0.f },
+            { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, // 5x5 edge
+                -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
+                -1.0f, -1.0f, 24.0f, -1.0f, -1.0f,
+                -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
+                -1.0f, -1.0f, -1.0f, -1.0f, -1.0f } };
+        for (int j = 0; j < data.length; j++, i++) {
+            biop[i] = new ConvolveOp(new Kernel(dim[j][0], dim[j][1], data[j]));
+        }
+    }
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public ImageOps() {
+        setDoubleBuffered(true);
+        setBackground(Color.white);
+        for (int i = 0; i < imgName.length; i++) {
+            Image image = getImage(imgName[i]);
+            int iw = image.getWidth(this);
+            int ih = image.getHeight(this);
+            img[i] = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
+            img[i].createGraphics().drawImage(image, 0, 0, null);
+        }
+        slider1 = new JSlider(SwingConstants.VERTICAL, 0, 255, low);
+        slider1.setPreferredSize(new Dimension(15, 100));
+        slider1.addChangeListener(this);
+        slider2 = new JSlider(SwingConstants.VERTICAL, 0, 255, high);
+        slider2.setPreferredSize(new Dimension(15, 100));
+        slider2.addChangeListener(this);
+        setControls(new Component[] { new DemoControls(this), slider1, slider2 });
+        setConstraints(new String[] {
+                    BorderLayout.NORTH, BorderLayout.WEST, BorderLayout.EAST });
+    }
+
+    public static void thresholdOp(int low, int high) {
+        byte threshold[] = new byte[256];
+        for (int j = 0; j < 256; j++) {
+            if (j > high) {
+                threshold[j] = (byte) 255;
+            } else if (j < low) {
+                threshold[j] = (byte) 0;
+            } else {
+                threshold[j] = (byte) j;
+            }
+        }
+        biop[0] = new LookupOp(new ByteLookupTable(0, threshold), null);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        int iw = img[imgIndex].getWidth(null);
+        int ih = img[imgIndex].getHeight(null);
+        AffineTransform oldXform = g2.getTransform();
+        g2.scale(((double) w) / iw, ((double) h) / ih);
+        g2.drawImage(img[imgIndex], biop[opsIndex], 0, 0);
+        g2.setTransform(oldXform);
+    }
+
+    @Override
+    public void stateChanged(ChangeEvent e) {
+        if (e.getSource().equals(slider1)) {
+            if (opsIndex == 0) {
+                thresholdOp(slider1.getValue(), high);
+            } else {
+                rescaleFactor = slider1.getValue();
+                biop[1] = new RescaleOp(rescaleFactor / 128.0f, rescaleOffset,
+                        null);
+            }
+        } else {
+            if (opsIndex == 0) {
+                thresholdOp(low, slider2.getValue());
+            } else {
+                rescaleOffset = slider2.getValue();
+                biop[1] = new RescaleOp(rescaleFactor / 128.0f, rescaleOffset,
+                        null);
+            }
+
+        }
+        repaint();
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new ImageOps());
+    }
+
+
+    static class DemoControls extends CustomControls implements ActionListener {
+
+        ImageOps demo;
+        JComboBox imgCombo, opsCombo;
+        Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(ImageOps demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(imgCombo = new JComboBox());
+            imgCombo.setFont(font);
+            for (String name : ImageOps.imgName) {
+                imgCombo.addItem(name);
+            }
+            imgCombo.addActionListener(this);
+            add(opsCombo = new JComboBox());
+            opsCombo.setFont(font);
+            for (String name : ImageOps.opsName) {
+                opsCombo.addItem(name);
+            }
+            opsCombo.addActionListener(this);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            if (e.getSource().equals(opsCombo)) {
+                demo.opsIndex = opsCombo.getSelectedIndex();
+                if (demo.opsIndex == 0) {
+                    demo.slider1.setValue(ImageOps.low);
+                    demo.slider2.setValue(ImageOps.high);
+                    demo.slider1.setEnabled(true);
+                    demo.slider2.setEnabled(true);
+                } else if (demo.opsIndex == 1) {
+                    demo.slider1.setValue(ImageOps.rescaleFactor);
+                    demo.slider2.setValue((int) ImageOps.rescaleOffset);
+                    demo.slider1.setEnabled(true);
+                    demo.slider2.setEnabled(true);
+                } else {
+                    demo.slider1.setEnabled(false);
+                    demo.slider2.setEnabled(false);
+                }
+            } else if (e.getSource().equals(imgCombo)) {
+                demo.imgIndex = imgCombo.getSelectedIndex();
+            }
+            demo.repaint(10);
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 39);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            try {
+                Thread.sleep(1111);
+            } catch (Exception e) {
+                return;
+            }
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 0; i < ImageOps.imgName.length; i++) {
+                    imgCombo.setSelectedIndex(i);
+                    for (int j = 0; j < ImageOps.opsName.length; j++) {
+                        opsCombo.setSelectedIndex(j);
+                        if (j <= 1) {
+                            for (int k = 50; k <= 200; k += 10) {
+                                demo.slider1.setValue(k);
+                                try {
+                                    Thread.sleep(200);
+                                } catch (InterruptedException e) {
+                                    return;
+                                }
+                            }
+                        }
+                        try {
+                            Thread.sleep(4444);
+                        } catch (InterruptedException e) {
+                            return;
+                        }
+                    }
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End ImageOps
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Images/JPEGFlip.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,182 @@
+/*
+ *
+ * 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.Images;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java2d.Surface;
+import javax.imageio.IIOImage;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
+import javax.imageio.stream.ImageOutputStream;
+
+
+/**
+ * Render a filled star & duke into a BufferedImage, save the BufferedImage
+ * as a JPEG, display the BufferedImage, using the decoded JPEG BufferedImage
+ * display the JPEG flipped BufferedImage.
+ */
+@SuppressWarnings("serial")
+public class JPEGFlip extends Surface {
+
+    private static Image img;
+
+    public JPEGFlip() {
+        setBackground(WHITE);
+        img = getImage("duke.png");
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        int hh = h / 2;
+
+        BufferedImage bi = new BufferedImage(w, hh, BufferedImage.TYPE_INT_RGB);
+        Graphics2D big = bi.createGraphics();
+
+        // .. use rendering hints from J2DCanvas ..
+        big.setRenderingHints(g2.getRenderingHints());
+
+        big.setBackground(getBackground());
+        big.clearRect(0, 0, w, hh);
+
+        big.setColor(GREEN.darker());
+        GeneralPath p = new GeneralPath(Path2D.WIND_NON_ZERO);
+        p.moveTo(-w / 2.0f, -hh / 8.0f);
+        p.lineTo(+w / 2.0f, -hh / 8.0f);
+        p.lineTo(-w / 4.0f, +hh / 2.0f);
+        p.lineTo(+0.0f, -hh / 2.0f);
+        p.lineTo(+w / 4.0f, +hh / 2.0f);
+        p.closePath();
+        big.translate(w / 2, hh / 2);
+        big.fill(p);
+
+        float scale = 0.09f;
+        int iw = (int) (scale * w);
+        int ih = (int) (img.getHeight(null) * iw / img.getWidth(null));
+        big.drawImage(img, -iw / 2, -ih / 2, iw, ih, this);
+
+        g2.drawImage(bi, 0, 0, this);
+        g2.setFont(new Font("Dialog", Font.PLAIN, 10));
+        g2.setColor(BLACK);
+        g2.drawString("BufferedImage", 4, 12);
+
+
+        BufferedImage bi1 = null;
+        ImageOutputStream ios = null;
+        // To write the jpeg to a file uncomment the File* lines and
+        // comment out the ByteArray*Stream lines.
+        //FileOutputStream out = null;
+        ByteArrayOutputStream out = null;
+        //FileInputStream in = null;
+        ByteArrayInputStream in = null;
+        try {
+            //File file = new File("images", "test.jpg");
+            //out = new FileOutputStream(file);
+            out = new ByteArrayOutputStream();
+            ios = ImageIO.createImageOutputStream(out);
+            ImageWriter encoder =
+                    ImageIO.getImageWritersByFormatName("JPEG").next();
+            JPEGImageWriteParam param = new JPEGImageWriteParam(null);
+
+            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+            param.setCompressionQuality(1.0f);
+
+            encoder.setOutput(ios);
+            encoder.write(null, new IIOImage(bi, null, null), param);
+
+            //in = new FileInputStream(file);
+            in = new ByteArrayInputStream(out.toByteArray());
+            bi1 = ImageIO.read(in);
+        } catch (Exception ex) {
+            g2.setColor(RED);
+            g2.drawString("Error encoding or decoding the image", 5, hh * 2 - 5);
+            return;
+        } finally {
+            if (ios != null) {
+                try {
+                    ios.close();
+                } catch (IOException ex) {
+                    Logger.getLogger(JPEGFlip.class.getName()).log(Level.SEVERE,
+                            null, ex);
+                }
+            }
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException ex) {
+                    Logger.getLogger(JPEGFlip.class.getName()).log(Level.SEVERE,
+                            null, ex);
+                }
+            }
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException ex) {
+                    Logger.getLogger(JPEGFlip.class.getName()).log(Level.SEVERE,
+                            null, ex);
+                }
+            }
+        }
+
+        if (bi1 == null) {
+            g2.setColor(RED);
+            g2.drawString("Error reading the image", 5, hh * 2 - 5);
+            return;
+        }
+
+        g2.drawImage(bi1, w, hh * 2, -w, -hh, null);
+
+        g2.drawString("JPEGImage Flipped", 4, hh * 2 - 4);
+        g2.drawLine(0, hh, w, hh);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new JPEGFlip());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Images/WarpImage.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,134 @@
+/*
+ *
+ * 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.Images;
+
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java2d.AnimatingSurface;
+
+
+/**
+ * Warps a image on a CubicCurve2D flattened path.
+ */
+@SuppressWarnings("serial")
+public class WarpImage extends AnimatingSurface {
+
+    private static int iw, ih, iw2, ih2;
+    private static Image img;
+    private static final int FORWARD = 0;
+    private static final int BACK = 1;
+    private Point2D pts[];
+    private int direction = FORWARD;
+    private int pNum;
+    private int x, y;
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public WarpImage() {
+        setBackground(Color.white);
+        img = getImage("surfing.png");
+        iw = img.getWidth(this);
+        ih = img.getHeight(this);
+        iw2 = iw / 2;
+        ih2 = ih / 2;
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        pNum = 0;
+        direction = FORWARD;
+        CubicCurve2D cc = new CubicCurve2D.Float(
+                w * .2f, h * .5f, w * .4f, 0, w * .6f, h, w * .8f, h * .5f);
+        PathIterator pi = cc.getPathIterator(null, 0.1);
+        Point2D tmp[] = new Point2D[200];
+        int i = 0;
+        while (!pi.isDone()) {
+            float[] coords = new float[6];
+            switch (pi.currentSegment(coords)) {
+                case PathIterator.SEG_MOVETO:
+                case PathIterator.SEG_LINETO:
+                    tmp[i] = new Point2D.Float(coords[0], coords[1]);
+            }
+            i++;
+            pi.next();
+        }
+        pts = new Point2D[i];
+        System.arraycopy(tmp, 0, pts, 0, i);
+    }
+
+    @Override
+    public void step(int w, int h) {
+        if (pts == null) {
+            return;
+        }
+        x = (int) pts[pNum].getX();
+        y = (int) pts[pNum].getY();
+        if (direction == FORWARD) {
+            if (++pNum == pts.length) {
+                direction = BACK;
+            }
+        }
+        if (direction == BACK) {
+            if (--pNum == 0) {
+                direction = FORWARD;
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        g2.drawImage(img,
+                0, 0, x, y,
+                0, 0, iw2, ih2,
+                this);
+        g2.drawImage(img,
+                x, 0, w, y,
+                iw2, 0, iw, ih2,
+                this);
+        g2.drawImage(img,
+                0, y, x, h,
+                0, ih2, iw2, ih,
+                this);
+        g2.drawImage(img,
+                x, y, w, h,
+                iw2, ih2, iw, ih,
+                this);
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new WarpImage());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/Caps.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.demos.Lines;
+
+
+import static java.awt.BasicStroke.CAP_BUTT;
+import static java.awt.BasicStroke.CAP_ROUND;
+import static java.awt.BasicStroke.CAP_SQUARE;
+import static java.awt.BasicStroke.JOIN_MITER;
+import static java.awt.Color.BLACK;
+import static java.awt.Color.WHITE;
+import java.awt.BasicStroke;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.Line2D;
+import java2d.Surface;
+
+
+/**
+ * Shows the three different styles of stroke ending.
+ */
+@SuppressWarnings("serial")
+public class Caps extends Surface {
+
+    private static int cap[] = { CAP_BUTT, CAP_ROUND, CAP_SQUARE };
+    private static String desc[] = { "Butt Cap", "Round Cap", "Square Cap" };
+
+    public Caps() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        FontRenderContext frc = g2.getFontRenderContext();
+        Font font = g2.getFont();
+        g2.setColor(BLACK);
+        for (int i = 0; i < cap.length; i++) {
+            g2.setStroke(new BasicStroke(15, cap[i], JOIN_MITER));
+            g2.draw(new Line2D.Float(w / 4, (i + 1) * h / 4, w - w / 4, (i + 1)
+                    * h / 4));
+            TextLayout tl = new TextLayout(desc[i], font, frc);
+            tl.draw(g2, (float) (w / 2 - tl.getBounds().getWidth() / 2), (i + 1)
+                    * h / 4 - 10);
+        }
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Caps());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/Dash.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,134 @@
+/*
+ *
+ * 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.Lines;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.WHITE;
+import java.awt.BasicStroke;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.Arc2D;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java2d.Surface;
+
+
+/**
+ * Various shapes stroked with a dashing pattern.
+ */
+@SuppressWarnings("serial")
+public class Dash extends Surface {
+
+    public Dash() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        FontRenderContext frc = g2.getFontRenderContext();
+        Font font = g2.getFont();
+        TextLayout tl = new TextLayout("Dashes", font, frc);
+        float sw = (float) tl.getBounds().getWidth();
+        float sh = tl.getAscent() + tl.getDescent();
+        g2.setColor(BLACK);
+        tl.draw(g2, (w / 2 - sw / 2), sh + 5);
+
+        BasicStroke dotted = new BasicStroke(3, BasicStroke.CAP_ROUND,
+                BasicStroke.JOIN_ROUND, 0, new float[] { 0, 6, 0, 6 }, 0);
+        g2.setStroke(dotted);
+        g2.drawRect(3, 3, w - 6, h - 6);
+
+        int x = 0;
+        int y = h - 34;
+        BasicStroke bs[] = new BasicStroke[6];
+
+        float j = 1.1f;
+        for (int i = 0; i < bs.length; i++, j += 1.0f) {
+            float dash[] = { j };
+            BasicStroke b = new BasicStroke(1.0f, BasicStroke.CAP_BUTT,
+                    BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f);
+            g2.setStroke(b);
+            g2.drawLine(20, y, w - 20, y);
+            bs[i] = new BasicStroke(3.0f, BasicStroke.CAP_BUTT,
+                    BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f);
+            y += 5;
+        }
+
+        Shape shape = null;
+        y = 0;
+        for (int i = 0; i < 6; i++) {
+            x = (i == 0 || i == 3) ? (w / 3 - w / 5) / 2 : x + w / 3;
+            y = (i <= 2) ? (int) sh + h / 12 : h / 2;
+
+            g2.setStroke(bs[i]);
+            g2.translate(x, y);
+            switch (i) {
+                case 0:
+                    shape = new Arc2D.Float(0.0f, 0.0f, w / 5, h / 4, 45, 270,
+                            Arc2D.PIE);
+                    break;
+                case 1:
+                    shape = new Ellipse2D.Float(0.0f, 0.0f, w / 5, h / 4);
+                    break;
+                case 2:
+                    shape = new RoundRectangle2D.Float(0.0f, 0.0f, w / 5, h / 4,
+                            10.0f, 10.0f);
+                    break;
+                case 3:
+                    shape = new Rectangle2D.Float(0.0f, 0.0f, w / 5, h / 4);
+                    break;
+                case 4:
+                    shape = new QuadCurve2D.Float(0.0f, 0.0f, w / 10, h / 2, w
+                            / 5, 0.0f);
+                    break;
+                case 5:
+                    shape = new CubicCurve2D.Float(0.0f, 0.0f, w / 15, h / 2, w
+                            / 10, h / 4, w / 5, 0.0f);
+                    break;
+            }
+
+            g2.draw(shape);
+            g2.translate(-x, -y);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Dash());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/Joins.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,247 @@
+/*
+ *
+ * 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.Lines;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.WHITE;
+import java.awt.BasicStroke;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.GeneralPath;
+import java2d.ControlsSurface;
+import java2d.CustomControls;
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JSlider;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+/**
+ * BasicStroke join types and width sizes illustrated.  Control for
+ * rendering a shape returned from BasicStroke.createStrokedShape(Shape).
+ */
+@SuppressWarnings("serial")
+public class Joins extends ControlsSurface {
+
+    protected int joinType = BasicStroke.JOIN_MITER;
+    protected float bswidth = 20.0f;
+    protected JSlider slider;
+    protected JLabel label;
+
+    public Joins() {
+        setBackground(WHITE);
+        slider = new JSlider(SwingConstants.VERTICAL, 0, 100,
+                (int) (bswidth * 2));
+        slider.setPreferredSize(new Dimension(15, 100));
+        slider.addChangeListener(new ChangeListener() {
+
+            public void stateChanged(ChangeEvent e) {
+                // when using these sliders use double buffering, which means
+                // ignoring when DemoSurface.imageType = 'On Screen'
+                if (getImageType() <= 1) {
+                    setImageType(2);
+                }
+                bswidth = slider.getValue() / 2.0f;
+                label.setText(" Width = " + String.valueOf(bswidth));
+                label.repaint();
+                repaint();
+            }
+        });
+        setControls(new Component[] { new DemoControls(this), slider });
+        setConstraints(new String[] { BorderLayout.NORTH, BorderLayout.WEST });
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        BasicStroke bs = new BasicStroke(bswidth,
+                BasicStroke.CAP_BUTT, joinType);
+        GeneralPath p = new GeneralPath();
+        p.moveTo(-w / 4.0f, -h / 12.0f);
+        p.lineTo(+w / 4.0f, -h / 12.0f);
+        p.lineTo(-w / 6.0f, +h / 4.0f);
+        p.lineTo(+0.0f, -h / 4.0f);
+        p.lineTo(+w / 6.0f, +h / 4.0f);
+        p.closePath();
+        p.closePath();
+        g2.translate(w / 2, h / 2);
+        g2.setColor(BLACK);
+        g2.draw(bs.createStrokedShape(p));
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Joins());
+    }
+
+
+    class DemoControls extends CustomControls implements ActionListener {
+
+        Joins demo;
+        int joinType[] = { BasicStroke.JOIN_MITER,
+            BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL };
+        String joinName[] = { "Mitered Join", "Rounded Join", "Beveled Join" };
+        JMenu menu;
+        JMenuItem menuitem[] = new JMenuItem[joinType.length];
+        JoinIcon icons[] = new JoinIcon[joinType.length];
+        JToolBar toolbar;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(Joins demo) {
+            super(demo.name);
+            setBorder(new CompoundBorder(getBorder(),
+                    new EmptyBorder(2, 2, 2, 2)));
+            this.demo = demo;
+            setLayout(new BorderLayout());
+            label = new JLabel(" Width = " + String.valueOf(demo.bswidth));
+            Font font = new Font(Font.SERIF, Font.BOLD, 14);
+            label.setFont(font);
+            add("West", label);
+            JMenuBar menubar = new JMenuBar();
+            add("East", menubar);
+            menu = menubar.add(new JMenu(joinName[0]));
+            menu.setFont(font = new Font(Font.SERIF, Font.PLAIN, 10));
+            ActionListener actionListener = new ActionListener() {
+
+                public void actionPerformed(ActionEvent e) {
+                    throw new UnsupportedOperationException("Not supported yet.");
+                }
+            };
+            for (int i = 0; i < joinType.length; i++) {
+                icons[i] = new JoinIcon(joinType[i]);
+                menuitem[i] = menu.add(new JMenuItem(joinName[i]));
+                menuitem[i].setFont(font);
+                menuitem[i].setIcon(icons[i]);
+                menuitem[i].addActionListener(this);
+            }
+            menu.setIcon(icons[0]);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            for (int i = 0; i < joinType.length; i++) {
+                if (e.getSource().equals(menuitem[i])) {
+                    demo.joinType = joinType[i];
+                    menu.setIcon(icons[i]);
+                    menu.setText(joinName[i]);
+                    break;
+                }
+            }
+            demo.repaint();
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 37);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            try {
+                Thread.sleep(999);
+            } catch (Exception e) {
+                return;
+            }
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 0; i < menuitem.length; i++) {
+                    menuitem[i].doClick();
+                    for (int k = 10; k < 60; k += 2) {
+                        demo.slider.setValue(k);
+                        try {
+                            Thread.sleep(100);
+                        } catch (InterruptedException e) {
+                            return;
+                        }
+                    }
+                    try {
+                        Thread.sleep(999);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }
+            thread = null;
+        }
+
+
+        class JoinIcon implements Icon {
+
+            int joinType;
+
+            public JoinIcon(int joinType) {
+                this.joinType = joinType;
+            }
+
+            @Override
+            public void paintIcon(Component c, Graphics g, int x, int y) {
+                ((Graphics2D) g).setRenderingHint(
+                        RenderingHints.KEY_ANTIALIASING,
+                        RenderingHints.VALUE_ANTIALIAS_ON);
+                BasicStroke bs = new BasicStroke(8.0f,
+                        BasicStroke.CAP_BUTT, joinType);
+                ((Graphics2D) g).setStroke(bs);
+                GeneralPath p = new GeneralPath();
+                p.moveTo(0, 3);
+                p.lineTo(getIconWidth() - 2, getIconHeight() / 2);
+                p.lineTo(0, getIconHeight());
+                ((Graphics2D) g).draw(p);
+            }
+
+            @Override
+            public int getIconWidth() {
+                return 20;
+            }
+
+            @Override
+            public int getIconHeight() {
+                return 20;
+            }
+        } // End JoinIcon class
+    } // End DemoControls class
+} // End Joins class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Lines/LineAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,164 @@
+/*
+ *
+ * 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.Lines;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.PINK;
+import static java.awt.Color.WHITE;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java2d.AnimatingSurface;
+
+
+/**
+ * Lines & Paths animation illustrating BasicStroke attributes.
+ */
+@SuppressWarnings("serial")
+public class LineAnim extends AnimatingSurface {
+
+    private static int caps[] = { BasicStroke.CAP_BUTT,
+        BasicStroke.CAP_SQUARE, BasicStroke.CAP_ROUND };
+    private static int joins[] = { BasicStroke.JOIN_MITER,
+        BasicStroke.JOIN_BEVEL, BasicStroke.JOIN_ROUND };
+    private static Color colors[] = { GRAY, PINK, LIGHT_GRAY };
+    private static BasicStroke bs1 = new BasicStroke(1.0f);
+    private static final int CLOCKWISE = 0;
+    private Line2D lines[] = new Line2D[3];
+    private int rAmt[] = new int[lines.length];
+    private int direction[] = new int[lines.length];
+    private int speed[] = new int[lines.length];
+    private BasicStroke strokes[] = new BasicStroke[lines.length];
+    private GeneralPath path;
+    private Point2D[] pts;
+    private float size;
+    private Ellipse2D ellipse = new Ellipse2D.Double();
+
+    public LineAnim() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        size = (w > h) ? h / 6f : w / 6f;
+        for (int i = 0; i < lines.length; i++) {
+            lines[i] = new Line2D.Float(0, 0, size, 0);
+            strokes[i] = new BasicStroke(size / 3, caps[i], joins[i]);
+            rAmt[i] = i * 360 / lines.length;
+            direction[i] = i % 2;
+            speed[i] = i + 1;
+        }
+
+        path = new GeneralPath();
+        path.moveTo(size, -size / 2);
+        path.lineTo(size + size / 2, 0);
+        path.lineTo(size, +size / 2);
+
+        ellipse.setFrame(w / 2 - size * 2 - 4.5f, h / 2 - size * 2 - 4.5f, size
+                * 4, size * 4);
+        PathIterator pi = ellipse.getPathIterator(null, 0.9);
+        Point2D[] points = new Point2D[100];
+        int num_pts = 0;
+        while (!pi.isDone()) {
+            float[] pt = new float[6];
+            switch (pi.currentSegment(pt)) {
+                case PathIterator.SEG_MOVETO:
+                case PathIterator.SEG_LINETO:
+                    points[num_pts] = new Point2D.Float(pt[0], pt[1]);
+                    num_pts++;
+            }
+            pi.next();
+        }
+        pts = new Point2D[num_pts];
+        System.arraycopy(points, 0, pts, 0, num_pts);
+    }
+
+    @Override
+    public void step(int w, int h) {
+        for (int i = 0; i < lines.length; i++) {
+            if (direction[i] == CLOCKWISE) {
+                rAmt[i] += speed[i];
+                if (rAmt[i] == 360) {
+                    rAmt[i] = 0;
+                }
+            } else {
+                rAmt[i] -= speed[i];
+                if (rAmt[i] == 0) {
+                    rAmt[i] = 360;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        ellipse.setFrame(w / 2 - size, h / 2 - size, size * 2, size * 2);
+        g2.setColor(BLACK);
+        g2.draw(ellipse);
+
+        for (int i = 0; i < lines.length; i++) {
+            AffineTransform at = AffineTransform.getTranslateInstance(w / 2, h
+                    / 2);
+            at.rotate(Math.toRadians(rAmt[i]));
+            g2.setStroke(strokes[i]);
+            g2.setColor(colors[i]);
+            g2.draw(at.createTransformedShape(lines[i]));
+            g2.draw(at.createTransformedShape(path));
+
+            int j = (int) ((double) rAmt[i] / 360 * pts.length);
+            j = (j == pts.length) ? pts.length - 1 : j;
+            ellipse.setFrame(pts[j].getX(), pts[j].getY(), 9, 9);
+            g2.fill(ellipse);
+        }
+
+        g2.setStroke(bs1);
+        g2.setColor(BLACK);
+        for (int i = 0; i < pts.length; i++) {
+            ellipse.setFrame(pts[i].getX(), pts[i].getY(), 9, 9);
+            g2.draw(ellipse);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new LineAnim());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Mix/Balls.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,359 @@
+/*
+ *
+ * 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.Mix;
+
+
+import static java.awt.Color.BLUE;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.ORANGE;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import static java.awt.Color.YELLOW;
+import static java.lang.Math.random;
+import static java.lang.Math.sqrt;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.AbstractButton;
+import javax.swing.JComboBox;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+
+
+/**
+ * Animated color bouncing balls with custom controls.
+ */
+@SuppressWarnings("serial")
+public class Balls extends AnimatingControlsSurface {
+
+    private static Color colors[] = { RED, ORANGE, YELLOW, GREEN.darker(), BLUE,
+        new Color(75, 00, 82), new Color(238, 130, 238) };
+    private long now, deltaT, lasttime;
+    private boolean active;
+    protected Ball balls[] = new Ball[colors.length];
+    protected boolean clearToggle;
+    protected JComboBox combo;
+
+    public Balls() {
+        setBackground(WHITE);
+        for (int i = 0; i < colors.length; i++) {
+            balls[i] = new Ball(colors[i], 30);
+        }
+        balls[0].isSelected = true;
+        balls[3].isSelected = true;
+        balls[4].isSelected = true;
+        balls[6].isSelected = true;
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        if (w > 400 && h > 100) {
+            combo.setSelectedIndex(5);
+        }
+    }
+
+    @Override
+    public void step(int w, int h) {
+        if (lasttime == 0) {
+            lasttime = System.currentTimeMillis();
+        }
+        now = System.currentTimeMillis();
+        deltaT = now - lasttime;
+        active = false;
+        for (Ball ball : balls) {
+            if (ball == null) {
+                return;
+            }
+            ball.step(deltaT, w, h);
+            if (ball.Vy > .02 || -ball.Vy > .02 || ball.y + ball.bsize < h) {
+                active = true;
+            }
+        }
+        if (!active) {
+            for (Ball ball : balls) {
+                ball.Vx = (float) random() / 4.0f - 0.125f;
+                ball.Vy = -(float) random() / 4.0f - 0.2f;
+            }
+            clearToggle = true;
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        for (Ball b : balls) {
+            if (b == null || b.imgs[b.index] == null || !b.isSelected) {
+                continue;
+            }
+            g2.drawImage(b.imgs[b.index], (int) b.x, (int) b.y, this);
+        }
+        lasttime = now;
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Balls());
+    }
+
+
+    protected static final class Ball {
+
+        public static final int nImgs = 5;
+        public int bsize;
+        public float x, y;
+        public float Vx = 0.1f;
+        public float Vy = 0.05f;
+        public BufferedImage imgs[];
+        // Pick a random starting image index, but not the last: we're going UP
+        // and that would throw us off the end.
+        public int index = (int) (random() * (nImgs - 1));
+        private static final float inelasticity = .96f;
+        private static final float Ax = 0.0f;
+        private static final float Ay = 0.0002f;
+        private static final int UP = 0;
+        private static final int DOWN = 1;
+        private int indexDirection = UP;
+        private float jitter;
+        private Color color;
+        private boolean isSelected;
+
+        public Ball(Color color, int bsize) {
+            this.color = color;
+            makeImages(bsize);
+        }
+
+        public void makeImages(int bsize) {
+            this.bsize = bsize * 2;
+            int R = bsize;
+            byte[] data = new byte[R * 2 * R * 2];
+            int maxr = 0;
+            for (int Y = 2 * R; --Y >= 0;) {
+                int x0 = (int) (sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
+                int p = Y * (R * 2) + R - x0;
+                for (int X = -x0; X < x0; X++) {
+                    int xx = X + 15;
+                    int yy = Y - R + 15;
+                    int r = (int) (Math.hypot(xx, yy) + 0.5);
+                    if (r > maxr) {
+                        maxr = r;
+                    }
+                    data[p++] = r <= 0 ? 1 : (byte) r;
+                }
+            }
+
+            imgs = new BufferedImage[nImgs];
+
+            int bg = 255;
+            byte red[] = new byte[256];
+            red[0] = (byte) bg;
+            byte green[] = new byte[256];
+            green[0] = (byte) bg;
+            byte blue[] = new byte[256];
+            blue[0] = (byte) bg;
+
+            for (int r = 0; r < imgs.length; r++) {
+                float b = 0.5f + ((r + 1f) / imgs.length / 2f);
+                for (int i = maxr; i >= 1; --i) {
+                    float d = (float) i / maxr;
+                    red[i] = (byte) blend(blend(color.getRed(), 255, d), bg, b);
+                    green[i] = (byte) blend(blend(color.getGreen(), 255, d), bg,
+                            b);
+                    blue[i] =
+                            (byte) blend(blend(color.getBlue(), 255, d), bg, b);
+                }
+                IndexColorModel icm = new IndexColorModel(8, maxr + 1,
+                        red, green, blue, 0);
+                DataBufferByte dbb = new DataBufferByte(data, data.length);
+                int bandOffsets[] = { 0 };
+                WritableRaster wr = Raster.createInterleavedRaster(dbb,
+                        R * 2, R * 2, R * 2, 1, bandOffsets, null);
+                imgs[r] = new BufferedImage(icm, wr, icm.isAlphaPremultiplied(),
+                        null);
+            }
+        }
+
+        private int blend(int fg, int bg, float fgfactor) {
+            return (int) (bg + (fg - bg) * fgfactor);
+        }
+
+        public void step(long deltaT, int w, int h) {
+
+            jitter = (float) random() * .01f - .005f;
+
+            x += Vx * deltaT + (Ax / 2.0) * deltaT * deltaT;
+            y += Vy * deltaT + (Ay / 2.0) * deltaT * deltaT;
+            if (x <= 0.0f) {
+                x = 0.0f;
+                Vx = -Vx * inelasticity + jitter;
+                //collision_x = true;
+            }
+            if (x + bsize >= w) {
+                x = w - bsize;
+                Vx = -Vx * inelasticity + jitter;
+                //collision_x = true;
+            }
+            if (y <= 0) {
+                y = 0;
+                Vy = -Vy * inelasticity + jitter;
+                //collision_y = true;
+            }
+            if (y + bsize >= h) {
+                y = h - bsize;
+                Vx *= inelasticity;
+                Vy = -Vy * inelasticity + jitter;
+                //collision_y = true;
+            }
+            Vy = Vy + Ay * deltaT;
+            Vx = Vx + Ax * deltaT;
+
+            if (indexDirection == UP) {
+                index++;
+            }
+            if (indexDirection == DOWN) {
+                --index;
+            }
+            if (index + 1 == nImgs) {
+                indexDirection = DOWN;
+            }
+            if (index == 0) {
+                indexDirection = UP;
+            }
+        }
+    }  // End class Ball
+
+
+    final class DemoControls extends CustomControls implements ActionListener {
+
+        Balls demo;
+        JToolBar toolbar;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(Balls demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("Clear", true);
+            addTool("R", demo.balls[0].isSelected);
+            addTool("O", demo.balls[1].isSelected);
+            addTool("Y", demo.balls[2].isSelected);
+            addTool("G", demo.balls[3].isSelected);
+            addTool("B", demo.balls[4].isSelected);
+            addTool("I", demo.balls[5].isSelected);
+            addTool("V", demo.balls[6].isSelected);
+            add(combo = new JComboBox());
+            combo.addItem("10");
+            combo.addItem("20");
+            combo.addItem("30");
+            combo.addItem("40");
+            combo.addItem("50");
+            combo.addItem("60");
+            combo.addItem("70");
+            combo.addItem("80");
+            combo.setSelectedIndex(2);
+            combo.addActionListener(this);
+        }
+
+        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() instanceof JComboBox) {
+                int size = Integer.parseInt((String) combo.getSelectedItem());
+                for (Ball ball : demo.balls) {
+                    ball.makeImages(size);
+                }
+                return;
+            }
+            JToggleButton b = (JToggleButton) e.getSource();
+            if (b.getText().equals("Clear")) {
+                demo.clearSurface = b.isSelected();
+            } else {
+                int index = toolbar.getComponentIndex(b) - 1;
+                demo.balls[index].isSelected = b.isSelected();
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 40);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            try {
+                Thread.sleep(999);
+            } catch (Exception e) {
+                return;
+            }
+            Thread me = Thread.currentThread();
+            ((AbstractButton) toolbar.getComponentAtIndex(2)).doClick();
+            while (thread == me) {
+                try {
+                    Thread.sleep(222);
+                } catch (InterruptedException e) {
+                    return;
+                }
+                if (demo.clearToggle) {
+                    if (demo.clearSurface) {
+                        combo.setSelectedIndex((int) (random() * 5));
+                    }
+                    ((AbstractButton) toolbar.getComponentAtIndex(0)).doClick();
+                    demo.clearToggle = false;
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End Balls
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Mix/BezierScroller.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,389 @@
+/*
+ *
+ * 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.Mix;
+
+
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import static java.lang.Math.random;
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.image.BufferedImage;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.AbstractButton;
+import javax.swing.JComboBox;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+
+
+/**
+ * Animated Bezier Curve shape with images at the control points.
+ * README.txt file scrolling up. Composited Image fading in and out.
+ */
+@SuppressWarnings("serial")
+public class BezierScroller extends AnimatingControlsSurface {
+
+    private static String appletStrs[] = { " ", "J2Ddemo",
+        "BezierScroller - Animated Bezier Curve shape with images",
+        "For README.txt file scrolling run in application mode", " " };
+    private static final int NUMPTS = 6;
+    private static Color greenBlend = new Color(0, 255, 0, 100);
+    private static Color blueBlend = new Color(0, 0, 255, 100);
+    private static Font font = new Font(Font.SERIF, Font.PLAIN, 12);
+    private static BasicStroke bs = new BasicStroke(3.0f);
+    private static Image hotj_img;
+    private static BufferedImage img;
+    private static final int UP = 0;
+    private static final int DOWN = 1;
+    private float animpts[] = new float[NUMPTS * 2];
+    private float deltas[] = new float[NUMPTS * 2];
+    private BufferedReader reader;
+    private int nStrs;
+    private int strH;
+    private int yy, ix, iy, imgX;
+    private List<String> vector, appletVector;
+    private float alpha = 0.2f;
+    private int alphaDirection;
+    protected boolean doImage, doShape, doText;
+    protected boolean buttonToggle;
+
+    /*
+     * Using this to scale down globe.png since we want a smaller version,
+     * I know it is 100 x 160 and has a transparent pixel.
+     */
+    private Image scaled(Image src) {
+        int sw = src.getWidth(null);
+        int sh = src.getHeight(null);
+        int dw = sw/5;
+        int dh = sh/5;
+        BufferedImage bi =
+            new BufferedImage(dw, dh, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g2d = bi.createGraphics();
+        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                             RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+        g2d.drawImage(src, 0, 0, dw, dh, 0, 0, sw, sh, null);
+        g2d.dispose();
+        return bi;
+    }
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public BezierScroller() {
+        setBackground(WHITE);
+        doShape = doText = true;
+        hotj_img = scaled(getImage("globe.png"));
+        Image image = getImage("jumptojavastrip.png");
+        int iw = image.getWidth(this);
+        int ih = image.getHeight(this);
+        img = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
+        img.createGraphics().drawImage(image, 0, 0, this);
+        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) (random() * 4.0 + 2.0);
+        } else if (newpt >= limit) {
+            newpt = 2.0f * limit - newpt;
+            deltas[index] = -(float) (random() * 4.0 + 2.0);
+        }
+        pts[index] = newpt;
+    }
+
+    public void getFile() {
+        try {
+            String fName = "README.txt";
+            if ((reader = new BufferedReader(new FileReader(fName))) != null) {
+                getLine();
+            }
+        } catch (Exception e) {
+            reader = null;
+        }
+        if (reader == null) {
+            appletVector = new ArrayList<String>(100);
+            for (int i = 0; i < 100; i++) {
+                appletVector.add(appletStrs[i % appletStrs.length]);
+            }
+            getLine();
+        }
+        buttonToggle = true;
+    }
+
+    public String getLine() {
+        String str = null;
+        if (reader != null) {
+            try {
+                if ((str = reader.readLine()) != null) {
+                    if (str.length() == 0) {
+                        str = " ";
+                    }
+                    vector.add(str);
+                }
+            } catch (Exception e) {
+                Logger.getLogger(BezierScroller.class.getName()).log(
+                        Level.SEVERE,
+                        null, e);
+                reader = null;
+            }
+        } else {
+            if (!appletVector.isEmpty()) {
+                vector.add(str = appletVector.remove(0));
+            }
+        }
+        return str;
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        for (int i = 0; i < animpts.length; i += 2) {
+            animpts[i + 0] = (float) (random() * w);
+            animpts[i + 1] = (float) (random() * h);
+            deltas[i + 0] = (float) (random() * 6.0 + 4.0);
+            deltas[i + 1] = (float) (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];
+            }
+        }
+        FontMetrics fm = getFontMetrics(font);
+        strH = fm.getAscent() + fm.getDescent();
+        nStrs = h / strH + 2;
+        vector = new ArrayList<String>(nStrs);
+        ix = (int) (random() * (w - 80));
+        iy = (int) (random() * (h - 80));
+    }
+
+    @Override
+    public void step(int w, int h) {
+        if (doText && vector.isEmpty()) {
+            getFile();
+        }
+        if (doText) {
+            String s = getLine();
+            if (s == null || vector.size() == nStrs && !vector.isEmpty()) {
+                vector.remove(0);
+            }
+            yy = (s == null) ? 0 : h - vector.size() * strH;
+        }
+
+        for (int i = 0; i < animpts.length && doShape; i += 2) {
+            animate(animpts, deltas, i + 0, w);
+            animate(animpts, deltas, i + 1, h);
+        }
+        if (doImage && alphaDirection == UP) {
+            if ((alpha += 0.025) > .99) {
+                alphaDirection = DOWN;
+                alpha = 1.0f;
+            }
+        } else if (doImage && alphaDirection == DOWN) {
+            if ((alpha -= .02) < 0.01) {
+                alphaDirection = UP;
+                alpha = 0;
+                ix = (int) (random() * (w - 80));
+                iy = (int) (random() * (h - 80));
+            }
+        }
+        if (doImage) {
+            if ((imgX += 80) == 800) {
+                imgX = 0;
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        if (doText) {
+            g2.setColor(LIGHT_GRAY);
+            g2.setFont(font);
+            float y = yy;
+            //for (int i = 0; i < vector.size(); i++) {
+            for (String string : vector) {
+                g2.drawString(string, 1, y += strH);
+            }
+        }
+
+        if (doShape) {
+            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();
+
+            g2.setColor(blueBlend);
+            g2.setStroke(bs);
+            g2.draw(gp);
+            g2.setColor(greenBlend);
+            g2.fill(gp);
+
+            PathIterator pi = gp.getPathIterator(null);
+            float pts[] = new float[6];
+            while (!pi.isDone()) {
+                if (pi.currentSegment(pts) == PathIterator.SEG_CUBICTO) {
+                    g2.drawImage(hotj_img, (int) pts[0], (int) pts[1], this);
+                }
+                pi.next();
+            }
+        }
+
+        if (doImage) {
+            AlphaComposite ac = AlphaComposite.getInstance(
+                    AlphaComposite.SRC_OVER, alpha);
+            g2.setComposite(ac);
+            g2.drawImage(img.getSubimage(imgX, 0, 80, 80), ix, iy, this);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new BezierScroller());
+    }
+
+
+    static final class DemoControls extends CustomControls implements
+            ActionListener {
+
+        BezierScroller demo;
+        JToolBar toolbar;
+        JComboBox combo;
+
+        public DemoControls(BezierScroller demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("Image", false);
+            addTool("Shape", true);
+            addTool("Text", 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("Image")) {
+                demo.doImage = b.isSelected();
+            } else if (b.getText().equals("Shape")) {
+                demo.doShape = b.isSelected();
+            } else {
+                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();
+            int i = 0;
+            while (thread == me) {
+                try {
+                    Thread.sleep(250);
+                } catch (InterruptedException e) {
+                    return;
+                }
+                if (demo.buttonToggle) {
+                    ((AbstractButton) toolbar.getComponentAtIndex(i++ % 2)).
+                            doClick();
+                    demo.buttonToggle = false;
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End BezierScroller
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Mix/Stars3D.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,328 @@
+/*
+ *
+ * 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.Mix;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.BLUE;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.RED;
+import static java.awt.Color.WHITE;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java2d.ControlsSurface;
+import java2d.CustomControls;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+
+/**
+ * Generate a 3D text shape with GeneralPath, render a number of small
+ * multi-colored rectangles and then render the 3D text shape.
+ */
+@SuppressWarnings("serial")
+public class Stars3D extends ControlsSurface {
+
+    private static Color colors[] = { RED, GREEN, WHITE };
+    private static AffineTransform at = AffineTransform.getTranslateInstance(-5,
+            -5);
+    private Shape shape, tshape;
+    private Shape ribbon;
+    protected int fontSize = 72;
+    protected String text = "OpenJDK";
+    protected int numStars = 300;
+
+    public Stars3D() {
+        setBackground(BLACK);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        Rectangle2D rect = new Rectangle2D.Double();
+        for (int i = 0; i < numStars; i++) {
+            g2.setColor(colors[i % 3]);
+            g2.setComposite(AlphaComposite.getInstance(
+                    AlphaComposite.SRC_OVER, (float) Math.random()));
+            rect.setRect(w * Math.random(), h * Math.random(), 2, 2);
+            g2.fill(rect);
+        }
+
+        FontRenderContext frc = g2.getFontRenderContext();
+        Font font = new Font(Font.SERIF, Font.BOLD|Font.ITALIC, fontSize);
+        shape = font.createGlyphVector(frc, text).getOutline();
+        tshape = at.createTransformedShape(shape);
+        PathIterator pi = shape.getPathIterator(null);
+
+        float seg[] = new float[6];
+        float tseg[] = new float[6];
+
+        GeneralPath working = new GeneralPath(Path2D.WIND_NON_ZERO);
+        float x = 0, y = 0; // Current point on the path
+        float tx = 0, ty = 0; // Transformed path point
+        float cx = 0, cy = 0; // Last moveTo point, for SEG_CLOSE
+        float tcx = 0, tcy = 0; // Transformed last moveTo point
+
+        //
+        // Iterate through the Shape and build the ribbon
+        // by adding general path objects.
+        //
+        while (!pi.isDone()) {
+            int segType = pi.currentSegment(seg);
+            switch (segType) {
+                case PathIterator.SEG_MOVETO:
+                    at.transform(seg, 0, tseg, 0, 1);
+                    x = seg[0];
+                    y = seg[1];
+                    tx = tseg[0];
+                    ty = tseg[1];
+                    cx = x;
+                    cy = y;
+                    tcx = tx;
+                    tcy = ty;
+                    break;
+                case PathIterator.SEG_LINETO:
+                    at.transform(seg, 0, tseg, 0, 1);
+                    if (Line2D.relativeCCW(x, y, tx, ty, seg[0], seg[1]) < 0) {
+                        working.moveTo(x, y);
+                        working.lineTo(seg[0], seg[1]);
+                        working.lineTo(tseg[0], tseg[1]);
+                        working.lineTo(tx, ty);
+                        working.lineTo(x, y);
+                    } else {
+                        working.moveTo(x, y);
+                        working.lineTo(tx, ty);
+                        working.lineTo(tseg[0], tseg[1]);
+                        working.lineTo(seg[0], seg[1]);
+                        working.lineTo(x, y);
+                    }
+
+                    x = seg[0];
+                    y = seg[1];
+                    tx = tseg[0];
+                    ty = tseg[1];
+                    break;
+
+                case PathIterator.SEG_QUADTO:
+                    at.transform(seg, 0, tseg, 0, 2);
+                    if (Line2D.relativeCCW(x, y, tx, ty, seg[2], seg[3]) < 0) {
+                        working.moveTo(x, y);
+                        working.quadTo(seg[0], seg[1],
+                                seg[2], seg[3]);
+                        working.lineTo(tseg[2], tseg[3]);
+                        working.quadTo(tseg[0], tseg[1],
+                                tx, ty);
+                        working.lineTo(x, y);
+                    } else {
+                        working.moveTo(x, y);
+                        working.lineTo(tx, ty);
+                        working.quadTo(tseg[0], tseg[1],
+                                tseg[2], tseg[3]);
+                        working.lineTo(seg[2], seg[3]);
+                        working.quadTo(seg[0], seg[1],
+                                x, y);
+                    }
+
+                    x = seg[2];
+                    y = seg[3];
+                    tx = tseg[2];
+                    ty = tseg[3];
+                    break;
+
+                case PathIterator.SEG_CUBICTO:
+                    at.transform(seg, 0, tseg, 0, 3);
+                    if (Line2D.relativeCCW(x, y, tx, ty, seg[4], seg[5]) < 0) {
+                        working.moveTo(x, y);
+                        working.curveTo(seg[0], seg[1],
+                                seg[2], seg[3],
+                                seg[4], seg[5]);
+                        working.lineTo(tseg[4], tseg[5]);
+                        working.curveTo(tseg[2], tseg[3],
+                                tseg[0], tseg[1],
+                                tx, ty);
+                        working.lineTo(x, y);
+                    } else {
+                        working.moveTo(x, y);
+                        working.lineTo(tx, ty);
+                        working.curveTo(tseg[0], tseg[1],
+                                tseg[2], tseg[3],
+                                tseg[4], tseg[5]);
+                        working.lineTo(seg[4], seg[5]);
+                        working.curveTo(seg[2], seg[3],
+                                seg[0], seg[1],
+                                x, y);
+                    }
+
+                    x = seg[4];
+                    y = seg[5];
+                    tx = tseg[4];
+                    ty = tseg[5];
+                    break;
+
+                case PathIterator.SEG_CLOSE:
+                    if (Line2D.relativeCCW(x, y, tx, ty, cx, cy) < 0) {
+                        working.moveTo(x, y);
+                        working.lineTo(cx, cy);
+                        working.lineTo(tcx, tcy);
+                        working.lineTo(tx, ty);
+                        working.lineTo(x, y);
+                    } else {
+                        working.moveTo(x, y);
+                        working.lineTo(tx, ty);
+                        working.lineTo(tcx, tcy);
+                        working.lineTo(cx, cy);
+                        working.lineTo(x, y);
+                    }
+                    x = cx;
+                    y = cy;
+                    tx = tcx;
+                    ty = tcy;
+            }
+            pi.next();
+        } // while
+        ribbon = working;
+
+        if (composite != null) {
+            g2.setComposite(composite);
+        } else {
+            g2.setComposite(AlphaComposite.SrcOver);
+        }
+        Rectangle r = shape.getBounds();
+        g2.translate(w * .5 - r.width * .5, h * .5 + r.height * .5);
+
+        g2.setColor(BLUE);
+        g2.fill(tshape);
+        g2.setColor(new Color(255, 255, 255, 200));
+        g2.fill(ribbon);
+
+        g2.setColor(WHITE);
+        g2.fill(shape);
+
+        g2.setColor(BLUE);
+        g2.draw(shape);
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new Stars3D());
+    }
+
+
+    static class DemoControls extends CustomControls implements ActionListener {
+
+        Stars3D demo;
+        JTextField tf1, tf2;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(Stars3D demo) {
+            super(demo.name);
+            this.demo = demo;
+            JLabel l = new JLabel("  Text:");
+            l.setForeground(BLACK);
+            add(l);
+            add(tf1 = new JTextField(demo.text));
+            tf1.setPreferredSize(new Dimension(60, 20));
+            tf1.addActionListener(this);
+            l = new JLabel("  Size:");
+            l.setForeground(BLACK);
+            add(l);
+            add(tf2 = new JTextField(String.valueOf(demo.fontSize)));
+            tf2.setPreferredSize(new Dimension(30, 20));
+            tf2.addActionListener(this);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            try {
+                if (e.getSource().equals(tf1)) {
+                    demo.text = tf1.getText().trim();
+                } else if (e.getSource().equals(tf2)) {
+                    demo.fontSize = Integer.parseInt(tf2.getText().trim());
+                    if (demo.fontSize < 10) {
+                        demo.fontSize = 10;
+                    }
+                }
+                demo.repaint();
+            } catch (Exception ignored) {
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 37);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            try {
+                Thread.sleep(999);
+            } catch (Exception e) {
+                return;
+            }
+            int length = getSize().width / 4;
+            int size[] = { length, length };
+            String str[] = { "OpenJDK", "J2D" };
+            while (thread == me) {
+                for (int i = 0; i < str.length; i++) {
+                    demo.fontSize = size[i];
+                    tf2.setText(String.valueOf(demo.fontSize));
+                    tf1.setText(demo.text = str[i]);
+                    demo.repaint();
+                    try {
+                        Thread.sleep(5555);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End Stars3D
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/GradAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,318 @@
+/*
+ *
+ * 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.Paint;
+
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.LinearGradientPaint;
+import java.awt.MultipleGradientPaint.CycleMethod;
+import java.awt.Paint;
+import java.awt.RadialGradientPaint;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.Point2D;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.JComboBox;
+
+
+/**
+ * GradientPaint animation.
+ */
+@SuppressWarnings("serial")
+public class GradAnim extends AnimatingControlsSurface {
+
+    private static final int BASIC_GRADIENT = 0;
+    private static final int LINEAR_GRADIENT = 1;
+    private static final int RADIAL_GRADIENT = 2;
+    private static final int FOCUS_GRADIENT = 3;
+    private static final int MAX_HUE = 256 * 6;
+    private animval x1, y1, x2, y2;
+    private int hue = (int) (Math.random() * MAX_HUE);
+    private int gradientType;
+
+    public GradAnim() {
+        setBackground(Color.white);
+        setControls(new Component[] { new DemoControls(this) });
+        x1 = new animval(0, 300, 2, 10);
+        y1 = new animval(0, 300, 2, 10);
+        x2 = new animval(0, 300, 2, 10);
+        y2 = new animval(0, 300, 2, 10);
+        gradientType = BASIC_GRADIENT;
+    }
+
+    @Override
+    public void reset(int w, int h) {
+        x1.newlimits(0, w);
+        y1.newlimits(0, h);
+        x2.newlimits(0, w);
+        y2.newlimits(0, h);
+    }
+
+    @Override
+    public void step(int w, int h) {
+        x1.anim();
+        y1.anim();
+        x2.anim();
+        y2.anim();
+        hue = (hue + (int) (Math.random() * 10)) % MAX_HUE;
+    }
+
+    public static Color getColor(int hue) {
+        int leg = (hue / 256) % 6;
+        int step = (hue % 256) * 2;
+        int falling = (step < 256) ? 255 : 511 - step;
+        int rising = (step < 256) ? step : 255;
+        int r, g, b;
+        r = g = b = 0;
+        switch (leg) {
+            case 0:
+                r = 255;
+                break;
+            case 1:
+                r = falling;
+                g = rising;
+                break;
+            case 2:
+                g = 255;
+                break;
+            case 3:
+                g = falling;
+                b = rising;
+                break;
+            case 4:
+                b = 255;
+                break;
+            case 5:
+                b = falling;
+                r = rising;
+                break;
+        }
+        return new Color(r, g, b);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        float fx1 = x1.getFlt();
+        float fy1 = y1.getFlt();
+        float fx2 = x2.getFlt();
+        float fy2 = y2.getFlt();
+
+        if ((fx1 == fx2) && (fy1 == fy2)) {
+            // just to prevent the points from being coincident
+            fx2++;
+            fy2++;
+        }
+
+        Color c1 = getColor(hue);
+        Color c2 = getColor(hue + 256 * 3);
+        Paint gp;
+
+        switch (gradientType) {
+            case BASIC_GRADIENT:
+            default:
+                gp = new GradientPaint(fx1, fy1, c1,
+                        fx2, fy2, c2,
+                        true);
+                break;
+            case LINEAR_GRADIENT: {
+                float[] fractions = new float[] { 0.0f, 0.2f, 1.0f };
+                Color c3 = getColor(hue + 256 * 2);
+                Color[] colors = new Color[] { c1, c2, c3 };
+                gp = new LinearGradientPaint(fx1, fy1,
+                        fx2, fy2,
+                        fractions, colors,
+                        CycleMethod.REFLECT);
+            }
+            break;
+
+            case RADIAL_GRADIENT: {
+                float[] fractions = { 0.0f, 0.2f, 0.8f, 1.0f };
+                Color c3 = getColor(hue + 256 * 2);
+                Color c4 = getColor(hue + 256 * 4);
+                Color[] colors = new Color[] { c1, c2, c3, c4 };
+                float radius = (float) Point2D.distance(fx1, fy1, fx2, fy2);
+                gp = new RadialGradientPaint(fx1, fy1, radius,
+                        fractions, colors,
+                        CycleMethod.REFLECT);
+            }
+            break;
+
+            case FOCUS_GRADIENT: {
+                float[] fractions = { 0.0f, 0.2f, 0.8f, 1.0f };
+                Color c3 = getColor(hue + 256 * 4);
+                Color c4 = getColor(hue + 256 * 2);
+                Color[] colors = new Color[] { c1, c2, c3, c4 };
+                float radius = (float) Point2D.distance(fx1, fy1, fx2, fy2);
+                float max = Math.max(w, h);
+                // This function will map the smallest radius to
+                // max/10 when the points are next to each other,
+                // max when the points are max distance apart,
+                // and >max when they are further apart (in which
+                // case the focus clipping code in RGP will clip
+                // the focus to be inside the radius).
+                radius = max * (((radius / max) * 0.9f) + 0.1f);
+                gp = new RadialGradientPaint(fx2, fy2, radius,
+                        fx1, fy1,
+                        fractions, colors,
+                        CycleMethod.REPEAT);
+            }
+            break;
+        }
+        g2.setPaint(gp);
+        g2.fillRect(0, 0, w, h);
+        g2.setColor(Color.yellow);
+        g2.drawLine(x1.getInt(), y1.getInt(), x2.getInt(), y2.getInt());
+    }
+
+
+    public final class animval {
+
+        float curval;
+        float lowval;
+        float highval;
+        float currate;
+        float lowrate;
+        float highrate;
+
+        public animval(int lowval, int highval,
+                int lowrate, int highrate) {
+            this.lowval = lowval;
+            this.highval = highval;
+            this.lowrate = lowrate;
+            this.highrate = highrate;
+            this.curval = randval(lowval, highval);
+            this.currate = randval(lowrate, highrate);
+        }
+
+        public float randval(float low, float high) {
+            return (float) (low + Math.random() * (high - low));
+        }
+
+        public float getFlt() {
+            return curval;
+        }
+
+        public int getInt() {
+            return (int) curval;
+        }
+
+        public void anim() {
+            curval += currate;
+            clip();
+        }
+
+        public void clip() {
+            if (curval > highval) {
+                curval = highval - (curval - highval);
+                if (curval < lowval) {
+                    curval = highval;
+                }
+                currate = -randval(lowrate, highrate);
+            } else if (curval < lowval) {
+                curval = lowval + (lowval - curval);
+                if (curval > highval) {
+                    curval = lowval;
+                }
+                currate = randval(lowrate, highrate);
+            }
+        }
+
+        public void newlimits(int lowval, int highval) {
+            this.lowval = lowval;
+            this.highval = highval;
+            clip();
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new GradAnim());
+    }
+
+
+    class DemoControls extends CustomControls implements ActionListener {
+
+        GradAnim demo;
+        JComboBox combo;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(GradAnim demo) {
+            super(demo.name);
+            this.demo = demo;
+            combo = new JComboBox();
+            combo.addActionListener(this);
+            combo.addItem("2-color GradientPaint");
+            combo.addItem("3-color LinearGradientPaint");
+            combo.addItem("4-color RadialGradientPaint");
+            combo.addItem("4-color RadialGradientPaint with focus");
+            combo.setSelectedIndex(0);
+            add(combo);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            int index = combo.getSelectedIndex();
+            if (index >= 0) {
+                demo.gradientType = index;
+            }
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 41);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 0; i < combo.getItemCount(); i++) {
+                    combo.setSelectedIndex(i);
+                    try {
+                        Thread.sleep(4444);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }
+            thread = null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/Gradient.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,215 @@
+/*
+ *
+ * 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.Paint;
+
+
+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.lightGray;
+import static java.awt.Color.magenta;
+import static java.awt.Color.orange;
+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.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.font.TextLayout;
+import java2d.ControlsSurface;
+import java2d.CustomControls;
+import javax.swing.Icon;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+
+
+@SuppressWarnings("serial")
+public class Gradient extends ControlsSurface {
+
+    protected Color innerC, outerC;
+
+    public Gradient() {
+        setBackground(white);
+        innerC = green;
+        outerC = blue;
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        int w2 = w / 2;
+        int h2 = h / 2;
+        g2.setPaint(new GradientPaint(0, 0, outerC, w * .35f, h * .35f, innerC));
+        g2.fillRect(0, 0, w2, h2);
+        g2.setPaint(new GradientPaint(w, 0, outerC, w * .65f, h * .35f, innerC));
+        g2.fillRect(w2, 0, w2, h2);
+        g2.setPaint(new GradientPaint(0, h, outerC, w * .35f, h * .65f, innerC));
+        g2.fillRect(0, h2, w2, h2);
+        g2.setPaint(new GradientPaint(w, h, outerC, w * .65f, h * .65f, innerC));
+        g2.fillRect(w2, h2, w2, h2);
+
+        g2.setColor(black);
+        TextLayout tl = new TextLayout(
+                "GradientPaint", g2.getFont(), g2.getFontRenderContext());
+        tl.draw(g2, (int) (w / 2 - tl.getBounds().getWidth() / 2),
+                (int) (h / 2 + tl.getBounds().getHeight() / 2));
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Gradient());
+    }
+
+
+    static class DemoControls extends CustomControls implements ActionListener {
+
+        Gradient demo;
+        Color colors[] = { red, orange, yellow, green, blue, lightGray, cyan,
+            magenta };
+        String colorName[] = { "Red", "Orange", "Yellow", "Green",
+            "Blue", "lightGray", "Cyan", "Magenta" };
+        JMenuItem innerMI[] = new JMenuItem[colors.length];
+        JMenuItem outerMI[] = new JMenuItem[colors.length];
+        ColoredSquare squares[] = new ColoredSquare[colors.length];
+        JMenu imenu, omenu;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(Gradient demo) {
+            super(demo.name);
+            this.demo = demo;
+            JMenuBar inMenuBar = new JMenuBar();
+            add(inMenuBar);
+            JMenuBar outMenuBar = new JMenuBar();
+            add(outMenuBar);
+            Font font = new Font(Font.SERIF, Font.PLAIN, 10);
+
+            imenu = inMenuBar.add(new JMenu("Inner Color"));
+            imenu.setFont(font);
+            imenu.setIcon(new ColoredSquare(demo.innerC));
+            omenu = outMenuBar.add(new JMenu("Outer Color"));
+            omenu.setFont(font);
+            omenu.setIcon(new ColoredSquare(demo.outerC));
+            for (int i = 0; i < colors.length; i++) {
+                squares[i] = new ColoredSquare(colors[i]);
+                innerMI[i] = imenu.add(new JMenuItem(colorName[i]));
+                innerMI[i].setFont(font);
+                innerMI[i].setIcon(squares[i]);
+                innerMI[i].addActionListener(this);
+                outerMI[i] = omenu.add(new JMenuItem(colorName[i]));
+                outerMI[i].setFont(font);
+                outerMI[i].setIcon(squares[i]);
+                outerMI[i].addActionListener(this);
+            }
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            for (int i = 0; i < colors.length; i++) {
+                if (e.getSource().equals(innerMI[i])) {
+                    demo.innerC = colors[i];
+                    imenu.setIcon(squares[i]);
+                    break;
+                } else if (e.getSource().equals(outerMI[i])) {
+                    demo.outerC = colors[i];
+                    omenu.setIcon(squares[i]);
+                    break;
+                }
+            }
+            demo.repaint();
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 37);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            // goto double buffering
+            if (demo.getImageType() <= 1) {
+                demo.setImageType(2);
+            }
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 0; i < innerMI.length; i++) {
+                    if (i != 4) {
+                        try {
+                            Thread.sleep(4444);
+                        } catch (InterruptedException e) {
+                            return;
+                        }
+                        innerMI[i].doClick();
+                    }
+                }
+            }
+            thread = null;
+        }
+
+
+        class ColoredSquare implements Icon {
+
+            Color color;
+
+            public ColoredSquare(Color c) {
+                this.color = c;
+            }
+
+            @Override
+            public void paintIcon(Component c, Graphics g, int x, int y) {
+                Color oldColor = g.getColor();
+                g.setColor(color);
+                g.fill3DRect(x, y, getIconWidth(), getIconHeight(), true);
+                g.setColor(oldColor);
+            }
+
+            @Override
+            public int getIconWidth() {
+                return 12;
+            }
+
+            @Override
+            public int getIconHeight() {
+                return 12;
+            }
+        } // End ColoredSquare class
+    } // End DemoControls
+} // End Gradient class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/Texture.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,172 @@
+/*
+ *
+ * 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.Paint;
+
+
+import static java.awt.Color.BLACK;
+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.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.TexturePaint;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.image.BufferedImage;
+import java2d.Surface;
+
+
+/**
+ * TexturePaint of gradient, buffered image and shapes.
+ */
+@SuppressWarnings("serial")
+public class Texture extends Surface {
+
+    private static TexturePaint bluedots, greendots, triangles;
+    private static TexturePaint blacklines, gradient;
+
+    static {
+        BufferedImage bi = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
+        Graphics2D gi = bi.createGraphics();
+        gi.setBackground(WHITE);
+        gi.clearRect(0, 0, 10, 10);
+        GeneralPath p1 = new GeneralPath();
+        p1.moveTo(0, 0);
+        p1.lineTo(5, 10);
+        p1.lineTo(10, 0);
+        p1.closePath();
+        gi.setColor(LIGHT_GRAY);
+        gi.fill(p1);
+        triangles = new TexturePaint(bi, new Rectangle(0, 0, 10, 10));
+
+        bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
+        gi = bi.createGraphics();
+        gi.setColor(BLACK);
+        gi.fillRect(0, 0, 5, 5);
+        gi.setColor(GRAY);
+        gi.fillRect(1, 1, 4, 4);
+        blacklines = new TexturePaint(bi, new Rectangle(0, 0, 5, 5));
+
+        int w = 30;
+        int h = 30;
+        bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        gi = bi.createGraphics();
+        Color oc = WHITE;
+        Color ic = LIGHT_GRAY;
+        gi.setPaint(new GradientPaint(0, 0, oc, w * .35f, h * .35f, ic));
+        gi.fillRect(0, 0, w / 2, h / 2);
+        gi.setPaint(new GradientPaint(w, 0, oc, w * .65f, h * .35f, ic));
+        gi.fillRect(w / 2, 0, w / 2, h / 2);
+        gi.setPaint(new GradientPaint(0, h, oc, w * .35f, h * .65f, ic));
+        gi.fillRect(0, h / 2, w / 2, h / 2);
+        gi.setPaint(new GradientPaint(w, h, oc, w * .65f, h * .65f, ic));
+        gi.fillRect(w / 2, h / 2, w / 2, h / 2);
+        gradient = new TexturePaint(bi, new Rectangle(0, 0, w, h));
+
+        bi = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB);
+        bi.setRGB(0, 0, 0xffffffff);
+        bi.setRGB(1, 0, 0xffffffff);
+        bi.setRGB(0, 1, 0xffffffff);
+        bi.setRGB(1, 1, 0xff0000ff);
+        bluedots = new TexturePaint(bi, new Rectangle(0, 0, 2, 2));
+
+        bi = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB);
+        bi.setRGB(0, 0, 0xffffffff);
+        bi.setRGB(1, 0, 0xffffffff);
+        bi.setRGB(0, 1, 0xffffffff);
+        bi.setRGB(1, 1, 0xff00ff00);
+        greendots = new TexturePaint(bi, new Rectangle(0, 0, 2, 2));
+    }
+
+    public Texture() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        Rectangle r = new Rectangle(10, 10, w - 20, h / 2 - 20);
+        g2.setPaint(gradient);
+        g2.fill(r);
+        g2.setPaint(GREEN);
+        g2.setStroke(new BasicStroke(20));
+        g2.draw(r);
+        g2.setPaint(blacklines);
+        g2.setStroke(new BasicStroke(15));
+        g2.draw(r);
+
+        Font f = new Font(Font.SERIF, Font.BOLD, w / 5);
+        TextLayout tl = new TextLayout("Texture", f, g2.getFontRenderContext());
+        int sw = (int) tl.getBounds().getWidth();
+        int sh = (int) tl.getBounds().getHeight();
+        Shape sha = tl.getOutline(AffineTransform.getTranslateInstance(w / 2 - sw
+                / 2, h * .25 + sh / 2));
+        g2.setColor(BLACK);
+        g2.setStroke(new BasicStroke(3));
+        g2.draw(sha);
+        g2.setPaint(greendots);
+        g2.fill(sha);
+
+        r.setLocation(10, h / 2 + 10);
+        g2.setPaint(triangles);
+        g2.fill(r);
+        g2.setPaint(blacklines);
+        g2.setStroke(new BasicStroke(20));
+        g2.draw(r);
+        g2.setPaint(GREEN);
+        g2.setStroke(new BasicStroke(4));
+        g2.draw(r);
+
+        f = new Font(Font.SERIF, Font.BOLD, w / 4);
+        tl = new TextLayout("Paint", f, g2.getFontRenderContext());
+        sw = (int) tl.getBounds().getWidth();
+        sh = (int) tl.getBounds().getHeight();
+        sha = tl.getOutline(AffineTransform.getTranslateInstance(w / 2 - sw / 2, h
+                * .75 + sh / 2));
+        g2.setColor(BLACK);
+        g2.setStroke(new BasicStroke(5));
+        g2.draw(sha);
+        g2.setPaint(bluedots);
+        g2.fill(sha);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Texture());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paint/TextureAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,450 @@
+/*
+ *
+ * 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.Paint;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.TexturePaint;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.AbstractButton;
+import javax.swing.Icon;
+import javax.swing.JComboBox;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.plaf.metal.MetalBorders.ButtonBorder;
+
+
+/**
+ * TexturePaint animation with controls for transformations.
+ */
+@SuppressWarnings("serial")
+public final class TextureAnim extends AnimatingControlsSurface {
+
+    public static final Color colorblend = new Color(0f, 0f, 1f, .5f);
+    protected static BufferedImage textureImg;
+    protected int bNum;
+    protected int tilesize;
+    private boolean newtexture;
+    private TexturePaint texturePaint;
+    private Rectangle tilerect;
+    private boolean bouncesize = false;
+    private boolean bouncerect = true;
+    private boolean rotate = false;
+    private boolean shearx = false;
+    private boolean sheary = false;
+    private boolean showanchor = true;
+    private AnimVal w, h, x, y, rot, shx, shy;
+    private static Image img[] = new Image[2];
+
+    public TextureAnim() {
+        img[0] = getImage("duke.gif");   // 8 bit gif
+        img[1] = getImage("duke.png");   // 24 bit png
+
+        textureImg = makeImage(32, 0);
+        tilesize = textureImg.getWidth();
+        w = new AnimVal(0, 200, 3, 10, tilesize);
+        h = new AnimVal(0, 200, 3, 10, tilesize);
+        x = new AnimVal(0, 200, 3, 10, 0);
+        y = new AnimVal(0, 200, 3, 10, 0);
+        rot = new AnimVal(-360, 360, 5, 15, 0);
+        shx = new AnimVal(-50, 50, 3, 10, 0);
+        shy = new AnimVal(-50, 50, 3, 10, 0);
+        tilerect = new Rectangle(x.getInt(), y.getInt(),
+                w.getInt(), h.getInt());
+        texturePaint = new TexturePaint(textureImg, tilerect);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    protected BufferedImage makeImage(int size, int num) {
+        newtexture = true;
+        switch (bNum = num) {
+            case 0:
+                return makeRGBImage(size);
+            case 1:
+                return makeGIFImage(size);
+            case 2:
+                return makePNGImage(size);
+        }
+        return null;
+    }
+
+    private BufferedImage makeRGBImage(int size) {
+        BufferedImage bi = new BufferedImage(size, size,
+                BufferedImage.TYPE_INT_RGB);
+        Graphics2D big = bi.createGraphics();
+        big.setColor(WHITE);
+        big.fillRect(0, 0, size, size);
+        for (int j = 0; j < size; j++) {
+            float RED = j / (float) size;
+            for (int i = 0; i < size; i++) {
+                float GREEN = i / (float) size;
+                big.setColor(new Color(1.0f - RED, 1.0f - GREEN, 0.0f, 1.0f));
+                big.drawLine(i, j, i, j);
+            }
+        }
+        return bi;
+    }
+
+    private BufferedImage makeGIFImage(int d) {
+        BufferedImage bi = new BufferedImage(d, d, BufferedImage.TYPE_INT_RGB);
+        Graphics2D big = bi.createGraphics();
+        big.drawImage(img[0], 0, 0, d, d, new Color(204, 204, 255), null);
+        return bi;
+    }
+
+    private BufferedImage makePNGImage(int d) {
+        BufferedImage bi = new BufferedImage(d, d, BufferedImage.TYPE_INT_RGB);
+        Graphics2D big = bi.createGraphics();
+        big.drawImage(img[1], 0, 0, d, d, LIGHT_GRAY, null);
+        return bi;
+    }
+
+    @Override
+    public void reset(int width, int height) {
+        x.newlimits(-width / 4, width / 4 - w.getInt());
+        y.newlimits(-height / 4, height / 4 - h.getInt());
+    }
+
+    @Override
+    public void step(int width, int height) {
+        if (tilesize != textureImg.getWidth()) {
+            tilesize = textureImg.getWidth();
+        }
+        if (bouncesize) {
+            w.anim();
+            h.anim();
+            x.newlimits(-width / 4, width / 4 - w.getInt());
+            y.newlimits(-height / 4, height / 4 - h.getInt());
+        } else {
+            if (w.getInt() != tilesize) {
+                w.set(tilesize);
+                x.newlimits(-width / 4, width / 4 - w.getInt());
+            }
+            if (h.getInt() != tilesize) {
+                h.set(tilesize);
+                y.newlimits(-height / 4, height / 4 - h.getInt());
+            }
+        }
+        if (bouncerect) {
+            x.anim();
+            y.anim();
+        }
+        if (newtexture || x.getInt() != tilerect.x || y.getInt() != tilerect.y || w.
+                getInt() != tilerect.width || h.getInt() != tilerect.height) {
+            newtexture = false;
+            int X = x.getInt();
+            int Y = y.getInt();
+            int W = w.getInt();
+            int H = h.getInt();
+            tilerect = new Rectangle(X, Y, W, H);
+            texturePaint = new TexturePaint(textureImg, tilerect);
+        }
+    }
+
+    @Override
+    public void render(int width, int height, Graphics2D g2) {
+
+        g2.translate(width / 2, height / 2);
+        if (rotate) {
+            rot.anim();
+            g2.rotate(Math.toRadians(rot.getFlt()));
+        } else {
+            rot.set(0);
+        }
+        if (shearx) {
+            shx.anim();
+            g2.shear(shx.getFlt() / 100, 0.0f);
+        } else {
+            shx.set(0);
+        }
+        if (sheary) {
+            shy.anim();
+            g2.shear(0.0f, shy.getFlt() / 100);
+        } else {
+            shy.set(0);
+        }
+        g2.setPaint(texturePaint);
+        g2.fillRect(-1000, -1000, 2000, 2000);
+        if (showanchor) {
+            g2.setColor(BLACK);
+            g2.setColor(colorblend);
+            g2.fill(tilerect);
+        }
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new TextureAnim());
+    }
+
+
+    static final class AnimVal {
+
+        float curval;
+        float lowval;
+        float highval;
+        float currate;
+        float lowrate;
+        float highrate;
+
+        public AnimVal(int lowval, int highval,
+                int lowrate, int highrate) {
+            this.lowval = lowval;
+            this.highval = highval;
+            this.lowrate = lowrate;
+            this.highrate = highrate;
+            this.curval = randval(lowval, highval);
+            this.currate = randval(lowrate, highrate);
+        }
+
+        public AnimVal(int lowval, int highval,
+                int lowrate, int highrate,
+                int pos) {
+            this(lowval, highval, lowrate, highrate);
+            set(pos);
+        }
+
+        public float randval(float low, float high) {
+            return (float) (low + Math.random() * (high - low));
+        }
+
+        public float getFlt() {
+            return curval;
+        }
+
+        public int getInt() {
+            return (int) curval;
+        }
+
+        public void anim() {
+            curval += currate;
+            clip();
+        }
+
+        public void set(float val) {
+            curval = val;
+            clip();
+        }
+
+        public void clip() {
+            if (curval > highval) {
+                curval = highval - (curval - highval);
+                if (curval < lowval) {
+                    curval = highval;
+                }
+                currate = -randval(lowrate, highrate);
+            } else if (curval < lowval) {
+                curval = lowval + (lowval - curval);
+                if (curval > highval) {
+                    curval = lowval;
+                }
+                currate = randval(lowrate, highrate);
+            }
+        }
+
+        public void newlimits(int lowval, int highval) {
+            this.lowval = lowval;
+            this.highval = highval;
+            clip();
+        }
+    }  // End AnimVal class
+
+
+    final class DemoControls extends CustomControls implements ActionListener {
+
+        TextureAnim demo;
+        JToolBar toolbar;
+        JComboBox combo;
+        JMenu menu;
+        JMenuItem menuitems[];
+        int iconSize = 20;
+        ButtonBorder buttonBorder = new ButtonBorder();
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(TextureAnim demo) {
+            super(demo.name);
+            this.demo = demo;
+            menuitems = new JMenuItem[3];
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("BO", "bounce", true);
+            addTool("SA", "show anchor", true);
+            addTool("RS", "resize", false);
+            addTool("RO", "rotate", false);
+            addTool("SX", "shear x", false);
+            addTool("SY", "shear y", false);
+            add(combo = new JComboBox());
+            combo.addActionListener(this);
+            combo.addItem("8");
+            combo.addItem("16");
+            combo.addItem("32");
+            combo.addItem("64");
+            combo.addItem("80");
+            combo.setSelectedIndex(2);
+
+            JMenuBar menuBar = new JMenuBar();
+            menu = menuBar.add(new JMenu());
+            for (int i = 0; i < 3; i++) {
+                BufferedImage bimg = demo.makeImage(iconSize, i);
+                TexturedIcon icon = new TexturedIcon(bimg);
+                menuitems[i] = menu.add(new JMenuItem(icon));
+                menuitems[i].addActionListener(this);
+            }
+            menu.setIcon(menuitems[0].getIcon());
+            add(menuBar);
+            demo.bNum = 0;
+        }
+
+        public void addTool(String str, String toolTip, boolean state) {
+            JToggleButton b =
+                    (JToggleButton) toolbar.add(new JToggleButton(str));
+            b.setBorder(buttonBorder);
+            b.setFocusPainted(false);
+            b.setSelected(state);
+            b.setToolTipText(toolTip);
+            b.addActionListener(this);
+            int width = b.getPreferredSize().width+10;
+            Dimension prefSize = new Dimension(width, 21);
+            b.setPreferredSize(prefSize);
+            b.setMaximumSize(prefSize);
+            b.setMinimumSize(prefSize);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            Object obj = e.getSource();
+            if (obj instanceof JComboBox) {
+                String selItem = (String) combo.getSelectedItem();
+                if (selItem != null) {
+                    int size = Integer.parseInt(selItem);
+                    TextureAnim.textureImg = demo.makeImage(size, demo.bNum);
+                }
+            } else if (obj instanceof JMenuItem) {
+                for (int i = 0; i < menuitems.length; i++) {
+                    if (obj.equals(menuitems[i])) {
+                        TextureAnim.textureImg =
+                                demo.makeImage(demo.tilesize, i);
+                        menu.setIcon(menuitems[i].getIcon());
+                        break;
+                    }
+                }
+            } else {
+                JToggleButton b = (JToggleButton) obj;
+                if (b.getText().equals("BO")) {
+                    demo.bouncerect = b.isSelected();
+                } else if (b.getText().equals("SA")) {
+                    demo.showanchor = b.isSelected();
+                } else if (b.getText().equals("RS")) {
+                    demo.bouncesize = b.isSelected();
+                } else if (b.getText().equals("RO")) {
+                    demo.rotate = b.isSelected();
+                } else if (b.getText().equals("SX")) {
+                    demo.shearx = b.isSelected();
+                } else if (b.getText().equals("SY")) {
+                    demo.sheary = b.isSelected();
+                }
+            }
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 41);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 2; i < toolbar.getComponentCount(); i++) {
+                    try {
+                        Thread.sleep(4444);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                    ((AbstractButton) toolbar.getComponentAtIndex(i)).doClick();
+                }
+            }
+            thread = null;
+        }
+
+
+        class TexturedIcon implements Icon {
+
+            BufferedImage bi;
+
+            public TexturedIcon(BufferedImage bi) {
+                this.bi = bi;
+            }
+
+            @Override
+            public void paintIcon(Component c, Graphics g, int x, int y) {
+                Graphics2D g2 = (Graphics2D) g;
+                Rectangle r = new Rectangle(x, y, iconSize, iconSize);
+                g2.setPaint(new TexturePaint(bi, r));
+                g2.fillRect(x, y, iconSize, iconSize);
+                g2.setColor(GRAY);
+                g2.draw3DRect(x, y, iconSize - 1, iconSize - 1, true);
+            }
+
+            @Override
+            public int getIconWidth() {
+                return iconSize;
+            }
+
+            @Override
+            public int getIconHeight() {
+                return iconSize;
+            }
+        } // End TexturedIcon class
+    } // End DemoControls class
+} // End TextureAnim class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/Append.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,83 @@
+/*
+ *
+ * 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.Paths;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.Graphics2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+import java2d.Surface;
+
+
+/**
+ * Simple append of rectangle to path with & without the connect.
+ */
+@SuppressWarnings("serial")
+public class Append extends Surface {
+
+    public Append() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        GeneralPath p = new GeneralPath(Path2D.WIND_NON_ZERO);
+        p.moveTo(w * 0.25f, h * 0.2f);
+        p.lineTo(w * 0.75f, h * 0.2f);
+        p.closePath();
+        p.append(new Rectangle2D.Double(w * .4, h * .3, w * .2, h * .1), false);
+        g2.setColor(GRAY);
+        g2.fill(p);
+        g2.setColor(BLACK);
+        g2.draw(p);
+        g2.drawString("Append rect to path", (int) (w * .25), (int) (h * .2) - 5);
+
+        p.reset();
+        p.moveTo(w * 0.25f, h * 0.6f);
+        p.lineTo(w * 0.75f, h * 0.6f);
+        p.closePath();
+        p.append(new Rectangle2D.Double(w * .4, h * .7, w * .2, h * .1), true);
+        g2.setColor(GRAY);
+        g2.fill(p);
+        g2.setColor(BLACK);
+        g2.draw(p);
+        g2.drawString("Append, connect", (int) (w * .25), (int) (h * .6) - 5);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Append());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/CurveQuadTo.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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.Paths;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.Graphics2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java2d.Surface;
+
+
+/**
+ * Cubic & Quad curves implemented through GeneralPath.
+ */
+@SuppressWarnings("serial")
+public class CurveQuadTo extends Surface {
+
+    public CurveQuadTo() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        GeneralPath p = new GeneralPath(Path2D.WIND_EVEN_ODD);
+        p.moveTo(w * .2f, h * .25f);
+        p.curveTo(w * .4f, h * .5f, w * .6f, 0.0f, w * .8f, h * .25f);
+        p.moveTo(w * .2f, h * .6f);
+        p.quadTo(w * .5f, h * 1.0f, w * .8f, h * .6f);
+        g2.setColor(LIGHT_GRAY);
+        g2.fill(p);
+        g2.setColor(BLACK);
+        g2.draw(p);
+        g2.drawString("curveTo", (int) (w * .2), (int) (h * .25f) - 5);
+        g2.drawString("quadTo", (int) (w * .2), (int) (h * .6f) - 5);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new CurveQuadTo());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/FillStroke.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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.Paths;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.font.TextLayout;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java2d.Surface;
+
+
+/**
+ * Basic implementation of GeneralPath, filling & drawing a path w/o closing it.
+ */
+@SuppressWarnings("serial")
+public class FillStroke extends Surface {
+
+    public FillStroke() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        GeneralPath p = new GeneralPath(Path2D.WIND_EVEN_ODD);
+        p.moveTo(w * .5f, h * .15f);
+        p.lineTo(w * .8f, h * .75f);
+        p.lineTo(w * .2f, h * .75f);
+        g2.setColor(LIGHT_GRAY);
+        g2.fill(p);
+        g2.setColor(BLACK);
+        g2.setStroke(new BasicStroke(10));
+        g2.draw(p);
+        TextLayout tl = new TextLayout("Fill, Stroke w/o closePath",
+                g2.getFont(), g2.getFontRenderContext());
+        tl.draw(g2, (float) (w / 2 - tl.getBounds().getWidth() / 2), h * .85f);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new FillStroke());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Paths/WindingRule.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,92 @@
+/*
+ *
+ * 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.Paths;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.LIGHT_GRAY;
+import static java.awt.Color.WHITE;
+import java.awt.Graphics2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java2d.Surface;
+
+
+/**
+ * Rectangles filled to illustrate the GenerPath winding rule, determining
+ * the interior of a path.
+ */
+@SuppressWarnings("serial")
+public class WindingRule extends Surface {
+
+    public WindingRule() {
+        setBackground(WHITE);
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        g2.translate(w * .2, h * .2);
+
+        GeneralPath p = new GeneralPath(Path2D.WIND_NON_ZERO);
+        p.moveTo(0.0f, 0.0f);
+        p.lineTo(w * .5f, 0.0f);
+        p.lineTo(w * .5f, h * .2f);
+        p.lineTo(0.0f, h * .2f);
+        p.closePath();
+
+        p.moveTo(w * .05f, h * .05f);
+        p.lineTo(w * .55f, h * .05f);
+        p.lineTo(w * .55f, h * .25f);
+        p.lineTo(w * .05f, h * .25f);
+        p.closePath();
+
+        g2.setColor(LIGHT_GRAY);
+        g2.fill(p);
+        g2.setColor(BLACK);
+        g2.draw(p);
+        g2.drawString("NON_ZERO rule", 0, -5);
+
+        g2.translate(0.0f, h * .45);
+
+        p.setWindingRule(Path2D.WIND_EVEN_ODD);
+        g2.setColor(LIGHT_GRAY);
+        g2.fill(p);
+        g2.setColor(BLACK);
+        g2.draw(p);
+        g2.drawString("EVEN_ODD rule", 0, -5);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new WindingRule());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Transforms/Rotate.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,170 @@
+/*
+ *
+ * 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.Transforms;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.BLUE;
+import static java.awt.Color.GRAY;
+import static java.awt.Color.LIGHT_GRAY;
+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.Graphics2D;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java2d.ControlsSurface;
+import java2d.CustomControls;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+
+/**
+ * Rotate ellipses with controls for increment and emphasis.
+ * Emphasis is defined as which ellipses have a darker color and thicker stroke.
+ */
+@SuppressWarnings("serial")
+public class Rotate extends ControlsSurface {
+
+    protected double increment = 5.0;
+    protected int emphasis = 9;
+
+    public Rotate() {
+        setBackground(WHITE);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        int size = Math.min(w, h);
+        float ew = size / 4;
+        float eh = size - 20;
+        Ellipse2D ellipse = new Ellipse2D.Float(-ew / 2, -eh / 2, ew, eh);
+        for (double angdeg = 0; angdeg < 360; angdeg += increment) {
+            if (angdeg % emphasis == 0) {
+                g2.setColor(GRAY);
+                g2.setStroke(new BasicStroke(2.0f));
+            } else {
+                g2.setColor(LIGHT_GRAY);
+                g2.setStroke(new BasicStroke(0.5f));
+            }
+            AffineTransform at = AffineTransform.getTranslateInstance(w / 2, h
+                    / 2);
+            at.rotate(Math.toRadians(angdeg));
+            g2.draw(at.createTransformedShape(ellipse));
+        }
+        g2.setColor(BLUE);
+        ellipse.setFrame(w / 2 - 10, h / 2 - 10, 20, 20);
+        g2.fill(ellipse);
+        g2.setColor(GRAY);
+        g2.setStroke(new BasicStroke(6));
+        g2.draw(ellipse);
+        g2.setColor(YELLOW);
+        g2.setStroke(new BasicStroke(4));
+        g2.draw(ellipse);
+        g2.setColor(BLACK);
+        g2.drawString("Rotate", 5, 15);
+    }
+
+    public static void main(String s[]) {
+        createDemoFrame(new Rotate());
+    }
+
+
+    static class DemoControls extends CustomControls implements ActionListener {
+
+        Rotate demo;
+        JTextField tf1, tf2;
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(Rotate demo) {
+            super(demo.name);
+            this.demo = demo;
+            JLabel l = new JLabel("Increment:");
+            l.setForeground(BLACK);
+            add(l);
+            add(tf1 = new JTextField("5.0"));
+            tf1.setPreferredSize(new Dimension(30, 24));
+            tf1.addActionListener(this);
+            add(l = new JLabel("  Emphasis:"));
+            l.setForeground(BLACK);
+            add(tf2 = new JTextField("9"));
+            tf2.setPreferredSize(new Dimension(30, 24));
+            tf2.addActionListener(this);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            try {
+                if (e.getSource().equals(tf1)) {
+                    demo.increment = Double.parseDouble(tf1.getText().trim());
+                    if (demo.increment < 1.0) {
+                        demo.increment = 1.0;
+                    }
+                } else {
+                    demo.emphasis = Integer.parseInt(tf2.getText().trim());
+                }
+                demo.repaint();
+            } catch (Exception ex) {
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 39);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 3; i < 13; i += 3) {
+                    try {
+                        Thread.sleep(4444);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                    tf1.setText(String.valueOf(i));
+                    demo.increment = i;
+                    demo.repaint();
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls class
+} // End Rotate class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Transforms/SelectTx.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,316 @@
+/*
+ *
+ * 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.Transforms;
+
+
+import static java.awt.Color.BLACK;
+import static java.awt.Color.ORANGE;
+import static java.awt.Color.WHITE;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.AbstractButton;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+
+
+/**
+ * Scaling or Shearing or Rotating an image & rectangle.
+ */
+@SuppressWarnings("serial")
+public class SelectTx extends AnimatingControlsSurface {
+
+    protected static final int RIGHT = 0;
+    private static final int LEFT = 1;
+    private static final int XMIDDLE = 2;
+    private static final int DOWN = 3;
+    private static final int UP = 4;
+    private static final int YMIDDLE = 5;
+    private static final int XupYup = 6;
+    private static final int XdownYdown = 7;
+    private static final String[] title = { "Scale", "Shear", "Rotate" };
+    protected static final int SCALE = 0;
+    protected static final int SHEAR = 1;
+    protected static final int ROTATE = 2;
+    private Image original;
+    private int iw, ih;
+    protected int transformType = SHEAR;
+    protected double sx, sy;
+    protected double angdeg;
+    protected int direction = RIGHT;
+    protected int transformToggle;
+
+    @SuppressWarnings("LeakingThisInConstructor")
+    public SelectTx() {
+        setBackground(WHITE);
+        original = getImage("painting.png");
+        iw = original.getWidth(this);
+        ih = original.getHeight(this);
+        setControls(new Component[] { new DemoControls(this) });
+    }
+
+    @Override
+    public void reset(int w, int h) {
+
+        iw = w > 3 ? w / 3 : 1;
+        ih = h > 3 ? h / 3 : 1;
+
+        if (transformType == SCALE) {
+            direction = RIGHT;
+            sx = sy = 1.0;
+        } else if (transformType == SHEAR) {
+            direction = RIGHT;
+            sx = sy = 0;
+        } else {
+            angdeg = 0;
+        }
+    }
+
+    @Override
+    public void step(int w, int h) {
+        int rw = iw + 10;
+        int rh = ih + 10;
+
+        if (transformType == SCALE && direction == RIGHT) {
+            sx += .05;
+            if (w * .5 - iw * .5 + rw * sx + 10 > w) {
+                direction = DOWN;
+            }
+        } else if (transformType == SCALE && direction == DOWN) {
+            sy += .05;
+            if (h * .5 - ih * .5 + rh * sy + 20 > h) {
+                direction = LEFT;
+            }
+        } else if (transformType == SCALE && direction == LEFT) {
+            sx -= .05;
+            if (rw * sx - 10 <= -(w * .5 - iw * .5)) {
+                direction = UP;
+            }
+        } else if (transformType == SCALE && direction == UP) {
+            sy -= .05;
+            if (rh * sy - 20 <= -(h * .5 - ih * .5)) {
+                direction = RIGHT;
+                transformToggle = SHEAR;
+            }
+        }
+
+        if (transformType == SHEAR && direction == RIGHT) {
+            sx += .05;
+            if (rw + 2 * rh * sx + 20 > w) {
+                direction = LEFT;
+                sx -= .1;
+            }
+        } else if (transformType == SHEAR && direction == LEFT) {
+            sx -= .05;
+            if (rw - 2 * rh * sx + 20 > w) {
+                direction = XMIDDLE;
+            }
+        } else if (transformType == SHEAR && direction == XMIDDLE) {
+            sx += .05;
+            if (sx > 0) {
+                direction = DOWN;
+                sx = 0;
+            }
+        } else if (transformType == SHEAR && direction == DOWN) {
+            sy -= .05;
+            if (rh - 2 * rw * sy + 20 > h) {
+                direction = UP;
+                sy += .1;
+            }
+        } else if (transformType == SHEAR && direction == UP) {
+            sy += .05;
+            if (rh + 2 * rw * sy + 20 > h) {
+                direction = YMIDDLE;
+            }
+        } else if (transformType == SHEAR && direction == YMIDDLE) {
+            sy -= .05;
+            if (sy < 0) {
+                direction = XupYup;
+                sy = 0;
+            }
+        } else if (transformType == SHEAR && direction == XupYup) {
+            sx += .05;
+            sy += .05;
+            if (rw + 2 * rh * sx + 30 > w || rh + 2 * rw * sy + 30 > h) {
+                direction = XdownYdown;
+            }
+        } else if (transformType == SHEAR && direction == XdownYdown) {
+            sy -= .05;
+            sx -= .05;
+            if (sy < 0) {
+                direction = RIGHT;
+                sx = sy = 0.0;
+                transformToggle = ROTATE;
+            }
+        }
+
+        if (transformType == ROTATE) {
+            angdeg += 5;
+            if (angdeg == 360) {
+                angdeg = 0;
+                transformToggle = SCALE;
+            }
+        }
+    }
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+
+        Font font = g2.getFont();
+        FontRenderContext frc = g2.getFontRenderContext();
+        TextLayout tl = new TextLayout(title[transformType], font, frc);
+        g2.setColor(BLACK);
+        tl.draw(g2, (float) (w / 2 - tl.getBounds().getWidth() / 2),
+                (tl.getAscent() + tl.getDescent()));
+
+        if (transformType == ROTATE) {
+            String s = Double.toString(angdeg);
+            g2.drawString("angdeg=" + s, 2, h - 4);
+        } else {
+            String s = Double.toString(sx);
+            s = (s.length() < 5) ? s : s.substring(0, 5);
+            TextLayout tlsx = new TextLayout("sx=" + s, font, frc);
+            tlsx.draw(g2, 2, h - 4);
+
+            s = Double.toString(sy);
+            s = (s.length() < 5) ? s : s.substring(0, 5);
+            g2.drawString("sy=" + s, (int) (tlsx.getBounds().getWidth() + 4), h
+                    - 4);
+        }
+
+        if (transformType == SCALE) {
+            g2.translate(w / 2 - iw / 2, h / 2 - ih / 2);
+            g2.scale(sx, sy);
+        } else if (transformType == SHEAR) {
+            g2.translate(w / 2 - iw / 2, h / 2 - ih / 2);
+            g2.shear(sx, sy);
+        } else {
+            g2.rotate(Math.toRadians(angdeg), w / 2, h / 2);
+            g2.translate(w / 2 - iw / 2, h / 2 - ih / 2);
+        }
+
+        g2.setColor(ORANGE);
+        g2.fillRect(0, 0, iw + 10, ih + 10);
+        g2.drawImage(original, 5, 5, iw, ih, ORANGE, this);
+
+    }
+
+    public static void main(String argv[]) {
+        createDemoFrame(new SelectTx());
+    }
+
+
+    static final class DemoControls extends CustomControls implements
+            ActionListener {
+
+        SelectTx demo;
+        JToolBar toolbar;
+
+        public DemoControls(SelectTx demo) {
+            super(demo.name);
+            this.demo = demo;
+            add(toolbar = new JToolBar());
+            toolbar.setFloatable(false);
+            addTool("Scale", false);
+            addTool("Shear", true);
+            addTool("Rotate", 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) {
+            for (int i = 0; i < toolbar.getComponentCount(); i++) {
+                JToggleButton b = (JToggleButton) toolbar.getComponentAtIndex(i);
+                b.setSelected(false);
+            }
+            JToggleButton b = (JToggleButton) e.getSource();
+            b.setSelected(true);
+            if (b.getText().equals("Scale")) {
+                demo.transformType = SelectTx.SCALE;
+                demo.direction = SelectTx.RIGHT;
+                demo.sx = demo.sy = 1;
+            } else if (b.getText().equals("Shear")) {
+                demo.transformType = SelectTx.SHEAR;
+                demo.direction = SelectTx.RIGHT;
+                demo.sx = demo.sy = 0;
+            } else if (b.getText().equals("Rotate")) {
+                demo.transformType = SelectTx.ROTATE;
+                demo.angdeg = 0;
+            }
+        }
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(200, 39);
+        }
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            demo.transformToggle = demo.transformType;
+            while (thread == me) {
+                try {
+                    Thread.sleep(222);
+                } catch (InterruptedException e) {
+                    return;
+                }
+                if (demo.transformToggle != demo.transformType) {
+                    ((AbstractButton) toolbar.getComponentAtIndex(
+                            demo.transformToggle)).doClick();
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls class
+} // End SelectTx class
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/J2Ddemo/java2d/demos/Transforms/TransformAnim.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,519 @@
+/*
+ *
+ * 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.Transforms;
+
+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 static java.awt.Font.BOLD;
+import static java.awt.Font.ITALIC;
+import static java.awt.Font.PLAIN;
+import java.awt.BasicStroke;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.TexturePaint;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.List;
+import java2d.AnimatingControlsSurface;
+import java2d.CustomControls;
+import javax.swing.AbstractButton;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JSlider;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.metal.MetalBorders.ButtonBorder;
+
+/**
+ * Animation of shapes, text and images rotating, scaling and translating
+ * around a canvas.
+ */
+@SuppressWarnings("serial")
+public final class TransformAnim extends AnimatingControlsSurface {
+
+    private static final TexturePaint texturePaint;
+    static {
+        BufferedImage bi = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
+        Graphics2D gi = bi.createGraphics();
+        gi.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                            RenderingHints.VALUE_ANTIALIAS_ON);
+        gi.setColor(RED);
+        gi.fillOval(0,0,9,9);
+        texturePaint = new TexturePaint(bi,new Rectangle(0,0,10,10));
+    }
+
+    private static BasicStroke bs = new BasicStroke(6);
+    private static Font fonts[] = {
+                new Font(Font.SERIF,      PLAIN,       48),
+                new Font(Font.SERIF,      BOLD|ITALIC, 24),
+                new Font(Font.MONOSPACED, BOLD,        36),
+                new Font(Font.SANS_SERIF, BOLD|ITALIC, 64),
+                new Font(Font.SANS_SERIF, PLAIN,       52)};
+    private static String strings[] = {
+                "Transformation", "Rotate", "Translate", "Shear", "Scale" };
+    private static String imgs[] = { "duke.png" };
+    private static Paint paints[] = {
+                RED, BLUE, texturePaint, GREEN, MAGENTA, ORANGE, PINK, CYAN,
+                new Color(0, 255, 0, 128), new Color(0, 0, 255, 128),
+                YELLOW, LIGHT_GRAY, WHITE};
+    private List<ObjData> objDatas = new ArrayList<ObjData>(13);
+    private int numShapes, numStrings, numImages;
+    protected boolean doRotate = true;
+    protected boolean doTranslate = true;
+    protected boolean doScale = true;
+    protected boolean doShear;
+
+
+    public TransformAnim() {
+        setBackground(BLACK);
+        setStrings(1);
+        setImages(2);
+        setShapes(10);
+        setControls(new Component[] { new DemoControls(this) });
+        setConstraints(new String[] { BorderLayout.EAST });
+    }
+
+
+    public void setImages(int num) {
+        if (num < numImages) {
+            List<ObjData> v = new ArrayList<ObjData>(objDatas.size());
+            for (ObjData objData : objDatas) {
+                if (objData.object instanceof Image) {
+                    v.add(objData);
+                }
+            }
+            objDatas.removeAll(v.subList(num, v.size()));
+        } else {
+            Dimension d = getSize();
+            for (int i = numImages; i < num; i++) {
+                Object obj = getImage(imgs[i % imgs.length]);
+                ObjData objData = new ObjData(obj, BLACK);
+                objData.reset(d.width, d.height);
+                objDatas.add(objData);
+            }
+        }
+        numImages = num;
+    }
+
+
+    public void setStrings(int num) {
+        if (num < numStrings) {
+            List<ObjData> v = new ArrayList<ObjData>(objDatas.size());
+            for (ObjData objData : objDatas) {
+                if (objData.object instanceof TextData) {
+                    v.add(objData);
+                }
+            }
+            objDatas.removeAll(v.subList(num, v.size()));
+        } else {
+            Dimension d = getSize();
+            for (int i = numStrings; i < num; i++) {
+                int j = i %   fonts.length;
+                int k = i % strings.length;
+                Object obj = new TextData(strings[k], fonts[j]);
+                ObjData objData = new ObjData(obj, paints[i%paints.length]);
+                objData.reset(d.width, d.height);
+                objDatas.add(objData);
+            }
+        }
+        numStrings = num;
+    }
+
+
+    public void setShapes(int num) {
+        if (num < numShapes) {
+            List<ObjData> v = new ArrayList<ObjData>(objDatas.size());
+            for (ObjData objData : objDatas) {
+                if (objData.object instanceof Shape) {
+                    v.add(objData);
+                }
+            }
+            objDatas.removeAll(v.subList(num, v.size()));
+        } else {
+            Dimension d = getSize();
+            for (int i = numShapes; i < num; i++) {
+                Object obj = null;
+                switch (i % 7) {
+                    case 0 : obj = new GeneralPath(); break;
+                    case 1 : obj = new Rectangle2D.Double(); break;
+                    case 2 : obj = new Ellipse2D.Double(); break;
+                    case 3 : obj = new Arc2D.Double(); break;
+                    case 4 : obj = new RoundRectangle2D.Double(); break;
+                    case 5 : obj = new CubicCurve2D.Double(); break;
+                    case 6 : obj = new QuadCurve2D.Double(); break;
+                }
+                ObjData objData = new ObjData(obj, paints[i%paints.length]);
+                objData.reset(d.width, d.height);
+                objDatas.add(objData);
+            }
+        }
+        numShapes = num;
+    }
+
+
+    @Override
+    public void reset(int w, int h) {
+        for (ObjData objData : objDatas) {
+            objData.reset(w, h);
+        }
+    }
+
+
+    @Override
+    public void step(int w, int h) {
+        for (ObjData objData : objDatas) {
+            objData.step(w, h, this);
+        }
+    }
+
+
+    @Override
+    public void render(int w, int h, Graphics2D g2) {
+        for (ObjData objData : objDatas) {
+            g2.setTransform(objData.at);
+            g2.setPaint(objData.paint);
+            if (objData.object instanceof Image) {
+                g2.drawImage((Image) objData.object, 0, 0, this);
+            } else if (objData.object instanceof TextData) {
+                g2.setFont(((TextData) objData.object).font);
+                g2.drawString(((TextData) objData.object).string, 0, 0);
+            } else if (objData.object instanceof  QuadCurve2D
+                    || objData.object instanceof CubicCurve2D)
+            {
+                g2.setStroke(bs);
+                g2.draw((Shape) objData.object);
+            } else if (objData.object instanceof Shape) {
+                g2.fill((Shape) objData.object);
+            }
+        }
+    }
+
+
+    public static void main(String argv[]) {
+        createDemoFrame(new TransformAnim());
+    }
+
+
+    static class TextData extends Object {
+
+        public String string;
+        public Font font;
+
+        public TextData(String str, Font font) {
+            string = str;
+            this.font = font;
+        }
+    }
+
+
+    static class ObjData extends Object {
+        Object object;
+        Paint paint;
+        static final int UP   = 0;
+        static final int DOWN = 1;
+        double x, y;
+        double ix=5, iy=3;
+        int rotate;
+        double scale, shear;
+        int scaleDirection, shearDirection;
+        AffineTransform at = new AffineTransform();
+
+
+        public ObjData(Object object, Paint paint) {
+            this.object = object;
+            this.paint = paint;
+            rotate = (int)(Math.random() * 360);
+            scale = Math.random() * 1.5;
+            scaleDirection = Math.random() > 0.5 ? UP : DOWN;
+            shear = Math.random() * 0.5;
+            shearDirection = Math.random() > 0.5 ? UP : DOWN;
+        }
+
+
+        public void reset(int w, int h) {
+            x = Math.random()*w;
+            y = Math.random()*h;
+            double ww = 20 + Math.random()*((w == 0 ? 400 : w)/4);
+            double hh = 20 + Math.random()*((h == 0 ? 300 : h)/4);
+            if (object instanceof Ellipse2D) {
+                ((Ellipse2D) object).setFrame(0, 0, ww, hh);
+            } else if (object instanceof Rectangle2D) {
+                ((Rectangle2D) object).setRect(0, 0, ww, ww);
+            } else if (object instanceof RoundRectangle2D) {
+                ((RoundRectangle2D) object).setRoundRect(0, 0, hh, hh, 20, 20);
+            } else if (object instanceof Arc2D) {
+                ((Arc2D) object).setArc(0, 0, hh, hh, 45, 270, Arc2D.PIE);
+            } else if (object instanceof QuadCurve2D) {
+                ((QuadCurve2D) object).setCurve(0, 0, w*.2, h*.4, w*.4, 0);
+            } else if (object instanceof CubicCurve2D) {
+                    ((CubicCurve2D) object).setCurve(0,0,30,-60,60,60,90,0);
+            } else if (object instanceof GeneralPath) {
+                GeneralPath p = new GeneralPath();
+                float size = (float) ww;
+                p.moveTo(- size / 2.0f, - size / 8.0f);
+                p.lineTo(+ size / 2.0f, - size / 8.0f);
+                p.lineTo(- size / 4.0f, + size / 2.0f);
+                p.lineTo(+         0.0f, - size / 2.0f);
+                p.lineTo(+ size / 4.0f, + size / 2.0f);
+                p.closePath();
+                object = p;
+            }
+        }
+
+
+        public void step(int w, int h, TransformAnim demo) {
+            at.setToIdentity();
+            if (demo.doRotate) {
+                if ((rotate+=5) == 360) {
+                    rotate = 0;
+                }
+                at.rotate(Math.toRadians(rotate), x, y);
+            }
+            at.translate(x, y);
+            if (demo.doTranslate) {
+                x += ix;
+                y += iy;
+                if (x > w) {
+                    x = w - 1;
+                    ix = Math.random() * -w/32 - 1;
+                }
+                if (x < 0) {
+                    x = 2;
+                    ix = Math.random() * w/32 + 1;
+                }
+                if (y > h ) {
+                    y = h - 2;
+                    iy = Math.random() * -h/32 - 1;
+                }
+                if (y < 0) {
+                    y = 2;
+                    iy = Math.random() * h/32 + 1;
+                }
+            }
+            if (demo.doScale && scaleDirection == UP) {
+                if ((scale += 0.05) > 1.5) {
+                    scaleDirection = DOWN;
+                }
+            } else if (demo.doScale && scaleDirection == DOWN) {
+                if ((scale -= .05) < 0.5) {
+                    scaleDirection = UP;
+                }
+            }
+            if (demo.doScale) {
+                at.scale(scale, scale);
+            }
+            if (demo.doShear && shearDirection == UP) {
+                if ((shear += 0.05) > 0.5) {
+                    shearDirection = DOWN;
+                }
+            } else if (demo.doShear && shearDirection == DOWN) {
+                if ((shear -= .05) < -0.5) {
+                    shearDirection = UP;
+                }
+            }
+            if (demo.doShear) {
+                at.shear(shear, shear);
+            }
+        }
+    } // End ObjData class
+
+
+
+    static final class DemoControls extends CustomControls implements ActionListener, ChangeListener {
+
+        TransformAnim demo;
+        JSlider shapeSlider, stringSlider, imageSlider;
+        Font font = new Font(Font.SERIF, Font.BOLD, 10);
+        JToolBar toolbar;
+        ButtonBorder buttonBorder = new ButtonBorder();
+
+        @SuppressWarnings("LeakingThisInConstructor")
+        public DemoControls(TransformAnim demo) {
+            super(demo.name);
+            this.demo = demo;
+            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+            add(Box.createVerticalStrut(5));
+
+            JToolBar bar = new JToolBar(SwingConstants.VERTICAL);
+            bar.setFloatable(false);
+            shapeSlider = new JSlider(SwingConstants.HORIZONTAL,0,20,demo.numShapes);
+            shapeSlider.addChangeListener(this);
+            TitledBorder tb = new TitledBorder(new EtchedBorder());
+            tb.setTitleFont(font);
+            tb.setTitle(String.valueOf(demo.numShapes) + " Shapes");
+            shapeSlider.setBorder(tb);
+            shapeSlider.setOpaque(true);
+            shapeSlider.setPreferredSize(new Dimension(80,44));
+            bar.add(shapeSlider);
+            bar.addSeparator();
+
+            stringSlider = new JSlider(SwingConstants.HORIZONTAL,0,10,demo.numStrings);
+            stringSlider.addChangeListener(this);
+            tb = new TitledBorder(new EtchedBorder());
+            tb.setTitleFont(font);
+            tb.setTitle(String.valueOf(demo.numStrings) + " Strings");
+            stringSlider.setBorder(tb);
+            stringSlider.setOpaque(true);
+            stringSlider.setPreferredSize(new Dimension(80,44));
+            bar.add(stringSlider);
+            bar.addSeparator();
+
+            imageSlider = new JSlider(SwingConstants.HORIZONTAL,0,10,demo.numImages);
+            imageSlider.addChangeListener(this);
+            tb = new TitledBorder(new EtchedBorder());
+            tb.setTitleFont(font);
+            tb.setTitle(String.valueOf(demo.numImages) + " Images");
+            imageSlider.setBorder(tb);
+            imageSlider.setOpaque(true);
+            imageSlider.setPreferredSize(new Dimension(80,44));
+            bar.add(imageSlider);
+            bar.addSeparator();
+            add(bar);
+
+            toolbar = new JToolBar();
+            toolbar.setFloatable(false);
+            addButton("T", "translate", demo.doTranslate);
+            addButton("R", "rotate", demo.doRotate);
+            addButton("SC", "scale", demo.doScale);
+            addButton("SH", "shear", demo.doShear);
+            add(toolbar);
+        }
+
+
+        public void addButton(String s, String tt, boolean state) {
+            JToggleButton b = (JToggleButton) toolbar.add(new JToggleButton(s));
+            b.setFont(font);
+            b.setSelected(state);
+            b.setToolTipText(tt);
+            b.setFocusPainted(false);
+            b.setBorder(buttonBorder);
+            b.addActionListener(this);
+        }
+
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JToggleButton b = (JToggleButton) e.getSource();
+            if (b.getText().equals("T")) {
+                demo.doTranslate = b.isSelected();
+            } else if (b.getText().equals("R")) {
+                demo.doRotate = b.isSelected();
+            } else if (b.getText().equals("SC")) {
+                demo.doScale = b.isSelected();
+            } else if (b.getText().equals("SH")) {
+                demo.doShear = b.isSelected();
+            }
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+        }
+
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            JSlider slider = (JSlider) e.getSource();
+            int value = slider.getValue();
+            TitledBorder tb = (TitledBorder) slider.getBorder();
+            if (slider.equals(shapeSlider)) {
+                tb.setTitle(String.valueOf(value) + " Shapes");
+                demo.setShapes(value);
+            } else if (slider.equals(stringSlider)) {
+                tb.setTitle(String.valueOf(value) + " Strings");
+                demo.setStrings(value);
+            } else if (slider.equals(imageSlider)) {
+                tb.setTitle(String.valueOf(value) + " Images");
+                demo.setImages(value);
+            }
+            if (!demo.animating.running()) {
+                demo.repaint();
+            }
+            slider.repaint();
+        }
+
+
+        @Override
+        public Dimension getPreferredSize() {
+            return new Dimension(80,38);
+        }
+
+
+        @Override
+        @SuppressWarnings("SleepWhileHoldingLock")
+        public void run() {
+            Thread me = Thread.currentThread();
+            while (thread == me) {
+                for (int i = 1; i < toolbar.getComponentCount(); i++) {
+                    try {
+                        Thread.sleep(4444);
+                    } catch (InterruptedException e) { return; }
+                    ((AbstractButton) toolbar.getComponentAtIndex(i)).doClick();
+                }
+            }
+            thread = null;
+        }
+    } // End DemoControls
+} // End TransformAnim
--- a/test/jdk/TEST.ROOT	Fri May 11 20:59:21 2018 -0700
+++ b/test/jdk/TEST.ROOT	Mon May 14 08:58:32 2018 -0700
@@ -18,7 +18,7 @@
 
 # Tests that must run in othervm mode
 othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/swing javax/print \
-sun/applet com/apple/laf com/sun/java/accessibility com/sun/java/swing sanity/client \
+sun/applet com/apple/laf com/sun/java/accessibility com/sun/java/swing sanity/client demo/jfc \
 javax/management com/sun/awt sun/awt sun/java2d javax/xml/jaxp/testng/validation java/lang/ProcessHandle
 
 # Tests that cannot run concurrently
--- a/test/jdk/TEST.groups	Fri May 11 20:59:21 2018 -0700
+++ b/test/jdk/TEST.groups	Mon May 14 08:58:32 2018 -0700
@@ -359,13 +359,17 @@
 jdk_imageio = \
     javax/imageio
 
+jfc_demo = \
+     demo/jfc
+
 jdk_desktop = \
     :jdk_awt \
     :jdk_2d \
     :jdk_beans \
     :jdk_swing \
     :jdk_sound \
-    :jdk_imageio
+    :jdk_imageio \
+    :jfc_demo
 
 # SwingSet3 tests.
 jdk_client_sanity = \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/demo/jfc/J2Ddemo/J2DdemoTest.java	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @key headful
+ * @summary Test J2Ddemo.jar
+ * @run main/timeout=200 J2DdemoTest
+ */
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.io.PrintStream;
+
+public class J2DdemoTest {
+
+    public static void main(String args[]) throws Exception {
+        DemoRun test;
+
+        /* Run the J2Ddemo.jar with the -runs=1 option */
+        test = new DemoRun("demo/jfc/J2Ddemo/J2Ddemo.jar", "-runs=1");
+        test.runit();
+
+        /* Make sure patterns in output look ok */
+        if (test.output_contains("ERROR")) {
+            throw new RuntimeException("Test failed - ERROR seen in output");
+        }
+        if (test.output_contains("Exception")) {
+            throw new RuntimeException("Test failed - Exception seen in output");
+        }
+
+        /* Must be a pass. */
+        System.out.println("Test passed - cleanly terminated");
+    }
+
+    /*
+     * Helper class to direct process output to a StringBuffer
+     */
+    static class MyInputStream implements Runnable {
+        private String              name;
+        private BufferedInputStream in;
+        private StringBuffer        buffer;
+
+        /* Create MyInputStream that saves all output to a StringBuffer */
+        MyInputStream(String name, InputStream in) {
+            this.name = name;
+            this.in = new BufferedInputStream(in);
+            buffer = new StringBuffer(4096);
+            Thread thr = new Thread(this);
+            thr.setDaemon(true);
+            thr.start();
+        }
+
+        /* Dump the buffer */
+        void dump(PrintStream x) {
+            String str = buffer.toString();
+            x.println("<beginning of " + name + " buffer>");
+            x.println(str);
+            x.println("<end of buffer>");
+        }
+
+        /* Check to see if a pattern is inside the output. */
+        boolean contains(String pattern) {
+            String str = buffer.toString();
+            return str.contains(pattern);
+        }
+
+        /* Runs as a separate thread capturing all output in a StringBuffer */
+        public void run() {
+            try {
+                byte b[] = new byte[100];
+                for (;;) {
+                    int n = in.read(b);
+                    String str;
+                    if (n < 0) {
+                        break;
+                    }
+                    str = new String(b, 0, n);
+                    buffer.append(str);
+                    System.out.print(str);
+                }
+            } catch (IOException ioe) { /* skip */ }
+        }
+    }
+
+    /*
+     * Generic run of a demo jar file.
+     */
+    static class DemoRun {
+
+        private String        demo_name;
+        private String        demo_options;
+        private MyInputStream output;
+        private MyInputStream error;
+
+        /* Create a Demo run process */
+        public DemoRun(String name, String options)
+        {
+            demo_name    = name;
+            demo_options = options;
+        }
+
+        /*
+         * Execute the demo
+         */
+        public void runit()
+        {
+            String jre_home  = System.getProperty("java.home");
+            String sdk_home  = (jre_home.endsWith("jre") ?
+                                (jre_home + File.separator + "..") :
+                                jre_home );
+            String java      = sdk_home
+                                 + File.separator + "bin"
+                                 + File.separator + "java";
+
+            /* VM options */
+            String vm_opts[] = new String[0];
+            String vopts = System.getProperty("test.vm.opts");
+            if ( vopts != null && vopts.length()>0 ) {
+                vm_opts = vopts.split("\\p{Space}+");
+            } else {
+                vm_opts = new String[0];
+            }
+
+            /* Command line */
+            String cmd[] = new String[1 + vm_opts.length + 3];
+            String cmdLine;
+            int i;
+
+            i = 0;
+            cmdLine = "";
+            cmdLine += (cmd[i++] = java);
+            cmdLine += " ";
+            for ( String vopt : vm_opts ) {
+                cmdLine += (cmd[i++] = vopt);
+                cmdLine += " ";
+            }
+            cmdLine += (cmd[i++] = "-jar");
+            cmdLine += " ";
+            cmdLine += (cmd[i++] = sdk_home + File.separator + demo_name);
+            cmdLine += " ";
+            cmdLine += (cmd[i++] = demo_options);
+
+            /* Begin process */
+            Process p;
+
+            System.out.println("Starting: " + cmdLine);
+            try {
+                p = Runtime.getRuntime().exec(cmd);
+            } catch ( IOException e ) {
+                throw new RuntimeException("Test failed - exec got IO exception");
+            }
+
+            /* Save process output in StringBuffers */
+            output = new MyInputStream("Input Stream", p.getInputStream());
+            error  = new MyInputStream("Error Stream", p.getErrorStream());
+
+            /* Wait for process to complete, and if exit code is non-zero we fail */
+            int exitStatus;
+            try {
+                exitStatus = p.waitFor();
+                if ( exitStatus != 0) {
+                    System.out.println("Exit code is " + exitStatus);
+                    error.dump(System.out);
+                    output.dump(System.out);
+                    throw new RuntimeException("Test failed - " +
+                                        "exit return code non-zero " +
+                                        "(exitStatus==" + exitStatus + ")");
+                }
+            } catch ( InterruptedException e ) {
+                throw new RuntimeException("Test failed - process interrupted");
+            }
+            System.out.println("Completed: " + cmdLine);
+        }
+
+        /* Does the pattern appear in the output of this process */
+        public boolean output_contains(String pattern)
+        {
+            return output.contains(pattern) || error.contains(pattern);
+        }
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/demo/jfc/TEST.properties	Mon May 14 08:58:32 2018 -0700
@@ -0,0 +1,2 @@
+modules=java.desktop
+