1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.xmerge.converter.xml.sxw.wordsmith;
25 
26 import org.openoffice.xmerge.converter.xml.TextStyle;
27 import org.openoffice.xmerge.converter.xml.StyleCatalog;
28 import java.awt.Color;
29 
30 /**
31  *  <p>This class represents a text run (aka text atom) in a WordSmith
32  *  document.</p>
33  *
34  *  <p>WordSmith represents a text run as follows:</p>
35  *
36  *  <p><ul><li>
37  *    1 byte   Value of "1", indicating beginning of a text atom
38  *  </li><li>
39  *    2 bytes  Length of text (does not include attributes, this length field,
40  *             etc)
41  *  </li><li>
42  *    1 byte   Font index - Index in the font table of font to be used
43  *  </li><li>
44  *    1 byte   Font size (DJP: get details of representation)
45  *  </li><li>
46  *    1 byte   Color index - Index in the color table of font color to be used
47  *  </li><li>
48  *    1 byte   Modifiers - bit flags for bold, italic, etc
49  *  </li><li>
50  *    n bytes  Text - the actual text
51  *  </li></ul></p>
52  *
53  *  @author   David Proulx
54  */
55 class WseTextRun extends Wse {
56 
57     /**  Font specifier.  This is an index into the font table. */
58     private byte fontIndex = 0;
59     private String fontName = null;
60 
61     /**  Size of the font. */
62     private byte fontSize = 0;
63 
64     /**
65      *  Color of the font.  This is an index into the color table.
66      *  High nibble is background color index, low nibble is font color
67      *  index.
68      */
69     private byte colorIndex = 0;
70 
71     /**
72      *  Reference to color table for color lookups.
73      */
74     private WseColorTable ct;
75 
76     /**
77      *  The modifiers for the text run.  (Mostly) Bitwise flags. The "_TOKEN"
78      *  values are not yet implemented in this converter.  They may not even
79      *  be implemented in WordSmith yet.
80      */
81     private byte modifiers = 0;
82     final public static int BOLD             = 0x01;
83     final public static int ITALIC           = 0x02;
84     final public static int UNDERLINE        = 0x04;
85     final public static int STRIKETHRU       = 0x08;
86     final public static int SUPERSCRIPT      = 0x10;
87     final public static int SUBSCRIPT        = 0x20;
88     final public static int LINK             = 0x40;
89     final public static int CUSTOM_TOKEN     = 0x80;
90     final public static int IMAGE_TOKEN      = 0x80;
91     final public static int BOOKMARK_TOKEN   = 0x81;
92     final public static int ANNOTATION_TOKEN = 0x82;
93     final public static int LINK_TOKEN       = 0x83;
94 
95     /**  The actual text. */
96     private String text;
97 
98     StyleCatalog sc;
99 
100 
101     /**
102      *  Constructor for use when going from DOM to WordSmith.
103      *
104      *  @param txt  The text.
105      *  @param t    The text style.
106      *  @param sc   The <code>StyleCatalog</code>.
107      *  @param ft   The font table.
108      *  @param ct   The color Table.
109      */
WseTextRun(String txt, TextStyle t, StyleCatalog sc, WseFontTable ft, WseColorTable ct)110     public WseTextRun(String txt, TextStyle t, StyleCatalog sc,
111                       WseFontTable ft, WseColorTable ct) {
112 
113         this.sc = sc;
114         this.ct = ct;
115 
116         TextStyle ts = (TextStyle)t.getResolved();
117 
118         if (ts.isSet(TextStyle.BOLD) && ts.getAttribute(TextStyle.BOLD))
119             modifiers |= BOLD;
120         if (ts.isSet(TextStyle.ITALIC) && ts.getAttribute(TextStyle.ITALIC))
121             modifiers |= ITALIC;
122         if (ts.isSet(TextStyle.UNDERLINE) && ts.getAttribute(TextStyle.UNDERLINE))
123             modifiers |= UNDERLINE;
124         if (ts.isSet(TextStyle.STRIKETHRU) && ts.getAttribute(TextStyle.STRIKETHRU))
125             modifiers |= STRIKETHRU;
126         if (ts.isSet(TextStyle.SUPERSCRIPT) && ts.getAttribute(TextStyle.SUPERSCRIPT))
127             modifiers |= SUPERSCRIPT;
128         if (ts.isSet(TextStyle.SUBSCRIPT) && ts.getAttribute(TextStyle.SUBSCRIPT))
129             modifiers |= SUBSCRIPT;
130 
131         fontSize = (byte)(ts.getFontSize() * 2);
132         fontName = ts.getFontName();
133         fontIndex = (byte)ft.getFontIndex(fontName);
134         if (fontIndex == -1) {
135             ft.add(fontName);
136             fontIndex = (byte)ft.getFontIndex(fontName);
137         }
138 
139         // Figure out the color index.
140         Color c = t.getFontColor();
141         if (c == null)
142             c = Color.black;
143         colorIndex = (byte)ct.findColor(c, true);
144         c = t.getBackgroundColor();
145         if (c == null)
146             c = Color.white;
147         colorIndex |= (byte)(ct.findColor(c, false) << 4);
148 
149         text = txt;
150     }
151 
152 
153     /**
154      *  Standard constructor for use when going from WordSmith to DOM.
155      *
156      *  @param dataArray   <code>byte</code> array.
157      *  @param startIndex  The start index.
158      *  @param ft          The font table.
159      *  @param ct          The color table.
160      */
WseTextRun(byte dataArray[], int startIndex, WseFontTable ft, WseColorTable ct)161     public WseTextRun(byte dataArray[], int startIndex, WseFontTable ft,
162                       WseColorTable ct) {
163 
164         this.ct = ct;
165 
166         startIndex++;  // Skip the leading "1"
167 
168         int textLen = ((dataArray[startIndex] << 8)
169                       | (dataArray[startIndex+1] & 0xFF));
170         startIndex += 2;
171 
172         fontIndex = dataArray[startIndex++];
173         if (ft != null)
174             fontName = ft.getFontName(fontIndex);
175 
176         fontSize = dataArray[startIndex++];
177 
178         colorIndex = dataArray[startIndex++];
179         modifiers = dataArray[startIndex++];
180 
181         text = new String(dataArray, startIndex, textLen);
182         startIndex += textLen;  // skip the text
183     }
184 
185 
186     /**
187      *  Given a <code>byte</code> sequence, assumed to be a text run,
188      *  compute the index of the first byte past the text run.
189      *
190      *  @param  dataArray   <code>byte</code> array.
191      *  @param  startIndex  The start index
192      *
193      *  @return  The index of the first <code>byte</code> past the
194      *           text run.
195      */
computeNewIndex(byte dataArray[], int startIndex)196     public static int computeNewIndex(byte dataArray[], int startIndex) {
197 
198         startIndex++;  // Skip the leading "1"
199 
200         int textLen = ((dataArray[startIndex] << 8)
201         | (dataArray[startIndex+1] & 0xFF));
202         startIndex += 2;
203 
204         startIndex += 4;  // skip attributes
205         //        text = new String(dataArray, startIndex, textLen);
206         startIndex += textLen;  // skip the text
207         return startIndex;
208     }
209 
210 
211     /**
212      *  Return true if the sequence starting at
213      *  <code>dataArray[startIndex]</code> is a valid text run.
214      *
215      *  @param  dataArray   <code>byte</code> array.
216      *  @param  startIndex  The start index.
217      *
218      *  @return  true if the sequence starting at
219      *           <code>dataArray[startIndex]</code> is a valid
220      *           text run, false otherwise.
221      */
isValid(byte dataArray[], int startIndex)222     public static boolean isValid(byte dataArray[], int startIndex) {
223         return (dataArray[startIndex] == 1);
224     }
225 
226     /**
227      *  Return the number of bytes needed to represent this text run.
228      *
229      *  @return  The number of bytes needed to represent this text run.
230      */
getByteCount()231     int getByteCount() {
232         return text.length() + 7;
233     }
234 
235 
236     /**
237      *  Return an <code>byte</code> array representing this text run.
238      *
239      *  @return  An <code>byte</code> array representing this text run.
240      */
getBytes()241     byte[] getBytes() {
242         short textLen = (short)text.length();
243         byte b[] = new byte[textLen + 7];
244         b[0] = 1;
245         b[1] = (byte)(textLen >> 8);
246         b[2] = (byte)(textLen & 0xFF);
247         b[3] = fontIndex;
248         b[4] = fontSize;
249         b[5] = colorIndex;
250         b[6] = modifiers;
251         byte[] txtBytes = text.getBytes();
252         System.arraycopy(txtBytes, 0, b, 7, textLen);
253         return b;
254     }
255 
256 
257     /**
258      *  Return the text of this run.
259      *
260      *  @return  The text of this run.
261      */
getText()262     public String getText() {
263         return text;
264     }
265 
266 
267     /**
268      *  Return a <code>TextStyle</code> that reflects the formatting
269      *  of this run.
270      *
271      *  @return  A <code>TextStyle</code> that reflects the formatting
272      *           of this run.
273      */
makeStyle()274     public TextStyle makeStyle() {
275         int mod = 0;
276         if ((modifiers & BOLD) != 0) mod |= TextStyle.BOLD;
277         if ((modifiers & ITALIC) != 0) mod |= TextStyle.ITALIC;
278         if ((modifiers & UNDERLINE) != 0) mod |= TextStyle.UNDERLINE;
279         if ((modifiers & STRIKETHRU) != 0)
280             mod |= TextStyle.STRIKETHRU;
281         if ((modifiers & SUPERSCRIPT) != 0) mod |= TextStyle.SUPERSCRIPT;
282         if ((modifiers & SUBSCRIPT) != 0) mod |= TextStyle.SUBSCRIPT;
283 
284         int mask = TextStyle.BOLD | TextStyle.ITALIC
285         | TextStyle.UNDERLINE
286         | TextStyle.STRIKETHRU | TextStyle.SUPERSCRIPT
287         | TextStyle.SUBSCRIPT;
288 
289         TextStyle x = new TextStyle(null, "text", null, mask,
290           mod, (int)(fontSize/2), fontName, sc);
291 
292         // If color table is available, set the colors.
293         if (ct != null) {
294             Color fc = ct.getColor(colorIndex & 0xF, true);
295             Color bc = ct.getColor(colorIndex >> 4, false);
296             x.setColors(fc, bc);
297         }
298 
299         return x;
300     }
301 
302 
303     /**
304      * Display debug information.
305      */
dump()306     public void dump() {
307         System.out.print("TEXT RUN: fontIndex = " + fontIndex
308         + " fontsize = " + fontSize
309         + " colorIndex = " + colorIndex
310         + " ");
311         if ((modifiers & BOLD) != 0) System.out.print("BOLD,");
312         if ((modifiers & ITALIC) != 0) System.out.print("ITALIC,");
313         if ((modifiers & UNDERLINE) != 0) System.out.print("UNDERLINE,");
314         if ((modifiers & STRIKETHRU) != 0) System.out.print("STRIKETHRU,");
315         if ((modifiers & SUPERSCRIPT) != 0) System.out.print("SUPERSCRIPT,");
316         if ((modifiers & SUBSCRIPT) != 0) System.out.print("SUBSCRIPT,");
317         System.out.println("\n" + text);
318     }
319 }
320 
321