1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.render.pdf;
import org.apache.fop.pdf.PDFArray;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFParentTree;
import org.apache.fop.pdf.PDFStructElem;
/**
* Handles the creation of the logical structure in the PDF document.
*/
class PDFLogicalStructureHandler {
private static final PDFName MCR = new PDFName("MCR");
private static final PDFName OBJR = new PDFName("OBJR");
private static final MarkedContentInfo ARTIFACT = new MarkedContentInfo(null, -1, null);
private final PDFDocument pdfDoc;
private final PDFParentTree parentTree = new PDFParentTree();
private int parentTreeKey;
private PDFPage currentPage;
/**
* The array of references, from marked-content sequences in the current
* page, to their parent structure elements. This will be a value in the
* structure parent tree, whose corresponding key will be the page's
* StructParents entry.
*/
private PDFArray pageParentTreeArray;
/**
* Class providing the necessary information for bracketing content
* associated to a structure element as a marked-content sequence.
*/
static final class MarkedContentInfo {
/**
* A value that can be used for the tag operand of a marked-content
* operator. This is the structure type of the corresponding structure
* element.
*/
final String tag;
/**
* The value for the MCID entry of the marked-content sequence's property list.
*/
final int mcid;
private final PDFStructElem parent;
private MarkedContentInfo(String tag, int mcid, PDFStructElem parent) {
this.tag = tag;
this.mcid = mcid;
this.parent = parent;
}
}
/**
* Creates a new instance for handling the logical structure of the given document.
*
* @param pdfDoc a document
*/
PDFLogicalStructureHandler(PDFDocument pdfDoc) {
this.pdfDoc = pdfDoc;
}
PDFParentTree getParentTree() {
return parentTree;
}
private int getNextParentTreeKey() {
return parentTreeKey++;
}
/**
* Receive notification of the beginning of a new page.
*
* @param page the page that will be rendered in PDF
*/
void startPage(PDFPage page) {
currentPage = page;
currentPage.setStructParents(getNextParentTreeKey());
pageParentTreeArray = new PDFArray();
}
/**
* Receive notification of the end of the current page.
*/
void endPage() {
// TODO
// Values in a number tree must be indirect references to the PDF
// objects associated to the keys. To enforce that the array is
// registered to the PDF document. Unfortunately that can't be done
// earlier since a call to PDFContentGenerator.flushPDFDoc can be made
// before the array is complete, which would result in only part of it
// being output to the PDF.
// This should really be handled by PDFNumsArray
pdfDoc.registerObject(pageParentTreeArray);
parentTree.addToNums(currentPage.getStructParents(), pageParentTreeArray);
}
private MarkedContentInfo addToParentTree(PDFStructElem structureTreeElement) {
PDFStructElem parent = structureTreeElement;
while (parent instanceof PDFStructElem.Placeholder) {
parent = parent.getParentStructElem();
}
pageParentTreeArray.add(parent);
String type = parent.getStructureType().getName().toString();
int mcid = pageParentTreeArray.length() - 1;
return new MarkedContentInfo(type, mcid, structureTreeElement);
}
/**
* Adds a content item corresponding to text into the structure tree, if
* there is a structure element associated to it.
*
* @param structElem the parent structure element of the piece of text
* @return the necessary information for bracketing the content as a
* marked-content sequence. If there is no element in the structure tree
* associated to that content, returns an instance whose
* {@link MarkedContentInfo#tag} value is <code>null</code>. The content
* must then be treated as an artifact.
*/
MarkedContentInfo addTextContentItem(PDFStructElem structElem) {
if (structElem == null) {
return ARTIFACT;
} else {
MarkedContentInfo mci = addToParentTree(structElem);
PDFDictionary contentItem = new PDFDictionary();
contentItem.put("Type", MCR);
contentItem.put("Pg", this.currentPage);
contentItem.put("MCID", mci.mcid);
mci.parent.addKid(contentItem);
return mci;
}
}
/**
* Adds a content item corresponding to an image into the structure tree, if
* there is a structure element associated to it.
*
* @param structElem the parent structure element of the image
* @return the necessary information for bracketing the content as a
* marked-content sequence. If there is no element in the structure tree
* associated to that image, returns an instance whose
* {@link MarkedContentInfo#tag} value is <code>null</code>. The image must
* then be treated as an artifact.
*/
MarkedContentInfo addImageContentItem(PDFStructElem structElem) {
if (structElem == null) {
return ARTIFACT;
} else {
MarkedContentInfo mci = addToParentTree(structElem);
mci.parent.setMCIDKid(mci.mcid);
mci.parent.setPage(this.currentPage);
return mci;
}
}
/**
* Adds a content item corresponding to the given link into the structure
* tree.
*
* @param link a link
* @param structureTreeElement its parent structure element
*/
void addLinkContentItem(PDFLink link, PDFStructElem structureTreeElement) {
int structParent = getNextParentTreeKey();
link.setStructParent(structParent);
PDFDictionary contentItem = new PDFDictionary();
contentItem.put("Type", OBJR);
contentItem.put("Pg", this.currentPage);
contentItem.put("Obj", link);
parentTree.addToNums(structParent, structureTreeElement);
structureTreeElement.addKid(contentItem);
}
}
|