You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FontRecord.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hssf.record;
  16. import java.util.Map;
  17. import java.util.Objects;
  18. import java.util.function.Supplier;
  19. import org.apache.poi.util.BitField;
  20. import org.apache.poi.util.BitFieldFactory;
  21. import org.apache.poi.util.GenericRecordUtil;
  22. import org.apache.poi.util.LittleEndianOutput;
  23. import org.apache.poi.util.StringUtil;
  24. /** Describes a font in the workbook */
  25. public final class FontRecord extends StandardRecord {
  26. // docs are wrong (0x231 Microsoft Support site article Q184647)
  27. public static final short sid = 0x0031;
  28. public static final short SS_NONE = 0;
  29. public static final short SS_SUPER = 1;
  30. public static final short SS_SUB = 2;
  31. public static final byte U_NONE = 0;
  32. public static final byte U_SINGLE = 1;
  33. public static final byte U_DOUBLE = 2;
  34. public static final byte U_SINGLE_ACCOUNTING = 0x21;
  35. public static final byte U_DOUBLE_ACCOUNTING = 0x22;
  36. // 0 0x01 - Reserved bit must be 0
  37. // is this font in italics
  38. private static final BitField italic = BitFieldFactory.getInstance(0x02);
  39. // 2 0x04 - reserved bit must be 0
  40. // is this font has a line through the center
  41. private static final BitField strikeout = BitFieldFactory.getInstance(0x08);
  42. // some weird macintosh thing....but who understands those mac people anyhow
  43. private static final BitField macoutline = BitFieldFactory.getInstance(0x10);
  44. private static final BitField macshadow = BitFieldFactory.getInstance(0x20);
  45. // in units of .05 of a point
  46. private short field_1_font_height;
  47. private short field_2_attributes;
  48. // 7-6 - reserved bits must be 0
  49. // the rest is unused
  50. private short field_3_color_palette_index;
  51. private short field_4_bold_weight;
  52. // 00none/01super/02sub
  53. private short field_5_super_sub_script;
  54. // 00none/01single/02double/21singleaccounting/22doubleaccounting
  55. private byte field_6_underline;
  56. // ?? defined by windows api logfont structure?
  57. private byte field_7_family;
  58. // ?? defined by windows api logfont structure?
  59. private byte field_8_charset;
  60. // must be 0
  61. private byte field_9_zero;
  62. /** possibly empty string never <code>null</code> */
  63. private String field_11_font_name;
  64. public FontRecord() {
  65. }
  66. public FontRecord(FontRecord other) {
  67. super(other);
  68. field_1_font_height = other.field_1_font_height;
  69. field_2_attributes = other.field_2_attributes;
  70. field_3_color_palette_index = other.field_3_color_palette_index;
  71. field_4_bold_weight = other.field_4_bold_weight;
  72. field_5_super_sub_script = other.field_5_super_sub_script;
  73. field_6_underline = other.field_6_underline;
  74. field_7_family = other.field_7_family;
  75. field_8_charset = other.field_8_charset;
  76. field_9_zero = other.field_9_zero;
  77. field_11_font_name = other.field_11_font_name;
  78. }
  79. public FontRecord(RecordInputStream in) {
  80. field_1_font_height = in.readShort();
  81. field_2_attributes = in.readShort();
  82. field_3_color_palette_index = in.readShort();
  83. field_4_bold_weight = in.readShort();
  84. field_5_super_sub_script = in.readShort();
  85. field_6_underline = in.readByte();
  86. field_7_family = in.readByte();
  87. field_8_charset = in.readByte();
  88. field_9_zero = in.readByte();
  89. int field_10_font_name_len = in.readUByte();
  90. int unicodeFlags = in.readUByte(); // options byte present always (even if no character data)
  91. if (field_10_font_name_len > 0) {
  92. if (unicodeFlags == 0) { // is compressed unicode
  93. field_11_font_name = in.readCompressedUnicode(field_10_font_name_len);
  94. } else { // is not compressed unicode
  95. field_11_font_name = in.readUnicodeLEString(field_10_font_name_len);
  96. }
  97. } else {
  98. field_11_font_name = "";
  99. }
  100. }
  101. /**
  102. * sets the height of the font in 1/20th point units
  103. *
  104. * @param height fontheight (in points/20)
  105. */
  106. public void setFontHeight(short height) {
  107. field_1_font_height = height;
  108. }
  109. /**
  110. * set the font attributes (see individual bit setters that reference this method)
  111. *
  112. * @param attributes the bitmask to set
  113. */
  114. public void setAttributes(short attributes) {
  115. field_2_attributes = attributes;
  116. }
  117. // attributes bitfields
  118. /**
  119. * set the font to be italics or not
  120. *
  121. * @param italics - whether the font is italics or not
  122. * @see #setAttributes(short)
  123. */
  124. public void setItalic(boolean italics) {
  125. field_2_attributes = italic.setShortBoolean(field_2_attributes, italics);
  126. }
  127. /**
  128. * set the font to be stricken out or not
  129. *
  130. * @param strike - whether the font is stricken out or not
  131. * @see #setAttributes(short)
  132. */
  133. public void setStrikeout(boolean strike) {
  134. field_2_attributes = strikeout.setShortBoolean(field_2_attributes, strike);
  135. }
  136. /**
  137. * whether to use the mac outline font style thing (mac only) - Some mac person
  138. * should comment this instead of me doing it (since I have no idea)
  139. *
  140. * @param mac - whether to do that mac font outline thing or not
  141. * @see #setAttributes(short)
  142. */
  143. public void setMacoutline(boolean mac) {
  144. field_2_attributes = macoutline.setShortBoolean(field_2_attributes, mac);
  145. }
  146. /**
  147. * whether to use the mac shado font style thing (mac only) - Some mac person
  148. * should comment this instead of me doing it (since I have no idea)
  149. *
  150. * @param mac - whether to do that mac font shadow thing or not
  151. * @see #setAttributes(short)
  152. */
  153. public void setMacshadow(boolean mac) {
  154. field_2_attributes = macshadow.setShortBoolean(field_2_attributes, mac);
  155. }
  156. /**
  157. * set the font's color palette index
  158. *
  159. * @param cpi - font color index
  160. */
  161. public void setColorPaletteIndex(short cpi) {
  162. field_3_color_palette_index = cpi;
  163. }
  164. /**
  165. * set the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is
  166. * 0x190 for normal and 0x2bc for bold
  167. *
  168. * @param bw - a number between 100-1000 for the fonts "boldness"
  169. */
  170. public void setBoldWeight(short bw) {
  171. field_4_bold_weight = bw;
  172. }
  173. /**
  174. * set the type of super or subscript for the font
  175. *
  176. * @param sss super or subscript option
  177. * @see #SS_NONE
  178. * @see #SS_SUPER
  179. * @see #SS_SUB
  180. */
  181. public void setSuperSubScript(short sss) {
  182. field_5_super_sub_script = sss;
  183. }
  184. /**
  185. * set the type of underlining for the font
  186. *
  187. * @param u super or subscript option
  188. *
  189. * @see #U_NONE
  190. * @see #U_SINGLE
  191. * @see #U_DOUBLE
  192. * @see #U_SINGLE_ACCOUNTING
  193. * @see #U_DOUBLE_ACCOUNTING
  194. */
  195. public void setUnderline(byte u) {
  196. field_6_underline = u;
  197. }
  198. /**
  199. * set the font family (TODO)
  200. *
  201. * @param f family
  202. */
  203. public void setFamily(byte f) {
  204. field_7_family = f;
  205. }
  206. /**
  207. * set the character set
  208. *
  209. * @param charset - character set
  210. */
  211. public void setCharset(byte charset) {
  212. field_8_charset = charset;
  213. }
  214. /**
  215. * set the name of the font
  216. *
  217. * @param fn - name of the font (i.e. "Arial")
  218. */
  219. public void setFontName(String fn) {
  220. field_11_font_name = fn;
  221. }
  222. /**
  223. * gets the height of the font in 1/20th point units
  224. *
  225. * @return fontheight (in points/20)
  226. */
  227. public short getFontHeight() {
  228. return field_1_font_height;
  229. }
  230. /**
  231. * get the font attributes (see individual bit getters that reference this method)
  232. *
  233. * @return attribute - the bitmask
  234. */
  235. public short getAttributes() {
  236. return field_2_attributes;
  237. }
  238. /**
  239. * get whether the font is to be italics or not
  240. *
  241. * @return italics - whether the font is italics or not
  242. * @see #getAttributes()
  243. */
  244. public boolean isItalic() {
  245. return italic.isSet(field_2_attributes);
  246. }
  247. /**
  248. * get whether the font is to be stricken out or not
  249. *
  250. * @return strike - whether the font is stricken out or not
  251. * @see #getAttributes()
  252. */
  253. public boolean isStruckout(){
  254. return strikeout.isSet(field_2_attributes);
  255. }
  256. /**
  257. * whether to use the mac outline font style thing (mac only) - Some mac person
  258. * should comment this instead of me doing it (since I have no idea)
  259. *
  260. * @return mac - whether to do that mac font outline thing or not
  261. * @see #getAttributes()
  262. */
  263. public boolean isMacoutlined(){
  264. return macoutline.isSet(field_2_attributes);
  265. }
  266. /**
  267. * whether to use the mac shado font style thing (mac only) - Some mac person
  268. * should comment this instead of me doing it (since I have no idea)
  269. *
  270. * @return mac - whether to do that mac font shadow thing or not
  271. * @see #getAttributes()
  272. */
  273. public boolean isMacshadowed(){
  274. return macshadow.isSet(field_2_attributes);
  275. }
  276. /**
  277. * get the font's color palette index
  278. *
  279. * @return cpi - font color index
  280. */
  281. public short getColorPaletteIndex(){
  282. return field_3_color_palette_index;
  283. }
  284. /**
  285. * get the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is
  286. * 0x190 for normal and 0x2bc for bold
  287. *
  288. * @return bw - a number between 100-1000 for the fonts "boldness"
  289. */
  290. public short getBoldWeight(){
  291. return field_4_bold_weight;
  292. }
  293. /**
  294. * get the type of super or subscript for the font
  295. *
  296. * @return super or subscript option
  297. * @see #SS_NONE
  298. * @see #SS_SUPER
  299. * @see #SS_SUB
  300. */
  301. public short getSuperSubScript(){
  302. return field_5_super_sub_script;
  303. }
  304. /**
  305. * get the type of underlining for the font
  306. *
  307. * @return super or subscript option
  308. *
  309. * @see #U_NONE
  310. * @see #U_SINGLE
  311. * @see #U_DOUBLE
  312. * @see #U_SINGLE_ACCOUNTING
  313. * @see #U_DOUBLE_ACCOUNTING
  314. */
  315. public byte getUnderline() {
  316. return field_6_underline;
  317. }
  318. /**
  319. * get the font family (TODO)
  320. *
  321. * @return family
  322. */
  323. public byte getFamily() {
  324. return field_7_family;
  325. }
  326. /**
  327. * get the character set
  328. *
  329. * @return charset - character set
  330. */
  331. public byte getCharset() {
  332. return field_8_charset;
  333. }
  334. /**
  335. * get the name of the font
  336. *
  337. * @return fn - name of the font (i.e. "Arial")
  338. */
  339. public String getFontName() {
  340. return field_11_font_name;
  341. }
  342. public void serialize(LittleEndianOutput out) {
  343. out.writeShort(getFontHeight());
  344. out.writeShort(getAttributes());
  345. out.writeShort(getColorPaletteIndex());
  346. out.writeShort(getBoldWeight());
  347. out.writeShort(getSuperSubScript());
  348. out.writeByte(getUnderline());
  349. out.writeByte(getFamily());
  350. out.writeByte(getCharset());
  351. out.writeByte(field_9_zero);
  352. int fontNameLen = field_11_font_name.length();
  353. out.writeByte(fontNameLen);
  354. boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name);
  355. out.writeByte(hasMultibyte ? 0x01 : 0x00);
  356. if (fontNameLen > 0) {
  357. if (hasMultibyte) {
  358. StringUtil.putUnicodeLE(field_11_font_name, out);
  359. } else {
  360. StringUtil.putCompressedUnicode(field_11_font_name, out);
  361. }
  362. }
  363. }
  364. protected int getDataSize() {
  365. int size = 16; // 5 shorts + 6 bytes
  366. int fontNameLen = field_11_font_name.length();
  367. if (fontNameLen < 1) {
  368. return size;
  369. }
  370. boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name);
  371. return size + fontNameLen * (hasMultibyte ? 2 : 1);
  372. }
  373. public short getSid() {
  374. return sid;
  375. }
  376. /**
  377. * Clones all the font style information from another
  378. * FontRecord, onto this one. This
  379. * will then hold all the same font style options.
  380. *
  381. * @param source the record to clone the properties from
  382. */
  383. public void cloneStyleFrom(FontRecord source) {
  384. field_1_font_height = source.field_1_font_height;
  385. field_2_attributes = source.field_2_attributes;
  386. field_3_color_palette_index = source.field_3_color_palette_index;
  387. field_4_bold_weight = source.field_4_bold_weight;
  388. field_5_super_sub_script = source.field_5_super_sub_script;
  389. field_6_underline = source.field_6_underline;
  390. field_7_family = source.field_7_family;
  391. field_8_charset = source.field_8_charset;
  392. field_9_zero = source.field_9_zero;
  393. field_11_font_name = source.field_11_font_name;
  394. }
  395. public int hashCode() {
  396. return Objects.hash(
  397. field_1_font_height
  398. , field_2_attributes
  399. , field_3_color_palette_index
  400. , field_4_bold_weight
  401. , field_5_super_sub_script
  402. , field_6_underline
  403. , field_7_family
  404. , field_8_charset
  405. , field_9_zero
  406. , field_11_font_name
  407. );
  408. }
  409. /**
  410. * Does this FontRecord have all the same font
  411. * properties as the supplied FontRecord?
  412. * Note that {@link #equals(Object)} will check
  413. * for exact objects, while this will check
  414. * for exact contents, because normally the
  415. * font record's position makes a big
  416. * difference too.
  417. *
  418. * @param other the record to compare with
  419. *
  420. * @return true, if the properties match
  421. */
  422. public boolean sameProperties(FontRecord other) {
  423. return
  424. field_1_font_height == other.field_1_font_height &&
  425. field_2_attributes == other.field_2_attributes &&
  426. field_3_color_palette_index == other.field_3_color_palette_index &&
  427. field_4_bold_weight == other.field_4_bold_weight &&
  428. field_5_super_sub_script == other.field_5_super_sub_script &&
  429. field_6_underline == other.field_6_underline &&
  430. field_7_family == other.field_7_family &&
  431. field_8_charset == other.field_8_charset &&
  432. field_9_zero == other.field_9_zero &&
  433. Objects.equals(this.field_11_font_name, other.field_11_font_name)
  434. ;
  435. }
  436. public boolean equals(Object o) {
  437. return (o instanceof FontRecord) && sameProperties((FontRecord) o);
  438. }
  439. @Override
  440. public FontRecord copy() {
  441. return new FontRecord(this);
  442. }
  443. @Override
  444. public HSSFRecordTypes getGenericRecordType() {
  445. return HSSFRecordTypes.FONT;
  446. }
  447. @Override
  448. public Map<String, Supplier<?>> getGenericProperties() {
  449. return GenericRecordUtil.getGenericProperties(
  450. "fontHeight", this::getFontHeight,
  451. "attributes", GenericRecordUtil.getBitsAsString(this::getAttributes,
  452. new BitField[]{italic,strikeout,macoutline,macshadow},
  453. new String[]{"ITALIC","STRIKEOUT","MACOUTLINE","MACSHADOW"}),
  454. "colorPalette", this::getColorPaletteIndex,
  455. "boldWeight", this::getBoldWeight,
  456. "superSubScript", this::getSuperSubScript,
  457. "underline", this::getUnderline,
  458. "family", this::getFamily,
  459. "charset", this::getCharset,
  460. "fontName", this::getFontName
  461. );
  462. }
  463. }