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