35 import java.awt.geom.Point2D; |
35 import java.awt.geom.Point2D; |
36 import java.awt.geom.Rectangle2D; |
36 import java.awt.geom.Rectangle2D; |
37 import java.awt.peer.FontPeer; |
37 import java.awt.peer.FontPeer; |
38 import java.io.*; |
38 import java.io.*; |
39 import java.lang.ref.SoftReference; |
39 import java.lang.ref.SoftReference; |
|
40 import java.security.AccessController; |
|
41 import java.security.PrivilegedExceptionAction; |
40 import java.text.AttributedCharacterIterator.Attribute; |
42 import java.text.AttributedCharacterIterator.Attribute; |
41 import java.text.CharacterIterator; |
43 import java.text.CharacterIterator; |
42 import java.text.StringCharacterIterator; |
44 import java.text.StringCharacterIterator; |
43 import java.util.HashMap; |
45 import java.util.HashMap; |
44 import java.util.Hashtable; |
46 import java.util.Hashtable; |
49 |
51 |
50 import sun.font.AttributeMap; |
52 import sun.font.AttributeMap; |
51 import sun.font.AttributeValues; |
53 import sun.font.AttributeValues; |
52 import sun.font.EAttribute; |
54 import sun.font.EAttribute; |
53 import sun.font.CompositeFont; |
55 import sun.font.CompositeFont; |
|
56 import sun.font.CreatedFontTracker; |
54 import sun.font.Font2D; |
57 import sun.font.Font2D; |
55 import sun.font.Font2DHandle; |
58 import sun.font.Font2DHandle; |
56 import sun.font.FontManager; |
59 import sun.font.FontManager; |
57 import sun.font.GlyphLayout; |
60 import sun.font.GlyphLayout; |
58 import sun.font.FontLineMetrics; |
61 import sun.font.FontLineMetrics; |
573 } |
576 } |
574 } |
577 } |
575 } |
578 } |
576 |
579 |
577 /* used to implement Font.createFont */ |
580 /* used to implement Font.createFont */ |
578 private Font(File fontFile, int fontFormat, boolean isCopy) |
581 private Font(File fontFile, int fontFormat, |
|
582 boolean isCopy, CreatedFontTracker tracker) |
579 throws FontFormatException { |
583 throws FontFormatException { |
580 this.createdFont = true; |
584 this.createdFont = true; |
581 /* Font2D instances created by this method track their font file |
585 /* Font2D instances created by this method track their font file |
582 * so that when the Font2D is GC'd it can also remove the file. |
586 * so that when the Font2D is GC'd it can also remove the file. |
583 */ |
587 */ |
584 this.font2DHandle = |
588 this.font2DHandle = |
585 FontManager.createFont2D(fontFile, fontFormat, isCopy).handle; |
589 FontManager.createFont2D(fontFile, fontFormat, |
|
590 isCopy, tracker).handle; |
586 this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault()); |
591 this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault()); |
587 this.style = Font.PLAIN; |
592 this.style = Font.PLAIN; |
588 this.size = 1; |
593 this.size = 1; |
589 this.pointSize = 1f; |
594 this.pointSize = 1f; |
590 } |
595 } |
820 |
848 |
821 if (fontFormat != Font.TRUETYPE_FONT && |
849 if (fontFormat != Font.TRUETYPE_FONT && |
822 fontFormat != Font.TYPE1_FONT) { |
850 fontFormat != Font.TYPE1_FONT) { |
823 throw new IllegalArgumentException ("font format not recognized"); |
851 throw new IllegalArgumentException ("font format not recognized"); |
824 } |
852 } |
825 final InputStream fStream = fontStream; |
853 boolean copiedFontData = false; |
826 Object ret = java.security.AccessController.doPrivileged( |
854 |
827 new java.security.PrivilegedAction() { |
855 try { |
828 public Object run() { |
856 final File tFile = AccessController.doPrivileged( |
829 File tFile = null; |
857 new PrivilegedExceptionAction<File>() { |
830 FileOutputStream outStream = null; |
858 public File run() throws IOException { |
831 try { |
859 return File.createTempFile("+~JF", ".tmp", null); |
832 tFile = File.createTempFile("+~JF", ".tmp", null); |
860 } |
833 /* Temp file deleted by font shutdown hook */ |
861 } |
834 BufferedInputStream inStream = |
862 ); |
835 new BufferedInputStream(fStream); |
863 |
836 outStream = new FileOutputStream(tFile); |
864 int totalSize = 0; |
837 int bytesRead = 0; |
865 CreatedFontTracker tracker = null; |
838 int bufSize = 8192; |
866 try { |
839 byte [] buf = new byte[bufSize]; |
867 final OutputStream outStream = |
840 while (bytesRead != -1) { |
868 AccessController.doPrivileged( |
841 try { |
869 new PrivilegedExceptionAction<OutputStream>() { |
842 bytesRead = inStream.read(buf, 0, bufSize); |
870 public OutputStream run() throws IOException { |
843 } catch (Throwable t) { |
871 return new FileOutputStream(tFile); |
844 throw new IOException(); |
872 } |
845 } |
873 } |
846 if (bytesRead != -1) { |
874 ); |
847 outStream.write(buf, 0, bytesRead); |
875 if (!hasTempPermission()) { |
848 } |
876 tracker = CreatedFontTracker.getTracker(); |
849 } |
877 } |
850 /* don't close the input stream */ |
878 try { |
851 outStream.close(); |
879 byte[] buf = new byte[8192]; |
852 } catch (IOException e) { |
880 for (;;) { |
853 if (outStream != null) { |
881 int bytesRead = fontStream.read(buf); |
854 try { |
882 if (bytesRead < 0) { |
855 outStream.close(); |
883 break; |
856 } catch (Exception e1) { |
884 } |
857 } |
885 if (tracker != null) { |
858 } |
886 if (totalSize+bytesRead > tracker.MAX_FILE_SIZE) { |
859 if (tFile != null) { |
887 throw new IOException("File too big."); |
860 try { |
888 } |
861 tFile.delete(); |
889 if (totalSize+tracker.getNumBytes() > |
862 } catch (Exception e2) { |
890 tracker.MAX_TOTAL_BYTES) |
863 } |
891 { |
864 } |
892 throw new IOException("Total files too big."); |
865 return e; |
893 } |
866 } |
894 totalSize += bytesRead; |
867 return tFile; |
895 tracker.addBytes(bytesRead); |
868 } |
896 } |
869 }); |
897 outStream.write(buf, 0, bytesRead); |
870 |
898 } |
871 if (ret instanceof File) { |
899 /* don't close the input stream */ |
872 return new Font((File)ret, fontFormat, true); |
900 } finally { |
873 } else if (ret instanceof IOException) { |
901 outStream.close(); |
874 throw (IOException)ret; |
902 } |
875 } else { |
903 /* After all references to a Font2D are dropped, the file |
876 throw new FontFormatException("Couldn't access font stream"); |
904 * will be removed. To support long-lived AppContexts, |
|
905 * we need to then decrement the byte count by the size |
|
906 * of the file. |
|
907 * If the data isn't a valid font, the implementation will |
|
908 * delete the tmp file and decrement the byte count |
|
909 * in the tracker object before returning from the |
|
910 * constructor, so we can set 'copiedFontData' to true here |
|
911 * without waiting for the results of that constructor. |
|
912 */ |
|
913 copiedFontData = true; |
|
914 Font font = new Font(tFile, fontFormat, true, tracker); |
|
915 return font; |
|
916 } finally { |
|
917 if (!copiedFontData) { |
|
918 if (tracker != null) { |
|
919 tracker.subBytes(totalSize); |
|
920 } |
|
921 AccessController.doPrivileged( |
|
922 new PrivilegedExceptionAction<Void>() { |
|
923 public Void run() { |
|
924 tFile.delete(); |
|
925 return null; |
|
926 } |
|
927 } |
|
928 ); |
|
929 } |
|
930 } |
|
931 } catch (Throwable t) { |
|
932 if (t instanceof FontFormatException) { |
|
933 throw (FontFormatException)t; |
|
934 } |
|
935 if (t instanceof IOException) { |
|
936 throw (IOException)t; |
|
937 } |
|
938 Throwable cause = t.getCause(); |
|
939 if (cause instanceof FontFormatException) { |
|
940 throw (FontFormatException)cause; |
|
941 } |
|
942 throw new IOException("Problem reading font data."); |
877 } |
943 } |
878 } |
944 } |
879 |
945 |
880 /** |
946 /** |
881 * Returns a new <code>Font</code> using the specified font type |
947 * Returns a new <code>Font</code> using the specified font type |