changeset 11099:0ff77c365fe9

Merge
author kcr
date Thu, 30 Aug 2018 13:24:18 -0700
parents d32be0af339a e1d1bb48b99a
children de710dfe9147 e0ca893a6fd6
files
diffstat 14 files changed, 271 insertions(+), 271 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Aug 24 15:16:27 2018 -0700
+++ b/.hgtags	Thu Aug 30 13:24:18 2018 -0700
@@ -509,3 +509,4 @@
 812efc1ce8017dcc0c5e150ad91a7e99f25a2d80 12+0
 15770e65250e465e67848f2d1b8016b134e3046c 11+23
 bf4a59920c38bb12404d504b0ced6bede615df4a 11+24
+5815764071f022f4595e3fb69ae7f79c6edd4fc1 11+25
--- a/apps/samples/.classpath	Fri Aug 24 15:16:27 2018 -0700
+++ b/apps/samples/.classpath	Thu Aug 30 13:24:18 2018 -0700
@@ -12,9 +12,9 @@
     <classpathentry kind="src" path="Ensemble8/src/compiletime/java"/>
     <classpathentry kind="src" path="Ensemble8/src/generated/java"/>
     <classpathentry kind="src" path="Ensemble8/src/generated/resources"/>
-    <classpathentry kind="lib" path="Ensemble8/lib/lucene-core-7.1.0.jar"/>
-    <classpathentry kind="lib" path="Ensemble8/lib/lucene-grouping-7.1.0.jar"/>
-    <classpathentry kind="lib" path="Ensemble8/lib/lucene-queryparser-7.1.0.jar"/>
+    <classpathentry kind="lib" path="Ensemble8/lib/lucene-core-7.4.0.jar"/>
+    <classpathentry kind="lib" path="Ensemble8/lib/lucene-grouping-7.4.0.jar"/>
+    <classpathentry kind="lib" path="Ensemble8/lib/lucene-queryparser-7.4.0.jar"/>
     <classpathentry kind="src" path="MandelbrotSet/src"/>
     <classpathentry kind="src" path="Modena/src/main/java"/>
     <classpathentry kind="src" path="Modena/src/main/resources"/>
