home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / font / TextAttributeSet.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  21.0 KB  |  644 lines

  1. /*
  2.  * @(#)TextAttributeSet.java    1.12 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. /*
  16.  * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
  17.  * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
  18.  *
  19.  * The original version of this source code and documentation is
  20.  * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
  21.  * of IBM. These materials are provided under terms of a License
  22.  * Agreement between Taligent and Sun. This technology is protected
  23.  * by multiple US and International patents.
  24.  *
  25.  * This notice and attribution to Taligent may not be removed.
  26.  * Taligent is a registered trademark of Taligent, Inc.
  27.  *
  28.  */
  29.  
  30. package java.awt.font;
  31.  
  32. import java.util.Enumeration;
  33. import java.util.Hashtable;
  34. import java.text.AttributeSet;
  35. import java.text.MutableAttributeSet;
  36. import java.awt.Color;
  37. import java.awt.Font;
  38.  
  39. /**
  40.  * TextAttributeSet provides a simple implementation of MutableAttributeSet.
  41.  */
  42. public final class TextAttributeSet implements MutableAttributeSet,
  43.     java.io.Serializable
  44. {
  45.     // For use by input system.
  46.  
  47.     /**
  48.      * Constant for the attribute "language". The value of this attribute should
  49.      * be an instance of Locale.
  50.      * @see java.util.Locale
  51.      */
  52.     public static final String LANGUAGE = "egaugnal";
  53.  
  54.     /**
  55.      * Constant for the attribute "reading". In languages where the written form
  56.      * and the pronunciation of a word are only loosely related (such as
  57.      * Japanese), it is often necessary to store the reading (pronunciation)
  58.      * along with the written form. This is an annotation attribute. The value
  59.      * should be an instance of Annotation holding an instance of String.
  60.      * @see Annotation
  61.      * @see java.lang.String
  62.      */
  63.     public static final String READING = "gnidaer";
  64.  
  65.     /**
  66.      * Constant for the attribute "input method segment". Input methods often
  67.      * break up text into segments, which usually correspond to words. This
  68.      * is an annotation attribute. The value should be an instance of
  69.      * Annotation holding a value of null.
  70.      * @see java.lang.String
  71.      */
  72.     public static final String INPUT_METHOD_SEGMENT = "tnemges dohtem tupni";
  73.  
  74.      /**
  75.       * Swap foreground and background colors (for input method use).
  76.       * <p>Values are instances of Boolean.
  77.       * The default is not to swap the colors.
  78.       * If the foreground and backround color attributes are both defined,
  79.       * this causes them to be swapped when rendering text.  If either is
  80.       * defaulted the exact effect is undefined-- generally it will produce
  81.       * an 'inverted' appearance.
  82.       */
  83.      public static final String SWAP_COLORS = "swap_colors";
  84.  
  85.     /** Swap foreground and background colors. */
  86.      public static final Boolean SWAP_COLORS_ON = new Boolean(true);
  87.  
  88.     /** Do not swap foreground and background colors. */
  89.      public static final Boolean SWAP_COLORS_OFF = new Boolean(false);
  90.  
  91.     /** Default to not swap foreground and background colors. */
  92.     public static final Boolean SWAP_COLORS_DEFAULT = SWAP_COLORS_OFF;
  93.  
  94.     // For use with Font.
  95.     // values for the features are examples; final values, including whether they are
  96.     // strings or numbers, are TBD.
  97.     // It's recommended that all Fonts support these values.  Custom fonts may add new
  98.     // values for these features, and even new features.
  99.  
  100.     /**
  101.      * The unlocalized font family name.
  102.      * <p>Values are instances of String, e.g. "Serif", "Palatino".
  103.      * The default value is unspecified.
  104.      */
  105.     public static final String FAMILY = "family";
  106.  
  107.     public static final String FAMILY_ALL = new String("All");
  108.  
  109.     /**
  110.      * The weight of the font.
  111.      * <p>Values are instances of Float.  The value is between 0.0 and 2.0.
  112.      * This roughly corresponds to the ratio of the stem width to the width of
  113.      * regular characters
  114.      * for this typeface.  Lower values are lighter.
  115.      */
  116.     public static final String WEIGHT = "weight";
  117.  
  118.     /**
  119.      * The default weight if WEIGHT is unspecified.  This value is 1.0.
  120.      * @see #WEIGHT
  121.      */
  122.     public static final Float WEIGHT_DEFAULT = new Float(1.0f);
  123.  
  124.     /**
  125.      * The bold weight for the font.  This value is 1.5.
  126.      * @see #WEIGHT
  127.      */
  128.     public static final Float WEIGHT_BOLD = new Float(1.5f);
  129.  
  130.     /**
  131.      * The light weight for the font.  This value is 0.7.
  132.      * @see #WEIGHT
  133.      */
  134.     public static final Float WEIGHT_LIGHT = new Float(0.7f);
  135.  
  136.     /**
  137.      * The posture of the font.
  138.      * <p>Values are instances of Float. The value is the run/rise, generally
  139.      * between -1.0 and 1.0, where negative values indicate a leftwards slant,
  140.      * positive a rightwards slant, and zero no slant.  There is no guarantee,
  141.      * however, that the slope of the text as returned by font will be the
  142.      * same as the posture value.
  143.      * @see Font#getItalicAngle
  144.      */
  145.     public static final String POSTURE = "posture";
  146.  
  147.     /**
  148.      * The default posture if POSTURE is unspecified.  This value is 0.0.
  149.      * @see #POSTURE
  150.      */
  151.     public static final Float POSTURE_DEFAULT = new Float(0.0f);
  152.  
  153.     /**
  154.      * The standard italic posture for the font.  This value is 0.333.
  155.      * @see #POSTURE
  156.      */
  157.     public static final Float POSTURE_ITALIC = new Float(0.333f);
  158.  
  159.     /**
  160.      * The font size in points.
  161.      * <p> Values are instances of Float.  The value can be any positive
  162.      * value, although most fonts will pin to a reasonable range.
  163.      * The default value is unspecified.
  164.      */
  165.     public static final String SIZE = "size";
  166.  
  167.     /**
  168.      * The transform of the font.
  169.      * <p> Values are instances of Transform.
  170.      * The default value is 'null', i.e. when not specified the font uses its default transform.
  171.      */
  172.     public static final String TRANSFORM = "transform";
  173.  
  174.     /**
  175.      * The font to use to render this text.
  176.      * <p>Values are instances of Font.
  177.      * The default value is 'null', i.e. text layout
  178.      * will try to resolve the font as best it can for the given text.
  179.      */
  180.     public static final String FONT = "font";
  181.  
  182.     /**
  183.      * An embedded graphic to display in the text.
  184.      * <p>Values are instances of GraphicAttribute.  All characters with
  185.      * this attribute appear as the graphic.  Usually, the character
  186.      * used to represent embedded graphics is the Unicode Replacement
  187.      * Character, '\uFFFD'.
  188.      */
  189.     public static final String EMBEDDED_GRAPHIC = "graphic";
  190.  
  191.     /**
  192.      * The embedding level for nested bidirectional runs.
  193.      * <p>TextLayout assumes this feature has the same value for all text in a
  194.      * paragraph.
  195.      * <p>Values are instances of Integer, between 0 and 31 inclusive. Values
  196.      * from 0 to 15 represent embeddings.  If bit 4 is set (values from 16 to
  197.      * 31) they represent directional overrides. Even values indicate
  198.      * left-to-right, odd indicate right-to-left.
  199.      * Within an embedding, text assumes a base line direction corresponding
  200.      * to the embedding, and the standard bidirectional properties of the text
  201.      * applies.  Within an override, all text flows in the given direction,
  202.      * and the standard bidirectional properties of the text are overridden.
  203.      * See the Unicode Standard v. 2.0, section 3-11.
  204.      */
  205.     public static final String BIDI_EMBEDDING = "bidi_embedding";
  206.  
  207.     /**
  208.      * The default embedding if BIDI_EMBEDDING is unspecified. This value is 0.
  209.      * @see #BIDI_EMBEDDING
  210.      */
  211.     public static final Integer BIDI_EMBEDDING_DEFAULT = new Integer(0);
  212.  
  213.     /**
  214.      * The background color.
  215.      * <p>Values are instances of Color.
  216.      * The default value is 'null', meaning a transparent background.
  217.      */
  218.     public static final String BACKGROUND = "background";
  219.  
  220.     /**
  221.      * The foreground color.
  222.      * <p>Values are instances of Color.
  223.      * The default value is 'null', meaning use the current color in the Graphics.
  224.      */
  225.     public static final String FOREGROUND = "foreground";
  226.  
  227.     /**
  228.      * Adorn the text with underlining.
  229.      * <p>Values are instances of Byte.  The standard underline is UNDERLINE_ON,
  230.      * the low underlines are for input method highlighting.
  231.      */
  232.     public static final String UNDERLINE = "underline";
  233.  
  234.     /** No underline. */
  235.     public static final Byte UNDERLINE_OFF = new Byte((byte)-1);
  236.  
  237.     /**
  238.      * Standard underline at the roman baseline for roman text, and below
  239.      * the decenders for other text.
  240.      */
  241.     public static final Byte UNDERLINE_ON = new Byte((byte)0);
  242.  
  243.     /** Single pixel solid low underline. */
  244.     public static final Byte UNDERLINE_LOW_ONE_PIXEL = new Byte((byte)1);
  245.  
  246.     /** Double pixel solid low underline. */
  247.     public static final Byte UNDERLINE_LOW_TWO_PIXEL = new Byte((byte)2);
  248.  
  249.     /** Single pixel dotted low underline. */
  250.     public static final Byte UNDERLINE_LOW_DOTTED = new Byte((byte)3);
  251.  
  252.     /** Double pixel gray low underline. */
  253.     public static final Byte UNDERLINE_LOW_GRAY = new Byte((byte)4);
  254.  
  255.     /** Single pixel dashed low underline. */
  256.     public static final Byte UNDERLINE_LOW_DASHED = new Byte((byte)5);
  257.  
  258.     /**
  259.      * Adorn the text with strikethrough.
  260.      * <p>Values are instances of Boolean.
  261.      */
  262.     public static final String STRIKETHROUGH = "strikethrough";
  263.  
  264.     /**
  265.      * The default strikethrough if STRIKETHROUGH is unspecified, the value is
  266.      * false.
  267.      * @see #STRIKETHROUGH
  268.      */
  269.     public static final Boolean STRIKETHROUGH_DEFAULT = new Boolean(false);
  270.  
  271.     /**
  272.      * A single strikethrough.  This value is true.
  273.      * @see #STRIKETHROUGH
  274.      */
  275.     public static final Boolean STRIKETHROUGH_ON = new Boolean(true);
  276.  
  277.     /**
  278.      * Super and subscripting.
  279.      * <p>Values are arrays of two floats. The first value is is used to scale
  280.      * the point size, the second computes the offset as a ratio of the point
  281.      * size.  For example, when applied to a 12 point font, a value of
  282.      * [.75, -.5] requests a point size of 9, positioned 6 points above
  283.      * the baseline.
  284.      */
  285.     public static final String SUPERSUBSCRIPT = "supersubscript";
  286.  
  287.     /**
  288.      * The default supersubscript if SUPERSUBSCRIPT is unspecified.  This
  289.      * value is [1, 0].
  290.      * @see #SUPERSUBSCRIPT
  291.      */
  292.     public static final float[] SUPERSUBSCRIPT_DEFAULT = { 1.0f, 0.0f };
  293.  
  294.     /**
  295.      * Standard superscript.  This value is [0.75, -0.5].
  296.      * @see #SUPERSUBSCRIPT
  297.      */
  298.     public static final float[] SUPERSUBSCRIPT_UP1 = { 0.75f, -0.5f };
  299.  
  300.     /**
  301.      * Standard subscript.  This value is [0.75, 0.5].
  302.      * @see #SUPERSUBSCRIPT
  303.      */
  304.     public static final float[] SUPERSUBSCRIPT_DOWN1 = { 0.75f, 0.5f };
  305.  
  306.     /**
  307.      * Justification for the paragraph.
  308.      * <p>TextLayout assumes this feature has the same value for all text in a
  309.      * paragraph. Value is a float, extracted as a Double.  This is a ratio
  310.      * controlling the space adjustment.  For example, if a line's natural
  311.      * advance is 50 pixels, and it is asked to justify to a width of 100
  312.      * pixels, a ratio of 1.0 results in a justified line with an advance of
  313.      * 100 pixels, and a ratio of 0.5 results in a justified
  314.      * line with an advance of 75 pixels.
  315.      */
  316.     public static final String JUSTIFICATION = "justification";
  317.  
  318.     /**
  319.      * The default justification if JUSTIFICATION is unspecified.  This value
  320.      * is 1.0.
  321.      * @see #JUSTIFICATION
  322.      */
  323.     public static final Float JUSTIFICATION_DEFAULT = new Float(1.0f);
  324.  
  325.     /**
  326.      * Justify the line to the full requested width.  This value is 1.0.
  327.      * @see #JUSTIFICATION
  328.      */
  329.     public static final Float JUSTIFICATION_FULL = new Float(1.0f);
  330.  
  331.     /**
  332.      * Do not allow the line to be justified.  This value is 0.0.
  333.      * @see #JUSTIFICATION
  334.      */
  335.     public static final Float JUSTIFICATION_NONE = new Float(0.0f);
  336.  
  337.     /**
  338.      * The run direction of the line, either left-to-right or right-to-left.
  339.      * On vertical lines, left-to-right means top-to-bottom.
  340.      * <p>TextLayout assumes this feature has the same value for all text in
  341.      * a paragraph.
  342.      * <p>Values are instances of boolean.
  343.      */
  344.     public static final String RUN_DIRECTION = "run_direction";
  345.  
  346.     /**
  347.      * The default direction if RUN_DIRECTION is unspecified.  This value is
  348.      * false, indicating left-to-right.
  349.      * @see #RUN_DIRECTION
  350.      */
  351.     public static final Boolean RUN_DIRECTION_DEFAULT = new Boolean(false);
  352.  
  353.     /**
  354.      * Left-to-right (top-to-bottom) run direction.  This value is false.
  355.      * @see #RUN_DIRECTION
  356.      */
  357.     public static final Boolean RUN_DIRECTION_LTR = new Boolean(false);
  358.  
  359.     /**
  360.      * Right-to-left (bottom-to-top) run direction.  This value is true.
  361.      * @see #RUN_DIRECTION
  362.      */
  363.     public static final Boolean RUN_DIRECTION_RTL = new Boolean(true);
  364.  
  365.     /**
  366.      * The bidirectional layout control for roman numeral text.
  367.      * <p>Values are instances of Integer.
  368.      */
  369.     static final String BIDI_NUMERIC = "bidi_numeric";
  370.  
  371.     /**
  372.      * Interpret roman numerals as roman numerals always.
  373.      */
  374.     static final Integer BIDI_NUMERIC_STRONG_ROMAN = new Integer(IncrementalBidi.EN);
  375.  
  376.     /**
  377.      * Interpret roman numerals as arabic numerals always.
  378.      */
  379.     static final Integer BIDI_NUMERIC_STRONG_ARABIC = new Integer(IncrementalBidi.AN);
  380.  
  381.     /**
  382.      * Interpret roman numerals as having arabic line order.
  383.      */
  384.     static final Integer BIDI_NUMERIC_WEAK_ARABIC = new Integer(IncrementalBidi.WA);
  385.  
  386.     /*
  387.      * The default interpretation if BIDI_NUMERIC is unspecified.  This value
  388.      * is STRONG_ROMAN,
  389.      * indicating that roman numerals should always be formatted as such.
  390.      */
  391.     static final Integer BIDI_NUMERIC_DEFAULT =
  392.         BIDI_NUMERIC_STRONG_ROMAN;
  393.  
  394.     /**
  395.      * Baseline to which to align lines.
  396.      * <p>TextLayout assumes this feature has the same value for all text
  397.      * in a paragraph. Regardless of the baselines to which characters align,
  398.      * the layout as a whole will align to this line.
  399.      * <p>Values are instances of Integer.
  400.      * @see Font#ROMAN_BASELINE
  401.      * @see Font#CENTER_BASELINE
  402.      * @see Font#HANGING_BASELINE
  403.      * @see Font#getBaselineOffsetsFor
  404.      * @see Font#getBaselineFor
  405.      */
  406.     public static final String BASELINE = "baseline";
  407.  
  408.     /**
  409.      * The default baseline if BASELINE is unspecified.  This value is
  410.      * Font.ROMAN_BASELINE.
  411.      * @see #BASELINE
  412.      */
  413.     public static final Byte BASELINE_DEFAULT =
  414.         new Byte(Font.ROMAN_BASELINE);
  415.     /**
  416.      * Use a roman baseline for the line.  This value is Font.ROMAN_BASELINE.
  417.      * @see #BASELINE
  418.      */
  419.     public static final Byte BASELINE_ROMAN =
  420.         new Byte(Font.ROMAN_BASELINE);
  421.     /**
  422.      * Use a center baseline for the line.  This value is Font.CENTER_BASELINE.
  423.      * @see #BASELINE
  424.      */
  425.     public static final Byte BASELINE_IDEOGRAPHIC =
  426.         new Byte(Font.CENTER_BASELINE);
  427.  
  428.     /**
  429.      * Use a hanging baseline for the line.  This value is
  430.      * Font.HANGING_BASELINE.
  431.      * @see #BASELINE
  432.      */
  433.     public static final Byte BASELINE_HANGING =
  434.         new Byte(Font.HANGING_BASELINE);
  435.  
  436.     /**
  437.      * Baseline offsets used by a line.
  438.      * <p>TextLayout assumes this feature has the same value for all text
  439.      * in a paragraph.
  440.      * <p>Values are arrays of three floats.  The distance from one baseline
  441.      * to another is <code>offsets[b] - offsets[a]</code>, where a is the
  442.      * starting baseline.  For example, the distance from the hanging
  443.      * baseline to the ideographic baseline is:
  444.      * <code>offsets[BASELINE_IDEOGRAPHIC.byteValue()]-
  445.      *     offsets[BASELINE_HANGING.byteValue()]</code>
  446.      * <p>If defaulted, TextLayout attempts to find a
  447.      * reasonable value for all text in the paragraph.
  448.      */
  449.     public static final String BASELINE_OFFSETS = "baseline_offsets";
  450.  
  451.  
  452.     /**
  453.      * An empty attribute set, for convenience.
  454.      */
  455.     public static final AttributeSet EMPTY = new TextAttributeSet();
  456.  
  457.     private Hashtable table = new Hashtable();
  458.  
  459.     /**
  460.      * Construct a new mutable attribute set.
  461.      */
  462.     public TextAttributeSet() {
  463.     }
  464.  
  465.     /**
  466.      * Construct a new mutable attribute set containing the provided attributes.
  467.      * @param source the attributes to copy into this set.
  468.      */
  469.     public TextAttributeSet(AttributeSet source) {
  470.         add(source);
  471.     }
  472.  
  473.     /**
  474.      * Construct a new mutable attribute set containing the provided attribute.
  475.      * @param name the name of the attribute.
  476.      * @param value the value of the attribute.
  477.      */
  478.     public TextAttributeSet(String name, Object value) {
  479.         add(name, value);
  480.     }
  481.  
  482.     // internal only
  483.     private TextAttributeSet(Hashtable table) {
  484.         this.table = table;
  485.     }
  486.  
  487.     /**
  488.      * Returns true if the set is empty.
  489.      */
  490.     public boolean isEmpty() {
  491.         return table.isEmpty();
  492.     }
  493.  
  494.     /**
  495.      * Returns the number of attributes.
  496.      */
  497.     public int getSize() {
  498.         return table.size();
  499.     }
  500.  
  501.     /**
  502.      * Returns an enumeration over the names of the attributes in the set.
  503.      * The elements of the enumeration are all Strings.
  504.      */
  505.     public Enumeration names() {
  506.         return table.keys();
  507.     }
  508.  
  509.     /**
  510.      * Returns the value of the attribute with this name, or null if the
  511.      * attribute is not defined.
  512.      */
  513.     public Object get(String name) {
  514.         return table.get(name);
  515.     }
  516.  
  517.     /**
  518.      * Returns true if this set contains this attribute with an equal value,
  519.      * or if the value is null and the attribute is not defined.
  520.      */
  521.     public boolean contains(String name, Object value) {
  522.         Object myValue = get(name);
  523.         return value == null ? myValue == null : value.equals(myValue);
  524.     }
  525.  
  526.     /**
  527.      * Returns true if this set contains all the attributes with equal values.
  528.      */
  529.     public boolean contains(AttributeSet rhs) {
  530.         if (table.size() < rhs.getSize()) {
  531.             return false;
  532.         }
  533.  
  534.         Enumeration names = rhs.names();
  535.         while (names.hasMoreElements()) {
  536.             String name = (String)names.nextElement();
  537.             if (!rhs.get(name).equals(table.get(name))) {
  538.                 return false;
  539.             }
  540.         }
  541.  
  542.         return true;
  543.     }
  544.  
  545.     /**
  546.      * Return true if the argument is an attribute set containing the same
  547.      * attributes as this.
  548.      * @param rhs the object which may be an attribute set.
  549.      */
  550.     public boolean equals(Object rhs) {
  551.         try {
  552.             return equals((AttributeSet) rhs);
  553.         }
  554.         catch (ClassCastException e) {
  555.             return false;
  556.         }
  557.     }
  558.  
  559.     /**
  560.      * Return true if the argument contains the same attributes as this.
  561.      * @param rhs the attribute set to test against.
  562.      */
  563.     public boolean equals(AttributeSet rhs) {
  564.         return rhs != null && getSize() == rhs.getSize() &&
  565.             rhs.contains(this);
  566.     }
  567.  
  568.     /**
  569.      * Return a hash code.
  570.      */
  571.     public int hashCode() {
  572.         // equal sets must have equal hash code
  573.         // so default hash code is no good, it is unique
  574.         int hash = table.size();
  575.  
  576.         /* this is too expensive unless we cache
  577.         Enumeration e = table.elements();
  578.         while (e.hasMoreElements()) {
  579.             hash = (hash << 2) ^ e.nextElement().hashCode();
  580.         }
  581.         */
  582.  
  583.         return hash;
  584.      }
  585.  
  586.     /**
  587.      * Remove any existing attribute with the same name, and add a new
  588.      * attribute with the given name and value.  The value must be
  589.      * immutable, or not mutated by any client.
  590.      * @param name the name of the attribute to add
  591.      * @param value the value of the attribute to add
  592.      */
  593.     public void add(String name, Object value) {
  594.         table.put(name, value);
  595.     }
  596.  
  597.     /**
  598.      * Remove any existing attributes with the same names, and add the
  599.      * new attributes.
  600.      * @param attributes the set of attributes to add
  601.      */
  602.     public void add(AttributeSet attributes) {
  603.         Enumeration names = attributes.names();
  604.         while (names.hasMoreElements()) {
  605.             String name = (String)names.nextElement();
  606.             table.put(name, attributes.get(name));
  607.         }
  608.     }
  609.  
  610.     /**
  611.      * Remove any existing attribute with the given name.
  612.      * @param name the name of the attribute to remove
  613.      */
  614.     public void remove(String name) {
  615.         table.remove(name);
  616.     }
  617.  
  618.     /**
  619.      * Remove any existing attributes with the given names.
  620.      * @param names an enumeration over the names of attributes to remove.  The
  621.      * elements of the enumeration are Strings.
  622.      */
  623.     public void remove(Enumeration names) {
  624.         while (names.hasMoreElements())
  625.             table.remove(names.nextElement());
  626.     }
  627.  
  628.     /**
  629.      * Removes all attributes, then adds the new attributes.
  630.      */
  631.     public void set(AttributeSet attributes) {
  632.         table.clear();
  633.         add(attributes);
  634.     }
  635.  
  636.     /**
  637.      * Return a copy of this attribute set.  Attributes are shared with the
  638.      * copy.
  639.      */
  640.     public Object clone() {
  641.         return new TextAttributeSet((Hashtable)table.clone());
  642.     }
  643. }
  644.