Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java
32288 views
1
/*
2
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.awt.X11;
27
28
import java.awt.Image;
29
30
import java.awt.datatransfer.DataFlavor;
31
import java.awt.datatransfer.Transferable;
32
import java.awt.datatransfer.UnsupportedFlavorException;
33
34
import java.awt.image.BufferedImage;
35
import java.awt.image.ColorModel;
36
import java.awt.image.WritableRaster;
37
38
import java.io.BufferedReader;
39
import java.io.InputStream;
40
import java.io.InputStreamReader;
41
import java.io.IOException;
42
43
import java.net.URI;
44
import java.net.URISyntaxException;
45
46
import java.util.ArrayList;
47
import java.util.Iterator;
48
import java.util.LinkedHashSet;
49
import java.util.List;
50
51
import javax.imageio.ImageIO;
52
import javax.imageio.ImageTypeSpecifier;
53
import javax.imageio.ImageWriter;
54
import javax.imageio.spi.ImageWriterSpi;
55
56
import sun.awt.datatransfer.DataTransferer;
57
import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
58
59
import java.io.ByteArrayOutputStream;
60
61
/**
62
* Platform-specific support for the data transfer subsystem.
63
*/
64
public class XDataTransferer extends DataTransferer {
65
static final XAtom FILE_NAME_ATOM = XAtom.get("FILE_NAME");
66
static final XAtom DT_NET_FILE_ATOM = XAtom.get("_DT_NETFILE");
67
static final XAtom PNG_ATOM = XAtom.get("PNG");
68
static final XAtom JFIF_ATOM = XAtom.get("JFIF");
69
static final XAtom TARGETS_ATOM = XAtom.get("TARGETS");
70
static final XAtom INCR_ATOM = XAtom.get("INCR");
71
static final XAtom MULTIPLE_ATOM = XAtom.get("MULTIPLE");
72
73
/**
74
* Singleton constructor
75
*/
76
private XDataTransferer() {
77
}
78
79
private static XDataTransferer transferer;
80
81
static synchronized XDataTransferer getInstanceImpl() {
82
if (transferer == null) {
83
transferer = new XDataTransferer();
84
}
85
return transferer;
86
}
87
88
public String getDefaultUnicodeEncoding() {
89
return "iso-10646-ucs-2";
90
}
91
92
public boolean isLocaleDependentTextFormat(long format) {
93
return false;
94
}
95
96
public boolean isTextFormat(long format) {
97
return super.isTextFormat(format)
98
|| isMimeFormat(format, "text");
99
}
100
101
protected String getCharsetForTextFormat(Long lFormat) {
102
long format = lFormat.longValue();
103
if (isMimeFormat(format, "text")) {
104
String nat = getNativeForFormat(format);
105
DataFlavor df = new DataFlavor(nat, null);
106
// Ignore the charset parameter of the MIME type if the subtype
107
// doesn't support charset.
108
if (!DataTransferer.doesSubtypeSupportCharset(df)) {
109
return null;
110
}
111
String charset = df.getParameter("charset");
112
if (charset != null) {
113
return charset;
114
}
115
}
116
return super.getCharsetForTextFormat(lFormat);
117
}
118
119
protected boolean isURIListFormat(long format) {
120
String nat = getNativeForFormat(format);
121
if (nat == null) {
122
return false;
123
}
124
try {
125
DataFlavor df = new DataFlavor(nat);
126
if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {
127
return true;
128
}
129
} catch (Exception e) {
130
// Not a MIME format.
131
}
132
return false;
133
}
134
135
public boolean isFileFormat(long format) {
136
return format == FILE_NAME_ATOM.getAtom() ||
137
format == DT_NET_FILE_ATOM.getAtom();
138
}
139
140
public boolean isImageFormat(long format) {
141
return format == PNG_ATOM.getAtom() ||
142
format == JFIF_ATOM.getAtom() ||
143
isMimeFormat(format, "image");
144
}
145
146
protected Long getFormatForNativeAsLong(String str) {
147
// Just get the atom. If it has already been retrived
148
// once, we'll get a copy so this should be very fast.
149
long atom = XAtom.get(str).getAtom();
150
return Long.valueOf(atom);
151
}
152
153
protected String getNativeForFormat(long format) {
154
return getTargetNameForAtom(format);
155
}
156
157
public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
158
return XToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler();
159
}
160
161
/**
162
* Gets an format name for a given format (atom)
163
*/
164
private String getTargetNameForAtom(long atom) {
165
return XAtom.get(atom).getName();
166
}
167
168
protected byte[] imageToPlatformBytes(Image image, long format)
169
throws IOException {
170
String mimeType = null;
171
if (format == PNG_ATOM.getAtom()) {
172
mimeType = "image/png";
173
} else if (format == JFIF_ATOM.getAtom()) {
174
mimeType = "image/jpeg";
175
} else {
176
// Check if an image MIME format.
177
try {
178
String nat = getNativeForFormat(format);
179
DataFlavor df = new DataFlavor(nat);
180
String primaryType = df.getPrimaryType();
181
if ("image".equals(primaryType)) {
182
mimeType = df.getPrimaryType() + "/" + df.getSubType();
183
}
184
} catch (Exception e) {
185
// Not an image MIME format.
186
}
187
}
188
if (mimeType != null) {
189
return imageToStandardBytes(image, mimeType);
190
} else {
191
String nativeFormat = getNativeForFormat(format);
192
throw new IOException("Translation to " + nativeFormat +
193
" is not supported.");
194
}
195
}
196
197
protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)
198
throws IOException
199
{
200
ByteArrayOutputStream bos = new ByteArrayOutputStream();
201
for (int i = 0; i < fileList.size(); i++)
202
{
203
byte[] bytes = fileList.get(i).getBytes();
204
if (i != 0) bos.write(0);
205
bos.write(bytes, 0, bytes.length);
206
}
207
return bos;
208
}
209
210
/**
211
* Translates either a byte array or an input stream which contain
212
* platform-specific image data in the given format into an Image.
213
*/
214
protected Image platformImageBytesToImage(
215
byte[] bytes, long format) throws IOException
216
{
217
String mimeType = null;
218
if (format == PNG_ATOM.getAtom()) {
219
mimeType = "image/png";
220
} else if (format == JFIF_ATOM.getAtom()) {
221
mimeType = "image/jpeg";
222
} else {
223
// Check if an image MIME format.
224
try {
225
String nat = getNativeForFormat(format);
226
DataFlavor df = new DataFlavor(nat);
227
String primaryType = df.getPrimaryType();
228
if ("image".equals(primaryType)) {
229
mimeType = df.getPrimaryType() + "/" + df.getSubType();
230
}
231
} catch (Exception e) {
232
// Not an image MIME format.
233
}
234
}
235
if (mimeType != null) {
236
return standardImageBytesToImage(bytes, mimeType);
237
} else {
238
String nativeFormat = getNativeForFormat(format);
239
throw new IOException("Translation from " + nativeFormat +
240
" is not supported.");
241
}
242
}
243
244
@Override
245
protected String[] dragQueryFile(byte[] bytes) {
246
XToolkit.awtLock();
247
try {
248
return XlibWrapper.XTextPropertyToStringList(bytes,
249
XAtom.get("STRING").getAtom());
250
} finally {
251
XToolkit.awtUnlock();
252
}
253
}
254
255
@Override
256
protected URI[] dragQueryURIs(InputStream stream,
257
long format,
258
Transferable localeTransferable)
259
throws IOException {
260
261
String charset = null;
262
if (localeTransferable != null &&
263
isLocaleDependentTextFormat(format) &&
264
localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor)) {
265
try {
266
charset = new String(
267
(byte[])localeTransferable.getTransferData(javaTextEncodingFlavor),
268
"UTF-8"
269
);
270
} catch (UnsupportedFlavorException cannotHappen) {
271
}
272
} else {
273
charset = getCharsetForTextFormat(format);
274
}
275
if (charset == null) {
276
// Only happens when we have a custom text type.
277
charset = getDefaultTextCharset();
278
}
279
280
BufferedReader reader = null;
281
try {
282
reader = new BufferedReader(new InputStreamReader(stream, charset));
283
String line;
284
ArrayList<URI> uriList = new ArrayList<URI>();
285
URI uri;
286
while ((line = reader.readLine()) != null) {
287
try {
288
uri = new URI(line);
289
} catch (URISyntaxException uriSyntaxException) {
290
throw new IOException(uriSyntaxException);
291
}
292
uriList.add(uri);
293
}
294
return uriList.toArray(new URI[uriList.size()]);
295
} finally {
296
if (reader != null)
297
reader.close();
298
}
299
}
300
301
/**
302
* Returns true if and only if the name of the specified format Atom
303
* constitutes a valid MIME type with the specified primary type.
304
*/
305
private boolean isMimeFormat(long format, String primaryType) {
306
String nat = getNativeForFormat(format);
307
308
if (nat == null) {
309
return false;
310
}
311
312
try {
313
DataFlavor df = new DataFlavor(nat);
314
if (primaryType.equals(df.getPrimaryType())) {
315
return true;
316
}
317
} catch (Exception e) {
318
// Not a MIME format.
319
}
320
321
return false;
322
}
323
324
/*
325
* The XDnD protocol prescribes that the Atoms used as targets for data
326
* transfer should have string names that represent the corresponding MIME
327
* types.
328
* To meet this requirement we check if the passed native format constitutes
329
* a valid MIME and return a list of flavors to which the data in this MIME
330
* type can be translated by the Data Transfer subsystem.
331
*/
332
public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {
333
LinkedHashSet<DataFlavor> flavors = new LinkedHashSet<>();
334
335
336
if (nat == null) {
337
return flavors;
338
}
339
340
DataFlavor df = null;
341
342
try {
343
df = new DataFlavor(nat);
344
} catch (Exception e) {
345
// The string doesn't constitute a valid MIME type.
346
return flavors;
347
}
348
349
DataFlavor value = df;
350
final String primaryType = df.getPrimaryType();
351
final String baseType = primaryType + "/" + df.getSubType();
352
353
// For text formats we map natives to MIME strings instead of data
354
// flavors to enable dynamic text native-to-flavor mapping generation.
355
// See SystemFlavorMap.getFlavorsForNative() for details.
356
if ("image".equals(primaryType)) {
357
Iterator readers = ImageIO.getImageReadersByMIMEType(baseType);
358
if (readers.hasNext()) {
359
flavors.add(DataFlavor.imageFlavor);
360
}
361
}
362
363
flavors.add(value);
364
365
return flavors;
366
}
367
368
private static ImageTypeSpecifier defaultSpecifier = null;
369
370
private ImageTypeSpecifier getDefaultImageTypeSpecifier() {
371
if (defaultSpecifier == null) {
372
ColorModel model = ColorModel.getRGBdefault();
373
WritableRaster raster =
374
model.createCompatibleWritableRaster(10, 10);
375
376
BufferedImage bufferedImage =
377
new BufferedImage(model, raster, model.isAlphaPremultiplied(),
378
null);
379
380
defaultSpecifier = new ImageTypeSpecifier(bufferedImage);
381
}
382
383
return defaultSpecifier;
384
}
385
386
/*
387
* The XDnD protocol prescribes that the Atoms used as targets for data
388
* transfer should have string names that represent the corresponding MIME
389
* types.
390
* To meet this requirement we return a list of formats that represent
391
* MIME types to which the data in this flavor can be translated by the Data
392
* Transfer subsystem.
393
*/
394
public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
395
LinkedHashSet<String> natives = new LinkedHashSet<>(1);
396
397
if (df == null) {
398
return natives;
399
}
400
401
String charset = df.getParameter("charset");
402
String baseType = df.getPrimaryType() + "/" + df.getSubType();
403
String mimeType = baseType;
404
405
if (charset != null && DataTransferer.isFlavorCharsetTextType(df)) {
406
mimeType += ";charset=" + charset;
407
}
408
409
// Add a mapping to the MIME native whenever the representation class
410
// doesn't require translation.
411
if (df.getRepresentationClass() != null &&
412
(df.isRepresentationClassInputStream() ||
413
df.isRepresentationClassByteBuffer() ||
414
byte[].class.equals(df.getRepresentationClass()))) {
415
natives.add(mimeType);
416
}
417
418
if (DataFlavor.imageFlavor.equals(df)) {
419
String[] mimeTypes = ImageIO.getWriterMIMETypes();
420
if (mimeTypes != null) {
421
for (int i = 0; i < mimeTypes.length; i++) {
422
Iterator writers =
423
ImageIO.getImageWritersByMIMEType(mimeTypes[i]);
424
425
while (writers.hasNext()) {
426
ImageWriter imageWriter = (ImageWriter)writers.next();
427
ImageWriterSpi writerSpi =
428
imageWriter.getOriginatingProvider();
429
430
if (writerSpi != null &&
431
writerSpi.canEncodeImage(getDefaultImageTypeSpecifier())) {
432
natives.add(mimeTypes[i]);
433
break;
434
}
435
}
436
}
437
}
438
} else if (DataTransferer.isFlavorCharsetTextType(df)) {
439
// stringFlavor is semantically equivalent to the standard
440
// "text/plain" MIME type.
441
if (DataFlavor.stringFlavor.equals(df)) {
442
baseType = "text/plain";
443
}
444
445
for (String encoding : DataTransferer.standardEncodings()) {
446
if (!encoding.equals(charset)) {
447
natives.add(baseType + ";charset=" + encoding);
448
}
449
}
450
451
// Add a MIME format without specified charset.
452
if (!natives.contains(baseType)) {
453
natives.add(baseType);
454
}
455
}
456
457
return natives;
458
}
459
}
460
461