1
2 /* ====================================================================
3 Licensed to the Apache Software Foundation (ASF) under one or more
4 contributor license agreements. See the NOTICE file distributed with
5 this work for additional information regarding copyright ownership.
6 The ASF licenses this file to You under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with
8 the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================== */
18
19
20 package org.apache.poi.hssf.record;
21
22 import org.apache.poi.util.LittleEndian;
23 import org.apache.poi.util.StringUtil;
24 import org.apache.poi.util.BitField;
25 import org.apache.poi.util.BitFieldFactory;
26
27 /**
28 * Title: Font Record - descrbes a font in the workbook (index = 0-3,5-infinity - skip 4)<P>
29 * Description: An element in the Font Table<P>
30 * REFERENCE: PG 315 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
31 * @author Andrew C. Oliver (acoliver at apache dot org)
32 * @version 2.0-pre
33 */
34
35 public class FontRecord
36 extends Record
37 {
38 public final static short sid =
39 0x31; // docs are wrong (0x231 Microsoft Support site article Q184647)
40 public final static short SS_NONE = 0;
41 public final static short SS_SUPER = 1;
42 public final static short SS_SUB = 2;
43 public final static byte U_NONE = 0;
44 public final static byte U_SINGLE = 1;
45 public final static byte U_DOUBLE = 2;
46 public final static byte U_SINGLE_ACCOUNTING = 0x21;
47 public final static byte U_DOUBLE_ACCOUNTING = 0x22;
48 private short field_1_font_height; // in units of .05 of a point
49 private short field_2_attributes;
50
51 // 0 0x01 - Reserved bit must be 0
52 static final private BitField italic =
53 BitFieldFactory.getInstance(0x02); // is this font in italics
54
55 // 2 0x04 - reserved bit must be 0
56 static final private BitField strikeout =
57 BitFieldFactory.getInstance(0x08); // is this font has a line through the center
58 static final private BitField macoutline = BitFieldFactory.getInstance(
59 0x10); // some weird macintosh thing....but who understands those mac people anyhow
60 static final private BitField macshadow = BitFieldFactory.getInstance(
61 0x20); // some weird macintosh thing....but who understands those mac people anyhow
62
63 // 7-6 - reserved bits must be 0
64 // the rest is unused
65 private short field_3_color_palette_index;
66 private short field_4_bold_weight;
67 private short field_5_super_sub_script; // 00none/01super/02sub
68 private byte field_6_underline; // 00none/01single/02double/21singleaccounting/22doubleaccounting
69 private byte field_7_family; // ?? defined by windows api logfont structure?
70 private byte field_8_charset; // ?? defined by windows api logfont structure?
71 private byte field_9_zero = 0; // must be 0
72 private byte field_10_font_name_len; // length of the font name
73 private String field_11_font_name; // whoa...the font name
74
75 public FontRecord()
76 {
77 }
78
79 /**
80 * Constructs a Font record and sets its fields appropriately.
81 *
82 * @param in the RecordInputstream to read the record from
83 */
84
85 public FontRecord(RecordInputStream in)
86 {
87 super(in);
88 }
89
90 protected void validateSid(short id)
91 {
92 if (id != sid)
93 {
94 throw new RecordFormatException("NOT A FONT RECORD");
95 }
96 }
97
98 protected void fillFields(RecordInputStream in)
99 {
100 field_1_font_height = in.readShort();
101 field_2_attributes = in.readShort();
102 field_3_color_palette_index = in.readShort();
103 field_4_bold_weight = in.readShort();
104 field_5_super_sub_script = in.readShort();
105 field_6_underline = in.readByte();
106 field_7_family = in.readByte();
107 field_8_charset = in.readByte();
108 field_9_zero = in.readByte();
109 field_10_font_name_len = in.readByte();
110 if (field_10_font_name_len > 0)
111 {
112 if (in.readByte() == 0)
113 { // is compressed unicode
114 field_11_font_name = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_10_font_name_len));
115 }
116 else
117 { // is not compressed unicode
118 field_11_font_name = in.readUnicodeLEString(field_10_font_name_len);
119 }
120 }
121 }
122
123 /**
124 * sets the height of the font in 1/20th point units
125 *
126 * @param height fontheight (in points/20)
127 */
128
129 public void setFontHeight(short height)
130 {
131 field_1_font_height = height;
132 }
133
134 /**
135 * set the font attributes (see individual bit setters that reference this method)
136 *
137 * @param attributes the bitmask to set
138 */
139
140 public void setAttributes(short attributes)
141 {
142 field_2_attributes = attributes;
143 }
144
145 // attributes bitfields
146
147 /**
148 * set the font to be italics or not
149 *
150 * @param italics - whether the font is italics or not
151 * @see #setAttributes(short)
152 */
153
154 public void setItalic(boolean italics)
155 {
156 field_2_attributes = italic.setShortBoolean(field_2_attributes, italics);
157 }
158
159 /**
160 * set the font to be stricken out or not
161 *
162 * @param strike - whether the font is stricken out or not
163 * @see #setAttributes(short)
164 */
165
166 public void setStrikeout(boolean strike)
167 {
168 field_2_attributes = strikeout.setShortBoolean(field_2_attributes, strike);
169 }
170
171 /**
172 * whether to use the mac outline font style thing (mac only) - Some mac person
173 * should comment this instead of me doing it (since I have no idea)
174 *
175 * @param mac - whether to do that mac font outline thing or not
176 * @see #setAttributes(short)
177 */
178
179 public void setMacoutline(boolean mac)
180 {
181 field_2_attributes = macoutline.setShortBoolean(field_2_attributes, mac);
182 }
183
184 /**
185 * whether to use the mac shado font style thing (mac only) - Some mac person
186 * should comment this instead of me doing it (since I have no idea)
187 *
188 * @param mac - whether to do that mac font shadow thing or not
189 * @see #setAttributes(short)
190 */
191
192 public void setMacshadow(boolean mac)
193 {
194 field_2_attributes = macshadow.setShortBoolean(field_2_attributes, mac);
195 }
196
197 /**
198 * set the font's color palette index
199 *
200 * @param cpi - font color index
201 */
202
203 public void setColorPaletteIndex(short cpi)
204 {
205 field_3_color_palette_index = cpi;
206 }
207
208 /**
209 * set the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is
210 * 0x190 for normal and 0x2bc for bold
211 *
212 * @param bw - a number between 100-1000 for the fonts "boldness"
213 */
214
215 public void setBoldWeight(short bw)
216 {
217 field_4_bold_weight = bw;
218 }
219
220 /**
221 * set the type of super or subscript for the font
222 *
223 * @param sss super or subscript option
224 * @see #SS_NONE
225 * @see #SS_SUPER
226 * @see #SS_SUB
227 */
228
229 public void setSuperSubScript(short sss)
230 {
231 field_5_super_sub_script = sss;
232 }
233
234 /**
235 * set the type of underlining for the font
236 *
237 * @param u super or subscript option
238 *
239 * @see #U_NONE
240 * @see #U_SINGLE
241 * @see #U_DOUBLE
242 * @see #U_SINGLE_ACCOUNTING
243 * @see #U_DOUBLE_ACCOUNTING
244 */
245
246 public void setUnderline(byte u)
247 {
248 field_6_underline = u;
249 }
250
251 /**
252 * set the font family (TODO)
253 *
254 * @param f family
255 */
256
257 public void setFamily(byte f)
258 {
259 field_7_family = f;
260 }
261
262 /**
263 * set the character set
264 *
265 * @param charset - characterset
266 */
267
268 public void setCharset(byte charset)
269 {
270 field_8_charset = charset;
271 }
272
273 /**
274 * set the length of the fontname string
275 *
276 * @param len length of the font name
277 * @see #setFontName(String)
278 */
279
280 public void setFontNameLength(byte len)
281 {
282 field_10_font_name_len = len;
283 }
284
285 /**
286 * set the name of the font
287 *
288 * @param fn - name of the font (i.e. "Arial")
289 */
290
291 public void setFontName(String fn)
292 {
293 field_11_font_name = fn;
294 }
295
296 /**
297 * gets the height of the font in 1/20th point units
298 *
299 * @return fontheight (in points/20)
300 */
301
302 public short getFontHeight()
303 {
304 return field_1_font_height;
305 }
306
307 /**
308 * get the font attributes (see individual bit getters that reference this method)
309 *
310 * @return attribute - the bitmask
311 */
312
313 public short getAttributes()
314 {
315 return field_2_attributes;
316 }
317
318 /**
319 * get whether the font is to be italics or not
320 *
321 * @return italics - whether the font is italics or not
322 * @see #getAttributes()
323 */
324
325 public boolean isItalic()
326 {
327 return italic.isSet(field_2_attributes);
328 }
329
330 /**
331 * get whether the font is to be stricken out or not
332 *
333 * @return strike - whether the font is stricken out or not
334 * @see #getAttributes()
335 */
336
337 public boolean isStruckout()
338 {
339 return strikeout.isSet(field_2_attributes);
340 }
341
342 /**
343 * whether to use the mac outline font style thing (mac only) - Some mac person
344 * should comment this instead of me doing it (since I have no idea)
345 *
346 * @return mac - whether to do that mac font outline thing or not
347 * @see #getAttributes()
348 */
349
350 public boolean isMacoutlined()
351 {
352 return macoutline.isSet(field_2_attributes);
353 }
354
355 /**
356 * whether to use the mac shado font style thing (mac only) - Some mac person
357 * should comment this instead of me doing it (since I have no idea)
358 *
359 * @return mac - whether to do that mac font shadow thing or not
360 * @see #getAttributes()
361 */
362
363 public boolean isMacshadowed()
364 {
365 return macshadow.isSet(field_2_attributes);
366 }
367
368 /**
369 * get the font's color palette index
370 *
371 * @return cpi - font color index
372 */
373
374 public short getColorPaletteIndex()
375 {
376 return field_3_color_palette_index;
377 }
378
379 /**
380 * get the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is
381 * 0x190 for normal and 0x2bc for bold
382 *
383 * @return bw - a number between 100-1000 for the fonts "boldness"
384 */
385
386 public short getBoldWeight()
387 {
388 return field_4_bold_weight;
389 }
390
391 /**
392 * get the type of super or subscript for the font
393 *
394 * @return super or subscript option
395 * @see #SS_NONE
396 * @see #SS_SUPER
397 * @see #SS_SUB
398 */
399
400 public short getSuperSubScript()
401 {
402 return field_5_super_sub_script;
403 }
404
405 /**
406 * get the type of underlining for the font
407 *
408 * @return super or subscript option
409 *
410 * @see #U_NONE
411 * @see #U_SINGLE
412 * @see #U_DOUBLE
413 * @see #U_SINGLE_ACCOUNTING
414 * @see #U_DOUBLE_ACCOUNTING
415 */
416
417 public byte getUnderline()
418 {
419 return field_6_underline;
420 }
421
422 /**
423 * get the font family (TODO)
424 *
425 * @return family
426 */
427
428 public byte getFamily()
429 {
430 return field_7_family;
431 }
432
433 /**
434 * get the character set
435 *
436 * @return charset - characterset
437 */
438
439 public byte getCharset()
440 {
441 return field_8_charset;
442 }
443
444 /**
445 * get the length of the fontname string
446 *
447 * @return length of the font name
448 * @see #getFontName()
449 */
450
451 public byte getFontNameLength()
452 {
453 return field_10_font_name_len;
454 }
455
456 /**
457 * get the name of the font
458 *
459 * @return fn - name of the font (i.e. "Arial")
460 */
461
462 public String getFontName()
463 {
464 return field_11_font_name;
465 }
466
467 public String toString()
468 {
469 StringBuffer buffer = new StringBuffer();
470
471 buffer.append("[FONT]\n");
472 buffer.append(" .fontheight = ")
473 .append(Integer.toHexString(getFontHeight())).append("\n");
474 buffer.append(" .attributes = ")
475 .append(Integer.toHexString(getAttributes())).append("\n");
476 buffer.append(" .italic = ").append(isItalic())
477 .append("\n");
478 buffer.append(" .strikout = ").append(isStruckout())
479 .append("\n");
480 buffer.append(" .macoutlined= ").append(isMacoutlined())
481 .append("\n");
482 buffer.append(" .macshadowed= ").append(isMacshadowed())
483 .append("\n");
484 buffer.append(" .colorpalette = ")
485 .append(Integer.toHexString(getColorPaletteIndex())).append("\n");
486 buffer.append(" .boldweight = ")
487 .append(Integer.toHexString(getBoldWeight())).append("\n");
488 buffer.append(" .supersubscript = ")
489 .append(Integer.toHexString(getSuperSubScript())).append("\n");
490 buffer.append(" .underline = ")
491 .append(Integer.toHexString(getUnderline())).append("\n");
492 buffer.append(" .family = ")
493 .append(Integer.toHexString(getFamily())).append("\n");
494 buffer.append(" .charset = ")
495 .append(Integer.toHexString(getCharset())).append("\n");
496 buffer.append(" .namelength = ")
497 .append(Integer.toHexString(getFontNameLength())).append("\n");
498 buffer.append(" .fontname = ").append(getFontName())
499 .append("\n");
500 buffer.append("[/FONT]\n");
501 return buffer.toString();
502 }
503
504 public int serialize(int offset, byte [] data)
505 {
506 int realflen = getFontNameLength() * 2;
507
508 LittleEndian.putShort(data, 0 + offset, sid);
509 LittleEndian.putShort(
510 data, 2 + offset,
511 ( short ) (15 + realflen
512 + 1)); // 19 - 4 (sid/len) + font name length = datasize
513
514 // undocumented single byte (1)
515 LittleEndian.putShort(data, 4 + offset, getFontHeight());
516 LittleEndian.putShort(data, 6 + offset, getAttributes());
517 LittleEndian.putShort(data, 8 + offset, getColorPaletteIndex());
518 LittleEndian.putShort(data, 10 + offset, getBoldWeight());
519 LittleEndian.putShort(data, 12 + offset, getSuperSubScript());
520 data[ 14 + offset ] = getUnderline();
521 data[ 15 + offset ] = getFamily();
522 data[ 16 + offset ] = getCharset();
523 data[ 17 + offset ] = field_9_zero;
524 data[ 18 + offset ] = getFontNameLength();
525 data[ 19 + offset ] = ( byte ) 1;
526 if (getFontName() != null) {
527 StringUtil.putUnicodeLE(getFontName(), data, 20 + offset);
528 }
529 return getRecordSize();
530 }
531
532 public int getRecordSize()
533 {
534 return (getFontNameLength() * 2) + 20;
535 }
536
537 public short getSid()
538 {
539 return sid;
540 }
541
542 public int hashCode() {
543 final int prime = 31;
544 int result = 1;
545 result = prime
546 * result
547 + ((field_11_font_name == null) ? 0 : field_11_font_name
548 .hashCode());
549 result = prime * result + field_1_font_height;
550 result = prime * result + field_2_attributes;
551 result = prime * result + field_3_color_palette_index;
552 result = prime * result + field_4_bold_weight;
553 result = prime * result + field_5_super_sub_script;
554 result = prime * result + field_6_underline;
555 result = prime * result + field_7_family;
556 result = prime * result + field_8_charset;
557 result = prime * result + field_9_zero;
558 result = prime * result + field_10_font_name_len;
559 return result;
560 }
561
562 /**
563 * Only returns two for the same exact object -
564 * creating a second FontRecord with the same
565 * properties won't be considered equal, as
566 * the record's position in the record stream
567 * matters.
568 */
569 public boolean equals(Object obj) {
570 if (this == obj)
571 return true;
572 return false;
573 }
574 }