--- a/apps/samples/Ensemble8/build.gradle	Fri Aug 24 15:16:27 2018 -0700
+++ b/apps/samples/Ensemble8/build.gradle	Thu Aug 30 13:24:18 2018 -0700
@@ -4,9 +4,9 @@
 def mainClassName = "ensemble.EnsembleApp"
 
 def FileCollection apachecp = files(
-   "./lib/lucene-core-7.1.0.jar",
-   "./lib/lucene-grouping-7.1.0.jar",
-   "./lib/lucene-queryparser-7.1.0.jar")
+   "./lib/lucene-core-7.4.0.jar",
+   "./lib/lucene-grouping-7.4.0.jar",
+   "./lib/lucene-queryparser-7.4.0.jar")
 
 sourceSets {
     main {
--- a/apps/samples/Ensemble8/build.xml	Fri Aug 24 15:16:27 2018 -0700
+++ b/apps/samples/Ensemble8/build.xml	Thu Aug 30 13:24:18 2018 -0700
@@ -128,30 +128,30 @@
         <zip destfile="${dist.jar}" update="true">
             <!-- Rename license and notice file -->
             <mappedresources>
-                <zipfileset src="${file.reference.lucene-core-7.1.0.jar}">
+                <zipfileset src="${file.reference.lucene-core.jar}">
                     <include name="META-INF/LICENSE.txt"/>
                 </zipfileset>
                 <globmapper from="*/LICENSE.txt" to="*/LUCENE_LICENSE.TXT" />
             </mappedresources>
             <mappedresources>
-                <zipfileset src="${file.reference.lucene-core-7.1.0.jar}">
+                <zipfileset src="${file.reference.lucene-core.jar}">
                     <include name="META-INF/NOTICE.txt"/>
                 </zipfileset>
                 <globmapper from="*/NOTICE.txt" to="*/LUCENE_NOTICE.TXT" />
             </mappedresources>
 
             <!-- Include the core SPI services -->
-            <zipfileset src="${file.reference.lucene-core-7.1.0.jar}">
+            <zipfileset src="${file.reference.lucene-core.jar}">
                 <include name="META-INF/services/**"/>
             </zipfileset>
 
-            <zipfileset src="${file.reference.lucene-core-7.1.0.jar}">
+            <zipfileset src="${file.reference.lucene-core.jar}">
                 <exclude name="META-INF/**"/>
             </zipfileset>
-            <zipfileset src="${file.reference.lucene-grouping-7.1.0.jar}">
+            <zipfileset src="${file.reference.lucene-grouping.jar}">
                 <exclude name="META-INF/**"/>
             </zipfileset>
-            <zipfileset src="${file.reference.lucene-queryparser-7.1.0.jar}">
+            <zipfileset src="${file.reference.lucene-queryparser.jar}">
                 <exclude name="META-INF/**"/>
             </zipfileset>
         </zip>
--- a/apps/samples/Ensemble8/legal/lucene.md	Fri Aug 24 15:16:27 2018 -0700
+++ b/apps/samples/Ensemble8/legal/lucene.md	Thu Aug 30 13:24:18 2018 -0700
@@ -1,4 +1,4 @@
-## Apache Lucene v7.1.0
+## Apache Lucene v7.4.0
 
 ### Apache 2.0 License
 <pre>
--- a/apps/samples/Ensemble8/nbproject/project.properties	Fri Aug 24 15:16:27 2018 -0700
+++ b/apps/samples/Ensemble8/nbproject/project.properties	Thu Aug 30 13:24:18 2018 -0700
@@ -31,17 +31,18 @@
 dist.javadoc.dir=${dist.dir}/javadoc
 endorsed.classpath=
 excludes=
-file.reference.lucene-core-7.1.0.jar=lib/lucene-core-7.1.0.jar
-file.reference.lucene-grouping-7.1.0.jar=lib/lucene-grouping-7.1.0.jar
-file.reference.lucene-queryparser-7.1.0.jar=lib/lucene-queryparser-7.1.0.jar
+lucene.version=7.4.0
+file.reference.lucene-core.jar=lib/lucene-core-${lucene.version}.jar
+file.reference.lucene-grouping.jar=lib/lucene-grouping-${lucene.version}.jar
+file.reference.lucene-queryparser.jar=lib/lucene-queryparser-${lucene.version}.jar
 includes=**
 jar.archive.disabled=${jnlp.enabled}
 jar.compress=true
 jar.index=${jnlp.enabled}
 javac.classpath=\
-    ${file.reference.lucene-core-7.1.0.jar}:\
-    ${file.reference.lucene-grouping-7.1.0.jar}:\
-    ${file.reference.lucene-queryparser-7.1.0.jar}
+    ${file.reference.lucene-core.jar}:\
+    ${file.reference.lucene-grouping.jar}:\
+    ${file.reference.lucene-queryparser.jar}
 # Space-separated list of extra javac options
 compile.patch=@../../../build/compile.args
 javac.compilerargs=${compile.patch} 
--- a/build.gradle	Fri Aug 24 15:16:27 2018 -0700
+++ b/build.gradle	Thu Aug 30 13:24:18 2018 -0700
@@ -537,7 +537,7 @@
 defineProperty("RELEASE_SUFFIX", relSuffix)
 defineProperty("RELEASE_VERSION_SHORT", "${RELEASE_VERSION}${RELEASE_SUFFIX}")
 defineProperty("RELEASE_VERSION_LONG", "${RELEASE_VERSION_SHORT}+${PROMOTED_BUILD_NUMBER}${relOpt}")
-defineProperty("MAVEN_VERSION", "$RELEASE_VERSION_LONG")
+defineProperty("MAVEN_VERSION", IS_MILESTONE_FCS ? "${RELEASE_VERSION_SHORT}" : "${RELEASE_VERSION_LONG}")
 
 // Check whether the COMPILE_TARGETS property has been specified (if so, it was done by
 // the user and not by this script). If it has not been defined then default
@@ -1212,14 +1212,14 @@
     NUM_COMPILE_THREADS = 1
 }
 
-// Check for Gradle 4.8, error if < 4.3.
+// Check for Gradle 4.8, error if < 4.8.
 if (gradle.gradleVersion != "4.8") {
     def ver = gradle.gradleVersion.split("[\\.]");
     def gradleMajor = Integer.parseInt(ver[0]);
     def gradleMinor = Integer.parseInt(ver[1].split("[^0-9]")[0]);
     def err = "";
-    if (gradleMajor < 4 || (gradleMajor == 4 && gradleMinor < 3)) {
-        err = "Gradle version too old: ${gradle.gradleVersion}; must be at least 4.3"
+    if (gradleMajor < 4 || (gradleMajor == 4 && gradleMinor < 8)) {
+        err = "Gradle version too old: ${gradle.gradleVersion}; must be at least 4.8"
     }
 
     if (IS_GRADLE_VERSION_CHECK && err != "") {
@@ -3947,18 +3947,19 @@
     // The apps build is Ant based, we will exec ant from gradle.
 
     // Download the Lucene libraries needed for the Ensemble8 app
+    def luceneVersion = "7.4.0"
     getConfigurations().create("lucene");
     dependencies {
-        lucene group: "org.apache.lucene", name: "lucene-core", version: "7.1.0"
-        lucene group: "org.apache.lucene", name: "lucene-grouping", version: "7.1.0"
-        lucene group: "org.apache.lucene", name: "lucene-queryparser", version: "7.1.0"
+        lucene group: "org.apache.lucene", name: "lucene-core", version: luceneVersion
+        lucene group: "org.apache.lucene", name: "lucene-grouping", version: luceneVersion
+        lucene group: "org.apache.lucene", name: "lucene-queryparser", version: luceneVersion
     }
 
     // Copy Lucene libraries into the Ensemble8/lib directory
     File ensembleLibDir = rootProject.file("apps/samples/Ensemble8/lib");
-    def libNames = [ "lucene-core-7.1.0.jar",
-                     "lucene-grouping-7.1.0.jar",
-                     "lucene-queryparser-7.1.0.jar" ]
+    def libNames = [ "lucene-core-${luceneVersion}.jar",
+                     "lucene-grouping-${luceneVersion}.jar",
+                     "lucene-queryparser-${luceneVersion}.jar" ]
 
 
     task getLucene(type: Copy) {
--- a/modules/javafx.graphics/src/main/native-prism/PrismPrint.c	Fri Aug 24 15:16:27 2018 -0700
+++ b/modules/javafx.graphics/src/main/native-prism/PrismPrint.c	Thu Aug 30 13:24:18 2018 -0700
@@ -31,7 +31,7 @@
  * Method: getAlwaysOnTop
  * Signature (Ljava/lang/Class;J)Ljavax.print.attribute.standard.DialogOwner;
  */
-JNIEXPORT jobject
+JNIEXPORT jobject JNICALL
 Java_com_sun_prism_j2d_print_J2DPrinterJob_getAlwaysOnTop(
  JNIEnv *env, jclass cls, jclass ownerClass, jlong id) {
 
--- a/modules/javafx.web/src/main/java/com/sun/javafx/webkit/PasteboardImpl.java	Fri Aug 24 15:16:27 2018 -0700
+++ b/modules/javafx.web/src/main/java/com/sun/javafx/webkit/PasteboardImpl.java	Thu Aug 30 13:24:18 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -26,9 +26,8 @@
 package com.sun.javafx.webkit;
 
 import com.sun.javafx.tk.Toolkit;
-import com.sun.javafx.webkit.UIClientImpl;
 import com.sun.webkit.Pasteboard;
-import com.sun.webkit.graphics.WCGraphicsManager;
+import com.sun.webkit.graphics.WCImage;
 import com.sun.webkit.graphics.WCImageFrame;
 import java.io.File;
 import java.io.IOException;
@@ -66,20 +65,17 @@
         clipboard.setContent(content);
     }
 
-    @Override public void writeImage(WCImageFrame wcImage) {
-        Object platformImage = WCGraphicsManager.getGraphicsManager().
-                toPlatformImage(wcImage.getFrame());
-        Image fxImage = Toolkit.getImageAccessor().fromPlatformImage(platformImage);
+    @Override public void writeImage(WCImageFrame frame) {
+        final WCImage img = frame.getFrame();
+        final Image fxImage = img != null && !img.isNull() ? Toolkit.getImageAccessor().fromPlatformImage(img.getPlatformImage()) : null;
         if (fxImage != null) {
             ClipboardContent content = new ClipboardContent();
             content.putImage(fxImage);
-            String fileExtension = wcImage.getFrame().getFileExtension();
+            String fileExtension = img.getFileExtension();
             try {
                 File imageDump = File.createTempFile("jfx", "." + fileExtension);
                 imageDump.deleteOnExit();
-                ImageIO.write(UIClientImpl.toBufferedImage(fxImage),
-                    fileExtension,
-                    imageDump);
+                ImageIO.write(img.toBufferedImage(), fileExtension, imageDump);
                 content.putFiles(Arrays.asList(imageDump));
             } catch (IOException | SecurityException e) {
                 // Nothing specific to be done as of now
--- a/modules/javafx.web/src/main/java/com/sun/javafx/webkit/UIClientImpl.java	Fri Aug 24 15:16:27 2018 -0700
+++ b/modules/javafx.web/src/main/java/com/sun/javafx/webkit/UIClientImpl.java	Thu Aug 30 13:24:18 2018 -0700
@@ -33,22 +33,14 @@
 import static javafx.scene.web.WebEvent.STATUS_CHANGED;
 import static javafx.scene.web.WebEvent.VISIBILITY_CHANGED;
 
-import com.sun.javafx.tk.Toolkit;
 import com.sun.webkit.UIClient;
 import com.sun.webkit.WebPage;
 import com.sun.webkit.graphics.WCImage;
 import com.sun.webkit.graphics.WCRectangle;
-import java.awt.AlphaComposite;
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
-import java.awt.image.SampleModel;
-import java.awt.image.SinglePixelPackedSampleModel;
 import java.io.File;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -58,10 +50,6 @@
 import java.util.Map;
 import javafx.event.EventHandler;
 import javafx.geometry.Rectangle2D;
-import javafx.scene.image.Image;
-import javafx.scene.image.PixelFormat;
-import javafx.scene.image.PixelReader;
-import javafx.scene.image.WritablePixelFormat;
 import javafx.scene.input.ClipboardContent;
 import javafx.scene.input.DataFormat;
 import javafx.scene.input.Dragboard;
@@ -342,7 +330,7 @@
                 //never happens
             }
         }
-        if (image != null) {
+        if (image != null && !image.isNull()) {
             ByteBuffer dragImageOffset = ByteBuffer.allocate(8);
             dragImageOffset.rewind();
             dragImageOffset.putInt(imageOffsetX);
@@ -364,26 +352,18 @@
             //QuantumClipboard.putContent have to be rewritten in Glass manner
             //with postponed data requests (DelayedCallback data object).
             if (isImageSource) {
-                Object platformImage = image.getWidth() > 0 && image.getHeight() > 0 ?
-                        image.getPlatformImage() : null;
                 String fileExtension = image.getFileExtension();
-                if (platformImage != null) {
-                    try {
-                        File temp = File.createTempFile("jfx", "." + fileExtension);
-                        temp.deleteOnExit();
-                        ImageIO.write(
-                            toBufferedImage(Toolkit.getImageAccessor().fromPlatformImage(
-                                Toolkit.getToolkit().loadPlatformImage(
-                                    platformImage
-                                )
-                            )),
-                            fileExtension,
-                            temp);
-                        content.put(DataFormat.FILES, Arrays.asList(temp));
-                    } catch (IOException | SecurityException e) {
-                        //That is ok. It was just an attempt.
-                        //e.printStackTrace();
-                    }
+                try {
+                    File temp = File.createTempFile("jfx", "." + fileExtension);
+                    temp.deleteOnExit();
+                    ImageIO.write(
+                        image.toBufferedImage(),
+                        fileExtension,
+                        temp);
+                    content.put(DataFormat.FILES, Arrays.asList(temp));
+                } catch (IOException | SecurityException e) {
+                    //That is ok. It was just an attempt.
+                    //e.printStackTrace();
                 }
             }
         }
@@ -403,143 +383,4 @@
         return accessor.getView() != null && content != null;
     }
 
-    private static int
-            getBestBufferedImageType(PixelFormat<?> fxFormat, BufferedImage bimg,
-                                     boolean isOpaque)
-    {
-        if (bimg != null) {
-            int bimgType = bimg.getType();
-            if (bimgType == BufferedImage.TYPE_INT_ARGB ||
-                bimgType == BufferedImage.TYPE_INT_ARGB_PRE ||
-                (isOpaque &&
-                     (bimgType == BufferedImage.TYPE_INT_BGR ||
-                      bimgType == BufferedImage.TYPE_INT_RGB)))
-            {
-                // We will allow the caller to give us a BufferedImage
-                // that has an alpha channel, but we might not otherwise
-                // construct one ourselves.
-                // We will also allow them to choose their own premultiply
-                // type which may not match the image.
-                // If left to our own devices we might choose a more specific
-                // format as indicated by the choices below.
-                return bimgType;
-            }
-        }
-        switch (fxFormat.getType()) {
-            default:
-            case BYTE_BGRA_PRE:
-            case INT_ARGB_PRE:
-                return BufferedImage.TYPE_INT_ARGB_PRE;
-            case BYTE_BGRA:
-            case INT_ARGB:
-                return BufferedImage.TYPE_INT_ARGB;
-            case BYTE_RGB:
-                return BufferedImage.TYPE_INT_RGB;
-            case BYTE_INDEXED:
-                return (fxFormat.isPremultiplied()
-                        ? BufferedImage.TYPE_INT_ARGB_PRE
-                        : BufferedImage.TYPE_INT_ARGB);
-        }
-    }
-
-    private static WritablePixelFormat<IntBuffer>
-        getAssociatedPixelFormat(BufferedImage bimg)
-    {
-        switch (bimg.getType()) {
-            // We lie here for xRGB, but we vetted that the src data was opaque
-            // so we can ignore the alpha.  We use ArgbPre instead of Argb
-            // just to get a loop that does not have divides in it if the
-            // PixelReader happens to not know the data is opaque.
-            case BufferedImage.TYPE_INT_RGB:
-            case BufferedImage.TYPE_INT_ARGB_PRE:
-                return PixelFormat.getIntArgbPreInstance();
-            case BufferedImage.TYPE_INT_ARGB:
-                return PixelFormat.getIntArgbInstance();
-            default:
-                // Should not happen...
-                throw new InternalError("Failed to validate BufferedImage type");
-        }
-    }
-
-    private static boolean checkFXImageOpaque(PixelReader pr, int iw, int ih) {
-        for (int x = 0; x < iw; x++) {
-            for (int y = 0; y < ih; y++) {
-                Color color = pr.getColor(x,y);
-                if (color.getOpacity() != 1.0) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    private static BufferedImage fromFXImage(Image img, BufferedImage bimg) {
-        PixelReader pr = img.getPixelReader();
-        if (pr == null) {
-            return null;
-        }
-        int iw = (int) img.getWidth();
-        int ih = (int) img.getHeight();
-        PixelFormat<?> fxFormat = pr.getPixelFormat();
-        boolean srcPixelsAreOpaque = false;
-        switch (fxFormat.getType()) {
-            case INT_ARGB_PRE:
-            case INT_ARGB:
-            case BYTE_BGRA_PRE:
-            case BYTE_BGRA:
-                // Check fx image opacity only if
-                // supplied BufferedImage is without alpha channel
-                if (bimg != null &&
-                        (bimg.getType() == BufferedImage.TYPE_INT_BGR ||
-                         bimg.getType() == BufferedImage.TYPE_INT_RGB)) {
-                    srcPixelsAreOpaque = checkFXImageOpaque(pr, iw, ih);
-                }
-                break;
-            case BYTE_RGB:
-                srcPixelsAreOpaque = true;
-                break;
-        }
-        int prefBimgType = getBestBufferedImageType(pr.getPixelFormat(), bimg, srcPixelsAreOpaque);
-        if (bimg != null) {
-            int bw = bimg.getWidth();
-            int bh = bimg.getHeight();
-            if (bw < iw || bh < ih || bimg.getType() != prefBimgType) {
-                bimg = null;
-            } else if (iw < bw || ih < bh) {
-                Graphics2D g2d = bimg.createGraphics();
-                g2d.setComposite(AlphaComposite.Clear);
-                g2d.fillRect(0, 0, bw, bh);
-                g2d.dispose();
-            }
-        }
-        if (bimg == null) {
-            bimg = new BufferedImage(iw, ih, prefBimgType);
-        }
-        DataBufferInt db = (DataBufferInt)bimg.getRaster().getDataBuffer();
-        int data[] = db.getData();
-        int offset = bimg.getRaster().getDataBuffer().getOffset();
-        int scan =  0;
-        SampleModel sm = bimg.getRaster().getSampleModel();
-        if (sm instanceof SinglePixelPackedSampleModel) {
-            scan = ((SinglePixelPackedSampleModel)sm).getScanlineStride();
-        }
-
-        WritablePixelFormat<IntBuffer> pf = getAssociatedPixelFormat(bimg);
-        pr.getPixels(0, 0, iw, ih, pf, data, offset, scan);
-        return bimg;
-    }
-
-    // Method to implement the following via reflection:
-    //     SwingFXUtils.fromFXImage(img, null)
-    public static BufferedImage toBufferedImage(Image img) {
-        try {
-            return fromFXImage(img, null);
-        } catch (Exception ex) {
-            ex.printStackTrace(System.err);
-        }
-
-        // return null upon any exception
-        return null;
-    }
-
 }
--- a/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/PrismImage.java	Fri Aug 24 15:16:27 2018 -0700
+++ b/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/PrismImage.java	Thu Aug 30 13:24:18 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -25,18 +25,23 @@
 
 package com.sun.javafx.webkit.prism;
 
-import com.sun.javafx.tk.Toolkit;
 import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.nio.IntBuffer;
 import java.util.Base64;
 import java.util.Iterator;
+import javafx.scene.image.PixelFormat;
+import javafx.scene.image.WritablePixelFormat;
 import javax.imageio.ImageIO;
 import javax.imageio.ImageWriter;
 
 import com.sun.javafx.webkit.UIClientImpl;
+import com.sun.prism.Graphics;
 import com.sun.prism.Image;
-import com.sun.prism.Graphics;
 import com.sun.webkit.graphics.WCImage;
 
 /**
@@ -65,8 +70,8 @@
 
     @Override
     protected final byte[] toData(String mimeType) {
-        Object image = UIClientImpl.toBufferedImage(Toolkit.getImageAccessor().fromPlatformImage(getImage()));
-        if (image instanceof BufferedImage) {
+        final BufferedImage image = toBufferedImage(mimeType.equals("image/jpeg"));
+        if (image != null) {
             Iterator<ImageWriter> it = ImageIO.getImageWritersByMIMEType(mimeType);
             while (it.hasNext()) {
                 ByteArrayOutputStream output = new ByteArrayOutputStream();
@@ -98,4 +103,79 @@
         }
         return null;
     }
+
+    private static int
+            getBestBufferedImageType(PixelFormat<?> fxFormat)
+    {
+        switch (fxFormat.getType()) {
+            default:
+            case BYTE_BGRA_PRE:
+            case INT_ARGB_PRE:
+                return BufferedImage.TYPE_INT_ARGB_PRE;
+            case BYTE_BGRA:
+            case INT_ARGB:
+                return BufferedImage.TYPE_INT_ARGB;
+            case BYTE_RGB:
+                return BufferedImage.TYPE_INT_RGB;
+            case BYTE_INDEXED:
+                return (fxFormat.isPremultiplied()
+                        ? BufferedImage.TYPE_INT_ARGB_PRE
+                        : BufferedImage.TYPE_INT_ARGB);
+        }
+    }
+
+    private static WritablePixelFormat<IntBuffer>
+        getAssociatedPixelFormat(BufferedImage bimg)
+    {
+        switch (bimg.getType()) {
+            // We lie here for xRGB, but we vetted that the src data was opaque
+            // so we can ignore the alpha.  We use ArgbPre instead of Argb
+            // just to get a loop that does not have divides in it if the
+            // PixelReader happens to not know the data is opaque.
+            case BufferedImage.TYPE_INT_RGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+                return PixelFormat.getIntArgbPreInstance();
+            case BufferedImage.TYPE_INT_ARGB:
+                return PixelFormat.getIntArgbInstance();
+            default:
+                // Should not happen...
+                throw new InternalError("Failed to validate BufferedImage type");
+        }
+    }
+
+    private static BufferedImage fromFXImage(Image img, boolean forceRGB) {
+        final int iw = (int) img.getWidth();
+        final int ih = (int) img.getHeight();
+        final int destImageType = forceRGB ? BufferedImage.TYPE_INT_RGB : getBestBufferedImageType(img.getPlatformPixelFormat());
+        final BufferedImage bimg = new BufferedImage(iw, ih, destImageType);
+        final DataBufferInt db = (DataBufferInt) bimg.getRaster().getDataBuffer();
+        final int data[] = db.getData();
+        final int offset = bimg.getRaster().getDataBuffer().getOffset();
+        int scan =  0;
+        final SampleModel sm = bimg.getRaster().getSampleModel();
+        if (sm instanceof SinglePixelPackedSampleModel) {
+            scan = ((SinglePixelPackedSampleModel)sm).getScanlineStride();
+        }
+
+        final WritablePixelFormat<IntBuffer> pf = getAssociatedPixelFormat(bimg);
+        img.getPixels(0, 0, iw, ih, pf, data, offset, scan);
+        return bimg;
+    }
+
+    private BufferedImage toBufferedImage(boolean forceRGB) {
+        try {
+            return fromFXImage(getImage(), forceRGB);
+        } catch (Exception ex) {
+            ex.printStackTrace(System.err);
+        }
+
+        // return null upon any exception
+        return null;
+    }
+
+    @Override
+    public BufferedImage toBufferedImage() {
+        return toBufferedImage(false);
+    }
+
 }
--- a/modules/javafx.web/src/main/java/com/sun/webkit/graphics/WCImage.java	Fri Aug 24 15:16:27 2018 -0700
+++ b/modules/javafx.web/src/main/java/com/sun/webkit/graphics/WCImage.java	Thu Aug 30 13:24:18 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -25,6 +25,7 @@
 
 package com.sun.webkit.graphics;
 
+import java.awt.image.BufferedImage;
 import java.nio.ByteBuffer;
 
 public abstract class WCImage extends Ref {
@@ -84,5 +85,10 @@
         return img;
     }
 
+    public boolean isNull() {
+        return getWidth() <= 0 || getHeight() <= 0 || getPlatformImage() == null;
+    }
+
     public abstract float getPixelScale();
+    public abstract BufferedImage toBufferedImage();
 }
--- a/modules/javafx.web/src/test/java/test/javafx/scene/web/CanvasTest.java	Fri Aug 24 15:16:27 2018 -0700
+++ b/modules/javafx.web/src/test/java/test/javafx/scene/web/CanvasTest.java	Thu Aug 30 13:24:18 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, 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
@@ -25,7 +25,17 @@
 
 package test.javafx.scene.web;
 
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Base64;
+import javax.imageio.ImageIO;
+
 import netscape.javascript.JSObject;
+import org.junit.After;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.w3c.dom.Document;
@@ -38,61 +48,10 @@
  */
 public class CanvasTest extends TestBase {
 
-    private static final String expectedURL = "data:image/png;base64," +
-        "iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAACPklEQVR42u3T" +
-        "MSsGAByE8b9BDJIiJSnpLTGIQZSkJCW9JQYxiJKUpCQlBjaTzWazmWw2m81m" +
-        "stlsNps6PsRluJ6nfh/ghquflhLgVil9t5YAt5iDfLWXALeYg3x2lAC3mIN8" +
-        "dJUAt5iDvHeXALeYg7z1lgC3mIO89pUAt5iDvAyUALeYgzwPlgC3mIM8NUqA" +
-        "W8xBHodLgFvMQR5GS4BbzEHux0qAW8xB7iZKgFvMQW4nS4BbzEFupkuAW8xB" +
-        "rmdKgFvMQa7mSoBbzEHO50uAW8xBThZLgFvMQQ6XSoBbzEH2miXALeYg2ysl" +
-        "wC3mIBtrJcAt5iCr6yXALeYgy5slwC3mIAtbJcAt5iCzOyXALeYgU7slwC3m" +
-        "IOP7JcAt5iAjByXALeYgQ0clwC3mIP3HJcAt5iA9pyXALeYgnWclwC3mIG0X" +
-        "JcAt5iB1+TcGcIvpok2AXUxnnQLsYjrtEWAX03G/ALuYjoYE2MV0MCLALqb9" +
-        "cQF2Me1OCbCLaWdWgF1MWwsC7GLaXBZgF9P6qgC7mNY2BNjFtLItwC6m5p4A" +
-        "u5iWDgXYxbR4IsAupvlzAXYxzV0JsItp5lqAXUzTNwLsYpq8FWAX08SdALuY" +
-        "xu4F2MU0+iDALqbhRwF2MTWeBNjFNPgswC6mgRcBdjH1vQqwi6n3TYBdTN3v" +
-        "Auxi6voQYBdTx6cAu5javwTYxdT6LcAuppYfAXZERERERERERERERERERERE" +
-        "RERERERERERERERERERERERERERERET/0S/+VJ8zeU9ECwAAAABJRU5ErkJg" +
-        "gg==";
-
-    private static final String htmlContent = "\n"
-        + "<!DOCTYPE html>\n"
-        + "<html>\n"
-        + "<body>\n"
-        + "<canvas id=\"theCanvas\" width=\"200\" height=\"100\">\n"
-        + "</canvas>\n"
-        + "<p id = \"encodedText\">\n"
-        + "</p>\n"
-        + "<script>\n"
-        + "var c = document.getElementById(\"theCanvas\");\n"
-        + "var ctx = c.getContext(\"2d\");\n"
-        + "var my_gradient=ctx.createLinearGradient(0,0,0,75);\n"
-        + "my_gradient.addColorStop(0,\"red\");\n"
-        + "my_gradient.addColorStop(0.5,\"green\");\n"
-        + "my_gradient.addColorStop(1,\"blue\");\n"
-        + "ctx.fillStyle=my_gradient;\n"
-        + "ctx.fillRect(0,0,150,75);\n"
-        + "var dataURL = c.toDataURL();\n"
-        + "document.getElementById(\"encodedText\").innerHTML=dataURL;\n"
-        + "</script>\n"
-        + "</body>\n"
-        + "</html>\n";
-
-    @Ignore("RT-40092")
-    @Test public void testImageToDataURL() {
-        loadContent(htmlContent);
-        submit(() -> {
-            final Document doc = getEngine().getDocument();
-            Element elem = doc.getElementById("encodedText");
-            String textContent = elem.getTextContent();
-            textContent = textContent.replaceAll("\\s", "");
-            assertEquals("Data URL not encoded correctly", expectedURL, textContent);
-        });
-    }
+    private static final PrintStream ERR = System.err;
 
     // JDK-8162922
     @Test public void testCanvasStrokeRect() {
-
         final String htmlCanvasContent = "\n"
             + "<!DOCTYPE html>\n"
             + "<html>\n"
@@ -166,4 +125,116 @@
                     (int) getEngine().executeScript("document.getElementById('canvas').getContext('2d').getImageData(300,75,1,1).data[0]"));
         });
     }
+
+    // Color comparison algorithm is based on WebKit's Tools/ImageDiff/PlaformImage.cpp#PlatformImage::difference implemenation.
+    // https://trac.webkit.org/browser/webkit/trunk/Tools/ImageDiff/PlatformImage.cpp
+    private static float getColorDifference(final Color base, final Color c) {
+        final float red = (c.getRed() - base.getRed()) / Math.max(255.0f - base.getRed(), base.getRed());
+        final float green = (c.getGreen() - base.getGreen()) / Math.max(255.0f - base.getGreen(), base.getGreen());
+        final float blue = (c.getBlue() - base.getBlue()) / Math.max(255.0f - base.getBlue(), base.getBlue());
+        final float alpha = (c.getAlpha() - base.getAlpha()) / Math.max(255.0f - base.getAlpha(), base.getAlpha());
+        final float distance = ((float) Math.sqrt(red * red + green * green + blue * blue + alpha * alpha)) / 2.0f;
+        return distance >= (1 / 255.0f) ? distance * 100.0f : 0;
+    }
+
+    private static boolean isColorsSimilar(final Color base, final Color c, float toleranceInPercentage) {
+        return toleranceInPercentage >= getColorDifference(base, c);
+    }
+
+    private BufferedImage htmlCanvasToBufferedImage(final String mime) throws Exception {
+        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
+        System.setErr(new PrintStream(errStream));
+
+        final String html = String.format(""
+            + "<body>"
+            + "<script>"
+            + "canvas = document.createElement('canvas');"
+            + "canvas.width = canvas.height = 100;"
+            + "var ctx = canvas.getContext('2d');"
+            + "ctx.fillStyle = 'red';"
+            + "ctx.fillRect(0, 0, 50, 100);"
+            + "data = canvas.toDataURL('%s');"
+            + "</script>"
+            + "</body>"
+         , mime);
+
+        loadContent(html);
+        System.setErr(ERR);
+
+        // Check whether any exception thrown
+        final String exMessage = errStream.toString();
+        assertFalse(String.format("Test failed with exception:\n%s", exMessage),
+            exMessage.contains("Exception") || exMessage.contains("Error"));
+
+        String img = (String) executeScript("window.data");
+        assertNotNull("window.data must have base64 encoded image", img);
+        // get rid of mime type
+        img = img.split(",")[1];
+        assertNotNull(img);
+
+        final byte[] imgBytes = Base64.getMimeDecoder().decode(img);
+        assertNotNull("Base64 decoded image data must be valid", imgBytes);
+        final ByteArrayInputStream inputStream = new ByteArrayInputStream(imgBytes);
+        final BufferedImage decodedImg = ImageIO.read(inputStream);
+        assertNotNull(decodedImg);
+        return decodedImg;
+    }
+
+    @Test
+    public void testColorSimilarityAlgorithm() {
+        assertTrue("Two Color.WHITE must be 100% equal", isColorsSimilar(Color.WHITE, Color.WHITE, 0));
+        assertTrue("Color.BLACK & Color.WHITE must be 100% different", isColorsSimilar(Color.WHITE, Color.BLACK, 100));
+
+        assertFalse("Color.BLACK & Color.WHITE must be different by at least 80%", isColorsSimilar(Color.WHITE, Color.BLACK, 80));
+        assertFalse("(0, 0, 0, 0) & Color.WHITE must be at least 99.99% different", isColorsSimilar(Color.WHITE, new Color(0, true), 99.99f));
+
+        assertTrue("Color.RED must be 100% equal to (255, 0, 0, 255)", isColorsSimilar(Color.RED, new Color(255, 0, 0, 255), 0));
+        assertTrue("Color.RED must be at least 99% similar to (255, 0, 0, 250)", isColorsSimilar(Color.RED, new Color(255, 0, 0, 250), 1));
+        assertTrue("Color.RED must be at least 95% similar to (250, 5, 5, 250)", isColorsSimilar(Color.RED, new Color(250, 5, 5, 250), 5));
+
+        assertTrue("Color.GREEN must be 100% equal to (0, 255, 0, 255)", isColorsSimilar(Color.GREEN, new Color(0, 255, 0, 255), 0));
+        assertTrue("Color.GREEN must be at least 99% similar to (0, 255, 0, 250)", isColorsSimilar(Color.GREEN, new Color(0, 255, 0, 250), 1));
+        assertTrue("Color.GREEN must be at least 95% similar to (5, 250, 5, 250)", isColorsSimilar(Color.GREEN, new Color(5, 250, 5, 250), 5));
+
+        assertTrue("Color.BLUE must be 100% equal to (0, 255, 0, 255)", isColorsSimilar(Color.BLUE, new Color(0, 0, 255, 255), 0));
+        assertTrue("Color.BLUE must be at least 99% similar to (0, 0, 255, 250)", isColorsSimilar(Color.BLUE, new Color(0, 0, 255, 250), 1));
+        assertTrue("Color.BLUE must be at least 95% similar to (5, 5, 250, 250)", isColorsSimilar(Color.BLUE, new Color(5, 5, 250, 250), 5));
+
+        assertTrue("(0, 0, 0, 0) must be at least 95% similar to (5, 5, 5, 5)", isColorsSimilar(new Color(0, true), new Color(5, 5, 5, 5), 5));
+        assertFalse("(0, 0, 0, 0) and (5, 5, 5, 5) must be different by at least 1%", isColorsSimilar(new Color(0, true), new Color(5, 5, 5, 5), 1));
+
+        assertTrue("Color.RED must be at least 25% similar to Color.GREEN", isColorsSimilar(Color.RED, Color.GREEN, 75));
+        assertFalse("Color.RED and Color.GREEN must be different by at least 70%", isColorsSimilar(Color.RED, Color.GREEN, 70));
+    }
+
+    @Test
+    public void testToDataURLWithPNGMimeType() throws Exception {
+        final BufferedImage decodedImg = htmlCanvasToBufferedImage("image/png");
+
+        // Pixel at (25 x 25) must be red
+        final Color pixelAt25x25 = new Color(decodedImg.getRGB(25, 25), true);
+        assertTrue("Color should be opaque red:" + pixelAt25x25, isColorsSimilar(Color.RED, pixelAt25x25, 1));
+
+        // PNG supports transparency, Pixel at (75 x 25) must be transparent black
+        final Color pixelAt75x25 = new Color(decodedImg.getRGB(75, 25), true);
+        assertTrue("Color should be transparent black:" + pixelAt75x25, isColorsSimilar(new Color(0, true), pixelAt75x25, 1));
+    }
+
+    @Test
+    public void testToDataURLWithJPEGMimeType() throws Exception {
+        final BufferedImage decodedImg = htmlCanvasToBufferedImage("image/jpeg");
+
+        // Pixel at (25 x 25) must be red
+        final Color pixelAt25x25 = new Color(decodedImg.getRGB(25, 25), true);
+        assertTrue("Color should be opaque red:" + pixelAt25x25, isColorsSimilar(Color.RED, pixelAt25x25, 1));
+
+        // JPEG doesn't supports transparency, Pixel at (75 x 25) must be opaque black
+        final Color pixelAt75x25 = new Color(decodedImg.getRGB(75, 25), true);
+        assertTrue("Color should be transparent black:" + pixelAt75x25, isColorsSimilar(Color.BLACK, pixelAt75x25, 1));
+    }
+
+    @After
+    public void resetSystemErr() {
+        System.setErr(ERR);
+    }
 }
--- a/tools/scripts/build.ps1	Fri Aug 24 15:16:27 2018 -0700
+++ b/tools/scripts/build.ps1	Thu Aug 30 13:24:18 2018 -0700
@@ -14,6 +14,9 @@
 refreshenv
 if ($env:APPVEYOR -eq "true") {
   .\gradlew all test -PCOMPILE_WEBKIT=false -PCONF=DebugNative --stacktrace -x :web:test --info --no-daemon
+  if ($lastexitcode -ne 0) {
+    exit $lastexitcode
+  }
 } else {
   .\gradlew all test -PCOMPILE_WEBKIT=false -PCONF=DebugNative --stacktrace -x :web:test --info
 }