1. /*
  2. * @(#)SwingUtilities2.java 1.20 04/08/03
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing;
  8. import java.security.*;
  9. import java.lang.reflect.*;
  10. import java.awt.*;
  11. import java.awt.event.*;
  12. import java.awt.font.*;
  13. import java.awt.geom.*;
  14. import java.awt.print.PrinterGraphics;
  15. import java.text.AttributedCharacterIterator;
  16. import javax.swing.*;
  17. import javax.swing.plaf.*;
  18. import javax.swing.text.Highlighter;
  19. import javax.swing.text.JTextComponent;
  20. import javax.swing.text.DefaultHighlighter;
  21. import sun.print.ProxyPrintGraphics;
  22. import sun.awt.AppContext;
  23. import sun.font.FontDesignMetrics;
  24. import sun.java2d.SunGraphics2D;
  25. import sun.security.action.GetPropertyAction;
  26. import sun.security.util.SecurityConstants;
  27. /**
  28. * A collection of utility methods for Swing.
  29. * <p>
  30. * <b>WARNING:</b> While this class is public, it should not be treated as
  31. * public API and its API may change in incompatable ways between dot dot
  32. * releases and even patch releases. You should not rely on this class even
  33. * existing.
  34. *
  35. * @version 1.20 08/03/04
  36. */
  37. public class SwingUtilities2 {
  38. // Maintain a cache of CACHE_SIZE fonts and the left side bearing
  39. // of the characters falling into the range MIN_CHAR_INDEX to
  40. // MAX_CHAR_INDEX. The values in fontCache are created as needed.
  41. private static LSBCacheEntry[] fontCache;
  42. // Windows defines 6 font desktop properties, we will therefore only
  43. // cache the metrics for 6 fonts.
  44. private static final int CACHE_SIZE = 6;
  45. // nextIndex in fontCache to insert a font into.
  46. private static int nextIndex;
  47. // LSBCacheEntry used to search in fontCache to see if we already
  48. // have an entry for a particular font
  49. private static LSBCacheEntry searchKey;
  50. public static final Object FRC_KEY = new StringBuilder("FontRenderContext");
  51. // getLeftSideBearing will consult all characters that fall in the
  52. // range MIN_CHAR_INDEX to MAX_CHAR_INDEX.
  53. private static final int MIN_CHAR_INDEX = (int)'W';
  54. private static final int MAX_CHAR_INDEX = (int)'W' + 1;
  55. private static final FontRenderContext DEFAULT_FRC = new FontRenderContext(
  56. null, false, false);
  57. /**
  58. * FontRenderContext with antialiased turned on.
  59. */
  60. public static final FontRenderContext AA_FRC;
  61. //
  62. // To determine if a JComponent should use AA text the following is
  63. // used:
  64. // 1. Is the system property 'swing.aatext' defined, return the value of
  65. // the system property.
  66. // 2. Use the JComponent client property AA_TEXT_PROPERTY_KEY. To
  67. // avoid having this property persist between look and feels changes
  68. // the value of this property is set to false in JComponent.setUI
  69. //
  70. /**
  71. * Whether or not text is drawn anti-aliased. This is only used if
  72. * <code>AA_TEXT_DEFINED</code> is true.
  73. */
  74. private static final boolean AA_TEXT;
  75. /**
  76. * Whether or not the system property 'swing.aatext' is defined.
  77. */
  78. private static final boolean AA_TEXT_DEFINED;
  79. /**
  80. * Key used in client properties to indicate whether or not the component
  81. * should use aa text.
  82. */
  83. public static final Object AA_TEXT_PROPERTY_KEY =
  84. new StringBuffer("AATextPropertyKey");
  85. // security stuff
  86. private static Field inputEvent_CanAccessSystemClipboard_Field = null;
  87. private static final String UntrustedClipboardAccess =
  88. "UNTRUSTED_CLIPBOARD_ACCESS_KEY";
  89. static {
  90. fontCache = new LSBCacheEntry[CACHE_SIZE];
  91. Object aa = java.security.AccessController.doPrivileged(
  92. new GetPropertyAction("swing.aatext"));
  93. AA_TEXT_DEFINED = (aa != null);
  94. AA_TEXT = "true".equals(aa);
  95. AA_FRC = new FontRenderContext(null, true, false);
  96. }
  97. //
  98. // WARNING WARNING WARNING WARNING WARNING WARNING
  99. // Many of the following methods are invoked from older API.
  100. // As this older API was not passed a Component, a null Component may
  101. // now be passsed in. For example, SwingUtilities.computeStringWidth
  102. // is implemented to call SwingUtilities2.stringWidth, the
  103. // SwingUtilities variant does not take a JComponent, as such
  104. // SwingUtilities2.stringWidth can be passed a null Component.
  105. // In other words, if you add new functionality to these methods you
  106. // need to gracefully handle null.
  107. //
  108. /**
  109. * Returns whether or not text should be drawn antialiased.
  110. *
  111. * @param c JComponent to test.
  112. * @return Whether or not text should be drawn antialiased for the
  113. * specified component.
  114. */
  115. private static boolean drawTextAntialiased(JComponent c) {
  116. if (!AA_TEXT_DEFINED) {
  117. if (c != null) {
  118. // Check if the component wants aa text
  119. return ((Boolean)c.getClientProperty(
  120. AA_TEXT_PROPERTY_KEY)).booleanValue();
  121. }
  122. // No component, assume aa is off
  123. return false;
  124. }
  125. // 'swing.aatext' was defined, use its value.
  126. return AA_TEXT;
  127. }
  128. /**
  129. * Returns whether or not text should be drawn antialiased.
  130. *
  131. * @param aaText Whether or not aa text has been turned on for the
  132. * component.
  133. * @return Whether or not text should be drawn antialiased.
  134. */
  135. public static boolean drawTextAntialiased(boolean aaText) {
  136. if (!AA_TEXT_DEFINED) {
  137. // 'swing.aatext' wasn't defined, use the components aa text value.
  138. return aaText;
  139. }
  140. // 'swing.aatext' was defined, use its value.
  141. return AA_TEXT;
  142. }
  143. /**
  144. * Returns the left side bearing of the first character of string. The
  145. * left side bearing is calculated from the passed in
  146. * FontMetrics. If the passed in String is less than one
  147. * character, this will throw a StringIndexOutOfBoundsException exception.
  148. *
  149. * @param c JComponent that will display the string
  150. * @param fm FontMetrics used to measure the String width
  151. * @param string String to get the left side bearing for.
  152. */
  153. public static int getLeftSideBearing(JComponent c, FontMetrics fm,
  154. String string) {
  155. return getLeftSideBearing(c, fm, string.charAt(0));
  156. }
  157. /**
  158. * Returns the left side bearing of the first character of string. The
  159. * left side bearing is calculated from the passed in FontMetrics.
  160. *
  161. * @param c JComponent that will display the string
  162. * @param fm FontMetrics used to measure the String width
  163. * @param char Character to get the left side bearing for.
  164. */
  165. public static int getLeftSideBearing(JComponent c, FontMetrics fm,
  166. char firstChar) {
  167. int charIndex = (int)firstChar;
  168. if (charIndex < MAX_CHAR_INDEX && charIndex >= MIN_CHAR_INDEX) {
  169. byte[] lsbs = null;
  170. FontRenderContext frc = getFRC(c, fm);
  171. Font font = fm.getFont();
  172. synchronized(SwingUtilities2.class) {
  173. LSBCacheEntry entry = null;
  174. if (searchKey == null) {
  175. searchKey = new LSBCacheEntry(frc, font);
  176. }
  177. else {
  178. searchKey.reset(frc, font);
  179. }
  180. // See if we already have an entry for this pair
  181. for (LSBCacheEntry cacheEntry : fontCache) {
  182. if (searchKey.equals(cacheEntry)) {
  183. entry = cacheEntry;
  184. break;
  185. }
  186. }
  187. if (entry == null) {
  188. // No entry for this pair, add it.
  189. entry = searchKey;
  190. fontCache[nextIndex] = searchKey;
  191. searchKey = null;
  192. nextIndex = (nextIndex + 1) % CACHE_SIZE;
  193. }
  194. return entry.getLeftSideBearing(firstChar);
  195. }
  196. }
  197. return 0;
  198. }
  199. /**
  200. * Returns the FontMetrics for the current Font of the passed
  201. * in Graphics. This method is used when a Graphics
  202. * is available, typically when painting. If a Graphics is not
  203. * available the JComponent method of the same name should be used.
  204. * <p>
  205. * Callers should pass in a non-null JComponent, the exception
  206. * to this is if a JComponent is not readily available at the time of
  207. * painting.
  208. * <p>
  209. * This does not necessarily return the FontMetrics from the
  210. * Graphics.
  211. *
  212. * @param c JComponent requesting FontMetrics, may be null
  213. * @param g Graphics Graphics
  214. */
  215. public static FontMetrics getFontMetrics(JComponent c, Graphics g) {
  216. return getFontMetrics(c, g, g.getFont());
  217. }
  218. /**
  219. * Returns the FontMetrics for the specified Font.
  220. * This method is used when a Graphics is available, typically when
  221. * painting. If a Graphics is not available the JComponent method of
  222. * the same name should be used.
  223. * <p>
  224. * Callers should pass in a non-null JComonent, the exception
  225. * to this is if a JComponent is not readily available at the time of
  226. * painting.
  227. * <p>
  228. * This does not necessarily return the FontMetrics from the
  229. * Graphics.
  230. *
  231. * @param c JComponent requesting FontMetrics, may be null
  232. * @param c Graphics Graphics
  233. * @param font Font to get FontMetrics for
  234. */
  235. public static FontMetrics getFontMetrics(JComponent c, Graphics g,
  236. Font font) {
  237. if (c != null) {
  238. // Note: We assume that we're using the FontMetrics
  239. // from the widget to layout out text, otherwise we can get
  240. // mismatches when printing.
  241. return c.getFontMetrics(font);
  242. }
  243. return Toolkit.getDefaultToolkit().getFontMetrics(font);
  244. }
  245. /**
  246. * Returns the width of the passed in String.
  247. *
  248. * @param c JComponent that will display the string, may be null
  249. * @param fm FontMetrics used to measure the String width
  250. * @param string String to get the width of
  251. */
  252. public static int stringWidth(JComponent c, FontMetrics fm, String string){
  253. return fm.stringWidth(string);
  254. }
  255. /**
  256. * Clips the passed in String to the space provided.
  257. *
  258. * @param c JComponent that will display the string, may be null
  259. * @param fm FontMetrics used to measure the String width
  260. * @param string String to display
  261. * @param availTextWidth Amount of space that the string can be drawn in
  262. * @return Clipped string that can fit in the provided space.
  263. */
  264. public static String clipStringIfNecessary(JComponent c, FontMetrics fm,
  265. String string,
  266. int availTextWidth) {
  267. if ((string == null) || (string.equals(""))) {
  268. return "";
  269. }
  270. int textWidth = SwingUtilities2.stringWidth(c, fm, string);
  271. if (textWidth > availTextWidth) {
  272. return SwingUtilities2.clipString(c, fm, string, availTextWidth);
  273. }
  274. return string;
  275. }
  276. /**
  277. * Clips the passed in String to the space provided. NOTE: this assumes
  278. * the string does not fit in the available space.
  279. *
  280. * @param c JComponent that will display the string, may be null
  281. * @param fm FontMetrics used to measure the String width
  282. * @param string String to display
  283. * @param availTextWidth Amount of space that the string can be drawn in
  284. * @return Clipped string that can fit in the provided space.
  285. */
  286. public static String clipString(JComponent c, FontMetrics fm,
  287. String string, int availTextWidth) {
  288. // c may be null here.
  289. String clipString = "...";
  290. int width = SwingUtilities2.stringWidth(c, fm, clipString);
  291. // NOTE: This does NOT work for surrogate pairs and other fun
  292. // stuff
  293. int nChars = 0;
  294. for(int max = string.length(); nChars < max; nChars++) {
  295. width += fm.charWidth(string.charAt(nChars));
  296. if (width > availTextWidth) {
  297. break;
  298. }
  299. }
  300. string = string.substring(0, nChars) + clipString;
  301. return string;
  302. }
  303. /**
  304. * Returns the FontRenderContext for the passed in FontMetrics.
  305. */
  306. private static FontRenderContext getFRC(JComponent c, FontMetrics fm) {
  307. // c may be null.
  308. if (fm instanceof FontDesignMetrics) {
  309. return ((FontDesignMetrics)fm).getFRC();
  310. }
  311. // PENDING: This shouldn't really happen, but if it does we
  312. // should try and handle AA as necessary.
  313. assert false;
  314. return DEFAULT_FRC;
  315. }
  316. /**
  317. * Draws the string at the specified location.
  318. *
  319. * @param c JComponent that will display the string, may be null
  320. * @param g Graphics to draw the text to
  321. * @param text String to display
  322. * @param x X coordinate to draw the text at
  323. * @param y Y coordinate to draw the text at
  324. */
  325. public static void drawString(JComponent c, Graphics g, String text,
  326. int x, int y) {
  327. // c may be null
  328. // All non-editable widgets that draw strings call into this
  329. // methods. By non-editable that means widgets like JLabel, JButton
  330. // but NOT JTextComponents.
  331. if ( text == null || text.length() <= 0 ) { //no need to paint empty strings
  332. return;
  333. }
  334. if (isPrinting(g)) {
  335. Graphics2D g2d = getGraphics2D(g);
  336. if (g2d != null) {
  337. TextLayout layout = new TextLayout(text, g2d.getFont(),
  338. DEFAULT_FRC);
  339. layout.draw(g2d, x, y);
  340. return;
  341. }
  342. }
  343. // If we get here we're not printing
  344. if (drawTextAntialiased(c) && (g instanceof Graphics2D)) {
  345. Graphics2D g2 = (Graphics2D)g;
  346. Object oldAAValue = g2.getRenderingHint(
  347. RenderingHints.KEY_TEXT_ANTIALIASING);
  348. g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
  349. RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  350. g.drawString(text, x, y);
  351. g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
  352. oldAAValue);
  353. }
  354. else {
  355. g.drawString(text, x, y);
  356. }
  357. }
  358. /**
  359. * Draws the string at the specified location underlining the specified
  360. * character.
  361. *
  362. * @param c JComponent that will display the string, may be null
  363. * @param g Graphics to draw the text to
  364. * @param text String to display
  365. * @param underlinedIndex Index of a character in the string to underline
  366. * @param x X coordinate to draw the text at
  367. * @param y Y coordinate to draw the text at
  368. */
  369. public static void drawStringUnderlineCharAt(JComponent c,Graphics g,
  370. String text, int underlinedIndex, int x,int y) {
  371. SwingUtilities2.drawString(c, g, text, x, y);
  372. if (underlinedIndex >= 0 && underlinedIndex < text.length() ) {
  373. // PENDING: this needs to change.
  374. FontMetrics fm = g.getFontMetrics();
  375. int underlineRectX = x + SwingUtilities2.stringWidth(c,
  376. fm, text.substring(0,underlinedIndex));
  377. int underlineRectY = y;
  378. int underlineRectWidth = fm.charWidth(text.
  379. charAt(underlinedIndex));
  380. int underlineRectHeight = 1;
  381. g.fillRect(underlineRectX, underlineRectY + 1,
  382. underlineRectWidth, underlineRectHeight);
  383. }
  384. }
  385. /**
  386. * A variation of locationToIndex() which only returns an index if the
  387. * Point is within the actual bounds of a list item (not just in the cell)
  388. * and if the JList has the "List.isFileList" client property set.
  389. * Otherwise, this method returns -1.
  390. * This is used to make WindowsL&F JFileChooser act like native dialogs.
  391. */
  392. public static int loc2IndexFileList(JList list, Point point) {
  393. int index = list.locationToIndex(point);
  394. if (index != -1) {
  395. Object bySize = list.getClientProperty("List.isFileList");
  396. if (bySize instanceof Boolean && ((Boolean)bySize).booleanValue() &&
  397. !pointIsInActualBounds(list, index, point)) {
  398. index = -1;
  399. }
  400. }
  401. return index;
  402. }
  403. /**
  404. * Returns true if the given point is within the actual bounds of the
  405. * JList item at index (not just inside the cell).
  406. */
  407. private static boolean pointIsInActualBounds(JList list, int index,
  408. Point point) {
  409. ListCellRenderer renderer = list.getCellRenderer();
  410. ListModel dataModel = list.getModel();
  411. Object value = dataModel.getElementAt(index);
  412. Component item = renderer.getListCellRendererComponent(list,
  413. value, index, false, false);
  414. Dimension itemSize = item.getPreferredSize();
  415. Rectangle cellBounds = list.getCellBounds(index, index);
  416. if (!item.getComponentOrientation().isLeftToRight()) {
  417. cellBounds.x += (cellBounds.width - itemSize.width);
  418. }
  419. cellBounds.width = itemSize.width;
  420. cellBounds.height = itemSize.height;
  421. return cellBounds.contains(point);
  422. }
  423. /**
  424. * The following draw functions have the same semantic as the
  425. * Graphics methods with the same names.
  426. *
  427. * this is used for printing
  428. */
  429. public static int drawChars(JComponent c, Graphics g,
  430. char[] data,
  431. int offset,
  432. int length,
  433. int x,
  434. int y) {
  435. if ( length <= 0 ) { //no need to paint empty strings
  436. return x;
  437. }
  438. int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length);
  439. if (isPrinting(g)) {
  440. Graphics2D g2d = getGraphics2D(g);
  441. if (g2d != null) {
  442. FontRenderContext deviceFontRenderContext = g2d.
  443. getFontRenderContext();
  444. FontRenderContext frc = (FontRenderContext)AppContext.
  445. getAppContext().get(FRC_KEY);
  446. if (frc != null
  447. && ! isFontRenderContextCompatible(deviceFontRenderContext,
  448. frc)) {
  449. TextLayout layout =
  450. new TextLayout(new String(data,offset,length),
  451. g2d.getFont(),
  452. frc);
  453. layout.draw(g2d,x,y);
  454. return nextX;
  455. }
  456. }
  457. }
  458. // Assume we're not printing if we get here.
  459. if (drawTextAntialiased(c) && (g instanceof Graphics2D)) {
  460. Graphics2D g2 = (Graphics2D)g;
  461. Object oldAAValue = g2.getRenderingHint(
  462. RenderingHints.KEY_TEXT_ANTIALIASING);
  463. g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
  464. RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  465. g.drawChars(data, offset, length, x, y);
  466. g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
  467. oldAAValue);
  468. }
  469. else {
  470. g.drawChars(data, offset, length, x, y);
  471. }
  472. return nextX;
  473. }
  474. /*
  475. * see documentation for drawChars
  476. * returns the advance
  477. */
  478. public static float drawString(JComponent c, Graphics g,
  479. AttributedCharacterIterator iterator,
  480. int x,
  481. int y) {
  482. Graphics2D g2d = getGraphics2D(g);
  483. if (g2d == null) {
  484. g.drawString(iterator,x,y); //for the cases where advance
  485. //matters it should not happen
  486. return x;
  487. } else {
  488. FontRenderContext frc;
  489. if (isPrinting(g)) {
  490. frc = (FontRenderContext)AppContext.getAppContext().
  491. get(FRC_KEY);
  492. } else if (drawTextAntialiased(c)) {
  493. frc = AA_FRC;
  494. } else {
  495. frc = g2d.getFontRenderContext();
  496. }
  497. TextLayout layout = new TextLayout(iterator, frc);
  498. layout.draw(g2d, x, y);
  499. return layout.getAdvance();
  500. }
  501. }
  502. /*
  503. * Checks if two given FontRenderContexts are compatible.
  504. * Compatible means no special handling needed for text painting
  505. */
  506. public static boolean isFontRenderContextCompatible(FontRenderContext frc1,
  507. FontRenderContext frc2) {
  508. return (frc1 != null) ? frc1.equals(frc2) : frc2 == null;
  509. }
  510. /*
  511. * Tries it best to get Graphics2D out of the given Graphics
  512. * returns null if can not derive it.
  513. */
  514. public static Graphics2D getGraphics2D(Graphics g) {
  515. if (g instanceof Graphics2D) {
  516. return (Graphics2D) g;
  517. } else if (g instanceof ProxyPrintGraphics) {
  518. return (Graphics2D)(((ProxyPrintGraphics)g).getGraphics());
  519. } else {
  520. return null;
  521. }
  522. }
  523. /*
  524. * Returns FontRendedrContext associated with JComponent
  525. * see JComponent.getFontMetrics
  526. */
  527. public static FontRenderContext getFontRenderContext(Component c) {
  528. FontMetrics fontMetrics = c.getFontMetrics(c.getFont());
  529. FontRenderContext frc = null;
  530. if (fontMetrics instanceof sun.font.FontDesignMetrics) {
  531. frc = ((sun.font.FontDesignMetrics)fontMetrics).getFRC();
  532. } else {
  533. frc = DEFAULT_FRC;
  534. }
  535. return frc;
  536. }
  537. /*
  538. * returns true if the Graphics is print Graphics
  539. * false otherwise
  540. */
  541. static boolean isPrinting(Graphics g) {
  542. return (g instanceof PrinterGraphics || g instanceof PrintGraphics);
  543. }
  544. /**
  545. * Determines whether the SelectedTextColor should be used for painting text
  546. * foreground for the specified highlight.
  547. *
  548. * Returns true only if the highlight painter for the specified highlight
  549. * is the swing painter (whether inner class of javax.swing.text.DefaultHighlighter
  550. * or com.sun.java.swing.plaf.windows.WindowsTextUI) and its background color
  551. * is null or equals to the selection color of the text component.
  552. *
  553. * This is a hack for fixing both bugs 4761990 and 5003294
  554. */
  555. public static boolean useSelectedTextColor(Highlighter.Highlight h, JTextComponent c) {
  556. Highlighter.HighlightPainter painter = h.getPainter();
  557. String painterClass = painter.getClass().getName();
  558. if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
  559. painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
  560. return false;
  561. }
  562. try {
  563. DefaultHighlighter.DefaultHighlightPainter defPainter =
  564. (DefaultHighlighter.DefaultHighlightPainter) painter;
  565. if (defPainter.getColor() != null &&
  566. !defPainter.getColor().equals(c.getSelectionColor())) {
  567. return false;
  568. }
  569. } catch (ClassCastException e) {
  570. return false;
  571. }
  572. return true;
  573. }
  574. /**
  575. * LSBCacheEntry is used to cache the left side bearing (lsb) for
  576. * a particular <code>Font</code> and <code>FontRenderContext</code>.
  577. * This only caches characters that fall in the range
  578. * <code>MIN_CHAR_INDEX</code> to <code>MAX_CHAR_INDEX</code>.
  579. */
  580. private static class LSBCacheEntry {
  581. // Used to indicate a particular entry in lsb has not been set.
  582. private static final byte UNSET = Byte.MAX_VALUE;
  583. // Used in creating a GlyphVector to get the lsb
  584. private static final char[] oneChar = new char[1];
  585. private byte[] lsbCache;
  586. private Font font;
  587. private FontRenderContext frc;
  588. public LSBCacheEntry(FontRenderContext frc, Font font) {
  589. lsbCache = new byte[MAX_CHAR_INDEX - MIN_CHAR_INDEX];
  590. reset(frc, font);
  591. }
  592. public void reset(FontRenderContext frc, Font font) {
  593. this.font = font;
  594. this.frc = frc;
  595. for (int counter = lsbCache.length - 1; counter >= 0; counter--) {
  596. lsbCache[counter] = UNSET;
  597. }
  598. }
  599. public int getLeftSideBearing(char aChar) {
  600. int index = aChar - MIN_CHAR_INDEX;
  601. assert (index >= 0 && index < (MAX_CHAR_INDEX - MIN_CHAR_INDEX));
  602. byte lsb = lsbCache[index];
  603. if (lsb == UNSET) {
  604. oneChar[0] = aChar;
  605. GlyphVector gv = font.createGlyphVector(frc, oneChar);
  606. lsb = (byte)gv.getGlyphPixelBounds(0, frc, 0f, 0f).x;
  607. lsbCache[index] = lsb;
  608. }
  609. return lsb;
  610. }
  611. public boolean equals(Object entry) {
  612. if (entry == this) {
  613. return true;
  614. }
  615. if (!(entry instanceof LSBCacheEntry)) {
  616. return false;
  617. }
  618. LSBCacheEntry oEntry = (LSBCacheEntry)entry;
  619. return (font.equals(oEntry.font) &&
  620. frc.equals(oEntry.frc));
  621. }
  622. public int hashCode() {
  623. int result = 17;
  624. if (font != null) {
  625. result = 37 * result + font.hashCode();
  626. }
  627. if (frc != null) {
  628. result = 37 * result + frc.hashCode();
  629. }
  630. return result;
  631. }
  632. }
  633. /*
  634. * here goes the fix for 4856343 [Problem with applet interaction
  635. * with system selection clipboard]
  636. *
  637. * NOTE. In case isTrustedContext() no checking
  638. * are to be performed
  639. */
  640. /**
  641. * checks the security permissions for accessing system clipboard
  642. *
  643. * for untrusted context (see isTrustedContext) checks the
  644. * permissions for the current event being handled
  645. *
  646. */
  647. public static boolean canAccessSystemClipboard() {
  648. boolean canAccess = false;
  649. if (!GraphicsEnvironment.isHeadless()) {
  650. SecurityManager sm = System.getSecurityManager();
  651. if (sm == null) {
  652. canAccess = true;
  653. } else {
  654. try {
  655. sm.checkPermission(SecurityConstants.
  656. ACCESS_CLIPBOARD_PERMISSION);
  657. canAccess = true;
  658. } catch (SecurityException e) {
  659. }
  660. if (canAccess && ! isTrustedContext()) {
  661. canAccess = canCurrentEventAccessSystemClipboard(true);
  662. }
  663. }
  664. }
  665. return canAccess;
  666. }
  667. /**
  668. * Returns true if EventQueue.getCurrentEvent() has the permissions to
  669. * access the system clipboard
  670. */
  671. public static boolean canCurrentEventAccessSystemClipboard() {
  672. return isTrustedContext()
  673. || canCurrentEventAccessSystemClipboard(false);
  674. }
  675. /**
  676. * Returns true if the given event has permissions to access the
  677. * system clipboard
  678. *
  679. * @param e AWTEvent to check
  680. */
  681. public static boolean canEventAccessSystemClipboard(AWTEvent e) {
  682. return isTrustedContext()
  683. || canEventAccessSystemClipboard(e, false);
  684. }
  685. /**
  686. * returns canAccessSystemClipboard field from InputEvent
  687. *
  688. * @param ie InputEvent to get the field from
  689. */
  690. private static synchronized boolean inputEvent_canAccessSystemClipboard(InputEvent ie) {
  691. if (inputEvent_CanAccessSystemClipboard_Field == null) {
  692. inputEvent_CanAccessSystemClipboard_Field =
  693. (Field)AccessController.doPrivileged(
  694. new java.security.PrivilegedAction() {
  695. public Object run() {
  696. Field field = null;
  697. try {
  698. field = InputEvent.class.
  699. getDeclaredField("canAccessSystemClipboard");
  700. field.setAccessible(true);
  701. return field;
  702. } catch (SecurityException e) {
  703. } catch (NoSuchFieldException e) {
  704. }
  705. return null;
  706. }
  707. });
  708. }
  709. if (inputEvent_CanAccessSystemClipboard_Field == null) {
  710. return false;
  711. }
  712. boolean ret = false;
  713. try {
  714. ret = inputEvent_CanAccessSystemClipboard_Field.
  715. getBoolean(ie);
  716. } catch(IllegalAccessException e) {
  717. }
  718. return ret;
  719. }
  720. /**
  721. * Returns true if the given event is corrent gesture for
  722. * accessing clipboard
  723. *
  724. * @param ie InputEvent to check
  725. */
  726. private static boolean isAccessClipboardGesture(InputEvent ie) {
  727. boolean allowedGesture = false;
  728. if (ie instanceof KeyEvent) { //we can validate only keyboard gestures
  729. KeyEvent ke = (KeyEvent)ie;
  730. int keyCode = ke.getKeyCode();
  731. int keyModifiers = ke.getModifiers();
  732. switch(keyCode) {
  733. case KeyEvent.VK_C:
  734. case KeyEvent.VK_V:
  735. case KeyEvent.VK_X:
  736. allowedGesture = (keyModifiers == InputEvent.CTRL_MASK);
  737. break;
  738. case KeyEvent.VK_INSERT:
  739. allowedGesture = (keyModifiers == InputEvent.CTRL_MASK ||
  740. keyModifiers == InputEvent.SHIFT_MASK);
  741. break;
  742. case KeyEvent.VK_COPY:
  743. case KeyEvent.VK_PASTE:
  744. case KeyEvent.VK_CUT:
  745. allowedGesture = true;
  746. break;
  747. case KeyEvent.VK_DELETE:
  748. allowedGesture = ( keyModifiers == InputEvent.SHIFT_MASK);
  749. break;
  750. }
  751. }
  752. return allowedGesture;
  753. }
  754. /**
  755. * Returns true if e has the permissions to
  756. * access the system clipboard and if it is allowed gesture (if
  757. * checkGesture is true)
  758. *
  759. * @param e AWTEvent to check
  760. * @param checkGesture boolean
  761. */
  762. private static boolean canEventAccessSystemClipboard(AWTEvent e,
  763. boolean checkGesture) {
  764. if (EventQueue.isDispatchThread()) {
  765. /*
  766. * Checking event permissions makes sense only for event
  767. * dispathing thread
  768. */
  769. if (e instanceof InputEvent
  770. && (! checkGesture || isAccessClipboardGesture((InputEvent)e))) {
  771. return inputEvent_canAccessSystemClipboard((InputEvent)e);
  772. } else {
  773. return false;
  774. }
  775. } else {
  776. return true;
  777. }
  778. }
  779. /**
  780. * Returns true if EventQueue.getCurrentEvent() has the permissions to
  781. * access the system clipboard and if it is allowed gesture (if
  782. * checkGesture true)
  783. *
  784. * @param checkGesture boolean
  785. */
  786. private static boolean canCurrentEventAccessSystemClipboard(boolean
  787. checkGesture) {
  788. AWTEvent event = EventQueue.getCurrentEvent();
  789. return canEventAccessSystemClipboard(event, checkGesture);
  790. }
  791. /**
  792. * see RFE 5012841 [Per AppContect security permissions] for the
  793. * details
  794. *
  795. */
  796. private static boolean isTrustedContext() {
  797. return (System.getSecurityManager() == null)
  798. || (AppContext.getAppContext().
  799. get(UntrustedClipboardAccess) == null);
  800. }
  801. public static String displayPropertiesToCSS(Font font, Color fg) {
  802. StringBuffer rule = new StringBuffer("body {");
  803. if (font != null) {
  804. rule.append(" font-family: ");
  805. rule.append(font.getFamily());
  806. rule.append(" ; ");
  807. rule.append(" font-size: ");
  808. rule.append(font.getSize());
  809. rule.append("pt ;");
  810. if (font.isBold()) {
  811. rule.append(" font-weight: 700 ; ");
  812. }
  813. if (font.isItalic()) {
  814. rule.append(" font-style: italic ; ");
  815. }
  816. }
  817. if (fg != null) {
  818. rule.append(" color: #");
  819. if (fg.getRed() < 16) {
  820. rule.append('0');
  821. }
  822. rule.append(Integer.toHexString(fg.getRed()));
  823. if (fg.getGreen() < 16) {
  824. rule.append('0');
  825. }
  826. rule.append(Integer.toHexString(fg.getGreen()));
  827. if (fg.getBlue() < 16) {
  828. rule.append('0');
  829. }
  830. rule.append(Integer.toHexString(fg.getBlue()));
  831. rule.append(" ; ");
  832. }
  833. rule.append(" }");
  834. return rule.toString();
  835. }
  836. }