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.

PDFStructElem.java 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.pdf;
  19. import java.io.IOException;
  20. import java.io.OutputStream;
  21. import java.util.ArrayList;
  22. import java.util.List;
  23. import java.util.Locale;
  24. import org.apache.fop.accessibility.StructureTreeElement;
  25. import org.apache.fop.pdf.StandardStructureAttributes.Table;
  26. import org.apache.fop.util.LanguageTags;
  27. /**
  28. * Class representing a PDF Structure Element.
  29. */
  30. public class PDFStructElem extends StructureHierarchyMember
  31. implements StructureTreeElement, CompressedObject {
  32. private StructureType structureType;
  33. private PDFStructElem parentElement;
  34. /**
  35. * Elements to be added to the kids array.
  36. */
  37. protected List<PDFObject> kids;
  38. private List<PDFDictionary> attributes;
  39. /**
  40. * Creates a new structure element.
  41. *
  42. * @param parent parent of this element
  43. * @param structureType the structure type of this element
  44. */
  45. public PDFStructElem(PDFObject parent, StructureType structureType) {
  46. this(parent);
  47. this.structureType = structureType;
  48. put("S", structureType.getName());
  49. setParent(parent);
  50. }
  51. private PDFStructElem(PDFObject parent) {
  52. if (parent instanceof PDFStructElem) {
  53. parentElement = (PDFStructElem) parent;
  54. }
  55. }
  56. /**
  57. * Returns the parent of this structure element.
  58. *
  59. * @return the parent, <code>null</code> if the parent is not a structure
  60. * element (i.e., is the structure tree root)
  61. */
  62. public PDFStructElem getParentStructElem() {
  63. return parentElement;
  64. }
  65. /** {@inheritDoc} */
  66. public void setParent(PDFObject parent) {
  67. if (parent != null && parent.hasObjectNumber()) {
  68. put("P", new PDFReference(parent));
  69. }
  70. }
  71. /**
  72. * Adds a kid to this structure element.
  73. *
  74. * @param kid element to be added
  75. */
  76. @Override
  77. public void addKid(PDFObject kid) {
  78. if (kids == null) {
  79. kids = new ArrayList<PDFObject>();
  80. }
  81. kids.add(kid);
  82. }
  83. /**
  84. * Sets the given mcid as the kid of this structure element. This element
  85. * will then add itself to its parent structure element if it has not
  86. * already, and so will the parent, and so on.
  87. *
  88. * @param mcid mcid of the marked-content sequence corresponding to this
  89. * structure element's kid
  90. */
  91. public void setMCIDKid(int mcid) {
  92. put("K", mcid);
  93. }
  94. /**
  95. * Sets the page reference of this structure element.
  96. *
  97. * @param page value for the Pg entry
  98. */
  99. public void setPage(PDFPage page) {
  100. put("Pg", page);
  101. }
  102. /**
  103. * Returns the structure type of this structure element.
  104. *
  105. * @return the value of the S entry
  106. */
  107. public StructureType getStructureType() {
  108. return structureType;
  109. }
  110. /**
  111. * Sets the language of this structure element.
  112. * @param language the language (as defined in the section about
  113. * "Natural Language Specification")
  114. */
  115. private void setLanguage(String language) {
  116. put("Lang", language);
  117. }
  118. /**
  119. * Sets the language of this structure element.
  120. *
  121. * @param language a value for the Lang entry
  122. */
  123. public void setLanguage(Locale language) {
  124. setLanguage(LanguageTags.toLanguageTag(language));
  125. }
  126. /**
  127. * Returns the language of this structure element.
  128. *
  129. * @return the value of the Lang entry (<code>null</code> if no language was specified)
  130. */
  131. public String getLanguage() {
  132. return (String) get("Lang");
  133. }
  134. @Override
  135. protected void writeDictionary(OutputStream out, StringBuilder textBuffer) throws IOException {
  136. attachKids();
  137. attachAttributes();
  138. super.writeDictionary(out, textBuffer);
  139. }
  140. private void attachAttributes() {
  141. if (attributes != null) {
  142. if (attributes.size() == 1) {
  143. put("A", attributes.get(0));
  144. } else {
  145. PDFArray array = new PDFArray(attributes);
  146. put("A", array);
  147. }
  148. }
  149. }
  150. /**
  151. * Attaches all valid kids to the kids array.
  152. *
  153. * @return true iff 1+ kids were added to the kids array
  154. */
  155. protected boolean attachKids() {
  156. List<PDFObject> validKids = new ArrayList<PDFObject>();
  157. if (kids != null) {
  158. for (PDFObject kid : kids) {
  159. if (kid instanceof Placeholder) {
  160. if (((Placeholder) kid).attachKids()) {
  161. validKids.add(kid);
  162. }
  163. } else {
  164. validKids.add(kid);
  165. }
  166. }
  167. }
  168. boolean kidsAttached = !validKids.isEmpty();
  169. if (kidsAttached) {
  170. PDFArray array = new PDFArray();
  171. for (PDFObject ob : validKids) {
  172. array.add(ob);
  173. }
  174. put("K", array);
  175. }
  176. return kidsAttached;
  177. }
  178. public void setTableAttributeColSpan(int colSpan) {
  179. setTableAttributeRowColumnSpan("ColSpan", colSpan);
  180. }
  181. public void setTableAttributeRowSpan(int rowSpan) {
  182. setTableAttributeRowColumnSpan("RowSpan", rowSpan);
  183. }
  184. private void setTableAttributeRowColumnSpan(String typeSpan, int span) {
  185. PDFDictionary attribute = new PDFDictionary();
  186. attribute.put("O", Table.NAME);
  187. attribute.put(typeSpan, span);
  188. if (attributes == null) {
  189. attributes = new ArrayList<PDFDictionary>(2);
  190. }
  191. attributes.add(attribute);
  192. }
  193. /**
  194. * Class representing a placeholder for a PDF Structure Element.
  195. */
  196. public static class Placeholder extends PDFStructElem {
  197. @Override
  198. public void outputInline(OutputStream out, StringBuilder textBuffer) throws IOException {
  199. if (kids != null) {
  200. assert kids.size() > 0;
  201. for (int i = 0; i < kids.size(); i++) {
  202. if (i > 0) {
  203. textBuffer.append(' ');
  204. }
  205. Object obj = kids.get(i);
  206. formatObject(obj, out, textBuffer);
  207. }
  208. }
  209. }
  210. public Placeholder(PDFObject parent) {
  211. super(parent);
  212. }
  213. }
  214. }