Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java
32288 views
/*1* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.awt.X11;2627import java.awt.Image;2829import java.awt.datatransfer.DataFlavor;30import java.awt.datatransfer.Transferable;31import java.awt.datatransfer.UnsupportedFlavorException;3233import java.awt.image.BufferedImage;34import java.awt.image.ColorModel;35import java.awt.image.WritableRaster;3637import java.io.BufferedReader;38import java.io.InputStream;39import java.io.InputStreamReader;40import java.io.IOException;4142import java.net.URI;43import java.net.URISyntaxException;4445import java.util.ArrayList;46import java.util.Iterator;47import java.util.LinkedHashSet;48import java.util.List;4950import javax.imageio.ImageIO;51import javax.imageio.ImageTypeSpecifier;52import javax.imageio.ImageWriter;53import javax.imageio.spi.ImageWriterSpi;5455import sun.awt.datatransfer.DataTransferer;56import sun.awt.datatransfer.ToolkitThreadBlockedHandler;5758import java.io.ByteArrayOutputStream;5960/**61* Platform-specific support for the data transfer subsystem.62*/63public class XDataTransferer extends DataTransferer {64static final XAtom FILE_NAME_ATOM = XAtom.get("FILE_NAME");65static final XAtom DT_NET_FILE_ATOM = XAtom.get("_DT_NETFILE");66static final XAtom PNG_ATOM = XAtom.get("PNG");67static final XAtom JFIF_ATOM = XAtom.get("JFIF");68static final XAtom TARGETS_ATOM = XAtom.get("TARGETS");69static final XAtom INCR_ATOM = XAtom.get("INCR");70static final XAtom MULTIPLE_ATOM = XAtom.get("MULTIPLE");7172/**73* Singleton constructor74*/75private XDataTransferer() {76}7778private static XDataTransferer transferer;7980static synchronized XDataTransferer getInstanceImpl() {81if (transferer == null) {82transferer = new XDataTransferer();83}84return transferer;85}8687public String getDefaultUnicodeEncoding() {88return "iso-10646-ucs-2";89}9091public boolean isLocaleDependentTextFormat(long format) {92return false;93}9495public boolean isTextFormat(long format) {96return super.isTextFormat(format)97|| isMimeFormat(format, "text");98}99100protected String getCharsetForTextFormat(Long lFormat) {101long format = lFormat.longValue();102if (isMimeFormat(format, "text")) {103String nat = getNativeForFormat(format);104DataFlavor df = new DataFlavor(nat, null);105// Ignore the charset parameter of the MIME type if the subtype106// doesn't support charset.107if (!DataTransferer.doesSubtypeSupportCharset(df)) {108return null;109}110String charset = df.getParameter("charset");111if (charset != null) {112return charset;113}114}115return super.getCharsetForTextFormat(lFormat);116}117118protected boolean isURIListFormat(long format) {119String nat = getNativeForFormat(format);120if (nat == null) {121return false;122}123try {124DataFlavor df = new DataFlavor(nat);125if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {126return true;127}128} catch (Exception e) {129// Not a MIME format.130}131return false;132}133134public boolean isFileFormat(long format) {135return format == FILE_NAME_ATOM.getAtom() ||136format == DT_NET_FILE_ATOM.getAtom();137}138139public boolean isImageFormat(long format) {140return format == PNG_ATOM.getAtom() ||141format == JFIF_ATOM.getAtom() ||142isMimeFormat(format, "image");143}144145protected Long getFormatForNativeAsLong(String str) {146// Just get the atom. If it has already been retrived147// once, we'll get a copy so this should be very fast.148long atom = XAtom.get(str).getAtom();149return Long.valueOf(atom);150}151152protected String getNativeForFormat(long format) {153return getTargetNameForAtom(format);154}155156public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {157return XToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler();158}159160/**161* Gets an format name for a given format (atom)162*/163private String getTargetNameForAtom(long atom) {164return XAtom.get(atom).getName();165}166167protected byte[] imageToPlatformBytes(Image image, long format)168throws IOException {169String mimeType = null;170if (format == PNG_ATOM.getAtom()) {171mimeType = "image/png";172} else if (format == JFIF_ATOM.getAtom()) {173mimeType = "image/jpeg";174} else {175// Check if an image MIME format.176try {177String nat = getNativeForFormat(format);178DataFlavor df = new DataFlavor(nat);179String primaryType = df.getPrimaryType();180if ("image".equals(primaryType)) {181mimeType = df.getPrimaryType() + "/" + df.getSubType();182}183} catch (Exception e) {184// Not an image MIME format.185}186}187if (mimeType != null) {188return imageToStandardBytes(image, mimeType);189} else {190String nativeFormat = getNativeForFormat(format);191throw new IOException("Translation to " + nativeFormat +192" is not supported.");193}194}195196protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)197throws IOException198{199ByteArrayOutputStream bos = new ByteArrayOutputStream();200for (int i = 0; i < fileList.size(); i++)201{202byte[] bytes = fileList.get(i).getBytes();203if (i != 0) bos.write(0);204bos.write(bytes, 0, bytes.length);205}206return bos;207}208209/**210* Translates either a byte array or an input stream which contain211* platform-specific image data in the given format into an Image.212*/213protected Image platformImageBytesToImage(214byte[] bytes, long format) throws IOException215{216String mimeType = null;217if (format == PNG_ATOM.getAtom()) {218mimeType = "image/png";219} else if (format == JFIF_ATOM.getAtom()) {220mimeType = "image/jpeg";221} else {222// Check if an image MIME format.223try {224String nat = getNativeForFormat(format);225DataFlavor df = new DataFlavor(nat);226String primaryType = df.getPrimaryType();227if ("image".equals(primaryType)) {228mimeType = df.getPrimaryType() + "/" + df.getSubType();229}230} catch (Exception e) {231// Not an image MIME format.232}233}234if (mimeType != null) {235return standardImageBytesToImage(bytes, mimeType);236} else {237String nativeFormat = getNativeForFormat(format);238throw new IOException("Translation from " + nativeFormat +239" is not supported.");240}241}242243@Override244protected String[] dragQueryFile(byte[] bytes) {245XToolkit.awtLock();246try {247return XlibWrapper.XTextPropertyToStringList(bytes,248XAtom.get("STRING").getAtom());249} finally {250XToolkit.awtUnlock();251}252}253254@Override255protected URI[] dragQueryURIs(InputStream stream,256long format,257Transferable localeTransferable)258throws IOException {259260String charset = null;261if (localeTransferable != null &&262isLocaleDependentTextFormat(format) &&263localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor)) {264try {265charset = new String(266(byte[])localeTransferable.getTransferData(javaTextEncodingFlavor),267"UTF-8"268);269} catch (UnsupportedFlavorException cannotHappen) {270}271} else {272charset = getCharsetForTextFormat(format);273}274if (charset == null) {275// Only happens when we have a custom text type.276charset = getDefaultTextCharset();277}278279BufferedReader reader = null;280try {281reader = new BufferedReader(new InputStreamReader(stream, charset));282String line;283ArrayList<URI> uriList = new ArrayList<URI>();284URI uri;285while ((line = reader.readLine()) != null) {286try {287uri = new URI(line);288} catch (URISyntaxException uriSyntaxException) {289throw new IOException(uriSyntaxException);290}291uriList.add(uri);292}293return uriList.toArray(new URI[uriList.size()]);294} finally {295if (reader != null)296reader.close();297}298}299300/**301* Returns true if and only if the name of the specified format Atom302* constitutes a valid MIME type with the specified primary type.303*/304private boolean isMimeFormat(long format, String primaryType) {305String nat = getNativeForFormat(format);306307if (nat == null) {308return false;309}310311try {312DataFlavor df = new DataFlavor(nat);313if (primaryType.equals(df.getPrimaryType())) {314return true;315}316} catch (Exception e) {317// Not a MIME format.318}319320return false;321}322323/*324* The XDnD protocol prescribes that the Atoms used as targets for data325* transfer should have string names that represent the corresponding MIME326* types.327* To meet this requirement we check if the passed native format constitutes328* a valid MIME and return a list of flavors to which the data in this MIME329* type can be translated by the Data Transfer subsystem.330*/331public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {332LinkedHashSet<DataFlavor> flavors = new LinkedHashSet<>();333334335if (nat == null) {336return flavors;337}338339DataFlavor df = null;340341try {342df = new DataFlavor(nat);343} catch (Exception e) {344// The string doesn't constitute a valid MIME type.345return flavors;346}347348DataFlavor value = df;349final String primaryType = df.getPrimaryType();350final String baseType = primaryType + "/" + df.getSubType();351352// For text formats we map natives to MIME strings instead of data353// flavors to enable dynamic text native-to-flavor mapping generation.354// See SystemFlavorMap.getFlavorsForNative() for details.355if ("image".equals(primaryType)) {356Iterator readers = ImageIO.getImageReadersByMIMEType(baseType);357if (readers.hasNext()) {358flavors.add(DataFlavor.imageFlavor);359}360}361362flavors.add(value);363364return flavors;365}366367private static ImageTypeSpecifier defaultSpecifier = null;368369private ImageTypeSpecifier getDefaultImageTypeSpecifier() {370if (defaultSpecifier == null) {371ColorModel model = ColorModel.getRGBdefault();372WritableRaster raster =373model.createCompatibleWritableRaster(10, 10);374375BufferedImage bufferedImage =376new BufferedImage(model, raster, model.isAlphaPremultiplied(),377null);378379defaultSpecifier = new ImageTypeSpecifier(bufferedImage);380}381382return defaultSpecifier;383}384385/*386* The XDnD protocol prescribes that the Atoms used as targets for data387* transfer should have string names that represent the corresponding MIME388* types.389* To meet this requirement we return a list of formats that represent390* MIME types to which the data in this flavor can be translated by the Data391* Transfer subsystem.392*/393public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {394LinkedHashSet<String> natives = new LinkedHashSet<>(1);395396if (df == null) {397return natives;398}399400String charset = df.getParameter("charset");401String baseType = df.getPrimaryType() + "/" + df.getSubType();402String mimeType = baseType;403404if (charset != null && DataTransferer.isFlavorCharsetTextType(df)) {405mimeType += ";charset=" + charset;406}407408// Add a mapping to the MIME native whenever the representation class409// doesn't require translation.410if (df.getRepresentationClass() != null &&411(df.isRepresentationClassInputStream() ||412df.isRepresentationClassByteBuffer() ||413byte[].class.equals(df.getRepresentationClass()))) {414natives.add(mimeType);415}416417if (DataFlavor.imageFlavor.equals(df)) {418String[] mimeTypes = ImageIO.getWriterMIMETypes();419if (mimeTypes != null) {420for (int i = 0; i < mimeTypes.length; i++) {421Iterator writers =422ImageIO.getImageWritersByMIMEType(mimeTypes[i]);423424while (writers.hasNext()) {425ImageWriter imageWriter = (ImageWriter)writers.next();426ImageWriterSpi writerSpi =427imageWriter.getOriginatingProvider();428429if (writerSpi != null &&430writerSpi.canEncodeImage(getDefaultImageTypeSpecifier())) {431natives.add(mimeTypes[i]);432break;433}434}435}436}437} else if (DataTransferer.isFlavorCharsetTextType(df)) {438// stringFlavor is semantically equivalent to the standard439// "text/plain" MIME type.440if (DataFlavor.stringFlavor.equals(df)) {441baseType = "text/plain";442}443444for (String encoding : DataTransferer.standardEncodings()) {445if (!encoding.equals(charset)) {446natives.add(baseType + ";charset=" + encoding);447}448}449450// Add a MIME format without specified charset.451if (!natives.contains(baseType)) {452natives.add(baseType);453}454}455456return natives;457}458}459460461