1022
// in src/sandbox/org/apache/fop/render/svg/SVGRenderer.java
public void startRenderer(OutputStream outputStream) throws IOException {
this.firstOutputStream = outputStream;
this.multiFileUtil = new MultiFileRenderingUtil(SVG_FILE_EXTENSION,
getUserAgent().getOutputFile());
super.startRenderer(this.firstOutputStream);
}
// in src/sandbox/org/apache/fop/render/svg/SVGRenderer.java
public void renderPage(PageViewport pageViewport) throws IOException {
log.debug("Rendering page: " + pageViewport.getPageNumberString());
// Get a DOMImplementation
DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
// Create an instance of org.w3c.dom.Document
this.document = domImpl.createDocument(null, "svg", null);
// Create an SVGGeneratorContext to customize SVG generation
SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(this.document);
ctx.setComment("Generated by " + userAgent.getProducer() + " with Batik SVG Generator");
ctx.setEmbeddedFontsOn(true);
// Create an instance of the SVG Generator
this.svgGenerator = new SVGGraphics2D(ctx, true);
Rectangle2D viewArea = pageViewport.getViewArea();
Dimension dim = new Dimension();
dim.setSize(viewArea.getWidth() / 1000, viewArea.getHeight() / 1000);
this.svgGenerator.setSVGCanvasSize(dim);
AffineTransform at = this.svgGenerator.getTransform();
this.state = new Java2DGraphicsState(this.svgGenerator, this.fontInfo, at);
try {
//super.renderPage(pageViewport);
renderPageAreas(pageViewport.getPage());
} finally {
this.state = null;
}
writeSVGFile(pageViewport.getPageIndex());
this.svgGenerator = null;
this.document = null;
}
// in src/sandbox/org/apache/fop/render/svg/SVGRenderer.java
public void stopRenderer() throws IOException {
super.stopRenderer();
// Cleaning
clearViewportList();
log.debug("SVG generation complete.");
}
// in src/sandbox/org/apache/fop/render/svg/SVGRenderer.java
private void writeSVGFile(int pageNumber) throws IOException {
log.debug("Writing out SVG file...");
// Finally, stream out SVG to the standard output using UTF-8
// character to byte encoding
boolean useCSS = true; // we want to use CSS style attribute
OutputStream out = getCurrentOutputStream(pageNumber);
if (out == null) {
log.warn("No filename information available."
+ " Stopping early after the first page.");
return;
}
try {
Writer writer = new java.io.OutputStreamWriter(out, "UTF-8");
this.svgGenerator.stream(writer, useCSS);
} finally {
if (out != this.firstOutputStream) {
IOUtils.closeQuietly(out);
} else {
out.flush();
}
}
}
// in src/sandbox/org/apache/fop/render/svg/SVGRenderer.java
protected OutputStream getCurrentOutputStream(int pageNumber) throws IOException {
if (pageNumber == 0) {
return firstOutputStream;
} else {
return multiFileUtil.createOutputStream(pageNumber);
}
}
// in src/sandbox/org/apache/fop/render/svg/SVGDataUrlImageHandler.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
SVGRenderingContext svgContext = (SVGRenderingContext)context;
ImageRawStream raw = (ImageRawStream)image;
InputStream in = raw.createInputStream();
try {
ContentHandler handler = svgContext.getContentHandler();
String url = DataURLUtil.createDataURL(in, raw.getMimeType());
AttributesImpl atts = new AttributesImpl();
addAttribute(atts, IFConstants.XLINK_HREF, url);
atts.addAttribute("", "x", "x", CDATA, Integer.toString(pos.x));
atts.addAttribute("", "y", "y", CDATA, Integer.toString(pos.y));
atts.addAttribute("", "width", "width", CDATA, Integer.toString(pos.width));
atts.addAttribute("", "height", "height", CDATA, Integer.toString(pos.height));
try {
handler.startElement(NAMESPACE, "image", "image", atts);
handler.endElement(NAMESPACE, "image", "image");
} catch (SAXException e) {
throw new IOException(e.getMessage());
}
} finally {
IOUtils.closeQuietly(in);
}
}
// in src/sandbox/org/apache/fop/render/svg/EmbeddedSVGImageHandler.java
public void handleImage(RenderingContext context, Image image, final Rectangle pos)
throws IOException {
SVGRenderingContext svgContext = (SVGRenderingContext)context;
ImageXMLDOM svg = (ImageXMLDOM)image;
ContentHandler handler = svgContext.getContentHandler();
AttributesImpl atts = new AttributesImpl();
atts.addAttribute("", "x", "x", CDATA, SVGUtil.formatMptToPt(pos.x));
atts.addAttribute("", "y", "y", CDATA, SVGUtil.formatMptToPt(pos.y));
atts.addAttribute("", "width", "width", CDATA, SVGUtil.formatMptToPt(pos.width));
atts.addAttribute("", "height", "height", CDATA, SVGUtil.formatMptToPt(pos.height));
try {
Document doc = (Document)svg.getDocument();
Element svgEl = (Element)doc.getDocumentElement();
if (svgEl.getAttribute("viewBox").length() == 0) {
log.warn("SVG doesn't have a viewBox. The result might not be scaled correctly!");
}
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource src = new DOMSource(svg.getDocument());
SAXResult res = new SAXResult(new DelegatingFragmentContentHandler(handler) {
private boolean topLevelSVGFound = false;
private void setAttribute(AttributesImpl atts, String localName, String value) {
int index;
index = atts.getIndex("", localName);
if (index < 0) {
atts.addAttribute("", localName, localName, CDATA, value);
} else {
atts.setAttribute(index, "", localName, localName, CDATA, value);
}
}
public void startElement(String uri, String localName, String name, Attributes atts)
throws SAXException {
if (!topLevelSVGFound
&& SVG_ELEMENT.getNamespaceURI().equals(uri)
&& SVG_ELEMENT.getLocalName().equals(localName)) {
topLevelSVGFound = true;
AttributesImpl modAtts = new AttributesImpl(atts);
setAttribute(modAtts, "x", SVGUtil.formatMptToPt(pos.x));
setAttribute(modAtts, "y", SVGUtil.formatMptToPt(pos.y));
setAttribute(modAtts, "width", SVGUtil.formatMptToPt(pos.width));
setAttribute(modAtts, "height", SVGUtil.formatMptToPt(pos.height));
super.startElement(uri, localName, name, modAtts);
} else {
super.startElement(uri, localName, name, atts);
}
}
});
transformer.transform(src, res);
} catch (TransformerException te) {
throw new IOException(te.getMessage());
}
}
// in src/sandbox/org/apache/fop/render/mif/MIFFile.java
public void output(OutputStream os) throws IOException {
if (finished) {
return;
}
if (!started) {
os.write(("<MIFFile 5.00> # Generated by FOP\n"/* + getVersion()*/).getBytes());
started = true;
}
boolean done = true;
for (Iterator iter = valueElements.iterator(); iter.hasNext();) {
MIFElement el = (MIFElement)iter.next();
boolean d = el.output(os, 0);
if (d) {
iter.remove();
} else {
done = false;
break;
}
}
if (done && finish) {
os.write(("# end of MIFFile").getBytes());
}
}
// in src/sandbox/org/apache/fop/render/mif/MIFElement.java
public boolean output(OutputStream os, int indent) throws IOException {
if (finished) {
return true;
}
if (valueElements == null && valueStr == null) {
return false;
}
String indentStr = "";
for (int c = 0; c < indent; c++) {
indentStr += " ";
}
if (!started) {
os.write((indentStr + "<" + name).getBytes());
if (valueElements != null) {
os.write(("\n").getBytes());
}
started = true;
}
if (valueElements != null) {
boolean done = true;
for (Iterator iter = valueElements.iterator(); iter.hasNext();) {
MIFElement el = (MIFElement)iter.next();
boolean d = el.output(os, indent + 1);
if (d) {
iter.remove();
} else {
done = false;
break;
}
}
if (!finish || !done) {
return false;
}
os.write((indentStr + "> # end of " + name + "\n").getBytes());
} else {
os.write((" " + valueStr + ">\n").getBytes());
}
finished = true;
return true;
}
// in src/java/org/apache/fop/apps/FopFactory.java
public void setUserConfig(File userConfigFile) throws SAXException, IOException {
config.setUserConfig(userConfigFile);
}
// in src/java/org/apache/fop/apps/FopFactory.java
public void setUserConfig(String uri) throws SAXException, IOException {
config.setUserConfig(uri);
}
// in src/java/org/apache/fop/apps/FopFactoryConfigurator.java
public void setUserConfig(File userConfigFile) throws SAXException, IOException {
try {
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
setUserConfig(cfgBuilder.buildFromFile(userConfigFile));
} catch (ConfigurationException e) {
throw new FOPException(e);
}
}
// in src/java/org/apache/fop/apps/FopFactoryConfigurator.java
public void setUserConfig(String uri) throws SAXException, IOException {
try {
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
setUserConfig(cfgBuilder.build(uri));
} catch (ConfigurationException e) {
throw new FOPException(e);
}
}
// in src/java/org/apache/fop/pdf/PDFEncryptionJCE.java
public OutputStream applyFilter(OutputStream out) throws IOException {
byte[] key = createEncryptionKey(streamNumber, streamGeneration);
Cipher cipher = initCipher(key);
return new CipherOutputStream(out, cipher);
}
// in src/java/org/apache/fop/pdf/PDFCMap.java
public int output(OutputStream stream) throws IOException {
CMapBuilder builder = createCMapBuilder(getBufferWriter());
builder.writeCMap();
return super.output(stream);
}
// in src/java/org/apache/fop/pdf/PDFObject.java
public int output(OutputStream stream) throws IOException {
byte[] pdf = this.toPDF();
stream.write(pdf);
return pdf.length;
}
// in src/java/org/apache/fop/pdf/PDFObject.java
public void outputInline(OutputStream out, Writer writer) throws IOException {
throw new UnsupportedOperationException("Don't use anymore: " + getClass().getName());
}
// in src/java/org/apache/fop/pdf/PDFObject.java
public void outputInline(OutputStream out, StringBuilder textBuffer) throws IOException {
if (hasObjectNumber()) {
textBuffer.append(referencePDF());
} else {
PDFDocument.flushTextBuffer(textBuffer, out);
output(out);
}
}
// in src/java/org/apache/fop/pdf/PDFObject.java
protected void encodeBinaryToHexString(byte[] data, OutputStream out) throws IOException {
out.write('<');
if (getDocumentSafely().isEncryptionActive()) {
data = getDocument().getEncryption().encrypt(data, this);
}
String hex = PDFText.toHex(data, false);
byte[] encoded = hex.getBytes("US-ASCII");
out.write(encoded);
out.write('>');
}
// in src/java/org/apache/fop/pdf/PDFObject.java
protected void formatObject(Object obj, OutputStream out, StringBuilder textBuffer)
throws IOException {
if (obj == null) {
textBuffer.append("null");
} else if (obj instanceof PDFWritable) {
((PDFWritable)obj).outputInline(out, textBuffer);
} else if (obj instanceof Number) {
if (obj instanceof Double || obj instanceof Float) {
textBuffer.append(PDFNumber.doubleOut(((Number)obj).doubleValue()));
} else {
textBuffer.append(obj.toString());
}
} else if (obj instanceof Boolean) {
textBuffer.append(obj.toString());
} else if (obj instanceof byte[]) {
PDFDocument.flushTextBuffer(textBuffer, out);
encodeBinaryToHexString((byte[])obj, out);
} else {
PDFDocument.flushTextBuffer(textBuffer, out);
out.write(encodeText(obj.toString()));
}
}
// in src/java/org/apache/fop/pdf/PDFFormXObject.java
public void setData(byte[] data) throws IOException {
this.contents.setData(data);
}
// in src/java/org/apache/fop/pdf/PDFFormXObject.java
protected void outputRawStreamData(OutputStream out) throws IOException {
contents.outputRawStreamData(out);
}
// in src/java/org/apache/fop/pdf/PDFFormXObject.java
public int output(OutputStream stream) throws IOException {
final int len = super.output(stream);
//Now that the data has been written, it can be discarded.
this.contents = null;
return len;
}
// in src/java/org/apache/fop/pdf/PDFRoot.java
public int output(OutputStream stream) throws IOException {
getDocument().getProfile().verifyTaggedPDF();
return super.output(stream);
}
// in src/java/org/apache/fop/pdf/ASCII85Filter.java
public OutputStream applyFilter(OutputStream out) throws IOException {
if (isApplied()) {
return out;
} else {
return new ASCII85OutputStream(out);
}
}
// in src/java/org/apache/fop/pdf/PDFRectangle.java
public void outputInline(OutputStream out, StringBuilder textBuffer) throws IOException {
format(textBuffer);
}
// in src/java/org/apache/fop/pdf/PDFPattern.java
public int output(OutputStream stream) throws IOException {
int vectorSize = 0;
int tempInt = 0;
byte[] buffer;
StringBuffer p = new StringBuffer(64);
p.append("<< \n/Type /Pattern \n");
if (this.resources != null) {
p.append("/Resources " + this.resources.referencePDF() + " \n");
}
p.append("/PatternType " + this.patternType + " \n");
PDFStream pdfStream = null;
StreamCache encodedStream = null;
if (this.patternType == 1) {
p.append("/PaintType " + this.paintType + " \n");
p.append("/TilingType " + this.tilingType + " \n");
if (this.bBox != null) {
vectorSize = this.bBox.size();
p.append("/BBox [ ");
for (tempInt = 0; tempInt < vectorSize; tempInt++) {
p.append(PDFNumber.doubleOut((Double)this.bBox.get(tempInt)));
p.append(" ");
}
p.append("] \n");
}
p.append("/XStep " + PDFNumber.doubleOut(new Double(this.xStep))
+ " \n");
p.append("/YStep " + PDFNumber.doubleOut(new Double(this.yStep))
+ " \n");
if (this.matrix != null) {
vectorSize = this.matrix.size();
p.append("/Matrix [ ");
for (tempInt = 0; tempInt < vectorSize; tempInt++) {
p.append(PDFNumber.doubleOut(
((Double)this.matrix.get(tempInt)).doubleValue(), 8));
p.append(" ");
}
p.append("] \n");
}
if (this.xUID != null) {
vectorSize = this.xUID.size();
p.append("/XUID [ ");
for (tempInt = 0; tempInt < vectorSize; tempInt++) {
p.append(((Integer)this.xUID.get(tempInt)) + " ");
}
p.append("] \n");
}
// don't forget the length of the stream.
if (this.patternDataStream != null) {
pdfStream = new PDFStream();
pdfStream.setDocument(getDocumentSafely());
pdfStream.add(this.patternDataStream.toString());
pdfStream.getFilterList().addDefaultFilters(
getDocument().getFilterMap(),
PDFFilterList.CONTENT_FILTER);
encodedStream = pdfStream.encodeStream();
p.append(pdfStream.getFilterList().buildFilterDictEntries());
p.append("/Length " + (encodedStream.getSize() + 1)
+ " \n");
}
} else {
// if (this.patternType ==2)
// Smooth Shading...
if (this.shading != null) {
p.append("/Shading " + this.shading.referencePDF() + " \n");
}
if (this.xUID != null) {
vectorSize = this.xUID.size();
p.append("/XUID [ ");
for (tempInt = 0; tempInt < vectorSize; tempInt++) {
p.append(((Integer)this.xUID.get(tempInt)) + " ");
}
p.append("] \n");
}
if (this.extGState != null) {
p.append("/ExtGState " + this.extGState + " \n");
}
if (this.matrix != null) {
vectorSize = this.matrix.size();
p.append("/Matrix [ ");
for (tempInt = 0; tempInt < vectorSize; tempInt++) {
p.append(PDFNumber.doubleOut(
((Double)this.matrix.get(tempInt)).doubleValue(), 8));
p.append(" ");
}
p.append("] \n");
}
} // end of if patterntype =1...else 2.
p.append(">> \n");
buffer = encode(p.toString());
int length = buffer.length;
stream.write(buffer);
// stream representing the function
if (pdfStream != null) {
length += pdfStream.outputStreamData(encodedStream, stream);
}
return length;
}
// in src/java/org/apache/fop/pdf/FlateFilter.java
public OutputStream applyFilter(OutputStream out) throws IOException {
if (isApplied()) {
return out;
} else {
return new FlateEncodeOutputStream(out);
}
}
// in src/java/org/apache/fop/pdf/PDFEmbeddedFiles.java
protected void writeDictionary(OutputStream out, StringBuilder textBuffer) throws IOException {
sortNames(); //Sort the names before writing them out
super.writeDictionary(out, textBuffer);
}
// in src/java/org/apache/fop/pdf/PDFStream.java
private void flush() throws IOException {
this.streamWriter.flush();
}
// in src/java/org/apache/fop/pdf/PDFStream.java
public OutputStream getBufferOutputStream() throws IOException {
if (this.streamWriter != null) {
flush(); //Just to be sure
}
return this.data.getOutputStream();
}
// in src/java/org/apache/fop/pdf/PDFStream.java
public void setData(byte[] data) throws IOException {
this.data.clear();
this.data.write(data);
}
// in src/java/org/apache/fop/pdf/PDFStream.java
protected int getSizeHint() throws IOException {
flush();
return data.getSize();
}
// in src/java/org/apache/fop/pdf/PDFStream.java
protected void outputRawStreamData(OutputStream out) throws IOException {
flush();
data.outputContents(out);
}
// in src/java/org/apache/fop/pdf/PDFStream.java
public int output(OutputStream stream) throws IOException {
final int len = super.output(stream);
//Now that the data has been written, it can be discarded.
this.data = null;
return len;
}
// in src/java/org/apache/fop/pdf/PDFICCStream.java
Override
public int output(java.io.OutputStream stream)
throws java.io.IOException {
int length = super.output(stream);
this.cp = null; //Free ICC stream when it's not used anymore
return length;
}
// in src/java/org/apache/fop/pdf/PDFICCStream.java
Override
protected void outputRawStreamData(OutputStream out) throws IOException {
cp.write(out);
}
// in src/java/org/apache/fop/pdf/PDFFont.java
public int output(OutputStream stream) throws IOException {
validate();
return super.output(stream);
}
// in src/java/org/apache/fop/pdf/ObjectStream.java
Override
protected void outputRawStreamData(OutputStream out) throws IOException {
int currentOffset = 0;
StringBuilder offsetsPart = new StringBuilder();
ByteArrayOutputStream streamContent = new ByteArrayOutputStream();
for (CompressedObject object : objects) {
offsetsPart.append(object.getObjectNumber())
.append(' ')
.append(currentOffset)
.append('\n');
currentOffset += object.output(streamContent);
}
byte[] offsets = PDFDocument.encode(offsetsPart.toString());
firstObjectOffset = offsets.length;
out.write(offsets);
streamContent.writeTo(out);
}
// in src/java/org/apache/fop/pdf/PDFStructElem.java
Override
protected void writeDictionary(OutputStream out, StringBuilder textBuffer) throws IOException {
attachKids();
super.writeDictionary(out, textBuffer);
}
// in src/java/org/apache/fop/pdf/PDFStructElem.java
Override
public void outputInline(OutputStream out, StringBuilder textBuffer) throws IOException {
if (kids != null) {
assert kids.size() > 0;
for (int i = 0; i < kids.size(); i++) {
if (i > 0) {
textBuffer.append(' ');
}
Object obj = kids.get(i);
formatObject(obj, out, textBuffer);
}
}
}
// in src/java/org/apache/fop/pdf/PDFDestination.java
Override
public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
formatObject(getIDRef(), cout, textBuffer);
textBuffer.append(' ');
formatObject(goToReference, cout, textBuffer);
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
// in src/java/org/apache/fop/pdf/PDFResources.java
Override
public int output(OutputStream stream) throws IOException {
populateDictionary();
return super.output(stream);
}
// in src/java/org/apache/fop/pdf/StreamCacheFactory.java
public StreamCache createStreamCache() throws IOException {
if (this.cacheToFile) {
return new TempFileStreamCache();
} else {
return new InMemoryStreamCache();
}
}
// in src/java/org/apache/fop/pdf/StreamCacheFactory.java
public StreamCache createStreamCache(int hintSize) throws IOException {
if (this.cacheToFile) {
return new TempFileStreamCache();
} else {
return new InMemoryStreamCache(hintSize);
}
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public static void flushTextBuffer(StringBuilder textBuffer, OutputStream out)
throws IOException {
out.write(encode(textBuffer.toString()));
textBuffer.setLength(0);
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public void output(OutputStream stream) throws IOException {
//Write out objects until the list is empty. This approach (used with a
//LinkedList) allows for output() methods to create and register objects
//on the fly even during serialization.
while (this.objects.size() > 0) {
PDFObject object = this.objects.remove(0);
streamIndirectObject(object, stream);
}
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
private void streamIndirectObject(PDFObject o, OutputStream stream) throws IOException {
recordObjectOffset(o);
this.position += outputIndirectObject(o, stream);
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
private void streamIndirectObjects(Collection<? extends PDFObject> objects, OutputStream stream)
throws IOException {
for (PDFObject o : objects) {
streamIndirectObject(o, stream);
}
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public static int outputIndirectObject(PDFObject object, OutputStream stream)
throws IOException {
if (!object.hasObjectNumber()) {
throw new IllegalArgumentException("Not an indirect object");
}
byte[] obj = encode(object.getObjectID());
stream.write(obj);
int length = object.output(stream);
byte[] endobj = encode("\nendobj\n");
stream.write(endobj);
return obj.length + length + endobj.length;
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public void outputHeader(OutputStream stream) throws IOException {
this.position = 0;
getProfile().verifyPDFVersion();
byte[] pdf = encode("%PDF-" + getPDFVersionString() + "\n");
stream.write(pdf);
this.position += pdf.length;
// output a binary comment as recommended by the PDF spec (3.4.1)
byte[] bin = {
(byte)'%',
(byte)0xAA,
(byte)0xAB,
(byte)0xAC,
(byte)0xAD,
(byte)'\n' };
stream.write(bin);
this.position += bin.length;
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public void outputTrailer(OutputStream stream) throws IOException {
createDestinations();
output(stream);
outputTrailerObjectsAndXref(stream);
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
private void outputTrailerObjectsAndXref(OutputStream stream) throws IOException {
TrailerOutputHelper trailerOutputHelper = mayCompressStructureTreeElements()
? new CompressedTrailerOutputHelper()
: new UncompressedTrailerOutputHelper();
if (structureTreeElements != null) {
trailerOutputHelper.outputStructureTreeElements(stream);
}
streamIndirectObjects(trailerObjects, stream);
TrailerDictionary trailerDictionary = createTrailerDictionary();
long startxref = trailerOutputHelper.outputCrossReferenceObject(stream, trailerDictionary);
String trailer = "startxref\n" + startxref + "\n%%EOF\n";
stream.write(encode(trailer));
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public void outputStructureTreeElements(OutputStream stream)
throws IOException {
streamIndirectObjects(structureTreeElements, stream);
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public long outputCrossReferenceObject(OutputStream stream,
TrailerDictionary trailerDictionary) throws IOException {
new CrossReferenceTable(trailerDictionary, position,
indirectObjectOffsets).output(stream);
return position;
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public void outputStructureTreeElements(OutputStream stream)
throws IOException {
assert structureTreeElements.size() > 0;
structureTreeObjectStreams = new ObjectStreamManager(PDFDocument.this);
for (PDFStructElem structElem : structureTreeElements) {
structureTreeObjectStreams.add(structElem);
}
}
// in src/java/org/apache/fop/pdf/PDFDocument.java
public long outputCrossReferenceObject(OutputStream stream,
TrailerDictionary trailerDictionary) throws IOException {
// Outputting the object streams should not have created new indirect objects
assert objects.isEmpty();
new CrossReferenceStream(PDFDocument.this, ++objectcount, trailerDictionary, position,
indirectObjectOffsets,
structureTreeObjectStreams.getCompressedObjectReferences())
.output(stream);
return position;
}
// in src/java/org/apache/fop/pdf/PDFNumsArray.java
Override
public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
textBuffer.append('[');
boolean first = true;
for (Map.Entry<Integer, Object> entry : this.map.entrySet()) {
if (!first) {
textBuffer.append(" ");
}
first = false;
formatObject(entry.getKey(), cout, textBuffer);
textBuffer.append(" ");
formatObject(entry.getValue(), cout, textBuffer);
}
textBuffer.append(']');
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
// in src/java/org/apache/fop/pdf/PDFNull.java
public void outputInline(OutputStream out, StringBuilder textBuffer) throws IOException {
textBuffer.append(toString());
}
// in src/java/org/apache/fop/pdf/ASCIIHexFilter.java
public OutputStream applyFilter(OutputStream out) throws IOException {
if (isApplied()) {
return out;
} else {
return new ASCIIHexOutputStream(out);
}
}
// in src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java
public void writeCMap() throws IOException {
writeCIDInit();
writeCIDSystemInfo("Adobe", "UCS", 0);
writeName("Adobe-Identity-UCS");
writeType("2");
writeCodeSpaceRange(singleByte);
writeBFEntries();
writeWrapUp();
}
// in src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java
protected void writeBFEntries() throws IOException {
if (unicodeCharMap != null) {
writeBFCharEntries(unicodeCharMap);
writeBFRangeEntries(unicodeCharMap);
}
}
// in src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java
protected void writeBFCharEntries(char[] charArray) throws IOException {
int totalEntries = 0;
for (int i = 0; i < charArray.length; i++) {
if (!partOfRange(charArray, i)) {
totalEntries++;
}
}
if (totalEntries < 1) {
return;
}
int remainingEntries = totalEntries;
int charIndex = 0;
do {
/* Limited to 100 entries in each section */
int entriesThisSection = Math.min(remainingEntries, 100);
writer.write(entriesThisSection + " beginbfchar\n");
for (int i = 0; i < entriesThisSection; i++) {
/* Go to the next char not in a range */
while (partOfRange(charArray, charIndex)) {
charIndex++;
}
writer.write("<" + padCharIndex(charIndex) + "> ");
writer.write("<" + padHexString(Integer.toHexString(charArray[charIndex]), 4)
+ ">\n");
charIndex++;
}
remainingEntries -= entriesThisSection;
writer.write("endbfchar\n");
} while (remainingEntries > 0);
}
// in src/java/org/apache/fop/pdf/PDFToUnicodeCMap.java
protected void writeBFRangeEntries(char[] charArray) throws IOException {
int totalEntries = 0;
for (int i = 0; i < charArray.length; i++) {
if (startOfRange(charArray, i)) {
totalEntries++;
}
}
if (totalEntries < 1) {
return;
}
int remainingEntries = totalEntries;
int charIndex = 0;
do {
/* Limited to 100 entries in each section */
int entriesThisSection = Math.min(remainingEntries, 100);
writer.write(entriesThisSection + " beginbfrange\n");
for (int i = 0; i < entriesThisSection; i++) {
/* Go to the next start of a range */
while (!startOfRange(charArray, charIndex)) {
charIndex++;
}
writer.write("<" + padCharIndex(charIndex) + "> ");
writer.write("<"
+ padCharIndex(endOfRange(charArray, charIndex))
+ "> ");
writer.write("<" + padHexString(Integer.toHexString(charArray[charIndex]), 4)
+ ">\n");
charIndex++;
}
remainingEntries -= entriesThisSection;
writer.write("endbfrange\n");
} while (remainingEntries > 0);
}
// in src/java/org/apache/fop/pdf/PDFTTFStream.java
protected int getSizeHint() throws IOException {
if (this.ttfData != null) {
return ttfData.length;
} else {
return 0; //no hint available
}
}
// in src/java/org/apache/fop/pdf/PDFTTFStream.java
public int output(java.io.OutputStream stream)
throws java.io.IOException {
if (log.isDebugEnabled()) {
log.debug("Writing " + origLength + " bytes of TTF font data");
}
int length = super.output(stream);
log.debug("Embedded TrueType/OpenType font");
return length;
}
// in src/java/org/apache/fop/pdf/PDFTTFStream.java
protected void outputRawStreamData(OutputStream out) throws IOException {
out.write(this.ttfData);
}
// in src/java/org/apache/fop/pdf/PDFTTFStream.java
public void setData(byte[] data, int size) throws IOException {
this.ttfData = new byte[size];
System.arraycopy(data, 0, this.ttfData, 0, size);
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
public void writeCMap() throws IOException {
writePreStream();
writeStreamComments();
writeCIDInit();
writeCIDSystemInfo();
writeVersion("1");
writeType("1");
writeName(name);
writeCodeSpaceRange();
writeCIDRange();
writeBFEntries();
writeWrapUp();
writeStreamAfterComments();
writeUseCMap();
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writePreStream() throws IOException {
// writer.write("/Type /CMap\n");
// writer.write(sysInfo.toPDFString());
// writer.write("/CMapName /" + name + EOL);
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeStreamComments() throws IOException {
writer.write("%!PS-Adobe-3.0 Resource-CMap\n");
writer.write("%%DocumentNeededResources: ProcSet (CIDInit)\n");
writer.write("%%IncludeResource: ProcSet (CIDInit)\n");
writer.write("%%BeginResource: CMap (" + name + ")\n");
writer.write("%%EndComments\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeCIDInit() throws IOException {
writer.write("/CIDInit /ProcSet findresource begin\n");
writer.write("12 dict begin\n");
writer.write("begincmap\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeCIDSystemInfo(String registry, String ordering, int supplement)
throws IOException {
writer.write("/CIDSystemInfo 3 dict dup begin\n");
writer.write(" /Registry (");
writer.write(registry);
writer.write(") def\n");
writer.write(" /Ordering (");
writer.write(ordering);
writer.write(") def\n");
writer.write(" /Supplement ");
writer.write(Integer.toString(supplement));
writer.write(" def\n");
writer.write("end def\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeCIDSystemInfo() throws IOException {
writeCIDSystemInfo("Adobe", "Identity", 0);
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeVersion(String version) throws IOException {
writer.write("/CMapVersion ");
writer.write(version);
writer.write(" def\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeType(String type) throws IOException {
writer.write("/CMapType ");
writer.write(type);
writer.write(" def\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeName(String name) throws IOException {
writer.write("/CMapName /");
writer.write(name);
writer.write(" def\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeCodeSpaceRange() throws IOException {
writeCodeSpaceRange(false);
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeCodeSpaceRange(boolean singleByte) throws IOException {
writer.write("1 begincodespacerange\n");
if (singleByte) {
writer.write("<00> <FF>\n");
} else {
writer.write("<0000> <FFFF>\n");
}
writer.write("endcodespacerange\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeCIDRange() throws IOException {
writer.write("1 begincidrange\n");
writer.write("<0000> <FFFF> 0\n");
writer.write("endcidrange\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeBFEntries() throws IOException {
// writer.write("1 beginbfrange\n");
// writer.write("<0020> <0100> <0000>\n");
// writer.write("endbfrange\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeWrapUp() throws IOException {
writer.write("endcmap\n");
writer.write("CMapName currentdict /CMap defineresource pop\n");
writer.write("end\n");
writer.write("end\n");
}
// in src/java/org/apache/fop/pdf/CMapBuilder.java
protected void writeStreamAfterComments() throws IOException {
writer.write("%%EndResource\n");
writer.write("%%EOF\n");
}
// in src/java/org/apache/fop/pdf/PDFMetadata.java
public int output(java.io.OutputStream stream)
throws java.io.IOException {
int length = super.output(stream);
this.xmpMetadata = null; //Release DOM when it's not used anymore
return length;
}
// in src/java/org/apache/fop/pdf/PDFMetadata.java
protected void outputRawStreamData(OutputStream out) throws IOException {
try {
XMPSerializer.writeXMPPacket(xmpMetadata, out, this.readOnly);
} catch (TransformerConfigurationException tce) {
throw new IOException("Error setting up Transformer for XMP stream serialization: "
+ tce.getMessage());
} catch (SAXException saxe) {
throw new IOException("Error while serializing XMP stream: "
+ saxe.getMessage());
}
}
// in src/java/org/apache/fop/pdf/AlphaRasterImage.java
public void outputContents(OutputStream out) throws IOException {
int w = getWidth();
int h = getHeight();
//Check Raster
int nbands = alpha.getNumBands();
if (nbands != 1) {
throw new UnsupportedOperationException(
"Expected only one band/component for the alpha channel");
}
//...and write the Raster line by line with a reusable buffer
int dataType = alpha.getDataBuffer().getDataType();
if (dataType == DataBuffer.TYPE_BYTE) {
byte[] line = new byte[nbands * w];
for (int y = 0; y < h; y++) {
alpha.getDataElements(0, y, w, 1, line);
out.write(line);
}
} else if (dataType == DataBuffer.TYPE_USHORT) {
short[] sline = new short[nbands * w];
byte[] line = new byte[nbands * w];
for (int y = 0; y < h; y++) {
alpha.getDataElements(0, y, w, 1, sline);
for (int i = 0; i < w; i++) {
//this compresses a 16-bit alpha channel to 8 bits!
//we probably don't ever need a 16-bit channel
line[i] = (byte)(sline[i] >> 8);
}
out.write(line);
}
} else if (dataType == DataBuffer.TYPE_INT) {
//Is there an better way to get a 8bit raster from a TYPE_INT raster?
int shift = 24;
SampleModel sampleModel = alpha.getSampleModel();
if (sampleModel instanceof SinglePixelPackedSampleModel) {
SinglePixelPackedSampleModel m = (SinglePixelPackedSampleModel)sampleModel;
shift = m.getBitOffsets()[0];
}
int[] iline = new int[nbands * w];
byte[] line = new byte[nbands * w];
for (int y = 0; y < h; y++) {
alpha.getDataElements(0, y, w, 1, iline);
for (int i = 0; i < w; i++) {
line[i] = (byte)(iline[i] >> shift);
}
out.write(line);
}
} else {
throw new UnsupportedOperationException("Unsupported DataBuffer type: "
+ alpha.getDataBuffer().getClass().getName());
}
}
// in src/java/org/apache/fop/pdf/TempFileStreamCache.java
public OutputStream getOutputStream() throws IOException {
if (output == null) {
output = new java.io.BufferedOutputStream(
new java.io.FileOutputStream(tempFile));
}
return output;
}
// in src/java/org/apache/fop/pdf/TempFileStreamCache.java
public void write(byte[] data) throws IOException {
getOutputStream().write(data);
}
// in src/java/org/apache/fop/pdf/TempFileStreamCache.java
public int outputContents(OutputStream out) throws IOException {
if (output == null) {
return 0;
}
output.close();
output = null;
// don't need a buffer because copy() is buffered
InputStream input = new java.io.FileInputStream(tempFile);
try {
return IOUtils.copy(input, out);
} finally {
IOUtils.closeQuietly(input);
}
}
// in src/java/org/apache/fop/pdf/TempFileStreamCache.java
public int getSize() throws IOException {
if (output != null) {
output.flush();
}
return (int) tempFile.length();
}
// in src/java/org/apache/fop/pdf/TempFileStreamCache.java
public void clear() throws IOException {
if (output != null) {
output.close();
output = null;
}
if (tempFile.exists()) {
tempFile.delete();
}
}
// in src/java/org/apache/fop/pdf/PDFXObject.java
protected int getSizeHint() throws IOException {
return 0;
}
// in src/java/org/apache/fop/pdf/PDFFilterList.java
public OutputStream applyFilters(OutputStream stream) throws IOException {
OutputStream out = stream;
if (!isDisableAllFilters()) {
for (int count = filters.size() - 1; count >= 0; count--) {
PDFFilter filter = (PDFFilter)filters.get(count);
out = filter.applyFilter(out);
}
}
return out;
}
// in src/java/org/apache/fop/pdf/PDFImageXObject.java
public int output(OutputStream stream) throws IOException {
int length = super.output(stream);
// let it gc
// this object is retained as a reference to inserting
// the same image but the image data is no longer needed
pdfimage = null;
return length;
}
// in src/java/org/apache/fop/pdf/PDFImageXObject.java
protected void outputRawStreamData(OutputStream out) throws IOException {
pdfimage.outputContents(out);
}
// in src/java/org/apache/fop/pdf/PDFImageXObject.java
protected int getSizeHint() throws IOException {
return 0;
}
// in src/java/org/apache/fop/pdf/AbstractPDFStream.java
protected int outputStreamData(StreamCache encodedStream, OutputStream out) throws IOException {
int length = 0;
byte[] p = encode("stream\n");
out.write(p);
length += p.length;
encodedStream.outputContents(out);
length += encodedStream.getSize();
p = encode("\nendstream");
out.write(p);
length += p.length;
return length;
}
// in src/java/org/apache/fop/pdf/AbstractPDFStream.java
protected StreamCache encodeStream() throws IOException {
//Allocate a temporary buffer to find out the size of the encoded stream
final StreamCache encodedStream = StreamCacheFactory.getInstance()
.createStreamCache(getSizeHint());
OutputStream filteredOutput
= getFilterList().applyFilters(encodedStream.getOutputStream());
outputRawStreamData(filteredOutput);
filteredOutput.flush();
filteredOutput.close();
return encodedStream;
}
// in src/java/org/apache/fop/pdf/AbstractPDFStream.java
protected int encodeAndWriteStream(OutputStream out, PDFNumber refLength)
throws IOException {
int bytesWritten = 0;
//Stream header
byte[] buf = encode("stream\n");
out.write(buf);
bytesWritten += buf.length;
//Stream contents
CloseBlockerOutputStream cbout = new CloseBlockerOutputStream(out);
CountingOutputStream cout = new CountingOutputStream(cbout);
OutputStream filteredOutput = getFilterList().applyFilters(cout);
outputRawStreamData(filteredOutput);
filteredOutput.close();
refLength.setNumber(Integer.valueOf(cout.getCount()));
bytesWritten += cout.getCount();
//Stream trailer
buf = encode("\nendstream");
out.write(buf);
bytesWritten += buf.length;
return bytesWritten;
}
// in src/java/org/apache/fop/pdf/AbstractPDFStream.java
Override
public int output(OutputStream stream) throws IOException {
setupFilterList();
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
StreamCache encodedStream = null;
PDFNumber refLength = null;
final Object lengthEntry;
if (encodeOnTheFly) {
refLength = new PDFNumber();
getDocumentSafely().registerObject(refLength);
lengthEntry = refLength;
} else {
encodedStream = encodeStream();
lengthEntry = Integer.valueOf(encodedStream.getSize() + 1);
}
populateStreamDict(lengthEntry);
dictionary.writeDictionary(cout, textBuffer);
//Send encoded stream to target OutputStream
PDFDocument.flushTextBuffer(textBuffer, cout);
if (encodedStream == null) {
encodeAndWriteStream(cout, refLength);
} else {
outputStreamData(encodedStream, cout);
encodedStream.clear(); //Encoded stream can now be discarded
}
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
// in src/java/org/apache/fop/pdf/xref/CrossReferenceStream.java
public void output(OutputStream stream) throws IOException {
populateDictionary();
PDFStream helperStream = new PDFStream(trailerDictionary.getDictionary(), false) {
@Override
protected void setupFilterList() {
PDFFilterList filterList = getFilterList();
assert !filterList.isInitialized();
filterList.addDefaultFilters(document.getFilterMap(), getDefaultFilterName());
}
};
helperStream.setObjectNumber(objectNumber);
helperStream.setDocument(document);
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
DataOutputStream data = new DataOutputStream(byteArray);
addFreeEntryForObject0(data);
for (ObjectReference objectReference : objectReferences) {
assert objectReference != null;
objectReference.output(data);
}
new UncompressedObjectReference(startxref).output(data);
data.close();
helperStream.setData(byteArray.toByteArray());
PDFDocument.outputIndirectObject(helperStream, stream);
}
// in src/java/org/apache/fop/pdf/xref/CrossReferenceStream.java
private void populateDictionary() throws IOException {
int objectCount = objectReferences.size() + 1;
PDFDictionary dictionary = trailerDictionary.getDictionary();
dictionary.put("/Type", XREF);
dictionary.put("/Size", objectCount + 1);
dictionary.put("/W", new PDFArray(1, 8, 2));
}
// in src/java/org/apache/fop/pdf/xref/CrossReferenceStream.java
private void addFreeEntryForObject0(DataOutputStream data) throws IOException {
data.write(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xff, (byte) 0xff});
}
// in src/java/org/apache/fop/pdf/xref/UncompressedObjectReference.java
public void output(DataOutputStream out) throws IOException {
out.write(1);
out.writeLong(offset);
out.write(0);
out.write(0);
}
// in src/java/org/apache/fop/pdf/xref/CompressedObjectReference.java
public void output(DataOutputStream out) throws IOException {
out.write(2);
out.writeLong(objectStreamNumber);
out.write(0);
out.write(index);
}
// in src/java/org/apache/fop/pdf/xref/CrossReferenceTable.java
public void output(OutputStream stream) throws IOException {
outputXref();
writeTrailer(stream);
}
// in src/java/org/apache/fop/pdf/xref/CrossReferenceTable.java
private void outputXref() throws IOException {
pdf.append("xref\n0 ");
pdf.append(objectReferences.size() + 1);
pdf.append("\n0000000000 65535 f \n");
for (Long objectReference : objectReferences) {
final String padding = "0000000000";
String s = String.valueOf(objectReference);
if (s.length() > 10) {
throw new IOException("PDF file too large."
+ " PDF 1.4 cannot grow beyond approx. 9.3GB.");
}
String loc = padding.substring(s.length()) + s;
pdf.append(loc).append(" 00000 n \n");
}
}
// in src/java/org/apache/fop/pdf/xref/CrossReferenceTable.java
private void writeTrailer(OutputStream stream) throws IOException {
pdf.append("trailer\n");
stream.write(PDFDocument.encode(pdf.toString()));
PDFDictionary dictionary = trailerDictionary.getDictionary();
dictionary.put("/Size", objectReferences.size() + 1);
dictionary.output(stream);
}
// in src/java/org/apache/fop/pdf/xref/TrailerDictionary.java
public TrailerDictionary setFileID(byte[] originalFileID, byte[] updatedFileID) {
// TODO this is ugly! Used to circumvent the fact that the file ID will be
// encrypted if directly stored as a byte array
class FileID implements PDFWritable {
private final byte[] fileID;
FileID(byte[] id) {
fileID = id;
}
public void outputInline(OutputStream out, StringBuilder textBuffer)
throws IOException {
PDFDocument.flushTextBuffer(textBuffer, out);
String hex = PDFText.toHex(fileID, true);
byte[] encoded = hex.getBytes("US-ASCII");
out.write(encoded);
}
}
PDFArray fileID = new PDFArray(new FileID(originalFileID), new FileID(updatedFileID));
dictionary.put("/ID", fileID);
return this;
}
// in src/java/org/apache/fop/pdf/xref/TrailerDictionary.java
public void outputInline(OutputStream out, StringBuilder textBuffer)
throws IOException {
PDFDocument.flushTextBuffer(textBuffer, out);
String hex = PDFText.toHex(fileID, true);
byte[] encoded = hex.getBytes("US-ASCII");
out.write(encoded);
}
// in src/java/org/apache/fop/pdf/PDFDictionary.java
Override
public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
writeDictionary(cout, textBuffer);
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
// in src/java/org/apache/fop/pdf/PDFDictionary.java
protected void writeDictionary(OutputStream out, StringBuilder textBuffer) throws IOException {
textBuffer.append("<<");
boolean compact = (this.order.size() <= 2);
for (String key : this.order) {
if (compact) {
textBuffer.append(' ');
} else {
textBuffer.append("\n ");
}
textBuffer.append(PDFName.escapeName(key));
textBuffer.append(' ');
Object obj = this.entries.get(key);
formatObject(obj, out, textBuffer);
}
if (compact) {
textBuffer.append(' ');
} else {
textBuffer.append('\n');
}
textBuffer.append(">>\n");
}
// in src/java/org/apache/fop/pdf/BitmapImage.java
public void outputContents(OutputStream out) throws IOException {
out.write(bitmaps);
}
// in src/java/org/apache/fop/pdf/PDFT1Stream.java
protected int getSizeHint() throws IOException {
if (this.pfb != null) {
return pfb.getLength();
} else {
return 0; //no hint available
}
}
// in src/java/org/apache/fop/pdf/PDFT1Stream.java
public int output(java.io.OutputStream stream)
throws java.io.IOException {
if (pfb == null) {
throw new IllegalStateException("pfb must not be null at this point");
}
if (log.isDebugEnabled()) {
log.debug("Writing " + pfb.getLength() + " bytes of Type 1 font data");
}
int length = super.output(stream);
log.debug("Embedded Type1 font");
return length;
}
// in src/java/org/apache/fop/pdf/PDFT1Stream.java
protected void outputRawStreamData(OutputStream out) throws IOException {
this.pfb.outputAllParts(out);
}
// in src/java/org/apache/fop/pdf/PDFT1Stream.java
public void setData(PFBData pfb) throws IOException {
this.pfb = pfb;
}
// in src/java/org/apache/fop/pdf/InMemoryStreamCache.java
public OutputStream getOutputStream() throws IOException {
if (output == null) {
if (this.hintSize <= 0) {
output = new ByteArrayOutputStream(512);
} else {
output = new ByteArrayOutputStream(this.hintSize);
}
}
return output;
}
// in src/java/org/apache/fop/pdf/InMemoryStreamCache.java
public void write(byte[] data) throws IOException {
getOutputStream().write(data);
}
// in src/java/org/apache/fop/pdf/InMemoryStreamCache.java
public int outputContents(OutputStream out) throws IOException {
if (output == null) {
return 0;
}
output.writeTo(out);
return output.size();
}
// in src/java/org/apache/fop/pdf/InMemoryStreamCache.java
public int getSize() throws IOException {
if (output == null) {
return 0;
} else {
return output.size();
}
}
// in src/java/org/apache/fop/pdf/InMemoryStreamCache.java
public void clear() throws IOException {
if (output != null) {
output.close();
output = null;
}
}
// in src/java/org/apache/fop/pdf/PDFArray.java
Override
public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
textBuffer.append('[');
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
textBuffer.append(' ');
}
Object obj = this.values.get(i);
formatObject(obj, cout, textBuffer);
}
textBuffer.append(']');
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
// in src/java/org/apache/fop/pdf/NullFilter.java
public OutputStream applyFilter(OutputStream out) throws IOException {
return out;
//No active filtering, NullFilter does nothing
}
// in src/java/org/apache/fop/pdf/PDFName.java
Override
public int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
StringBuilder textBuffer = new StringBuilder(64);
textBuffer.append(toString());
PDFDocument.flushTextBuffer(textBuffer, cout);
return cout.getCount();
}
// in src/java/org/apache/fop/pdf/PDFName.java
Override
public void outputInline(OutputStream out, StringBuilder textBuffer) throws IOException {
if (hasObjectNumber()) {
textBuffer.append(referencePDF());
} else {
textBuffer.append(toString());
}
}
// in src/java/org/apache/fop/tools/fontlist/FontListMain.java
private void prepare() throws SAXException, IOException {
if (this.configFile != null) {
fopFactory.setUserConfig(this.configFile);
}
}
// in src/java/org/apache/fop/tools/fontlist/FontListMain.java
private void generateXML(SortedMap fontFamilies, File outFile, String singleFamily)
throws TransformerConfigurationException, SAXException, IOException {
SAXTransformerFactory tFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
TransformerHandler handler;
if (this.mode == GENERATE_XML) {
handler = tFactory.newTransformerHandler();
} else {
URL url = getClass().getResource("fonts2fo.xsl");
if (url == null) {
throw new FileNotFoundException("Did not find resource: fonts2fo.xsl");
}
handler = tFactory.newTransformerHandler(new StreamSource(url.toExternalForm()));
}
if (singleFamily != null) {
Transformer transformer = handler.getTransformer();
transformer.setParameter("single-family", singleFamily);
}
OutputStream out = new java.io.FileOutputStream(outFile);
out = new java.io.BufferedOutputStream(out);
if (this.mode == GENERATE_RENDERED) {
handler.setResult(new SAXResult(getFOPContentHandler(out)));
} else {
handler.setResult(new StreamResult(out));
}
try {
GenerationHelperContentHandler helper = new GenerationHelperContentHandler(
handler, null);
FontListSerializer serializer = new FontListSerializer();
serializer.generateSAX(fontFamilies, singleFamily, helper);
} finally {
IOUtils.closeQuietly(out);
}
}
// in src/java/org/apache/fop/tools/fontlist/FontListMain.java
private void writeToConsole(SortedMap fontFamilies)
throws TransformerConfigurationException, SAXException, IOException {
Iterator iter = fontFamilies.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
String firstFamilyName = (String)entry.getKey();
System.out.println(firstFamilyName + ":");
List list = (List)entry.getValue();
Iterator fonts = list.iterator();
while (fonts.hasNext()) {
FontSpec f = (FontSpec)fonts.next();
System.out.println(" " + f.getKey() + " " + f.getFamilyNames());
Iterator triplets = f.getTriplets().iterator();
while (triplets.hasNext()) {
FontTriplet triplet = (FontTriplet)triplets.next();
System.out.println(" " + triplet.toString());
}
}
}
}
// in src/java/org/apache/fop/tools/fontlist/FontListMain.java
private void writeOutput(SortedMap fontFamilies)
throws TransformerConfigurationException, SAXException, IOException {
if (this.outputFile.isDirectory()) {
System.out.println("Creating one file for each family...");
Iterator iter = fontFamilies.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
String familyName = (String)entry.getKey();
System.out.println("Creating output file for " + familyName + "...");
String filename;
switch(this.mode) {
case GENERATE_RENDERED:
filename = familyName + ".pdf";
break;
case GENERATE_FO:
filename = familyName + ".fo";
break;
case GENERATE_XML:
filename = familyName + ".xml";
break;
default:
throw new IllegalStateException("Unsupported mode");
}
File outFile = new File(this.outputFile, filename);
generateXML(fontFamilies, outFile, familyName);
}
} else {
System.out.println("Creating output file...");
generateXML(fontFamilies, this.outputFile, this.singleFamilyFilter);
}
System.out.println(this.outputFile + " written.");
}
// in src/java/org/apache/fop/tools/anttasks/FileCompare.java
public static boolean compareFiles(File f1, File f2) throws IOException {
return (compareFileSize(f1, f2) && compareBytes(f1, f2));
}
// in src/java/org/apache/fop/tools/anttasks/FileCompare.java
private static boolean compareBytes(File file1, File file2) throws IOException {
BufferedInputStream file1Input
= new BufferedInputStream(new java.io.FileInputStream(file1));
BufferedInputStream file2Input
= new BufferedInputStream(new java.io.FileInputStream(file2));
int charact1 = 0;
int charact2 = 0;
while (charact1 != -1) {
if (charact1 == charact2) {
charact1 = file1Input.read();
charact2 = file2Input.read();
} else {
return false;
}
}
return true;
}
// in src/java/org/apache/fop/servlet/FopPrintServlet.java
protected void render(Source src, Transformer transformer, HttpServletResponse response)
throws FOPException, TransformerException, IOException {
FOUserAgent foUserAgent = getFOUserAgent();
//Setup FOP
Fop fop = fopFactory.newFop(MimeConstants.MIME_FOP_PRINT, foUserAgent);
//Make sure the XSL transformation's result is piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
//Start the transformation and rendering process
transformer.transform(src, res);
//Return the result
reportOK(response);
}
// in src/java/org/apache/fop/servlet/FopPrintServlet.java
private void reportOK(HttpServletResponse response) throws IOException {
String sMsg = "<html><title>Success</title>\n"
+ "<body><h1>FopPrintServlet: </h1>"
+ "<h3>The requested data was printed to the default printer.</h3></body></html>";
response.setContentType("text/html");
response.setContentLength(sMsg.length());
PrintWriter out = response.getWriter();
out.println(sMsg);
out.flush();
}
// in src/java/org/apache/fop/servlet/FopServlet.java
private void sendPDF(byte[] content, HttpServletResponse response) throws IOException {
//Send the result back to the client
response.setContentType("application/pdf");
response.setContentLength(content.length);
response.getOutputStream().write(content);
response.getOutputStream().flush();
}
// in src/java/org/apache/fop/servlet/FopServlet.java
protected void renderFO(String fo, HttpServletResponse response)
throws FOPException, TransformerException, IOException {
//Setup source
Source foSrc = convertString2Source(fo);
//Setup the identity transformation
Transformer transformer = this.transFactory.newTransformer();
transformer.setURIResolver(this.uriResolver);
//Start transformation and rendering process
render(foSrc, transformer, response);
}
// in src/java/org/apache/fop/servlet/FopServlet.java
protected void renderXML(String xml, String xslt, HttpServletResponse response)
throws FOPException, TransformerException, IOException {
//Setup sources
Source xmlSrc = convertString2Source(xml);
Source xsltSrc = convertString2Source(xslt);
//Setup the XSL transformation
Transformer transformer = this.transFactory.newTransformer(xsltSrc);
transformer.setURIResolver(this.uriResolver);
//Start transformation and rendering process
render(xmlSrc, transformer, response);
}
// in src/java/org/apache/fop/servlet/FopServlet.java
protected void render(Source src, Transformer transformer, HttpServletResponse response)
throws FOPException, TransformerException, IOException {
FOUserAgent foUserAgent = getFOUserAgent();
//Setup output
ByteArrayOutputStream out = new ByteArrayOutputStream();
//Setup FOP
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
//Make sure the XSL transformation's result is piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
//Start the transformation and rendering process
transformer.transform(src, res);
//Return the result
sendPDF(out.toByteArray(), response);
}
// in src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
public void setupDocument(OutputStream stream, int width, int height) throws IOException {
this.width = width;
this.height = height;
pdfDoc.outputHeader(stream);
setOutputStream(stream);
}
// in src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
protected void startPage() throws IOException {
if (pdfContext.isPagePending()) {
throw new IllegalStateException("Close page first before starting another");
}
//Start page
paintingState = new PDFPaintingState();
if (this.initialTransform == null) {
//Save initial transformation matrix
this.initialTransform = getTransform();
this.initialClip = getClip();
} else {
//Reset transformation matrix
setTransform(this.initialTransform);
setClip(this.initialClip);
}
currentFontName = "";
currentFontSize = 0;
if (currentStream == null) {
currentStream = new StringWriter();
}
PDFResources pdfResources = this.pdfDoc.getResources();
PDFPage page = this.pdfDoc.getFactory().makePage(pdfResources,
width, height);
resourceContext = page;
pdfContext.setCurrentPage(page);
pageRef = page.referencePDF();
currentStream.write("q\n");
AffineTransform at = new AffineTransform(1.0, 0.0, 0.0, -1.0,
0.0, height);
currentStream.write("1 0 0 -1 0 " + height + " cm\n");
if (svgWidth != 0) {
double scaleX = width / svgWidth;
double scaleY = height / svgHeight;
at.scale(scaleX, scaleY);
currentStream.write("" + PDFNumber.doubleOut(scaleX) + " 0 0 "
+ PDFNumber.doubleOut(scaleY) + " 0 0 cm\n");
}
if (deviceDPI != NORMAL_PDF_RESOLUTION) {
double s = NORMAL_PDF_RESOLUTION / deviceDPI;
at.scale(s, s);
currentStream.write("" + PDFNumber.doubleOut(s) + " 0 0 "
+ PDFNumber.doubleOut(s) + " 0 0 cm\n");
scale(1 / s, 1 / s);
}
// Remember the transform we installed.
paintingState.concatenate(at);
pdfContext.increasePageCount();
}
// in src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
public void finish() throws IOException {
// restorePDFState();
closePage();
if (fontInfo != null) {
pdfDoc.getResources().addFonts(pdfDoc, fontInfo);
}
this.pdfDoc.output(outputStream);
pdfDoc.outputTrailer(outputStream);
outputStream.flush();
}
// in src/java/org/apache/fop/fonts/apps/TTFReader.java
public TTFFile loadTTF(String fileName, String fontName, boolean useKerning, boolean useAdvanced) throws IOException {
TTFFile ttfFile = new TTFFile(useKerning, useAdvanced);
log.info("Reading " + fileName + "...");
FontFileReader reader = new FontFileReader(fileName);
boolean supported = ttfFile.readFont(reader, fontName);
if (!supported) {
return null;
}
log.info("Font Family: " + ttfFile.getFamilyNames());
if (ttfFile.isCFF()) {
throw new UnsupportedOperationException(
"OpenType fonts with CFF data are not supported, yet");
}
return ttfFile;
}
// in src/java/org/apache/fop/fonts/apps/PFMReader.java
public PFMFile loadPFM(String filename) throws IOException {
log.info("Reading " + filename + "...");
log.info("");
InputStream in = new java.io.FileInputStream(filename);
try {
PFMFile pfm = new PFMFile();
pfm.load(in);
return pfm;
} finally {
in.close();
}
}
// in src/java/org/apache/fop/fonts/FontLoader.java
public static CustomFont loadFont(File fontFile, String subFontName,
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException {
return loadFont(fontFile.toURI().toURL(), subFontName,
embedded, encodingMode, resolver);
}
// in src/java/org/apache/fop/fonts/FontLoader.java
public static CustomFont loadFont(URL fontUrl, String subFontName,
boolean embedded, EncodingMode encodingMode,
FontResolver resolver) throws IOException {
return loadFont(fontUrl.toExternalForm(), subFontName,
embedded, encodingMode, true, true,
resolver);
}
// in src/java/org/apache/fop/fonts/FontLoader.java
public static CustomFont loadFont(String fontFileURI, String subFontName,
boolean embedded, EncodingMode encodingMode, boolean useKerning,
boolean useAdvanced, FontResolver resolver) throws IOException {
fontFileURI = fontFileURI.trim();
boolean type1 = isType1(fontFileURI);
FontLoader loader;
if (type1) {
if (encodingMode == EncodingMode.CID) {
throw new IllegalArgumentException(
"CID encoding mode not supported for Type 1 fonts");
}
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver);
} else {
loader = new TTFFontLoader(fontFileURI, subFontName,
embedded, encodingMode, useKerning, useAdvanced, resolver);
}
return loader.getFont();
}
// in src/java/org/apache/fop/fonts/FontLoader.java
public static InputStream openFontUri(FontResolver resolver, String uri)
throws IOException, MalformedURLException {
InputStream in = null;
if (resolver != null) {
Source source = resolver.resolve(uri);
if (source == null) {
String err = "Cannot load font: failed to create Source for font file "
+ uri;
throw new IOException(err);
}
if (source instanceof StreamSource) {
in = ((StreamSource) source).getInputStream();
}
if (in == null && source.getSystemId() != null) {
in = new java.net.URL(source.getSystemId()).openStream();
}
if (in == null) {
String err = "Cannot load font: failed to create InputStream from"
+ " Source for font file " + uri;
throw new IOException(err);
}
} else {
in = new URL(uri).openStream();
}
return in;
}
// in src/java/org/apache/fop/fonts/FontLoader.java
public CustomFont getFont() throws IOException {
if (!loaded) {
read();
}
return this.returnFont;
}
// in src/java/org/apache/fop/fonts/CustomFont.java
public Source getEmbedFileSource() throws IOException {
Source result = null;
if (resolver != null && embedFileName != null) {
result = resolver.resolve(embedFileName);
if (result == null) {
throw new IOException("Unable to resolve Source '"
+ embedFileName + "' for embedded font");
}
}
return result;
}
// in src/java/org/apache/fop/fonts/EmbedFontInfo.java
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.embedded = true;
}
// in src/java/org/apache/fop/fonts/autodetect/WindowsFontDirFinder.java
private String getWinDir(String osName) throws IOException {
Process process = null;
Runtime runtime = Runtime.getRuntime();
if (osName.startsWith("Windows 9")) {
process = runtime.exec("command.com /c echo %windir%");
} else {
process = runtime.exec("cmd.exe /c echo %windir%");
}
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
return bufferedReader.readLine();
}
// in src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
public List<URL> find() throws IOException {
final FontDirFinder fontDirFinder;
final String osName = System.getProperty("os.name");
if (osName.startsWith("Windows")) {
fontDirFinder = new WindowsFontDirFinder();
} else {
if (osName.startsWith("Mac")) {
fontDirFinder = new MacFontDirFinder();
} else {
fontDirFinder = new UnixFontDirFinder();
}
}
List<File> fontDirs = fontDirFinder.find();
List<URL> results = new java.util.ArrayList<URL>();
for (File dir : fontDirs) {
super.walk(dir, results);
}
return results;
}
// in src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
public List<URL> find(String dir) throws IOException {
List<URL> results = new java.util.ArrayList<URL>();
File directory = new File(dir);
if (!directory.isDirectory()) {
eventListener.fontDirectoryNotFound(this, dir);
} else {
super.walk(directory, results);
}
return results;
}
// in src/java/org/apache/fop/fonts/type1/PFBData.java
public void outputAllParts(OutputStream out) throws IOException {
out.write(this.headerSegment);
out.write(this.encryptedSegment);
out.write(this.trailerSegment);
}
// in src/java/org/apache/fop/fonts/type1/Type1FontLoader.java
Override
protected void read() throws IOException {
AFMFile afm = null;
PFMFile pfm = null;
InputStream afmIn = null;
String afmUri = null;
for (int i = 0; i < AFM_EXTENSIONS.length; i++) {
try {
afmUri = this.fontFileURI.substring(0, this.fontFileURI.length() - 4)
+ AFM_EXTENSIONS[i];
afmIn = openFontUri(resolver, afmUri);
if (afmIn != null) {
break;
}
} catch (IOException ioe) {
// Ignore, AFM probably not available under the URI
}
}
if (afmIn != null) {
try {
AFMParser afmParser = new AFMParser();
afm = afmParser.parse(afmIn, afmUri);
} finally {
IOUtils.closeQuietly(afmIn);
}
}
String pfmUri = getPFMURI(this.fontFileURI);
InputStream pfmIn = null;
try {
pfmIn = openFontUri(resolver, pfmUri);
} catch (IOException ioe) {
// Ignore, PFM probably not available under the URI
}
if (pfmIn != null) {
try {
pfm = new PFMFile();
pfm.load(pfmIn);
} catch (IOException ioe) {
if (afm == null) {
// Ignore the exception if we have a valid PFM. PFM is only the fallback.
throw ioe;
}
} finally {
IOUtils.closeQuietly(pfmIn);
}
}
if (afm == null && pfm == null) {
throw new java.io.FileNotFoundException(
"Neither an AFM nor a PFM file was found for " + this.fontFileURI);
}
buildFont(afm, pfm);
this.loaded = true;
}
// in src/java/org/apache/fop/fonts/type1/PFMInputStream.java
public short readByte() throws IOException {
short s = datain.readByte();
// Now, we've got to trick Java into forgetting the sign
int s1 = (((s & 0xF0) >>> 4) << 4) + (s & 0x0F);
return (short)s1;
}
// in src/java/org/apache/fop/fonts/type1/PFMInputStream.java
public int readShort() throws IOException {
int i = datain.readShort();
// Change byte order
int high = (i & 0xFF00) >>> 8;
int low = (i & 0x00FF) << 8;
return low + high;
}
// in src/java/org/apache/fop/fonts/type1/PFMInputStream.java
public long readInt() throws IOException {
int i = datain.readInt();
// Change byte order
int i1 = (i & 0xFF000000) >>> 24;
int i2 = (i & 0x00FF0000) >>> 8;
int i3 = (i & 0x0000FF00) << 8;
int i4 = (i & 0x000000FF) << 24;
return i1 + i2 + i3 + i4;
}
// in src/java/org/apache/fop/fonts/type1/PFMInputStream.java
public String readString() throws IOException {
InputStreamReader reader = new InputStreamReader(in, "ISO-8859-1");
StringBuffer buf = new StringBuffer();
int ch = reader.read();
while (ch > 0) {
buf.append((char)ch);
ch = reader.read();
}
if (ch == -1) {
throw new EOFException("Unexpected end of stream reached");
}
return buf.toString();
}
// in src/java/org/apache/fop/fonts/type1/PFBParser.java
public PFBData parsePFB(java.net.URL url) throws IOException {
InputStream in = url.openStream();
try {
return parsePFB(in);
} finally {
in.close();
}
}
// in src/java/org/apache/fop/fonts/type1/PFBParser.java
public PFBData parsePFB(java.io.File pfbFile) throws IOException {
InputStream in = new java.io.FileInputStream(pfbFile);
try {
return parsePFB(in);
} finally {
in.close();
}
}
// in src/java/org/apache/fop/fonts/type1/PFBParser.java
public PFBData parsePFB(InputStream in) throws IOException {
PFBData pfb = new PFBData();
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);
din.mark(32);
int firstByte = din.readUnsignedByte();
din.reset();
if (firstByte == 128) {
pfb.setPFBFormat(PFBData.PFB_PC);
parsePCFormat(pfb, din);
} else {
pfb.setPFBFormat(PFBData.PFB_RAW);
parseRAWFormat(pfb, bin);
}
return pfb;
}
// in src/java/org/apache/fop/fonts/type1/PFBParser.java
private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException {
int segmentHead;
int segmentType;
int bytesRead;
//Read first segment
segmentHead = din.readUnsignedByte();
if (segmentHead != 128) {
throw new IOException("Invalid file format. Expected ASCII 80hex");
}
segmentType = din.readUnsignedByte(); //Read
int len1 = swapInteger(din.readInt());
byte[] headerSegment = new byte[len1];
din.readFully(headerSegment);
pfb.setHeaderSegment(headerSegment);
//Read second segment
segmentHead = din.readUnsignedByte();
if (segmentHead != 128) {
throw new IOException("Invalid file format. Expected ASCII 80hex");
}
segmentType = din.readUnsignedByte();
int len2 = swapInteger(din.readInt());
byte[] encryptedSegment = new byte[len2];
din.readFully(encryptedSegment);
pfb.setEncryptedSegment(encryptedSegment);
//Read third segment
segmentHead = din.readUnsignedByte();
if (segmentHead != 128) {
throw new IOException("Invalid file format. Expected ASCII 80hex");
}
segmentType = din.readUnsignedByte();
int len3 = swapInteger(din.readInt());
byte[] trailerSegment = new byte[len3];
din.readFully(trailerSegment);
pfb.setTrailerSegment(trailerSegment);
//Read EOF indicator
segmentHead = din.readUnsignedByte();
if (segmentHead != 128) {
throw new IOException("Invalid file format. Expected ASCII 80hex");
}
segmentType = din.readUnsignedByte();
if (segmentType != 3) {
throw new IOException("Expected segment type 3, but found: " + segmentType);
}
}
// in src/java/org/apache/fop/fonts/type1/PFBParser.java
private void parseRAWFormat(PFBData pfb, BufferedInputStream bin)
throws IOException {
calcLengths(pfb, IOUtils.toByteArray(bin));
}
// in src/java/org/apache/fop/fonts/type1/CharMetricsHandler.java
AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName)
throws IOException {
AFMCharMetrics chm = new AFMCharMetrics();
stack.push(chm);
String[] metrics = SPLIT_REGEX.split(line);
for (String metric : metrics) {
Matcher matcher = METRICS_REGEX.matcher(metric);
if (matcher.matches()) {
String operator = matcher.group(1);
String operands = matcher.group(2);
ValueHandler handler = valueParsers.get(operator);
if (handler != null) {
handler.parse(operands, 0, stack);
}
}
}
stack.pop();
return chm;
}
// in src/java/org/apache/fop/fonts/type1/CharMetricsHandler.java
AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName)
throws IOException {
AFMCharMetrics chm = defaultHandler.parse(line, stack, afmFileName);
NamedCharacter namedChar = chm.getCharacter();
if (namedChar != null) {
int codePoint = AdobeStandardEncoding.getAdobeCodePoint(namedChar.getName());
if (chm.getCharCode() != codePoint) {
LOG.info(afmFileName + ": named character '" + namedChar.getName() + "'"
+ " has an incorrect code point: " + chm.getCharCode()
+ ". Changed to " + codePoint);
chm.setCharCode(codePoint);
}
}
return chm;
}
// in src/java/org/apache/fop/fonts/type1/PFMFile.java
public void load(InputStream inStream) throws IOException {
byte[] pfmBytes = IOUtils.toByteArray(inStream);
InputStream bufin = inStream;
bufin = new ByteArrayInputStream(pfmBytes);
PFMInputStream in = new PFMInputStream(bufin);
bufin.mark(512);
short sh1 = in.readByte();
short sh2 = in.readByte();
if (sh1 == 128 && sh2 == 1) {
//Found the first section header of a PFB file!
throw new IOException("Cannot parse PFM file. You probably specified the PFB file"
+ " of a Type 1 font as parameter instead of the PFM.");
}
bufin.reset();
byte[] b = new byte[16];
bufin.read(b);
if (new String(b, "US-ASCII").equalsIgnoreCase("StartFontMetrics")) {
//Found the header of a AFM file!
throw new IOException("Cannot parse PFM file. You probably specified the AFM file"
+ " of a Type 1 font as parameter instead of the PFM.");
}
bufin.reset();
final int version = in.readShort();
if (version != 256) {
log.warn("PFM version expected to be '256' but got '" + version + "'."
+ " Please make sure you specify the PFM as parameter"
+ " and not the PFB or the AFM.");
}
//final long filesize = in.readInt();
bufin.reset();
loadHeader(in);
loadExtension(in);
}
// in src/java/org/apache/fop/fonts/type1/PFMFile.java
private void loadHeader(PFMInputStream inStream) throws IOException {
inStream.skip(80);
dfItalic = inStream.readByte();
inStream.skip(2);
dfWeight = inStream.readShort();
dfCharSet = inStream.readByte();
inStream.skip(4);
dfPitchAndFamily = inStream.readByte();
dfAvgWidth = inStream.readShort();
dfMaxWidth = inStream.readShort();
dfFirstChar = inStream.readByte();
dfLastChar = inStream.readByte();
inStream.skip(8);
long faceOffset = inStream.readInt();
inStream.reset();
inStream.skip(faceOffset);
windowsName = inStream.readString();
inStream.reset();
inStream.skip(117);
}
// in src/java/org/apache/fop/fonts/type1/PFMFile.java
private void loadExtension(PFMInputStream inStream) throws IOException {
final int size = inStream.readShort();
if (size != 30) {
log.warn("Size of extension block was expected to be "
+ "30 bytes, but was " + size + " bytes.");
}
final long extMetricsOffset = inStream.readInt();
final long extentTableOffset = inStream.readInt();
inStream.skip(4); //Skip dfOriginTable
final long kernPairOffset = inStream.readInt();
inStream.skip(4); //Skip dfTrackKernTable
long driverInfoOffset = inStream.readInt();
if (kernPairOffset > 0) {
inStream.reset();
inStream.skip(kernPairOffset);
loadKernPairs(inStream);
}
inStream.reset();
inStream.skip(driverInfoOffset);
postscriptName = inStream.readString();
if (extMetricsOffset != 0) {
inStream.reset();
inStream.skip(extMetricsOffset);
loadExtMetrics(inStream);
}
if (extentTableOffset != 0) {
inStream.reset();
inStream.skip(extentTableOffset);
loadExtentTable(inStream);
}
}
// in src/java/org/apache/fop/fonts/type1/PFMFile.java
private void loadKernPairs(PFMInputStream inStream) throws IOException {
int i = inStream.readShort();
if (log.isTraceEnabled()) {
log.trace(i + " kerning pairs");
}
while (i > 0) {
int g1 = (int)inStream.readByte();
i--;
int g2 = (int)inStream.readByte();
int adj = inStream.readShort();
if (adj > 0x8000) {
adj = -(0x10000 - adj);
}
if (log.isTraceEnabled()) {
log.trace("Char no: (" + g1 + ", " + g2 + ") kern: " + adj);
final String glyph1 = Glyphs.TEX8R_GLYPH_NAMES[g1];
final String glyph2 = Glyphs.TEX8R_GLYPH_NAMES[g2];
log.trace("glyphs: " + glyph1 + ", " + glyph2);
}
Map adjTab = (Map)kerningTab.get(new Integer(g1));
if (adjTab == null) {
adjTab = new java.util.HashMap();
}
adjTab.put(new Integer(g2), new Integer(adj));
kerningTab.put(new Integer(g1), adjTab);
}
}
// in src/java/org/apache/fop/fonts/type1/PFMFile.java
private void loadExtMetrics(PFMInputStream inStream) throws IOException {
final int size = inStream.readShort();
if (size != 52) {
log.warn("Size of extension block was expected to be "
+ "52 bytes, but was " + size + " bytes.");
}
inStream.skip(12); //Skip etmPointSize, etmOrientation, etmMasterHeight,
//etmMinScale, etmMaxScale, emtMasterUnits
etmCapHeight = inStream.readShort();
etmXHeight = inStream.readShort();
etmLowerCaseAscent = inStream.readShort();
etmLowerCaseDescent = -(inStream.readShort());
//Ignore the rest of the values
}
// in src/java/org/apache/fop/fonts/type1/PFMFile.java
private void loadExtentTable(PFMInputStream inStream) throws IOException {
extentTable = new int[dfLastChar - dfFirstChar + 1];
dfMinWidth = dfMaxWidth;
for (short i = dfFirstChar; i <= dfLastChar; i++) {
extentTable[i - dfFirstChar] = inStream.readShort();
if (extentTable[i - dfFirstChar] < dfMinWidth) {
dfMinWidth = extentTable[i - dfFirstChar];
}
}
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public AFMFile parse(InputStream in, String afmFileName) throws IOException {
Reader reader = new java.io.InputStreamReader(in, "US-ASCII");
try {
return parse(new BufferedReader(reader), afmFileName);
} finally {
IOUtils.closeQuietly(reader);
}
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public AFMFile parse(BufferedReader reader, String afmFileName) throws IOException {
Stack<Object> stack = new Stack<Object>();
int parseMode = PARSE_NORMAL;
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
String key = null;
switch (parseMode) {
case PARSE_NORMAL:
key = parseLine(line, stack);
break;
case PARSE_CHAR_METRICS:
key = parseCharMetrics(line, stack, afmFileName);
break;
default:
throw new IllegalStateException("Invalid parse mode");
}
Integer newParseMode = PARSE_MODE_CHANGES.get(key);
if (newParseMode != null) {
parseMode = newParseMode.intValue();
}
}
return (AFMFile)stack.pop();
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
private String parseLine(String line, Stack<Object> stack) throws IOException {
int startpos = 0;
//Find key
startpos = skipToNonWhiteSpace(line, startpos);
int endpos = skipToWhiteSpace(line, startpos);
String key = line.substring(startpos, endpos);
//Parse value
startpos = skipToNonWhiteSpace(line, endpos);
ValueHandler vp = VALUE_PARSERS.get(key);
if (vp != null) {
vp.parse(line, startpos, stack);
}
return key;
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
private String parseCharMetrics(String line, Stack<Object> stack, String afmFileName)
throws IOException {
String trimmedLine = line.trim();
if (END_CHAR_METRICS.equals(trimmedLine)) {
return trimmedLine;
}
AFMFile afm = (AFMFile) stack.peek();
String encoding = afm.getEncodingScheme();
CharMetricsHandler charMetricsHandler = CharMetricsHandler.getHandler(VALUE_PARSERS,
encoding);
AFMCharMetrics chm = charMetricsHandler.parse(trimmedLine, stack, afmFileName);
afm.addCharMetrics(chm);
return null;
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
int endpos = findValue(line, startpos);
double version = Double.parseDouble(line.substring(startpos, endpos));
if (version < 2) {
throw new IOException(
"AFM version must be at least 2.0 but it is " + version + "!");
}
AFMFile afm = new AFMFile();
stack.push(afm);
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
String s = getStringValue(line, startpos);
Object obj = stack.peek();
setValue(obj, String.class, s);
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
NamedCharacter ch = new NamedCharacter(getStringValue(line, startpos));
Object obj = stack.peek();
setValue(obj, NamedCharacter.class, ch);
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
Number num = getNumberValue(line, startpos);
setValue(getContextObject(stack), Number.class, num);
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
int value = getIntegerValue(line, startpos);
setValue(getContextObject(stack), int.class, new Integer(value));
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
double value = getDoubleValue(line, startpos);
setValue(getContextObject(stack), double.class, new Double(value));
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
double value = getDoubleValue(line, startpos);
setValue(getContextObject(stack), double.class, new Double(value));
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
Boolean b = getBooleanValue(line, startpos);
Object target = getContextObject(stack);
Class<?> c = target.getClass();
try {
Method mth = c.getMethod(method, boolean.class);
mth.invoke(target, b);
} catch ( NoSuchMethodException e ) {
throw new RuntimeException("Bean error: " + e.getMessage(), e);
} catch ( IllegalAccessException e ) {
throw new RuntimeException("Bean error: " + e.getMessage(), e);
} catch ( InvocationTargetException e ) {
throw new RuntimeException("Bean error: " + e.getMessage(), e);
}
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
Rectangle rect = parseBBox(line, startpos);
AFMFile afm = (AFMFile)stack.peek();
afm.setFontBBox(rect);
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
Rectangle rect = parseBBox(line, startpos);
AFMCharMetrics metrics = (AFMCharMetrics)stack.peek();
metrics.setBBox(rect);
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
if (getBooleanValue(line, startpos).booleanValue()) {
throw new IOException("Only base fonts are currently supported!");
}
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
if (getBooleanValue(line, startpos).booleanValue()) {
throw new IOException("CID fonts are currently not supported!");
}
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack stack) throws IOException {
log.warn("Support for '" + key + "' has not been implemented, yet!"
+ " Some font data in the AFM file will be ignored.");
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
int index = getIntegerValue(line, startpos);
AFMWritingDirectionMetrics wdm = new AFMWritingDirectionMetrics();
AFMFile afm = (AFMFile)stack.peek();
afm.setWritingDirectionMetrics(index, wdm);
stack.push(wdm);
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
if (!(stack.pop() instanceof AFMWritingDirectionMetrics)) {
throw new IOException("AFM format error: nesting incorrect");
}
}
// in src/java/org/apache/fop/fonts/type1/AFMParser.java
public void parse(String line, int startpos, Stack<Object> stack) throws IOException {
AFMFile afm = (AFMFile)stack.peek();
int endpos;
endpos = findValue(line, startpos);
String name1 = line.substring(startpos, endpos);
startpos = skipToNonWhiteSpace(line, endpos);
endpos = findValue(line, startpos);
String name2 = line.substring(startpos, endpos);
startpos = skipToNonWhiteSpace(line, endpos);
endpos = findValue(line, startpos);
double kx = Double.parseDouble(line.substring(startpos, endpos));
startpos = skipToNonWhiteSpace(line, endpos);
afm.addXKerning(name1, name2, kx);
}
// in src/java/org/apache/fop/fonts/truetype/TTFDirTabEntry.java
public String read(FontFileReader in) throws IOException {
tag[0] = in.readTTFByte();
tag[1] = in.readTTFByte();
tag[2] = in.readTTFByte();
tag[3] = in.readTTFByte();
in.skip(4); // Skip checksum
offset = in.readTTFULong();
length = in.readTTFULong();
String tagStr = new String(tag, "ISO-8859-1");
return tagStr;
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
public boolean seekTab(FontFileReader in, String name,
long offset) throws IOException {
TTFDirTabEntry dt = getDirectoryEntry ( name );
if (dt == null) {
log.error("Dirtab " + name + " not found.");
return false;
} else {
in.seekSet(dt.getOffset() + offset);
this.currentDirTab = dt;
}
return true;
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private boolean readCMAP(FontFileReader in) throws IOException {
unicodeMappings = new java.util.TreeSet();
seekTab(in, "cmap", 2);
int numCMap = in.readTTFUShort(); // Number of cmap subtables
long cmapUniOffset = 0;
long symbolMapOffset = 0;
if (log.isDebugEnabled()) {
log.debug(numCMap + " cmap tables");
}
//Read offset for all tables. We are only interested in the unicode table
for (int i = 0; i < numCMap; i++) {
int cmapPID = in.readTTFUShort();
int cmapEID = in.readTTFUShort();
long cmapOffset = in.readTTFULong();
if (log.isDebugEnabled()) {
log.debug("Platform ID: " + cmapPID + " Encoding: " + cmapEID);
}
if (cmapPID == 3 && cmapEID == 1) {
cmapUniOffset = cmapOffset;
}
if (cmapPID == 3 && cmapEID == 0) {
symbolMapOffset = cmapOffset;
}
}
if (cmapUniOffset > 0) {
return readUnicodeCmap(in, cmapUniOffset, 1);
} else if (symbolMapOffset > 0) {
return readUnicodeCmap(in, symbolMapOffset, 0);
} else {
log.fatal("Unsupported TrueType font: No Unicode or Symbol cmap table"
+ " not present. Aborting");
return false;
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private boolean readUnicodeCmap // CSOK: MethodLength
(FontFileReader in, long cmapUniOffset, int encodingID)
throws IOException {
//Read CMAP table and correct mtxTab.index
int mtxPtr = 0;
// Read unicode cmap
seekTab(in, "cmap", cmapUniOffset);
int cmapFormat = in.readTTFUShort();
/*int cmap_length =*/ in.readTTFUShort(); //skip cmap length
if (log.isDebugEnabled()) {
log.debug("CMAP format: " + cmapFormat);
}
if (cmapFormat == 4) {
in.skip(2); // Skip version number
int cmapSegCountX2 = in.readTTFUShort();
int cmapSearchRange = in.readTTFUShort();
int cmapEntrySelector = in.readTTFUShort();
int cmapRangeShift = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("segCountX2 : " + cmapSegCountX2);
log.debug("searchRange : " + cmapSearchRange);
log.debug("entrySelector: " + cmapEntrySelector);
log.debug("rangeShift : " + cmapRangeShift);
}
int[] cmapEndCounts = new int[cmapSegCountX2 / 2];
int[] cmapStartCounts = new int[cmapSegCountX2 / 2];
int[] cmapDeltas = new int[cmapSegCountX2 / 2];
int[] cmapRangeOffsets = new int[cmapSegCountX2 / 2];
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapEndCounts[i] = in.readTTFUShort();
}
in.skip(2); // Skip reservedPad
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapStartCounts[i] = in.readTTFUShort();
}
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapDeltas[i] = in.readTTFShort();
}
//int startRangeOffset = in.getCurrentPos();
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapRangeOffsets[i] = in.readTTFUShort();
}
int glyphIdArrayOffset = in.getCurrentPos();
BitSet eightBitGlyphs = new BitSet(256);
// Insert the unicode id for the glyphs in mtxTab
// and fill in the cmaps ArrayList
for (int i = 0; i < cmapStartCounts.length; i++) {
if (log.isTraceEnabled()) {
log.trace(i + ": " + cmapStartCounts[i]
+ " - " + cmapEndCounts[i]);
}
if (log.isDebugEnabled()) {
if (isInPrivateUseArea(cmapStartCounts[i], cmapEndCounts[i])) {
log.debug("Font contains glyphs in the Unicode private use area: "
+ Integer.toHexString(cmapStartCounts[i]) + " - "
+ Integer.toHexString(cmapEndCounts[i]));
}
}
for (int j = cmapStartCounts[i]; j <= cmapEndCounts[i]; j++) {
// Update lastChar
if (j < 256 && j > lastChar) {
lastChar = (short)j;
}
if (j < 256) {
eightBitGlyphs.set(j);
}
if (mtxPtr < mtxTab.length) {
int glyphIdx;
// the last character 65535 = .notdef
// may have a range offset
if (cmapRangeOffsets[i] != 0 && j != 65535) {
int glyphOffset = glyphIdArrayOffset
+ ((cmapRangeOffsets[i] / 2)
+ (j - cmapStartCounts[i])
+ (i)
- cmapSegCountX2 / 2) * 2;
in.seekSet(glyphOffset);
glyphIdx = (in.readTTFUShort() + cmapDeltas[i])
& 0xffff;
unicodeMappings.add(new UnicodeMapping(glyphIdx, j));
mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
// Also add winAnsiWidth
List v = (List)ansiIndex.get(new Integer(j));
if (v != null) {
Iterator e = v.listIterator();
while (e.hasNext()) {
Integer aIdx = (Integer)e.next();
ansiWidth[aIdx.intValue()]
= mtxTab[glyphIdx].getWx();
if (log.isTraceEnabled()) {
log.trace("Added width "
+ mtxTab[glyphIdx].getWx()
+ " uni: " + j
+ " ansi: " + aIdx.intValue());
}
}
}
if (log.isTraceEnabled()) {
log.trace("Idx: "
+ glyphIdx
+ " Delta: " + cmapDeltas[i]
+ " Unicode: " + j
+ " name: " + mtxTab[glyphIdx].getName());
}
} else {
glyphIdx = (j + cmapDeltas[i]) & 0xffff;
if (glyphIdx < mtxTab.length) {
mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
} else {
log.debug("Glyph " + glyphIdx
+ " out of range: "
+ mtxTab.length);
}
unicodeMappings.add(new UnicodeMapping(glyphIdx, j));
if (glyphIdx < mtxTab.length) {
mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
} else {
log.debug("Glyph " + glyphIdx
+ " out of range: "
+ mtxTab.length);
}
// Also add winAnsiWidth
List v = (List)ansiIndex.get(new Integer(j));
if (v != null) {
Iterator e = v.listIterator();
while (e.hasNext()) {
Integer aIdx = (Integer)e.next();
ansiWidth[aIdx.intValue()] = mtxTab[glyphIdx].getWx();
}
}
//getLogger().debug("IIdx: " +
// mtxPtr +
// " Delta: " + cmap_deltas[i] +
// " Unicode: " + j +
// " name: " +
// mtxTab[(j+cmap_deltas[i]) & 0xffff].name);
}
if (glyphIdx < mtxTab.length) {
if (mtxTab[glyphIdx].getUnicodeIndex().size() < 2) {
mtxPtr++;
}
}
}
}
}
} else {
log.error("Cmap format not supported: " + cmapFormat);
return false;
}
return true;
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
public void readFont(FontFileReader in) throws IOException {
readFont(in, (String)null);
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
public boolean readFont(FontFileReader in, String name) throws IOException {
/*
* Check if TrueType collection, and that the name
* exists in the collection
*/
if (!checkTTC(in, name)) {
if (name == null) {
throw new IllegalArgumentException(
"For TrueType collection you must specify which font "
+ "to select (-ttcname)");
} else {
throw new IOException(
"Name does not exist in the TrueType collection: " + name);
}
}
readDirTabs(in);
readFontHeader(in);
getNumGlyphs(in);
if (log.isDebugEnabled()) {
log.debug("Number of glyphs in font: " + numberOfGlyphs);
}
readHorizontalHeader(in);
readHorizontalMetrics(in);
initAnsiWidths();
readPostScript(in);
readOS2(in);
determineAscDesc();
if (!isCFF) {
readIndexToLocation(in);
readGlyf(in);
}
readName(in);
boolean pcltFound = readPCLT(in);
// Read cmap table and fill in ansiwidths
boolean valid = readCMAP(in);
if (!valid) {
return false;
}
// Create cmaps for bfentries
createCMaps();
if ( useKerning ) {
readKerning(in);
}
// Read advanced typographic tables.
if ( useAdvanced ) {
try {
OTFAdvancedTypographicTableReader atr
= new OTFAdvancedTypographicTableReader ( this, in );
atr.readAll();
this.advancedTableReader = atr;
} catch ( AdvancedTypographicTableFormatException e ) {
log.warn (
"Encountered format constraint violation in advanced (typographic) table (AT) "
+ "in font '" + getFullName() + "', ignoring AT data: "
+ e.getMessage()
);
}
}
guessVerticalMetricsFromGlyphBBox();
return true;
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
protected void readDirTabs(FontFileReader in) throws IOException {
int sfntVersion = in.readTTFLong(); // TTF_FIXED_SIZE (4 bytes)
switch (sfntVersion) {
case 0x10000:
log.debug("sfnt version: OpenType 1.0");
break;
case 0x4F54544F: //"OTTO"
this.isCFF = true;
log.debug("sfnt version: OpenType with CFF data");
break;
case 0x74727565: //"true"
log.debug("sfnt version: Apple TrueType");
break;
case 0x74797031: //"typ1"
log.debug("sfnt version: Apple Type 1 housed in sfnt wrapper");
break;
default:
log.debug("Unknown sfnt version: " + Integer.toHexString(sfntVersion));
break;
}
int ntabs = in.readTTFUShort();
in.skip(6); // 3xTTF_USHORT_SIZE
dirTabs = new java.util.HashMap();
TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs];
log.debug("Reading " + ntabs + " dir tables");
for (int i = 0; i < ntabs; i++) {
pd[i] = new TTFDirTabEntry();
dirTabs.put(pd[i].read(in), pd[i]);
}
log.debug("dir tables: " + dirTabs.keySet());
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
protected void readFontHeader(FontFileReader in) throws IOException {
seekTab(in, "head", 2 * 4 + 2 * 4);
int flags = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("flags: " + flags + " - " + Integer.toString(flags, 2));
}
upem = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("unit per em: " + upem);
}
in.skip(16);
fontBBox1 = in.readTTFShort();
fontBBox2 = in.readTTFShort();
fontBBox3 = in.readTTFShort();
fontBBox4 = in.readTTFShort();
if (log.isDebugEnabled()) {
log.debug("font bbox: xMin=" + fontBBox1
+ " yMin=" + fontBBox2
+ " xMax=" + fontBBox3
+ " yMax=" + fontBBox4);
}
in.skip(2 + 2 + 2);
locaFormat = in.readTTFShort();
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
protected void getNumGlyphs(FontFileReader in) throws IOException {
seekTab(in, "maxp", 4);
numberOfGlyphs = in.readTTFUShort();
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
protected void readHorizontalHeader(FontFileReader in)
throws IOException {
seekTab(in, "hhea", 4);
hheaAscender = in.readTTFShort();
hheaDescender = in.readTTFShort();
in.skip(2 + 2 + 3 * 2 + 8 * 2);
nhmtx = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("hhea.Ascender: " + formatUnitsForDebug(hheaAscender));
log.debug("hhea.Descender: " + formatUnitsForDebug(hheaDescender));
log.debug("Number of horizontal metrics: " + nhmtx);
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
protected void readHorizontalMetrics(FontFileReader in)
throws IOException {
seekTab(in, "hmtx", 0);
int mtxSize = Math.max(numberOfGlyphs, nhmtx);
mtxTab = new TTFMtxEntry[mtxSize];
if (log.isTraceEnabled()) {
log.trace("*** Widths array: \n");
}
for (int i = 0; i < mtxSize; i++) {
mtxTab[i] = new TTFMtxEntry();
}
for (int i = 0; i < nhmtx; i++) {
mtxTab[i].setWx(in.readTTFUShort());
mtxTab[i].setLsb(in.readTTFUShort());
if (log.isTraceEnabled()) {
log.trace(" width[" + i + "] = "
+ convertTTFUnit2PDFUnit(mtxTab[i].getWx()) + ";");
}
}
if (nhmtx < mtxSize) {
// Fill in the missing widths
int lastWidth = mtxTab[nhmtx - 1].getWx();
for (int i = nhmtx; i < mtxSize; i++) {
mtxTab[i].setWx(lastWidth);
mtxTab[i].setLsb(in.readTTFUShort());
}
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private void readPostScript(FontFileReader in) throws IOException {
seekTab(in, "post", 0);
postFormat = in.readTTFLong();
italicAngle = in.readTTFULong();
underlinePosition = in.readTTFShort();
underlineThickness = in.readTTFShort();
isFixedPitch = in.readTTFULong();
//Skip memory usage values
in.skip(4 * 4);
log.debug("PostScript format: 0x" + Integer.toHexString(postFormat));
switch (postFormat) {
case 0x00010000:
log.debug("PostScript format 1");
for (int i = 0; i < Glyphs.MAC_GLYPH_NAMES.length; i++) {
mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[i]);
}
break;
case 0x00020000:
log.debug("PostScript format 2");
int numGlyphStrings = 0;
// Read Number of Glyphs
int l = in.readTTFUShort();
// Read indexes
for (int i = 0; i < l; i++) {
mtxTab[i].setIndex(in.readTTFUShort());
if (mtxTab[i].getIndex() > 257) {
//Index is not in the Macintosh standard set
numGlyphStrings++;
}
if (log.isTraceEnabled()) {
log.trace("PostScript index: " + mtxTab[i].getIndexAsString());
}
}
// firstChar=minIndex;
String[] psGlyphsBuffer = new String[numGlyphStrings];
if (log.isDebugEnabled()) {
log.debug("Reading " + numGlyphStrings
+ " glyphnames, that are not in the standard Macintosh"
+ " set. Total number of glyphs=" + l);
}
for (int i = 0; i < psGlyphsBuffer.length; i++) {
psGlyphsBuffer[i] = in.readTTFString(in.readTTFUByte());
}
//Set glyph names
for (int i = 0; i < l; i++) {
if (mtxTab[i].getIndex() < NMACGLYPHS) {
mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[mtxTab[i].getIndex()]);
} else {
if (!mtxTab[i].isIndexReserved()) {
int k = mtxTab[i].getIndex() - NMACGLYPHS;
if (log.isTraceEnabled()) {
log.trace(k + " i=" + i + " mtx=" + mtxTab.length
+ " ps=" + psGlyphsBuffer.length);
}
mtxTab[i].setName(psGlyphsBuffer[k]);
}
}
}
break;
case 0x00030000:
// PostScript format 3 contains no glyph names
log.debug("PostScript format 3");
break;
default:
log.error("Unknown PostScript format: " + postFormat);
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private void readOS2(FontFileReader in) throws IOException {
// Check if font is embeddable
TTFDirTabEntry os2Entry = getDirectoryEntry ( "OS/2" );
if (os2Entry != null) {
seekTab(in, "OS/2", 0);
int version = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("OS/2 table: version=" + version
+ ", offset=" + os2Entry.getOffset() + ", len=" + os2Entry.getLength());
}
in.skip(2); //xAvgCharWidth
this.usWeightClass = in.readTTFUShort();
// usWidthClass
in.skip(2);
int fsType = in.readTTFUShort();
if (fsType == 2) {
isEmbeddable = false;
} else {
isEmbeddable = true;
}
in.skip(11 * 2);
in.skip(10); //panose array
in.skip(4 * 4); //unicode ranges
in.skip(4);
in.skip(3 * 2);
int v;
os2Ascender = in.readTTFShort(); //sTypoAscender
os2Descender = in.readTTFShort(); //sTypoDescender
if (log.isDebugEnabled()) {
log.debug("sTypoAscender: " + os2Ascender
+ " -> internal " + convertTTFUnit2PDFUnit(os2Ascender));
log.debug("sTypoDescender: " + os2Descender
+ " -> internal " + convertTTFUnit2PDFUnit(os2Descender));
}
v = in.readTTFShort(); //sTypoLineGap
if (log.isDebugEnabled()) {
log.debug("sTypoLineGap: " + v);
}
v = in.readTTFUShort(); //usWinAscent
if (log.isDebugEnabled()) {
log.debug("usWinAscent: " + formatUnitsForDebug(v));
}
v = in.readTTFUShort(); //usWinDescent
if (log.isDebugEnabled()) {
log.debug("usWinDescent: " + formatUnitsForDebug(v));
}
//version 1 OS/2 table might end here
if (os2Entry.getLength() >= 78 + (2 * 4) + (2 * 2)) {
in.skip(2 * 4);
this.os2xHeight = in.readTTFShort(); //sxHeight
this.os2CapHeight = in.readTTFShort(); //sCapHeight
if (log.isDebugEnabled()) {
log.debug("sxHeight: " + this.os2xHeight);
log.debug("sCapHeight: " + this.os2CapHeight);
}
}
} else {
isEmbeddable = true;
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
protected final void readIndexToLocation(FontFileReader in)
throws IOException {
if (!seekTab(in, "loca", 0)) {
throw new IOException("'loca' table not found, happens when the font file doesn't"
+ " contain TrueType outlines (trying to read an OpenType CFF font maybe?)");
}
for (int i = 0; i < numberOfGlyphs; i++) {
mtxTab[i].setOffset(locaFormat == 1 ? in.readTTFULong()
: (in.readTTFUShort() << 1));
}
lastLoca = (locaFormat == 1 ? in.readTTFULong()
: (in.readTTFUShort() << 1));
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private void readGlyf(FontFileReader in) throws IOException {
TTFDirTabEntry dirTab = getDirectoryEntry ( "glyf" );
if (dirTab == null) {
throw new IOException("glyf table not found, cannot continue");
}
for (int i = 0; i < (numberOfGlyphs - 1); i++) {
if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
in.seekSet(dirTab.getOffset() + mtxTab[i].getOffset());
in.skip(2);
final int[] bbox = {
in.readTTFShort(),
in.readTTFShort(),
in.readTTFShort(),
in.readTTFShort()};
mtxTab[i].setBoundingBox(bbox);
} else {
mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox());
}
}
long n = dirTab.getOffset();
for (int i = 0; i < numberOfGlyphs; i++) {
if ((i + 1) >= mtxTab.length
|| mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
in.seekSet(n + mtxTab[i].getOffset());
in.skip(2);
final int[] bbox = {
in.readTTFShort(),
in.readTTFShort(),
in.readTTFShort(),
in.readTTFShort()};
mtxTab[i].setBoundingBox(bbox);
} else {
/**@todo Verify that this is correct, looks like a copy/paste bug (jm)*/
final int bbox0 = mtxTab[0].getBoundingBox()[0];
final int[] bbox = {bbox0, bbox0, bbox0, bbox0};
mtxTab[i].setBoundingBox(bbox);
/* Original code
mtxTab[i].bbox[0] = mtxTab[0].bbox[0];
mtxTab[i].bbox[1] = mtxTab[0].bbox[0];
mtxTab[i].bbox[2] = mtxTab[0].bbox[0];
mtxTab[i].bbox[3] = mtxTab[0].bbox[0]; */
}
if (log.isTraceEnabled()) {
log.trace(mtxTab[i].toString(this));
}
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private void readName(FontFileReader in) throws IOException {
seekTab(in, "name", 2);
int i = in.getCurrentPos();
int n = in.readTTFUShort();
int j = in.readTTFUShort() + i - 2;
i += 2 * 2;
while (n-- > 0) {
// getLogger().debug("Iteration: " + n);
in.seekSet(i);
final int platformID = in.readTTFUShort();
final int encodingID = in.readTTFUShort();
final int languageID = in.readTTFUShort();
int k = in.readTTFUShort();
int l = in.readTTFUShort();
if (((platformID == 1 || platformID == 3)
&& (encodingID == 0 || encodingID == 1))) {
in.seekSet(j + in.readTTFUShort());
String txt;
if (platformID == 3) {
txt = in.readTTFString(l, encodingID);
} else {
txt = in.readTTFString(l);
}
if (log.isDebugEnabled()) {
log.debug(platformID + " "
+ encodingID + " "
+ languageID + " "
+ k + " " + txt);
}
switch (k) {
case 0:
if (notice.length() == 0) {
notice = txt;
}
break;
case 1: //Font Family Name
case 16: //Preferred Family
familyNames.add(txt);
break;
case 2:
if (subFamilyName.length() == 0) {
subFamilyName = txt;
}
break;
case 4:
if (fullName.length() == 0 || (platformID == 3 && languageID == 1033)) {
fullName = txt;
}
break;
case 6:
if (postScriptName.length() == 0) {
postScriptName = txt;
}
break;
default:
break;
}
}
i += 6 * 2;
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private boolean readPCLT(FontFileReader in) throws IOException {
TTFDirTabEntry dirTab = getDirectoryEntry ( "PCLT" );
if (dirTab != null) {
in.seekSet(dirTab.getOffset() + 4 + 4 + 2);
xHeight = in.readTTFUShort();
log.debug("xHeight from PCLT: " + formatUnitsForDebug(xHeight));
in.skip(2 * 2);
capHeight = in.readTTFUShort();
log.debug("capHeight from PCLT: " + formatUnitsForDebug(capHeight));
in.skip(2 + 16 + 8 + 6 + 1 + 1);
int serifStyle = in.readTTFUByte();
serifStyle = serifStyle >> 6;
serifStyle = serifStyle & 3;
if (serifStyle == 1) {
hasSerifs = false;
} else {
hasSerifs = true;
}
return true;
} else {
return false;
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private void readKerning(FontFileReader in) throws IOException {
// Read kerning
kerningTab = new java.util.HashMap();
ansiKerningTab = new java.util.HashMap();
TTFDirTabEntry dirTab = getDirectoryEntry ( "kern" );
if (dirTab != null) {
seekTab(in, "kern", 2);
for (int n = in.readTTFUShort(); n > 0; n--) {
in.skip(2 * 2);
int k = in.readTTFUShort();
if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0) {
return;
}
if ((k >> 8) != 0) {
continue;
}
k = in.readTTFUShort();
in.skip(3 * 2);
while (k-- > 0) {
int i = in.readTTFUShort();
int j = in.readTTFUShort();
int kpx = in.readTTFShort();
if (kpx != 0) {
// CID kerning table entry, using unicode indexes
final Integer iObj = glyphToUnicode(i);
final Integer u2 = glyphToUnicode(j);
if (iObj == null) {
// happens for many fonts (Ubuntu font set),
// stray entries in the kerning table??
log.debug("Ignoring kerning pair because no Unicode index was"
+ " found for the first glyph " + i);
} else if (u2 == null) {
log.debug("Ignoring kerning pair because Unicode index was"
+ " found for the second glyph " + i);
} else {
Map adjTab = kerningTab.get(iObj);
if (adjTab == null) {
adjTab = new java.util.HashMap();
}
adjTab.put(u2, new Integer(convertTTFUnit2PDFUnit(kpx)));
kerningTab.put(iObj, adjTab);
}
}
}
}
// Create winAnsiEncoded kerning table from kerningTab
// (could probably be simplified, for now we remap back to CID indexes and
// then to winAnsi)
Iterator ae = kerningTab.keySet().iterator();
while (ae.hasNext()) {
Integer unicodeKey1 = (Integer)ae.next();
Integer cidKey1 = unicodeToGlyph(unicodeKey1.intValue());
Map<Integer, Integer> akpx = new java.util.HashMap();
Map ckpx = kerningTab.get(unicodeKey1);
Iterator aee = ckpx.keySet().iterator();
while (aee.hasNext()) {
Integer unicodeKey2 = (Integer)aee.next();
Integer cidKey2 = unicodeToGlyph(unicodeKey2.intValue());
Integer kern = (Integer)ckpx.get(unicodeKey2);
Iterator uniMap = mtxTab[cidKey2.intValue()].getUnicodeIndex().listIterator();
while (uniMap.hasNext()) {
Integer unicodeKey = (Integer)uniMap.next();
Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
for (int u = 0; u < ansiKeys.length; u++) {
akpx.put(ansiKeys[u], kern);
}
}
}
if (akpx.size() > 0) {
Iterator uniMap = mtxTab[cidKey1.intValue()].getUnicodeIndex().listIterator();
while (uniMap.hasNext()) {
Integer unicodeKey = (Integer)uniMap.next();
Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
for (int u = 0; u < ansiKeys.length; u++) {
ansiKerningTab.put(ansiKeys[u], akpx);
}
}
}
}
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
protected final boolean checkTTC(FontFileReader in, String name) throws IOException {
String tag = in.readTTFString(4);
if ("ttcf".equals(tag)) {
// This is a TrueType Collection
in.skip(4);
// Read directory offsets
int numDirectories = (int)in.readTTFULong();
// int numDirectories=in.readTTFUShort();
long[] dirOffsets = new long[numDirectories];
for (int i = 0; i < numDirectories; i++) {
dirOffsets[i] = in.readTTFULong();
}
log.info("This is a TrueType collection file with "
+ numDirectories + " fonts");
log.info("Containing the following fonts: ");
// Read all the directories and name tables to check
// If the font exists - this is a bit ugly, but...
boolean found = false;
// Iterate through all name tables even if font
// Is found, just to show all the names
long dirTabOffset = 0;
for (int i = 0; (i < numDirectories); i++) {
in.seekSet(dirOffsets[i]);
readDirTabs(in);
readName(in);
if (fullName.equals(name)) {
found = true;
dirTabOffset = dirOffsets[i];
log.info(fullName + " <-- selected");
} else {
log.info(fullName);
}
// Reset names
notice = "";
fullName = "";
familyNames.clear();
postScriptName = "";
subFamilyName = "";
}
in.seekSet(dirTabOffset);
return found;
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
public final List<String> getTTCnames(FontFileReader in) throws IOException {
List<String> fontNames = new java.util.ArrayList<String>();
String tag = in.readTTFString(4);
if ("ttcf".equals(tag)) {
// This is a TrueType Collection
in.skip(4);
// Read directory offsets
int numDirectories = (int)in.readTTFULong();
long[] dirOffsets = new long[numDirectories];
for (int i = 0; i < numDirectories; i++) {
dirOffsets[i] = in.readTTFULong();
}
log.info("This is a TrueType collection file with "
+ numDirectories + " fonts");
log.info("Containing the following fonts: ");
for (int i = 0; (i < numDirectories); i++) {
in.seekSet(dirOffsets[i]);
readDirTabs(in);
readName(in);
log.info(fullName);
fontNames.add(fullName);
// Reset names
notice = "";
fullName = "";
familyNames.clear();
postScriptName = "";
subFamilyName = "";
}
in.seekSet(0);
return fontNames;
}
// in src/java/org/apache/fop/fonts/truetype/TTFFile.java
private Integer unicodeToGlyph(int unicodeIndex) throws IOException {
final Integer result
= (Integer) unicodeToGlyphMap.get(new Integer(unicodeIndex));
if (result == null) {
throw new IOException(
"Glyph index not found for unicode value " + unicodeIndex);
}
return result;
}
// in src/java/org/apache/fop/fonts/truetype/GlyfTable.java
void populateGlyphsWithComposites() throws IOException {
for (int indexInOriginal : subset.keySet()) {
scanGlyphsRecursively(indexInOriginal);
}
addAllComposedGlyphsToSubset();
for (int compositeGlyph : compositeGlyphs) {
long offset = tableOffset + mtxTab[compositeGlyph].getOffset() + 10;
if (!remappedComposites.contains(offset)) {
remapComposite(offset);
}
}
}
// in src/java/org/apache/fop/fonts/truetype/GlyfTable.java
private void scanGlyphsRecursively(int indexInOriginal) throws IOException {
if (!subset.containsKey(indexInOriginal)) {
composedGlyphs.add(indexInOriginal);
}
if (isComposite(indexInOriginal)) {
compositeGlyphs.add(indexInOriginal);
Set<Integer> composedGlyphs = retrieveComposedGlyphs(indexInOriginal);
for (Integer composedGlyph : composedGlyphs) {
scanGlyphsRecursively(composedGlyph);
}
}
}
// in src/java/org/apache/fop/fonts/truetype/GlyfTable.java
private void remapComposite(long glyphOffset) throws IOException {
long currentGlyphOffset = glyphOffset;
remappedComposites.add(currentGlyphOffset);
int flags = 0;
do {
flags = in.readTTFUShort(currentGlyphOffset);
int glyphIndex = in.readTTFUShort(currentGlyphOffset + 2);
Integer indexInSubset = subset.get(glyphIndex);
assert indexInSubset != null;
/*
* TODO: this should not be done here!! We're writing to the stream we're reading from,
* this is asking for trouble! What should happen is when the glyph data is copied from
* subset, the remapping should be done there. So the original stream is left untouched.
*/
in.writeTTFUShort(currentGlyphOffset + 2, indexInSubset);
currentGlyphOffset += 4 + GlyfFlags.getOffsetToNextComposedGlyf(flags);
} while (GlyfFlags.hasMoreComposites(flags));
}
// in src/java/org/apache/fop/fonts/truetype/GlyfTable.java
private boolean isComposite(int indexInOriginal) throws IOException {
int numberOfContours = in.readTTFShort(tableOffset + mtxTab[indexInOriginal].getOffset());
return numberOfContours < 0;
}
// in src/java/org/apache/fop/fonts/truetype/GlyfTable.java
private Set<Integer> retrieveComposedGlyphs(int indexInOriginal)
throws IOException {
Set<Integer> composedGlyphs = new HashSet<Integer>();
long offset = tableOffset + mtxTab[indexInOriginal].getOffset() + 10;
int flags = 0;
do {
flags = in.readTTFUShort(offset);
composedGlyphs.add(in.readTTFUShort(offset + 2));
offset += 4 + GlyfFlags.getOffsetToNextComposedGlyf(flags);
} while (GlyfFlags.hasMoreComposites(flags));
return composedGlyphs;
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private boolean createCvt(FontFileReader in) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt ");
if (entry != null) {
pad4();
seekTab(in, "cvt ", 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(cvtDirOffset, checksum);
writeULong(cvtDirOffset + 4, currentPos);
writeULong(cvtDirOffset + 8, (int)entry.getLength());
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
return true;
} else {
return false;
//throw new IOException("Can't find cvt table");
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private boolean createFpgm(FontFileReader in) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm");
if (entry != null) {
pad4();
seekTab(in, "fpgm", 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(fpgmDirOffset, checksum);
writeULong(fpgmDirOffset + 4, currentPos);
writeULong(fpgmDirOffset + 8, (int)entry.getLength());
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
return true;
} else {
return false;
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private void createLoca(int size) throws IOException {
pad4();
locaOffset = currentPos;
writeULong(locaDirOffset + 4, currentPos);
writeULong(locaDirOffset + 8, size * 4 + 4);
currentPos += size * 4 + 4;
realSize += size * 4 + 4;
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private void createMaxp(FontFileReader in, int size) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp");
if (entry != null) {
pad4();
seekTab(in, "maxp", 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
writeUShort(currentPos + 4, size);
int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(maxpDirOffset, checksum);
writeULong(maxpDirOffset + 4, currentPos);
writeULong(maxpDirOffset + 8, (int)entry.getLength());
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find maxp table");
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private boolean createPrep(FontFileReader in) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep");
if (entry != null) {
pad4();
seekTab(in, "prep", 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(prepDirOffset, checksum);
writeULong(prepDirOffset + 4, currentPos);
writeULong(prepDirOffset + 8, (int)entry.getLength());
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
return true;
} else {
return false;
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private void createHhea(FontFileReader in, int size) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea");
if (entry != null) {
pad4();
seekTab(in, "hhea", 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
writeUShort((int)entry.getLength() + currentPos - 2, size);
int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(hheaDirOffset, checksum);
writeULong(hheaDirOffset + 4, currentPos);
writeULong(hheaDirOffset + 8, (int)entry.getLength());
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find hhea table");
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private void createHead(FontFileReader in) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head");
if (entry != null) {
pad4();
seekTab(in, "head", 0);
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
0, output, currentPos, (int)entry.getLength());
checkSumAdjustmentOffset = currentPos + 8;
output[currentPos + 8] = 0; // Set checkSumAdjustment to 0
output[currentPos + 9] = 0;
output[currentPos + 10] = 0;
output[currentPos + 11] = 0;
output[currentPos + 50] = 0; // long locaformat
output[currentPos + 51] = 1; // long locaformat
int checksum = getCheckSum(currentPos, (int)entry.getLength());
writeULong(headDirOffset, checksum);
writeULong(headDirOffset + 4, currentPos);
writeULong(headDirOffset + 8, (int)entry.getLength());
currentPos += (int)entry.getLength();
realSize += (int)entry.getLength();
} else {
throw new IOException("Can't find head table");
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private void createGlyf(FontFileReader in,
Map glyphs) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
int size = 0;
int start = 0;
int endOffset = 0; // Store this as the last loca
if (entry != null) {
pad4();
start = currentPos;
/* Loca table must be in order by glyph index, so build
* an array first and then write the glyph info and
* location offset.
*/
int[] origIndexes = new int[glyphs.size()];
Iterator e = glyphs.keySet().iterator();
while (e.hasNext()) {
Integer origIndex = (Integer)e.next();
Integer subsetIndex = (Integer)glyphs.get(origIndex);
origIndexes[subsetIndex.intValue()] = origIndex.intValue();
}
for (int i = 0; i < origIndexes.length; i++) {
int glyphLength = 0;
int nextOffset = 0;
int origGlyphIndex = origIndexes[i];
if (origGlyphIndex >= (mtxTab.length - 1)) {
nextOffset = (int)lastLoca;
} else {
nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset();
}
glyphLength = nextOffset - (int)mtxTab[origGlyphIndex].getOffset();
// Copy glyph
System.arraycopy(
in.getBytes((int)entry.getOffset() + (int)mtxTab[origGlyphIndex].getOffset(),
glyphLength), 0,
output, currentPos,
glyphLength);
// Update loca table
writeULong(locaOffset + i * 4, currentPos - start);
if ((currentPos - start + glyphLength) > endOffset) {
endOffset = (currentPos - start + glyphLength);
}
currentPos += glyphLength;
realSize += glyphLength;
}
size = currentPos - start;
int checksum = getCheckSum(start, size);
writeULong(glyfDirOffset, checksum);
writeULong(glyfDirOffset + 4, start);
writeULong(glyfDirOffset + 8, size);
currentPos += 12;
realSize += 12;
// Update loca checksum and last loca index
writeULong(locaOffset + glyphs.size() * 4, endOffset);
checksum = getCheckSum(locaOffset, glyphs.size() * 4 + 4);
writeULong(locaDirOffset, checksum);
} else {
throw new IOException("Can't find glyf table");
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private void createHmtx(FontFileReader in,
Map glyphs) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx");
int longHorMetricSize = glyphs.size() * 2;
int leftSideBearingSize = glyphs.size() * 2;
int hmtxSize = longHorMetricSize + leftSideBearingSize;
if (entry != null) {
pad4();
//int offset = (int)entry.offset;
Iterator e = glyphs.keySet().iterator();
while (e.hasNext()) {
Integer origIndex = (Integer)e.next();
Integer subsetIndex = (Integer)glyphs.get(origIndex);
writeUShort(currentPos + subsetIndex.intValue() * 4,
mtxTab[origIndex.intValue()].getWx());
writeUShort(currentPos + subsetIndex.intValue() * 4 + 2,
mtxTab[origIndex.intValue()].getLsb());
}
int checksum = getCheckSum(currentPos, hmtxSize);
writeULong(hmtxDirOffset, checksum);
writeULong(hmtxDirOffset + 4, currentPos);
writeULong(hmtxDirOffset + 8, hmtxSize);
currentPos += hmtxSize;
realSize += hmtxSize;
} else {
throw new IOException("Can't find hmtx table");
}
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
public byte[] readFont(FontFileReader in, String name,
Map<Integer, Integer> glyphs) throws IOException {
//Check if TrueType collection, and that the name exists in the collection
if (!checkTTC(in, name)) {
throw new IOException("Failed to read font");
}
//Copy the Map as we're going to modify it
Map<Integer, Integer> subsetGlyphs = new java.util.HashMap<Integer, Integer>(glyphs);
output = new byte[in.getFileSize()];
readDirTabs(in);
readFontHeader(in);
getNumGlyphs(in);
readHorizontalHeader(in);
readHorizontalMetrics(in);
readIndexToLocation(in);
scanGlyphs(in, subsetGlyphs);
createDirectory(); // Create the TrueType header and directory
createHead(in);
createHhea(in, subsetGlyphs.size()); // Create the hhea table
createHmtx(in, subsetGlyphs); // Create hmtx table
createMaxp(in, subsetGlyphs.size()); // copy the maxp table
boolean optionalTableFound;
optionalTableFound = createCvt(in); // copy the cvt table
if (!optionalTableFound) {
// cvt is optional (used in TrueType fonts only)
log.debug("TrueType: ctv table not present. Skipped.");
}
optionalTableFound = createFpgm(in); // copy fpgm table
if (!optionalTableFound) {
// fpgm is optional (used in TrueType fonts only)
log.debug("TrueType: fpgm table not present. Skipped.");
}
optionalTableFound = createPrep(in); // copy prep table
if (!optionalTableFound) {
// prep is optional (used in TrueType fonts only)
log.debug("TrueType: prep table not present. Skipped.");
}
createLoca(subsetGlyphs.size()); // create empty loca table
createGlyf(in, subsetGlyphs); //create glyf table and update loca table
pad4();
createCheckSumAdjustment();
byte[] ret = new byte[realSize];
System.arraycopy(output, 0, ret, 0, realSize);
return ret;
}
// in src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
private void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs)
throws IOException {
TTFDirTabEntry glyfTableInfo = (TTFDirTabEntry) dirTabs.get("glyf");
if (glyfTableInfo == null) {
throw new IOException("Glyf table could not be found");
}
GlyfTable glyfTable = new GlyfTable(in, mtxTab, glyfTableInfo, subsetGlyphs);
glyfTable.populateGlyphsWithComposites();
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
private void init(InputStream in) throws java.io.IOException {
this.file = IOUtils.toByteArray(in);
this.fsize = this.file.length;
this.current = 0;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public void seekSet(long offset) throws IOException {
if (offset > fsize || offset < 0) {
throw new java.io.EOFException("Reached EOF, file size=" + fsize
+ " offset=" + offset);
}
current = (int)offset;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public void seekAdd(long add) throws IOException {
seekSet(current + add);
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public void skip(long add) throws IOException {
seekAdd(add);
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public byte read() throws IOException {
if (current >= fsize) {
throw new java.io.EOFException("Reached EOF, file size=" + fsize);
}
final byte ret = file[current++];
return ret;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final byte readTTFByte() throws IOException {
return read();
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final int readTTFUByte() throws IOException {
final byte buf = read();
if (buf < 0) {
return (int)(256 + buf);
} else {
return (int)buf;
}
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final short readTTFShort() throws IOException {
final int ret = (readTTFUByte() << 8) + readTTFUByte();
final short sret = (short)ret;
return sret;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final int readTTFUShort() throws IOException {
final int ret = (readTTFUByte() << 8) + readTTFUByte();
return (int)ret;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final void writeTTFUShort(long pos, int val) throws IOException {
if ((pos + 2) > fsize) {
throw new java.io.EOFException("Reached EOF");
}
final byte b1 = (byte)((val >> 8) & 0xff);
final byte b2 = (byte)(val & 0xff);
final int fileIndex = (int) pos;
file[fileIndex] = b1;
file[fileIndex + 1] = b2;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final short readTTFShort(long pos) throws IOException {
final long cp = getCurrentPos();
seekSet(pos);
final short ret = readTTFShort();
seekSet(cp);
return ret;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final int readTTFUShort(long pos) throws IOException {
long cp = getCurrentPos();
seekSet(pos);
int ret = readTTFUShort();
seekSet(cp);
return ret;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final int readTTFLong() throws IOException {
long ret = readTTFUByte(); // << 8;
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
return (int)ret;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final long readTTFULong() throws IOException {
long ret = readTTFUByte();
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
ret = (ret << 8) + readTTFUByte();
return ret;
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final String readTTFString() throws IOException {
int i = current;
while (file[i++] != 0) {
if (i > fsize) {
throw new java.io.EOFException("Reached EOF, file size="
+ fsize);
}
}
byte[] tmp = new byte[i - current];
System.arraycopy(file, current, tmp, 0, i - current);
return new String(tmp, "ISO-8859-1");
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final String readTTFString(int len) throws IOException {
if ((len + current) > fsize) {
throw new java.io.EOFException("Reached EOF, file size=" + fsize);
}
byte[] tmp = new byte[len];
System.arraycopy(file, current, tmp, 0, len);
current += len;
final String encoding;
if ((tmp.length > 0) && (tmp[0] == 0)) {
encoding = "UTF-16BE";
} else {
encoding = "ISO-8859-1";
}
return new String(tmp, encoding);
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public final String readTTFString(int len, int encodingID) throws IOException {
if ((len + current) > fsize) {
throw new java.io.EOFException("Reached EOF, file size=" + fsize);
}
byte[] tmp = new byte[len];
System.arraycopy(file, current, tmp, 0, len);
current += len;
final String encoding;
encoding = "UTF-16BE"; //Use this for all known encoding IDs for now
return new String(tmp, encoding);
}
// in src/java/org/apache/fop/fonts/truetype/FontFileReader.java
public byte[] getBytes(int offset,
int length) throws IOException {
if ((offset + length) > fsize) {
throw new java.io.IOException("Reached EOF");
}
byte[] ret = new byte[length];
System.arraycopy(file, offset, ret, 0, length);
return ret;
}
// in src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
Override
protected void read() throws IOException {
read(this.subFontName);
}
// in src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
private void read(String ttcFontName) throws IOException {
InputStream in = openFontUri(resolver, this.fontFileURI);
try {
TTFFile ttf = new TTFFile(useKerning, useAdvanced);
FontFileReader reader = new FontFileReader(in);
boolean supported = ttf.readFont(reader, ttcFontName);
if (!supported) {
throw new IOException("TrueType font is not supported: " + fontFileURI);
}
buildFont(ttf, ttcFontName);
loaded = true;
} finally {
IOUtils.closeQuietly(in);
}
}
// in src/java/org/apache/fop/render/print/PrintRenderer.java
public void stopRenderer() throws IOException {
super.stopRenderer();
try {
printerJob.print();
} catch (PrinterException e) {
log.error(e);
throw new IOException("Unable to print: " + e.getClass().getName()
+ ": " + e.getMessage());
}
clearViewportList();
}
// in src/java/org/apache/fop/render/print/PageableRenderer.java
public void stopRenderer() throws IOException {
super.stopRenderer();
if (endNumber == -1) {
// was not set on command line
endNumber = getNumberOfPages();
}
}
// in src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java
public void outputContents(OutputStream out) throws IOException {
long start = System.currentTimeMillis();
encodingHelper.encode(out);
long duration = System.currentTimeMillis() - start;
if (log.isDebugEnabled()) {
log.debug("Image encoding took " + duration + "ms");
}
}
// in src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
private void addsRGBColorSpace() throws IOException {
if (disableSRGBColorSpace) {
if (this.pdfAMode != PDFAMode.DISABLED
|| this.pdfXMode != PDFXMode.DISABLED
|| this.outputProfileURI != null) {
throw new IllegalStateException("It is not possible to disable the sRGB color"
+ " space if PDF/A or PDF/X functionality is enabled or an"
+ " output profile is set!");
}
} else {
if (this.sRGBColorSpace != null) {
return;
}
//Map sRGB as default RGB profile for DeviceRGB
this.sRGBColorSpace = PDFICCBasedColorSpace.setupsRGBAsDefaultRGBColorSpace(pdfDoc);
}
}
// in src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
private void addDefaultOutputProfile() throws IOException {
if (this.outputProfile != null) {
return;
}
ICC_Profile profile;
InputStream in = null;
if (this.outputProfileURI != null) {
this.outputProfile = pdfDoc.getFactory().makePDFICCStream();
Source src = getUserAgent().resolveURI(this.outputProfileURI);
if (src == null) {
throw new IOException("Output profile not found: " + this.outputProfileURI);
}
if (src instanceof StreamSource) {
in = ((StreamSource)src).getInputStream();
} else {
in = new URL(src.getSystemId()).openStream();
}
try {
profile = ColorProfileUtil.getICC_Profile(in);
} finally {
IOUtils.closeQuietly(in);
}
this.outputProfile.setColorSpace(profile, null);
} else {
//Fall back to sRGB profile
outputProfile = sRGBColorSpace.getICCStream();
}
}
// in src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
private void addPDFA1OutputIntent() throws IOException {
addDefaultOutputProfile();
String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
outputIntent.setSubtype(PDFOutputIntent.GTS_PDFA1);
outputIntent.setDestOutputProfile(this.outputProfile);
outputIntent.setOutputConditionIdentifier(desc);
outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
pdfDoc.getRoot().addOutputIntent(outputIntent);
}
// in src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
private void addPDFXOutputIntent() throws IOException {
addDefaultOutputProfile();
String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
int deviceClass = this.outputProfile.getICCProfile().getProfileClass();
if (deviceClass != ICC_Profile.CLASS_OUTPUT) {
throw new PDFConformanceException(pdfDoc.getProfile().getPDFXMode() + " requires that"
+ " the DestOutputProfile be an Output Device Profile. "
+ desc + " does not match that requirement.");
}
PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
outputIntent.setSubtype(PDFOutputIntent.GTS_PDFX);
outputIntent.setDestOutputProfile(this.outputProfile);
outputIntent.setOutputConditionIdentifier(desc);
outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
pdfDoc.getRoot().addOutputIntent(outputIntent);
}
// in src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
public PDFDocument setupPDFDocument(OutputStream out) throws IOException {
if (this.pdfDoc != null) {
throw new IllegalStateException("PDFDocument already set up");
}
String producer = userAgent.getProducer() != null ? userAgent.getProducer() : "";
if (maxPDFVersion == null) {
this.pdfDoc = new PDFDocument(producer);
} else {
VersionController controller
= VersionController.getFixedVersionController(maxPDFVersion);
this.pdfDoc = new PDFDocument(producer, controller);
}
updateInfo();
updatePDFProfiles();
pdfDoc.setFilterMap(filterMap);
pdfDoc.outputHeader(out);
//Setup encryption if necessary
PDFEncryptionManager.setupPDFEncryption(encryptionParams, pdfDoc);
addsRGBColorSpace();
if (this.outputProfileURI != null) {
addDefaultOutputProfile();
}
if (pdfXMode != PDFXMode.DISABLED) {
log.debug(pdfXMode + " is active.");
log.warn("Note: " + pdfXMode
+ " support is work-in-progress and not fully implemented, yet!");
addPDFXOutputIntent();
}
if (pdfAMode.isPDFA1LevelB()) {
log.debug("PDF/A is active. Conformance Level: " + pdfAMode);
addPDFA1OutputIntent();
}
this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled());
return this.pdfDoc;
}
// in src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
public void addEmbeddedFile(PDFEmbeddedFileExtensionAttachment embeddedFile)
throws IOException {
this.pdfDoc.getProfile().verifyEmbeddedFilesAllowed();
PDFNames names = this.pdfDoc.getRoot().getNames();
if (names == null) {
//Add Names if not already present
names = this.pdfDoc.getFactory().makeNames();
this.pdfDoc.getRoot().setNames(names);
}
//Create embedded file
PDFEmbeddedFile file = new PDFEmbeddedFile();
this.pdfDoc.registerObject(file);
Source src = getUserAgent().resolveURI(embeddedFile.getSrc());
InputStream in = ImageUtil.getInputStream(src);
if (in == null) {
throw new FileNotFoundException(embeddedFile.getSrc());
}
try {
OutputStream out = file.getBufferOutputStream();
IOUtils.copyLarge(in, out);
} finally {
IOUtils.closeQuietly(in);
}
PDFDictionary dict = new PDFDictionary();
dict.put("F", file);
String filename = PDFText.toPDFString(embeddedFile.getFilename(), '_');
PDFFileSpec fileSpec = new PDFFileSpec(filename);
fileSpec.setEmbeddedFile(dict);
if (embeddedFile.getDesc() != null) {
fileSpec.setDescription(embeddedFile.getDesc());
}
this.pdfDoc.registerObject(fileSpec);
//Make sure there is an EmbeddedFiles in the Names dictionary
PDFEmbeddedFiles embeddedFiles = names.getEmbeddedFiles();
if (embeddedFiles == null) {
embeddedFiles = new PDFEmbeddedFiles();
this.pdfDoc.assignObjectNumber(embeddedFiles);
this.pdfDoc.addTrailerObject(embeddedFiles);
names.setEmbeddedFiles(embeddedFiles);
}
//Add to EmbeddedFiles in the Names dictionary
PDFArray nameArray = embeddedFiles.getNames();
if (nameArray == null) {
nameArray = new PDFArray();
embeddedFiles.setNames(nameArray);
}
String name = PDFText.toPDFString(filename);
nameArray.add(name);
nameArray.add(new PDFReference(fileSpec));
}
// in src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
public void flushPDFDoc() throws IOException {
this.document.output(this.outputStream);
}
// in src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
public void handleImage(RenderingContext context, // CSOK: MethodLength
Image image, Rectangle pos)
throws IOException {
PDFRenderingContext pdfContext = (PDFRenderingContext)context;
PDFContentGenerator generator = pdfContext.getGenerator();
ImageXMLDOM imageSVG = (ImageXMLDOM)image;
FOUserAgent userAgent = context.getUserAgent();
final float deviceResolution = userAgent.getTargetResolution();
if (log.isDebugEnabled()) {
log.debug("Generating SVG at " + deviceResolution + "dpi.");
}
final float uaResolution = userAgent.getSourceResolution();
SVGUserAgent ua = new SVGUserAgent(userAgent, new AffineTransform());
GVTBuilder builder = new GVTBuilder();
//Controls whether text painted by Batik is generated using text or path operations
boolean strokeText = false;
//TODO connect with configuration elsewhere.
BridgeContext ctx = new PDFBridgeContext(ua,
(strokeText ? null : pdfContext.getFontInfo()),
userAgent.getFactory().getImageManager(),
userAgent.getImageSessionContext(),
new AffineTransform());
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
//to it.
Document clonedDoc = BatikUtil.cloneSVGDocument(imageSVG.getDocument());
GraphicsNode root;
try {
root = builder.build(ctx, clonedDoc);
builder = null;
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI());
return;
}
// get the 'width' and 'height' attributes of the SVG document
float w = image.getSize().getWidthMpt();
float h = image.getSize().getHeightMpt();
float sx = pos.width / w;
float sy = pos.height / h;
//Scaling and translation for the bounding box of the image
AffineTransform scaling = new AffineTransform(
sx, 0, 0, sy, pos.x / 1000f, pos.y / 1000f);
double sourceScale = UnitConv.IN2PT / uaResolution;
scaling.scale(sourceScale, sourceScale);
//Scale for higher resolution on-the-fly images from Batik
AffineTransform resolutionScaling = new AffineTransform();
double targetScale = uaResolution / deviceResolution;
resolutionScaling.scale(targetScale, targetScale);
resolutionScaling.scale(1.0 / sx, 1.0 / sy);
//Transformation matrix that establishes the local coordinate system for the SVG graphic
//in relation to the current coordinate system
AffineTransform imageTransform = new AffineTransform();
imageTransform.concatenate(scaling);
imageTransform.concatenate(resolutionScaling);
if (log.isTraceEnabled()) {
log.trace("nat size: " + w + "/" + h);
log.trace("req size: " + pos.width + "/" + pos.height);
log.trace("source res: " + uaResolution + ", targetRes: " + deviceResolution
+ " --> target scaling: " + targetScale);
log.trace(image.getSize());
log.trace("sx: " + sx + ", sy: " + sy);
log.trace("scaling: " + scaling);
log.trace("resolution scaling: " + resolutionScaling);
log.trace("image transform: " + resolutionScaling);
}
/*
* Clip to the svg area.
* Note: To have the svg overlay (under) a text area then use
* an fo:block-container
*/
if (log.isTraceEnabled()) {
generator.comment("SVG setup");
}
generator.saveGraphicsState();
if (context.getUserAgent().isAccessibilityEnabled()) {
MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
generator.beginMarkedContentSequence(mci.tag, mci.mcid);
}
generator.updateColor(Color.black, false, null);
generator.updateColor(Color.black, true, null);
if (!scaling.isIdentity()) {
if (log.isTraceEnabled()) {
generator.comment("viewbox");
}
generator.add(CTMHelper.toPDFString(scaling, false) + " cm\n");
}
//SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
PDFGraphics2D graphics = new PDFGraphics2D(true, pdfContext.getFontInfo(),
generator.getDocument(),
generator.getResourceContext(), pdfContext.getPage().referencePDF(),
"", 0);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
if (!resolutionScaling.isIdentity()) {
if (log.isTraceEnabled()) {
generator.comment("resolution scaling for " + uaResolution
+ " -> " + deviceResolution);
}
generator.add(
CTMHelper.toPDFString(resolutionScaling, false) + " cm\n");
graphics.scale(
1.0 / resolutionScaling.getScaleX(),
1.0 / resolutionScaling.getScaleY());
}
if (log.isTraceEnabled()) {
generator.comment("SVG start");
}
//Save state and update coordinate system for the SVG image
generator.getState().save();
generator.getState().concatenate(imageTransform);
//Now that we have the complete transformation matrix for the image, we can update the
//transformation matrix for the AElementBridge.
PDFAElementBridge aBridge = (PDFAElementBridge)ctx.getBridge(
SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_A_TAG);
aBridge.getCurrentTransform().setTransform(generator.getState().getTransform());
graphics.setPaintingState(generator.getState());
graphics.setOutputStream(generator.getOutputStream());
try {
root.paint(graphics);
ctx.dispose();
generator.add(graphics.getString());
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
}
generator.getState().restore();
if (context.getUserAgent().isAccessibilityEnabled()) {
generator.restoreGraphicsStateAccess();
} else {
generator.restoreGraphicsState();
}
if (log.isTraceEnabled()) {
generator.comment("SVG end");
}
}
// in src/java/org/apache/fop/render/pdf/AbstractPDFImageHandler.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
assert context instanceof PDFRenderingContext;
PDFRenderingContext pdfContext = (PDFRenderingContext)context;
PDFContentGenerator generator = pdfContext.getGenerator();
PDFImage pdfimage = createPDFImage(image, image.getInfo().getOriginalURI());
PDFXObject xobj = generator.getDocument().addImage(
generator.getResourceContext(), pdfimage);
float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
if (context.getUserAgent().isAccessibilityEnabled()) {
MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
generator.placeImage(x, y, w, h, xobj, mci.tag, mci.mcid);
} else {
generator.placeImage(x, y, w, h, xobj);
}
}
// in src/java/org/apache/fop/render/pdf/ImageRawCCITTFaxAdapter.java
public void outputContents(OutputStream out) throws IOException {
getImage().writeTo(out);
}
// in src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PDFRenderingContext pdfContext = (PDFRenderingContext)context;
PDFContentGenerator generator = pdfContext.getGenerator();
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
float fwidth = pos.width / 1000f;
float fheight = pos.height / 1000f;
float fx = pos.x / 1000f;
float fy = pos.y / 1000f;
// get the 'width' and 'height' attributes of the SVG document
Dimension dim = image.getInfo().getSize().getDimensionMpt();
float imw = (float)dim.getWidth() / 1000f;
float imh = (float)dim.getHeight() / 1000f;
float sx = fwidth / imw;
float sy = fheight / imh;
generator.comment("G2D start");
boolean accessibilityEnabled = context.getUserAgent().isAccessibilityEnabled();
if (accessibilityEnabled) {
MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
generator.saveGraphicsState(mci.tag, mci.mcid);
} else {
generator.saveGraphicsState();
}
generator.updateColor(Color.black, false, null);
generator.updateColor(Color.black, true, null);
//TODO Clip to the image area.
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
generator.add(sx + " 0 0 " + sy + " " + fx + " " + fy + " cm\n");
final boolean textAsShapes = false;
PDFGraphics2D graphics = new PDFGraphics2D(textAsShapes,
pdfContext.getFontInfo(), generator.getDocument(),
generator.getResourceContext(), pdfContext.getPage().referencePDF(),
"", 0.0f);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
AffineTransform transform = new AffineTransform();
transform.translate(fx, fy);
generator.getState().concatenate(transform);
graphics.setPaintingState(generator.getState());
graphics.setOutputStream(generator.getOutputStream());
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
imageG2D.getGraphics2DImagePainter().paint(graphics, area);
generator.add(graphics.getString());
if (accessibilityEnabled) {
generator.restoreGraphicsStateAccess();
} else {
generator.restoreGraphicsState();
}
generator.comment("G2D end");
}
// in src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java
public void outputContents(OutputStream out) throws IOException {
InputStream in = getImage().createInputStream();
in = ImageUtil.decorateMarkSupported(in);
try {
JPEGFile jpeg = new JPEGFile(in);
DataInput din = jpeg.getDataInput();
//Copy the whole JPEG file except:
// - the ICC profile
//TODO Thumbnails could safely be skipped, too.
//TODO Metadata (XMP, IPTC, EXIF) could safely be skipped, too.
while (true) {
int reclen;
int segID = jpeg.readMarkerSegment();
switch (segID) {
case JPEGConstants.SOI:
out.write(0xFF);
out.write(segID);
break;
case JPEGConstants.EOI:
case JPEGConstants.SOS:
out.write(0xFF);
out.write(segID);
IOUtils.copy(in, out); //Just copy the rest!
return;
/*
case JPEGConstants.APP1: //Metadata
case JPEGConstants.APPD:
jpeg.skipCurrentMarkerSegment();
break;*/
case JPEGConstants.APP2: //ICC (see ICC1V42.pdf)
boolean skipICCProfile = false;
in.mark(16);
try {
reclen = jpeg.readSegmentLength();
// Check for ICC profile
byte[] iccString = new byte[11];
din.readFully(iccString);
din.skipBytes(1); //string terminator (null byte)
if ("ICC_PROFILE".equals(new String(iccString, "US-ASCII"))) {
skipICCProfile = (this.image.getICCProfile() != null);
}
} finally {
in.reset();
}
if (skipICCProfile) {
//ICC profile is skipped as it is already embedded as a PDF object
jpeg.skipCurrentMarkerSegment();
break;
}
default:
out.write(0xFF);
out.write(segID);
reclen = jpeg.readSegmentLength();
//write short
out.write((reclen >>> 8) & 0xFF);
out.write((reclen >>> 0) & 0xFF);
int left = reclen - 2;
byte[] buf = new byte[2048];
while (left > 0) {
int part = Math.min(buf.length, left);
din.readFully(buf, 0, part);
out.write(buf, 0, part);
left -= part;
}
}
}
} finally {
IOUtils.closeQuietly(in);
}
}
// in src/java/org/apache/fop/render/xml/AbstractXMLRenderer.java
public void startRenderer(OutputStream outputStream)
throws IOException {
if (this.handler == null) {
SAXTransformerFactory factory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
try {
TransformerHandler transformerHandler = factory.newTransformerHandler();
setContentHandler(transformerHandler);
StreamResult res = new StreamResult(outputStream);
transformerHandler.setResult(res);
} catch (TransformerConfigurationException tce) {
throw new RuntimeException(tce.getMessage());
}
this.out = outputStream;
}
try {
handler.startDocument();
} catch (SAXException saxe) {
handleSAXException(saxe);
}
}
// in src/java/org/apache/fop/render/xml/AbstractXMLRenderer.java
public void stopRenderer() throws IOException {
try {
handler.endDocument();
} catch (SAXException saxe) {
handleSAXException(saxe);
}
if (this.out != null) {
this.out.flush();
}
}
// in src/java/org/apache/fop/render/xml/XMLRenderer.java
Override
public void startRenderer(OutputStream outputStream)
throws IOException {
log.debug("Rendering areas to Area Tree XML");
if (this.handler == null) {
SAXTransformerFactory factory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
try {
TransformerHandler transformerHandler = factory.newTransformerHandler();
this.handler = transformerHandler;
StreamResult res = new StreamResult(outputStream);
transformerHandler.setResult(res);
} catch (TransformerConfigurationException tce) {
throw new RuntimeException(tce.getMessage());
}
this.out = outputStream;
}
try {
handler.startDocument();
} catch (SAXException saxe) {
handleSAXException(saxe);
}
if (userAgent.getProducer() != null) {
comment("Produced by " + userAgent.getProducer());
}
atts.clear();
addAttribute("version", VERSION);
startElement("areaTree", atts);
}
// in src/java/org/apache/fop/render/xml/XMLRenderer.java
Override
public void stopRenderer() throws IOException {
endPageSequence();
endElement("areaTree");
try {
handler.endDocument();
} catch (SAXException saxe) {
handleSAXException(saxe);
}
if (this.out != null) {
this.out.flush();
}
log.debug("Written out Area Tree XML");
}
// in src/java/org/apache/fop/render/xml/XMLRenderer.java
Override
public void renderPage(PageViewport page) throws IOException, FOPException {
atts.clear();
addAttribute("bounds", page.getViewArea());
addAttribute("key", page.getKey());
addAttribute("nr", page.getPageNumber());
addAttribute("formatted-nr", page.getPageNumberString());
if (page.getSimplePageMasterName() != null) {
addAttribute("simple-page-master-name", page.getSimplePageMasterName());
}
if (page.isBlank()) {
addAttribute("blank", "true");
}
transferForeignObjects(page);
startElement("pageViewport", atts);
startElement("page");
handlePageExtensionAttachments(page);
super.renderPage(page);
endElement("page");
endElement("pageViewport");
}
// in src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
protected void drawImageUsingImageHandler(ImageInfo info, Rectangle rect)
throws ImageException, IOException {
ImageManager manager = getFopFactory().getImageManager();
ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
ImageHandlerRegistry imageHandlerRegistry = getFopFactory().getImageHandlerRegistry();
//Load and convert the image to a supported format
RenderingContext context = createRenderingContext();
Map hints = createDefaultImageProcessingHints(sessionContext);
context.putHints(hints);
ImageFlavor[] flavors = imageHandlerRegistry.getSupportedFlavors(context);
org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
info, flavors,
hints, sessionContext);
try {
drawImage(img, rect, context);
} catch (IOException ioe) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageWritingError(this, ioe);
}
}
// in src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
protected void drawImage(Image image, Rectangle rect,
RenderingContext context) throws IOException, ImageException {
drawImage(image, rect, context, false, null);
}
// in src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
protected void drawImage(Image image, Rectangle rect,
RenderingContext context, boolean convert, Map additionalHints)
throws IOException, ImageException {
ImageManager manager = getFopFactory().getImageManager();
ImageHandlerRegistry imageHandlerRegistry = getFopFactory().getImageHandlerRegistry();
Image effImage;
context.putHints(additionalHints);
if (convert) {
Map hints = createDefaultImageProcessingHints(getUserAgent().getImageSessionContext());
if (additionalHints != null) {
hints.putAll(additionalHints);
}
effImage = manager.convertImage(image,
imageHandlerRegistry.getSupportedFlavors(context), hints);
} else {
effImage = image;
}
//First check for a dynamically registered handler
ImageHandler handler = imageHandlerRegistry.getHandler(context, effImage);
if (handler == null) {
throw new UnsupportedOperationException(
"No ImageHandler available for image: "
+ effImage.getInfo() + " (" + effImage.getClass().getName() + ")");
}
if (log.isTraceEnabled()) {
log.trace("Using ImageHandler: " + handler.getClass().getName());
}
handler.handleImage(context, effImage, rect);
}
// in src/java/org/apache/fop/render/intermediate/IFRenderer.java
private void handleIFExceptionWithIOException(IFException ife) throws IOException {
if (ife.getCause() instanceof IOException) {
throw (IOException)ife.getCause();
} else {
handleIFException(ife);
}
}
// in src/java/org/apache/fop/render/intermediate/IFRenderer.java
public void startRenderer(OutputStream outputStream)
throws IOException {
try {
if (outputStream != null) {
StreamResult result = new StreamResult(outputStream);
if (getUserAgent().getOutputFile() != null) {
result.setSystemId(
getUserAgent().getOutputFile().toURI().toURL().toExternalForm());
}
if (this.documentHandler == null) {
this.documentHandler = createDefaultDocumentHandler();
}
this.documentHandler.setResult(result);
}
super.startRenderer(null);
if (log.isDebugEnabled()) {
log.debug("Rendering areas via IF document handler ("
+ this.documentHandler.getClass().getName() + ")...");
}
documentHandler.startDocument();
documentHandler.startDocumentHeader();
} catch (IFException e) {
handleIFExceptionWithIOException(e);
}
}
// in src/java/org/apache/fop/render/intermediate/IFRenderer.java
public void stopRenderer() throws IOException {
try {
if (this.inPageSequence) {
documentHandler.endPageSequence();
this.inPageSequence = false;
}
documentHandler.startDocumentTrailer();
//Wrap up document navigation
if (hasDocumentNavigation()) {
finishOpenGoTos();
Iterator iter = this.deferredDestinations.iterator();
while (iter.hasNext()) {
NamedDestination dest = (NamedDestination)iter.next();
iter.remove();
getDocumentNavigationHandler().renderNamedDestination(dest);
}
if (this.bookmarkTree != null) {
getDocumentNavigationHandler().renderBookmarkTree(this.bookmarkTree);
}
}
documentHandler.endDocumentTrailer();
documentHandler.endDocument();
} catch (IFException e) {
handleIFExceptionWithIOException(e);
}
pageIndices.clear();
idPositions.clear();
actionSet.clear();
super.stopRenderer();
log.debug("Rendering finished.");
}
// in src/java/org/apache/fop/render/intermediate/IFRenderer.java
public void renderPage(PageViewport page) throws IOException, FOPException {
if (log.isTraceEnabled()) {
log.trace("renderPage() " + page);
}
try {
pageIndices.put(page.getKey(), new Integer(page.getPageIndex()));
Rectangle viewArea = page.getViewArea();
Dimension dim = new Dimension(viewArea.width, viewArea.height);
establishForeignAttributes(page.getForeignAttributes());
documentHandler.startPage(page.getPageIndex(), page.getPageNumberString(),
page.getSimplePageMasterName(), dim);
resetForeignAttributes();
documentHandler.startPageHeader();
//Add page attachments to page header
processExtensionAttachments(page);
documentHandler.endPageHeader();
this.painter = documentHandler.startPageContent();
super.renderPage(page);
this.painter = null;
documentHandler.endPageContent();
documentHandler.startPageTrailer();
if (hasDocumentNavigation()) {
Iterator iter = this.deferredLinks.iterator();
while (iter.hasNext()) {
Link link = (Link)iter.next();
iter.remove();
getDocumentNavigationHandler().renderLink(link);
}
}
documentHandler.endPageTrailer();
establishForeignAttributes(page.getForeignAttributes());
documentHandler.endPage();
resetForeignAttributes();
} catch (IFException e) {
handleIFException(e);
}
}
// in src/java/org/apache/fop/render/intermediate/BorderPainter.java
public void drawBorders(Rectangle borderRect, // CSOK: MethodLength
BorderProps bpsTop, BorderProps bpsBottom,
BorderProps bpsLeft, BorderProps bpsRight) throws IOException {
int startx = borderRect.x;
int starty = borderRect.y;
int width = borderRect.width;
int height = borderRect.height;
boolean[] b = new boolean[] {
(bpsTop != null), (bpsRight != null),
(bpsBottom != null), (bpsLeft != null)};
if (!b[0] && !b[1] && !b[2] && !b[3]) {
return;
}
int[] bw = new int[] {
(b[0] ? bpsTop.width : 0),
(b[1] ? bpsRight.width : 0),
(b[2] ? bpsBottom.width : 0),
(b[3] ? bpsLeft.width : 0)};
int[] clipw = new int[] {
BorderProps.getClippedWidth(bpsTop),
BorderProps.getClippedWidth(bpsRight),
BorderProps.getClippedWidth(bpsBottom),
BorderProps.getClippedWidth(bpsLeft)};
starty += clipw[0];
height -= clipw[0];
height -= clipw[2];
startx += clipw[3];
width -= clipw[3];
width -= clipw[1];
boolean[] slant = new boolean[] {
(b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
if (bpsTop != null) {
int sx1 = startx;
int sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
int ex1 = startx + width;
int ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
int outery = starty - clipw[0];
int clipy = outery + clipw[0];
int innery = outery + bw[0];
saveGraphicsState();
moveTo(sx1, clipy);
int sx1a = sx1;
int ex1a = ex1;
if (bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsLeft != null && bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
sx1a -= clipw[3];
}
if (bpsRight != null && bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
ex1a += clipw[1];
}
lineTo(sx1a, outery);
lineTo(ex1a, outery);
}
lineTo(ex1, clipy);
lineTo(ex2, innery);
lineTo(sx2, innery);
closePath();
clip();
drawBorderLine(sx1a, outery, ex1a, innery, true, true,
bpsTop.style, bpsTop.color);
restoreGraphicsState();
}
if (bpsRight != null) {
int sy1 = starty;
int sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
int ey1 = starty + height;
int ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
int outerx = startx + width + clipw[1];
int clipx = outerx - clipw[1];
int innerx = outerx - bw[1];
saveGraphicsState();
moveTo(clipx, sy1);
int sy1a = sy1;
int ey1a = ey1;
if (bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
sy1a -= clipw[0];
}
if (bpsBottom != null && bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
ey1a += clipw[2];
}
lineTo(outerx, sy1a);
lineTo(outerx, ey1a);
}
lineTo(clipx, ey1);
lineTo(innerx, ey2);
lineTo(innerx, sy2);
closePath();
clip();
drawBorderLine(innerx, sy1a, outerx, ey1a, false, false,
bpsRight.style, bpsRight.color);
restoreGraphicsState();
}
if (bpsBottom != null) {
int sx1 = startx;
int sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
int ex1 = startx + width;
int ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
int outery = starty + height + clipw[2];
int clipy = outery - clipw[2];
int innery = outery - bw[2];
saveGraphicsState();
moveTo(ex1, clipy);
int sx1a = sx1;
int ex1a = ex1;
if (bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsLeft != null && bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
sx1a -= clipw[3];
}
if (bpsRight != null && bpsRight.mode == BorderProps.COLLAPSE_OUTER) {
ex1a += clipw[1];
}
lineTo(ex1a, outery);
lineTo(sx1a, outery);
}
lineTo(sx1, clipy);
lineTo(sx2, innery);
lineTo(ex2, innery);
closePath();
clip();
drawBorderLine(sx1a, innery, ex1a, outery, true, false,
bpsBottom.style, bpsBottom.color);
restoreGraphicsState();
}
if (bpsLeft != null) {
int sy1 = starty;
int sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
int ey1 = sy1 + height;
int ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
int outerx = startx - clipw[3];
int clipx = outerx + clipw[3];
int innerx = outerx + bw[3];
saveGraphicsState();
moveTo(clipx, ey1);
int sy1a = sy1;
int ey1a = ey1;
if (bpsLeft.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsTop != null && bpsTop.mode == BorderProps.COLLAPSE_OUTER) {
sy1a -= clipw[0];
}
if (bpsBottom != null && bpsBottom.mode == BorderProps.COLLAPSE_OUTER) {
ey1a += clipw[2];
}
lineTo(outerx, ey1a);
lineTo(outerx, sy1a);
}
lineTo(clipx, sy1);
lineTo(innerx, sy2);
lineTo(innerx, ey2);
closePath();
clip();
drawBorderLine(outerx, sy1a, innerx, ey1a, false, true, bpsLeft.style, bpsLeft.color);
restoreGraphicsState();
}
}
// in src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
protected void renderSVGDocument(final RendererContext rendererContext,
final Document doc) throws IOException {
updateRendererContext(rendererContext);
//Prepare
FOUserAgent userAgent = rendererContext.getUserAgent();
SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new AffineTransform());
//Create Batik BridgeContext
final BridgeContext bridgeContext = new BridgeContext(svgUserAgent);
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
//to it.
Document clonedDoc = BatikUtil.cloneSVGDocument(doc);
//Build the GVT tree
final GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc);
// Create Graphics2DImagePainter
final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext(
rendererContext);
Dimension imageSize = getImageSize(wrappedContext);
final Graphics2DImagePainter painter = createGraphics2DImagePainter(
root, bridgeContext, imageSize);
//Let the painter paint the SVG on the Graphics2D instance
Graphics2DAdapter g2dAdapter = rendererContext.getRenderer().getGraphics2DAdapter();
//Paint the image
final int x = wrappedContext.getCurrentXPosition();
final int y = wrappedContext.getCurrentYPosition();
final int width = wrappedContext.getWidth();
final int height = wrappedContext.getHeight();
g2dAdapter.paintImage(painter, rendererContext, x, y, width, height);
}
// in src/java/org/apache/fop/render/txt/TXTRenderer.java
public void renderPage(PageViewport page) throws IOException, FOPException {
if (firstPage) {
firstPage = false;
} else {
currentStream.add(pageEnding);
}
Rectangle2D bounds = page.getViewArea();
double width = bounds.getWidth();
double height = bounds.getHeight();
pageWidth = Helper.ceilPosition((int) width, CHAR_WIDTH);
pageHeight = Helper.ceilPosition((int) height, CHAR_HEIGHT + 2 * LINE_LEADING);
// init buffers
charData = new StringBuffer[pageHeight];
decoData = new StringBuffer[pageHeight];
for (int i = 0; i < pageHeight; i++) {
charData[i] = new StringBuffer();
decoData[i] = new StringBuffer();
}
bm = new BorderManager(pageWidth, pageHeight, currentState);
super.renderPage(page);
flushBorderToBuffer();
flushBuffer();
}
// in src/java/org/apache/fop/render/txt/TXTRenderer.java
public void startRenderer(OutputStream os) throws IOException {
log.info("Rendering areas to TEXT.");
this.outputStream = os;
currentStream = new TXTStream(os);
currentStream.setEncoding(this.encoding);
firstPage = true;
}
// in src/java/org/apache/fop/render/txt/TXTRenderer.java
public void stopRenderer() throws IOException {
log.info("writing out TEXT");
outputStream.flush();
super.stopRenderer();
}
// in src/java/org/apache/fop/render/AbstractRenderer.java
public void startRenderer(OutputStream outputStream)
throws IOException {
if (userAgent == null) {
throw new IllegalStateException("FOUserAgent has not been set on Renderer");
}
}
// in src/java/org/apache/fop/render/AbstractRenderer.java
public void stopRenderer()
throws IOException { }
// in src/java/org/apache/fop/render/AbstractRenderer.java
public void renderPage(PageViewport page)
throws IOException, FOPException {
this.currentPageViewport = page;
try {
Page p = page.getPage();
renderPageAreas(p);
} finally {
this.currentPageViewport = null;
}
}
// in src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java
private void selectPageFormat(long pagewidth, long pageheight) throws IOException {
//Only set the page format if it changes (otherwise duplex printing won't work)
if ((pagewidth != this.pageWidth) || (pageheight != this.pageHeight)) {
this.pageWidth = pagewidth;
this.pageHeight = pageheight;
this.currentPageDefinition = PCLPageDefinition.getPageDefinition(
pagewidth, pageheight, 1000);
if (this.currentPageDefinition == null) {
this.currentPageDefinition = PCLPageDefinition.getDefaultPageDefinition();
log.warn("Paper type could not be determined. Falling back to: "
+ this.currentPageDefinition.getName());
}
if (log.isDebugEnabled()) {
log.debug("page size: " + currentPageDefinition.getPhysicalPageSize());
log.debug("logical page: " + currentPageDefinition.getLogicalPageRect());
}
if (this.currentPageDefinition.isLandscapeFormat()) {
gen.writeCommand("&l1O"); //Landscape Orientation
} else {
gen.writeCommand("&l0O"); //Portrait Orientation
}
gen.selectPageSize(this.currentPageDefinition.getSelector());
gen.clearHorizontalMargins();
gen.setTopMargin(0);
}
}
// in src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PCLRenderingContext pclContext = (PCLRenderingContext)context;
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
Dimension imageDim = imageG2D.getSize().getDimensionMpt();
PCLGenerator gen = pclContext.getPCLGenerator();
Point2D transPoint = pclContext.transformedPoint(pos.x, pos.y);
gen.setCursorPos(transPoint.getX(), transPoint.getY());
boolean painted = false;
ByteArrayOutputStream baout = new ByteArrayOutputStream();
PCLGenerator tempGen = new PCLGenerator(baout, gen.getMaximumBitmapResolution());
tempGen.setDitheringQuality(gen.getDitheringQuality());
try {
GraphicContext ctx = (GraphicContext)pclContext.getGraphicContext().clone();
AffineTransform prepareHPGL2 = new AffineTransform();
prepareHPGL2.scale(0.001, 0.001);
ctx.setTransform(prepareHPGL2);
PCLGraphics2D graphics = new PCLGraphics2D(tempGen);
graphics.setGraphicContext(ctx);
graphics.setClippingDisabled(false /*pclContext.isClippingDisabled()*/);
Rectangle2D area = new Rectangle2D.Double(
0.0, 0.0, imageDim.getWidth(), imageDim.getHeight());
imageG2D.getGraphics2DImagePainter().paint(graphics, area);
//If we arrive here, the graphic is natively paintable, so write the graphic
gen.writeCommand("*c" + gen.formatDouble4(pos.width / 100f) + "x"
+ gen.formatDouble4(pos.height / 100f) + "Y");
gen.writeCommand("*c0T");
gen.enterHPGL2Mode(false);
gen.writeText("\nIN;");
gen.writeText("SP1;");
//One Plotter unit is 0.025mm!
double scale = imageDim.getWidth() / UnitConv.mm2pt(imageDim.getWidth() * 0.025);
gen.writeText("SC0," + gen.formatDouble4(scale)
+ ",0,-" + gen.formatDouble4(scale) + ",2;");
gen.writeText("IR0,100,0,100;");
gen.writeText("PU;PA0,0;\n");
baout.writeTo(gen.getOutputStream()); //Buffer is written to output stream
gen.writeText("\n");
gen.enterPCLMode(false);
painted = true;
} catch (UnsupportedOperationException uoe) {
log.debug(
"Cannot paint graphic natively. Falling back to bitmap painting. Reason: "
+ uoe.getMessage());
}
if (!painted) {
//Fallback solution: Paint to a BufferedImage
FOUserAgent ua = context.getUserAgent();
ImageManager imageManager = ua.getFactory().getImageManager();
ImageRendered imgRend;
try {
imgRend = (ImageRendered)imageManager.convertImage(
imageG2D, new ImageFlavor[] {ImageFlavor.RENDERED_IMAGE}/*, hints*/);
} catch (ImageException e) {
throw new IOException(
"Image conversion error while converting the image to a bitmap"
+ " as a fallback measure: " + e.getMessage());
}
gen.paintBitmap(imgRend.getRenderedImage(), new Dimension(pos.width, pos.height),
pclContext.isSourceTransparencyEnabled());
}
}
// in src/java/org/apache/fop/render/pcl/PCLGraphics2D.java
protected void applyStroke(Stroke stroke) throws IOException {
if (stroke instanceof BasicStroke) {
BasicStroke bs = (BasicStroke)stroke;
float[] da = bs.getDashArray();
if (da != null) {
gen.writeText("UL1,");
int len = Math.min(20, da.length);
float patternLen = 0.0f;
for (int idx = 0; idx < len; idx++) {
patternLen += da[idx];
}
if (len == 1) {
patternLen *= 2;
}
for (int idx = 0; idx < len; idx++) {
float perc = da[idx] * 100 / patternLen;
gen.writeText(gen.formatDouble2(perc));
if (idx < da.length - 1) {
gen.writeText(",");
}
}
if (len == 1) {
gen.writeText("," + gen.formatDouble2(da[0] * 100 / patternLen ));
}
gen.writeText(";");
/* TODO Dash phase NYI
float offset = bs.getDashPhase();
gen.writeln(gen.formatDouble4(offset) + " setdash");
*/
Point2D ptLen = new Point2D.Double(patternLen, 0);
//interpret as absolute length
getTransform().deltaTransform(ptLen, ptLen);
double transLen = UnitConv.pt2mm(ptLen.distance(0, 0));
gen.writeText("LT1," + gen.formatDouble4(transLen) + ",1;");
} else {
gen.writeText("LT;");
}
gen.writeText("LA1"); //line cap
int ec = bs.getEndCap();
switch (ec) {
case BasicStroke.CAP_BUTT:
gen.writeText(",1");
break;
case BasicStroke.CAP_ROUND:
gen.writeText(",4");
break;
case BasicStroke.CAP_SQUARE:
gen.writeText(",2");
break;
default: System.err.println("Unsupported line cap: " + ec);
}
gen.writeText(",2"); //line join
int lj = bs.getLineJoin();
switch (lj) {
case BasicStroke.JOIN_MITER:
gen.writeText(",1");
break;
case BasicStroke.JOIN_ROUND:
gen.writeText(",4");
break;
case BasicStroke.JOIN_BEVEL:
gen.writeText(",5");
break;
default: System.err.println("Unsupported line join: " + lj);
}
float ml = bs.getMiterLimit();
gen.writeText(",3" + gen.formatDouble4(ml));
float lw = bs.getLineWidth();
Point2D ptSrc = new Point2D.Double(lw, 0);
//Pen widths are set as absolute metric values (WU0;)
Point2D ptDest = getTransform().deltaTransform(ptSrc, null);
double transDist = UnitConv.pt2mm(ptDest.distance(0, 0));
//System.out.println("--" + ptDest.distance(0, 0) + " " + transDist);
gen.writeText(";PW" + gen.formatDouble4(transDist) + ";");
} else {
handleUnsupportedFeature("Unsupported Stroke: " + stroke.getClass().getName());
}
}
// in src/java/org/apache/fop/render/pcl/PCLGraphics2D.java
protected void applyPaint(Paint paint) throws IOException {
if (paint instanceof Color) {
Color col = (Color)paint;
int shade = gen.convertToPCLShade(col);
gen.writeText("TR0;FT10," + shade + ";");
} else {
handleUnsupportedFeature("Unsupported Paint: " + paint.getClass().getName());
}
}
// in src/java/org/apache/fop/render/pcl/PCLGraphics2D.java
private void writeClip(Shape imclip) throws IOException {
if (clippingDisabled) {
return;
}
if (imclip == null) {
//gen.writeText("IW;");
} else {
handleUnsupportedFeature("Clipping is not supported. Shape: " + imclip);
/* This is an attempt to clip using the "InputWindow" (IW) but this only allows to
* clip a rectangular area. Force falling back to bitmap mode for now.
Rectangle2D bounds = imclip.getBounds2D();
Point2D p1 = new Point2D.Double(bounds.getX(), bounds.getY());
Point2D p2 = new Point2D.Double(
bounds.getX() + bounds.getWidth(), bounds.getY() + bounds.getHeight());
getTransform().transform(p1, p1);
getTransform().transform(p2, p2);
gen.writeText("IW" + gen.formatDouble4(p1.getX())
+ "," + gen.formatDouble4(p2.getY())
+ "," + gen.formatDouble4(p2.getX())
+ "," + gen.formatDouble4(p1.getY()) + ";");
*/
}
}
// in src/java/org/apache/fop/render/pcl/PCLGraphics2D.java
public void processPathIteratorStroke(PathIterator iter) throws IOException {
gen.writeText("\n");
double[] vals = new double[6];
boolean penDown = false;
double x = 0;
double y = 0;
StringBuffer sb = new StringBuffer(256);
penUp(sb);
while (!iter.isDone()) {
int type = iter.currentSegment(vals);
if (type == PathIterator.SEG_CLOSE) {
gen.writeText("PM;");
gen.writeText(sb.toString());
gen.writeText("PM2;EP;");
sb.setLength(0);
iter.next();
continue;
} else if (type == PathIterator.SEG_MOVETO) {
gen.writeText(sb.toString());
sb.setLength(0);
if (penDown) {
penUp(sb);
penDown = false;
}
} else {
if (!penDown) {
penDown(sb);
penDown = true;
}
}
switch (type) {
case PathIterator.SEG_CLOSE:
break;
case PathIterator.SEG_MOVETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y, sb);
gen.writeText(sb.toString());
sb.setLength(0);
break;
case PathIterator.SEG_LINETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y, sb);
break;
case PathIterator.SEG_CUBICTO:
x = vals[4];
y = vals[5];
bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
break;
case PathIterator.SEG_QUADTO:
double originX = x;
double originY = y;
x = vals[2];
y = vals[3];
quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
break;
default:
break;
}
iter.next();
}
sb.append("\n");
gen.writeText(sb.toString());
}
// in src/java/org/apache/fop/render/pcl/PCLGraphics2D.java
public void processPathIteratorFill(PathIterator iter) throws IOException {
gen.writeText("\n");
double[] vals = new double[6];
boolean penDown = false;
double x = 0;
double y = 0;
boolean pendingPM0 = true;
StringBuffer sb = new StringBuffer(256);
penUp(sb);
while (!iter.isDone()) {
int type = iter.currentSegment(vals);
if (type == PathIterator.SEG_CLOSE) {
sb.append("PM1;");
iter.next();
continue;
} else if (type == PathIterator.SEG_MOVETO) {
if (penDown) {
penUp(sb);
penDown = false;
}
} else {
if (!penDown) {
penDown(sb);
penDown = true;
}
}
switch (type) {
case PathIterator.SEG_MOVETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y, sb);
break;
case PathIterator.SEG_LINETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y, sb);
break;
case PathIterator.SEG_CUBICTO:
x = vals[4];
y = vals[5];
bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
break;
case PathIterator.SEG_QUADTO:
double originX = x;
double originY = y;
x = vals[2];
y = vals[3];
quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
break;
default:
throw new IllegalStateException("Must not get here");
}
if (pendingPM0) {
pendingPM0 = false;
sb.append("PM;");
}
iter.next();
}
sb.append("PM2;");
fillPolygon(iter.getWindingRule(), sb);
sb.append("\n");
gen.writeText(sb.toString());
}
// in src/java/org/apache/fop/render/pcl/PCLPainter.java
private void drawTextNative(int x, int y, int letterSpacing, int wordSpacing, int[][] dp,
String text, FontTriplet triplet) throws IOException {
Color textColor = state.getTextColor();
if (textColor != null) {
gen.setTransparencyMode(true, false);
gen.selectGrayscale(textColor);
}
gen.setTransparencyMode(true, true);
setCursorPos(x, y);
float fontSize = state.getFontSize() / 1000f;
Font font = parent.getFontInfo().getFontInstance(triplet, state.getFontSize());
int l = text.length();
int[] dx = IFUtil.convertDPToDX ( dp );
int dxl = (dx != null ? dx.length : 0);
StringBuffer sb = new StringBuffer(Math.max(16, l));
if (dx != null && dxl > 0 && dx[0] != 0) {
sb.append("\u001B&a+").append(gen.formatDouble2(dx[0] / 100.0)).append('H');
}
for (int i = 0; i < l; i++) {
char orgChar = text.charAt(i);
char ch;
float glyphAdjust = 0;
if (font.hasChar(orgChar)) {
ch = font.mapChar(orgChar);
} else {
if (CharUtilities.isFixedWidthSpace(orgChar)) {
//Fixed width space are rendered as spaces so copy/paste works in a reader
ch = font.mapChar(CharUtilities.SPACE);
int spaceDiff = font.getCharWidth(ch) - font.getCharWidth(orgChar);
glyphAdjust = -(10 * spaceDiff / fontSize);
} else {
ch = font.mapChar(orgChar);
}
}
sb.append(ch);
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
glyphAdjust += wordSpacing;
}
glyphAdjust += letterSpacing;
if (dx != null && i < dxl - 1) {
glyphAdjust += dx[i + 1];
}
if (glyphAdjust != 0) {
sb.append("\u001B&a+").append(gen.formatDouble2(glyphAdjust / 100.0)).append('H');
}
}
gen.getOutputStream().write(sb.toString().getBytes(gen.getTextEncoding()));
}
// in src/java/org/apache/fop/render/pcl/PCLPainter.java
private void concatenateTransformationMatrix(AffineTransform transform) throws IOException {
if (!transform.isIdentity()) {
graphicContext.transform(transform);
changePrintDirection();
}
}
// in src/java/org/apache/fop/render/pcl/PCLPainter.java
private void changePrintDirection() throws IOException {
AffineTransform at = graphicContext.getTransform();
int newDir;
newDir = PCLRenderingUtil.determinePrintDirection(at);
if (newDir != this.currentPrintDirection) {
this.currentPrintDirection = newDir;
gen.changePrintDirection(this.currentPrintDirection);
}
}
// in src/java/org/apache/fop/render/pcl/PCLPainter.java
void setCursorPos(int x, int y) throws IOException {
Point2D transPoint = transformedPoint(x, y);
gen.setCursorPos(transPoint.getX(), transPoint.getY());
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void writeCommand(String cmd) throws IOException {
out.write(27); //ESC
out.write(cmd.getBytes(US_ASCII));
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void writeText(String s) throws IOException {
out.write(s.getBytes(ISO_8859_1));
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void universalEndOfLanguage() throws IOException {
writeCommand("%-12345X");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void resetPrinter() throws IOException {
writeCommand("E");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void separateJobs() throws IOException {
writeCommand("&l1T");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void formFeed() throws IOException {
out.write(12); //=OC ("FF", Form feed)
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setUnitOfMeasure(int value) throws IOException {
writeCommand("&u" + value + "D");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setRasterGraphicsResolution(int value) throws IOException {
writeCommand("*t" + value + "R");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void selectPageSize(int selector) throws IOException {
writeCommand("&l" + selector + "A");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void selectPaperSource(int selector) throws IOException {
writeCommand("&l" + selector + "H");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void selectOutputBin(int selector) throws IOException {
writeCommand("&l" + selector + "G");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void selectDuplexMode(int selector) throws IOException {
writeCommand("&l" + selector + "S");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void clearHorizontalMargins() throws IOException {
writeCommand("9");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setTopMargin(int numberOfLines) throws IOException {
writeCommand("&l" + numberOfLines + "E");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setTextLength(int numberOfLines) throws IOException {
writeCommand("&l" + numberOfLines + "F");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setVMI(double value) throws IOException {
writeCommand("&l" + formatDouble4(value) + "C");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setCursorPos(double x, double y) throws IOException {
if (x < 0) {
//A negative x value will result in a relative movement so go to "0" first.
//But this will most probably have no effect anyway since you can't paint to the left
//of the logical page
writeCommand("&a0h" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
} else {
writeCommand("&a" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
}
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void pushCursorPos() throws IOException {
writeCommand("&f0S");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void popCursorPos() throws IOException {
writeCommand("&f1S");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void changePrintDirection(int rotate) throws IOException {
writeCommand("&a" + rotate + "P");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void enterHPGL2Mode(boolean restorePreviousHPGL2Cursor) throws IOException {
if (restorePreviousHPGL2Cursor) {
writeCommand("%0B");
} else {
writeCommand("%1B");
}
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void enterPCLMode(boolean restorePreviousPCLCursor) throws IOException {
if (restorePreviousPCLCursor) {
writeCommand("%0A");
} else {
writeCommand("%1A");
}
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
protected void fillRect(int w, int h, Color col) throws IOException {
if ((w == 0) || (h == 0)) {
return;
}
if (h < 0) {
h *= -1;
} else {
//y += h;
}
setPatternTransparencyMode(false);
if (usePCLShades
|| Color.black.equals(col)
|| Color.white.equals(col)) {
writeCommand("*c" + formatDouble4(w / 100.0) + "h"
+ formatDouble4(h / 100.0) + "V");
int lineshade = convertToPCLShade(col);
writeCommand("*c" + lineshade + "G");
writeCommand("*c2P"); //Shaded fill
} else {
defineGrayscalePattern(col, 32, DitherUtil.DITHER_MATRIX_4X4);
writeCommand("*c" + formatDouble4(w / 100.0) + "h"
+ formatDouble4(h / 100.0) + "V");
writeCommand("*c32G");
writeCommand("*c4P"); //User-defined pattern
}
// Reset pattern transparency mode.
setPatternTransparencyMode(true);
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void defineGrayscalePattern(Color col, int patternID, int ditherMatrixSize)
throws IOException {
ByteArrayOutputStream baout = new ByteArrayOutputStream();
DataOutputStream data = new DataOutputStream(baout);
data.writeByte(0); //Format
data.writeByte(0); //Continuation
data.writeByte(1); //Pixel Encoding
data.writeByte(0); //Reserved
data.writeShort(8); //Width in Pixels
data.writeShort(8); //Height in Pixels
//data.writeShort(600); //X Resolution (didn't manage to get that to work)
//data.writeShort(600); //Y Resolution
int gray255 = convertToGray(col.getRed(), col.getGreen(), col.getBlue());
byte[] pattern;
if (ditherMatrixSize == 8) {
pattern = DitherUtil.getBayerDither(DitherUtil.DITHER_MATRIX_8X8, gray255, false);
} else {
//Since a 4x4 pattern did not work, the 4x4 pattern is applied 4 times to an
//8x8 pattern. Maybe this could be changed to use an 8x8 bayer dither pattern
//instead of the 4x4 one.
pattern = DitherUtil.getBayerDither(DitherUtil.DITHER_MATRIX_4X4, gray255, true);
}
data.write(pattern);
if ((baout.size() % 2) > 0) {
baout.write(0);
}
writeCommand("*c" + patternID + "G");
writeCommand("*c" + baout.size() + "W");
baout.writeTo(this.out);
writeCommand("*c4Q"); //temporary pattern
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setSourceTransparencyMode(boolean transparent) throws IOException {
setTransparencyMode(transparent, currentPatternTransparency);
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setPatternTransparencyMode(boolean transparent) throws IOException {
setTransparencyMode(currentSourceTransparency, transparent);
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void setTransparencyMode(boolean source, boolean pattern) throws IOException {
if (source != currentSourceTransparency && pattern != currentPatternTransparency) {
writeCommand("*v" + (source ? '0' : '1') + "n" + (pattern ? '0' : '1') + "O");
} else if (source != currentSourceTransparency) {
writeCommand("*v" + (source ? '0' : '1') + "N");
} else if (pattern != currentPatternTransparency) {
writeCommand("*v" + (pattern ? '0' : '1') + "O");
}
this.currentSourceTransparency = source;
this.currentPatternTransparency = pattern;
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void selectGrayscale(Color col) throws IOException {
if (Color.black.equals(col)) {
selectCurrentPattern(0, 0); //black
} else if (Color.white.equals(col)) {
selectCurrentPattern(0, 1); //white
} else {
if (usePCLShades) {
selectCurrentPattern(convertToPCLShade(col), 2);
} else {
defineGrayscalePattern(col, 32, DitherUtil.DITHER_MATRIX_4X4);
selectCurrentPattern(32, 4);
}
}
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void selectCurrentPattern(int patternID, int pattern) throws IOException {
if (pattern > 1) {
writeCommand("*c" + patternID + "G");
}
writeCommand("*v" + pattern + "T");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void paintBitmap(RenderedImage img, Dimension targetDim, boolean sourceTransparency)
throws IOException {
double targetHResolution = img.getWidth() / UnitConv.mpt2in(targetDim.width);
double targetVResolution = img.getHeight() / UnitConv.mpt2in(targetDim.height);
double targetResolution = Math.max(targetHResolution, targetVResolution);
int resolution = (int)Math.round(targetResolution);
int effResolution = calculatePCLResolution(resolution, true);
Dimension orgDim = new Dimension(img.getWidth(), img.getHeight());
Dimension effDim;
if (targetResolution == effResolution) {
effDim = orgDim; //avoid scaling side-effects
} else {
effDim = new Dimension(
(int)Math.ceil(UnitConv.mpt2px(targetDim.width, effResolution)),
(int)Math.ceil(UnitConv.mpt2px(targetDim.height, effResolution)));
}
boolean scaled = !orgDim.equals(effDim);
//ImageWriterUtil.saveAsPNG(img, new java.io.File("D:/text-0-org.png"));
boolean monochrome = isMonochromeImage(img);
if (!monochrome) {
//Transparency mask disabled. Doesn't work reliably
final boolean transparencyDisabled = true;
RenderedImage mask = (transparencyDisabled ? null : getMask(img, effDim));
if (mask != null) {
pushCursorPos();
selectCurrentPattern(0, 1); //Solid white
setTransparencyMode(true, true);
paintMonochromeBitmap(mask, effResolution);
popCursorPos();
}
RenderedImage red = BitmapImageUtil.convertToMonochrome(
img, effDim, this.ditheringQuality);
selectCurrentPattern(0, 0); //Solid black
setTransparencyMode(sourceTransparency || mask != null, true);
paintMonochromeBitmap(red, effResolution);
} else {
RenderedImage effImg = img;
if (scaled) {
effImg = BitmapImageUtil.convertToMonochrome(img, effDim);
}
setSourceTransparencyMode(sourceTransparency);
selectCurrentPattern(0, 0); //Solid black
paintMonochromeBitmap(effImg, effResolution);
}
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void paintMonochromeBitmap(RenderedImage img, int resolution) throws IOException {
if (!isValidPCLResolution(resolution)) {
throw new IllegalArgumentException("Invalid PCL resolution: " + resolution);
}
boolean monochrome = isMonochromeImage(img);
if (!monochrome) {
throw new IllegalArgumentException("img must be a monochrome image");
}
setRasterGraphicsResolution(resolution);
writeCommand("*r0f" + img.getHeight() + "t" + img.getWidth() + "s1A");
Raster raster = img.getData();
Encoder encoder = new Encoder(img);
// Transfer graphics data
int imgw = img.getWidth();
IndexColorModel cm = (IndexColorModel)img.getColorModel();
if (cm.getTransferType() == DataBuffer.TYPE_BYTE) {
DataBufferByte dataBuffer = (DataBufferByte)raster.getDataBuffer();
MultiPixelPackedSampleModel packedSampleModel = new MultiPixelPackedSampleModel(
DataBuffer.TYPE_BYTE, img.getWidth(), img.getHeight(), 1);
if (img.getSampleModel().equals(packedSampleModel)
&& dataBuffer.getNumBanks() == 1) {
//Optimized packed encoding
byte[] buf = dataBuffer.getData();
int scanlineStride = packedSampleModel.getScanlineStride();
int idx = 0;
int c0 = toGray(cm.getRGB(0));
int c1 = toGray(cm.getRGB(1));
boolean zeroIsWhite = c0 > c1;
for (int y = 0, maxy = img.getHeight(); y < maxy; y++) {
for (int x = 0, maxx = scanlineStride; x < maxx; x++) {
if (zeroIsWhite) {
encoder.add8Bits(buf[idx]);
} else {
encoder.add8Bits((byte)~buf[idx]);
}
idx++;
}
encoder.endLine();
}
} else {
//Optimized non-packed encoding
for (int y = 0, maxy = img.getHeight(); y < maxy; y++) {
byte[] line = (byte[])raster.getDataElements(0, y, imgw, 1, null);
for (int x = 0, maxx = imgw; x < maxx; x++) {
encoder.addBit(line[x] == 0);
}
encoder.endLine();
}
}
} else {
//Safe but slow fallback
for (int y = 0, maxy = img.getHeight(); y < maxy; y++) {
for (int x = 0, maxx = imgw; x < maxx; x++) {
int sample = raster.getSample(x, y, 0);
encoder.addBit(sample == 0);
}
encoder.endLine();
}
}
// End raster graphics
writeCommand("*rB");
}
// in src/java/org/apache/fop/render/pcl/PCLGenerator.java
public void endLine() throws IOException {
if (zeroRow && PCLGenerator.this.currentSourceTransparency) {
writeCommand("*b1Y");
} else if (rlewidth < bytewidth) {
writeCommand("*b1m" + rlewidth + "W");
out.write(rle, 0, rlewidth);
} else {
writeCommand("*b0m" + bytewidth + "W");
out.write(uncompressed);
}
lastcount = -1;
rlewidth = 0;
ib = 0;
x = 0;
zeroRow = true;
}
// in src/java/org/apache/fop/render/pcl/HardcodedFonts.java
public static boolean setFont(PCLGenerator gen, String name, int size, String text)
throws IOException {
byte[] encoded = text.getBytes("ISO-8859-1");
for (int i = 0, c = encoded.length; i < c; i++) {
if (encoded[i] == 0x3F && text.charAt(i) != '?') {
return false;
}
}
return selectFont(gen, name, size);
}
// in src/java/org/apache/fop/render/pcl/HardcodedFonts.java
private static boolean selectFont(PCLGenerator gen, String name, int size) throws IOException {
int fontcode = 0;
if (name.length() > 1 && name.charAt(0) == 'F') {
try {
fontcode = Integer.parseInt(name.substring(1));
} catch (Exception e) {
LOG.error(e);
}
}
//Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
String formattedSize = gen.formatDouble2(size / 1000.0);
switch (fontcode) {
case 1: // F1 = Helvetica
// gen.writeCommand("(8U");
// gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
// Arial is more common among PCL5 printers than Helvetica - so use Arial
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
break;
case 2: // F2 = Helvetica Oblique
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
break;
case 3: // F3 = Helvetica Bold
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
break;
case 4: // F4 = Helvetica Bold Oblique
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
break;
case 5: // F5 = Times Roman
// gen.writeCommand("(8U");
// gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
// Times New is more common among PCL5 printers than Times - so use Times New
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
break;
case 6: // F6 = Times Italic
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
break;
case 7: // F7 = Times Bold
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
break;
case 8: // F8 = Times Bold Italic
gen.writeCommand("(0N");
gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
break;
case 9: // F9 = Courier
gen.writeCommand("(0N");
gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ "h0s0b4099T");
break;
case 10: // F10 = Courier Oblique
gen.writeCommand("(0N");
gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ "h1s0b4099T");
break;
case 11: // F11 = Courier Bold
gen.writeCommand("(0N");
gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ "h0s3b4099T");
break;
case 12: // F12 = Courier Bold Oblique
gen.writeCommand("(0N");
gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ "h1s3b4099T");
break;
case 13: // F13 = Symbol
return false;
//gen.writeCommand("(19M");
//gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
// ECMA Latin 1 Symbol Set in Times Roman???
// gen.writeCommand("(9U");
// gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
//break;
case 14: // F14 = Zapf Dingbats
return false;
//gen.writeCommand("(14L");
//gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
//break;
default:
//gen.writeCommand("(0N");
//gen.writeCommand("(s" + formattedSize + "V");
return false;
}
return true;
}
// in src/java/org/apache/fop/render/pcl/PCLImageHandlerRenderedImage.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PCLRenderingContext pclContext = (PCLRenderingContext)context;
ImageRendered imageRend = (ImageRendered)image;
PCLGenerator gen = pclContext.getPCLGenerator();
RenderedImage ri = imageRend.getRenderedImage();
Point2D transPoint = pclContext.transformedPoint(pos.x, pos.y);
gen.setCursorPos(transPoint.getX(), transPoint.getY());
gen.paintBitmap(ri, new Dimension(pos.width, pos.height),
pclContext.isSourceTransparencyEnabled());
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
public RtfTableCell newTableCell(int cellWidth) throws IOException {
highestCell++;
cell = new RtfTableCell(this, writer, cellWidth, highestCell);
return cell;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
public RtfTableCell newTableCell(int cellWidth, RtfAttributes attrs) throws IOException {
highestCell++;
cell = new RtfTableCell(this, writer, cellWidth, attrs, highestCell);
return cell;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
public RtfTableCell newTableCellMergedVertically(int cellWidth,
RtfAttributes attrs) throws IOException {
highestCell++;
cell = new RtfTableCell (this, writer, cellWidth, attrs, highestCell);
cell.setVMerge(RtfTableCell.MERGE_WITH_PREVIOUS);
return cell;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
public RtfTableCell newTableCellMergedHorizontally (int cellWidth,
RtfAttributes attrs) throws IOException, FOPException {
highestCell++;
// Added by Normand Masse
// Inherit attributes from base cell for merge
RtfAttributes wAttributes = null;
if (attrs != null) {
try {
wAttributes = (RtfAttributes)attrs.clone();
} catch (CloneNotSupportedException e) {
throw new FOPException(e);
}
}
cell = new RtfTableCell(this, writer, cellWidth, wAttributes, highestCell);
cell.setHMerge(RtfTableCell.MERGE_WITH_PREVIOUS);
return cell;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
protected void writeRtfPrefix() throws IOException {
newLine();
writeGroupMark(true);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
protected void writeRtfContent() throws IOException {
if (getTable().isNestedTable()) {
//nested table
writeControlWord("intbl");
//itap is the depth (level) of the current nested table
writeControlWord("itap" + getTable().getNestedTableDepth());
} else {
//normal (not nested) table
writeRowAndCellsDefintions();
}
// now children can write themselves, we have the correct RTF prefix code
super.writeRtfContent();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
public void writeRowAndCellsDefintions() throws IOException {
// render the row and cells definitions
writeControlWord("trowd");
if (!getTable().isNestedTable()) {
writeControlWord("itap0");
}
//check for keep-together
if (attrib != null && attrib.isSet(ITableAttributes.ROW_KEEP_TOGETHER)) {
writeControlWord(ROW_KEEP_TOGETHER);
}
writePaddingAttributes();
final RtfTable parentTable = (RtfTable) parent;
adjustBorderProperties(parentTable);
writeAttributes(attrib, new String[]{ITableAttributes.ATTR_HEADER});
writeAttributes(attrib, ITableAttributes.ROW_BORDER);
writeAttributes(attrib, ITableAttributes.CELL_BORDER);
writeAttributes(attrib, IBorderAttributes.BORDERS);
if (attrib.isSet(ITableAttributes.ROW_HEIGHT)) {
writeOneAttribute(
ITableAttributes.ROW_HEIGHT,
attrib.getValue(ITableAttributes.ROW_HEIGHT));
}
// write X positions of our cells
int xPos = 0;
final Object leftIndent = attrib.getValue(ITableAttributes.ATTR_ROW_LEFT_INDENT);
if (leftIndent != null) {
xPos = ((Integer)leftIndent).intValue();
}
RtfAttributes tableBorderAttributes = getTable().getBorderAttributes();
int index = 0;
for (Iterator it = getChildren().iterator(); it.hasNext();) {
final RtfElement e = (RtfElement)it.next();
if (e instanceof RtfTableCell) {
RtfTableCell rtfcell = (RtfTableCell)e;
// Adjust the cell's display attributes so the table's/row's borders
// are drawn properly.
if (tableBorderAttributes != null) {
// get border attributes from table
if (index == 0) {
String border = ITableAttributes.CELL_BORDER_LEFT;
if (!rtfcell.getRtfAttributes().isSet(border)) {
rtfcell.getRtfAttributes().set(border,
(RtfAttributes) tableBorderAttributes.getValue(border));
}
}
if (index == this.getChildCount() - 1) {
String border = ITableAttributes.CELL_BORDER_RIGHT;
if (!rtfcell.getRtfAttributes().isSet(border)) {
rtfcell.getRtfAttributes().set(border,
(RtfAttributes) tableBorderAttributes.getValue(border));
}
}
if (isFirstRow()) {
String border = ITableAttributes.CELL_BORDER_TOP;
if (!rtfcell.getRtfAttributes().isSet(border)) {
rtfcell.getRtfAttributes().set(border,
(RtfAttributes) tableBorderAttributes.getValue(border));
}
}
if ((parentTable != null) && (parentTable.isHighestRow(id))) {
String border = ITableAttributes.CELL_BORDER_BOTTOM;
if (!rtfcell.getRtfAttributes().isSet(border)) {
rtfcell.getRtfAttributes().set(border,
(RtfAttributes) tableBorderAttributes.getValue(border));
}
}
}
// get border attributes from row
if (index == 0) {
if (!rtfcell.getRtfAttributes().isSet(ITableAttributes.CELL_BORDER_LEFT)) {
rtfcell.getRtfAttributes().set(ITableAttributes.CELL_BORDER_LEFT,
(String) attrib.getValue(ITableAttributes.ROW_BORDER_LEFT));
}
}
if (index == this.getChildCount() - 1) {
if (!rtfcell.getRtfAttributes().isSet(ITableAttributes.CELL_BORDER_RIGHT)) {
rtfcell.getRtfAttributes().set(ITableAttributes.CELL_BORDER_RIGHT,
(String) attrib.getValue(ITableAttributes.ROW_BORDER_RIGHT));
}
}
if (isFirstRow()) {
if (!rtfcell.getRtfAttributes().isSet(ITableAttributes.CELL_BORDER_TOP)) {
rtfcell.getRtfAttributes().set(ITableAttributes.CELL_BORDER_TOP,
(String) attrib.getValue(ITableAttributes.ROW_BORDER_TOP));
}
}
if ((parentTable != null) && (parentTable.isHighestRow(id))) {
if (!rtfcell.getRtfAttributes().isSet(ITableAttributes.CELL_BORDER_BOTTOM)) {
rtfcell.getRtfAttributes().set(ITableAttributes.CELL_BORDER_BOTTOM,
(String) attrib.getValue(ITableAttributes.ROW_BORDER_BOTTOM));
}
}
// write cell's definition
xPos = rtfcell.writeCellDef(xPos);
}
index++; // Added by Boris POUDEROUS on 2002/07/02
}
newLine();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
protected void writeRtfSuffix() throws IOException {
if (getTable().isNestedTable()) {
//nested table
writeGroupMark(true);
writeStarControlWord("nesttableprops");
writeRowAndCellsDefintions();
writeControlWordNS("nestrow");
writeGroupMark(false);
writeGroupMark(true);
writeControlWord("nonesttables");
writeControlWord("par");
writeGroupMark(false);
} else {
writeControlWord("row");
}
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableRow.java
private void writePaddingAttributes()
throws IOException {
// Row padding attributes generated in the converter package
// use RTF 1.6 definitions - try to compute a reasonable RTF 1.5 value
// out of them if present
// how to do vertical padding with RTF 1.5?
if (attrib != null && !attrib.isSet(ATTR_RTF_15_TRGAPH)) {
int gaph = -1;
try {
// set (RTF 1.5) gaph to the average of the (RTF 1.6) left and right padding values
final Integer leftPadStr = (Integer)attrib.getValue(ATTR_ROW_PADDING_LEFT);
if (leftPadStr != null) {
gaph = leftPadStr.intValue();
}
final Integer rightPadStr = (Integer)attrib.getValue(ATTR_ROW_PADDING_RIGHT);
if (rightPadStr != null) {
gaph = (gaph + rightPadStr.intValue()) / 2;
}
} catch (Exception e) {
final String msg = "RtfTableRow.writePaddingAttributes: " + e.toString();
// getRtfFile().getLog().logWarning(msg);
}
if (gaph >= 0) {
attrib.set(ATTR_RTF_15_TRGAPH, gaph);
}
}
// write all padding attributes
writeAttributes(attrib, ATTRIB_ROW_PADDING);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfPageNumber.java
protected void writeRtfContent() throws IOException {
/*
writeGroupMark(true);
writeControlWord(RTF_FIELD);
writeGroupMark(true);
writeAttributes(attrib, RtfText.ATTR_NAMES); // Added by Boris Poudérous
writeStarControlWord(RTF_FIELD_PAGE);
writeGroupMark(false);
writeGroupMark(true);
writeControlWord(RTF_FIELD_RESULT);
writeGroupMark(false);
writeGroupMark(false);
*/
writeGroupMark(true);
writeAttributes(attrib, RtfText.ATTR_NAMES);
writeControlWord("chpgn");
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
public RtfHeader startHeader()
throws IOException, RtfStructureException {
if (header != null) {
throw new RtfStructureException("startHeader called more than once");
}
header = new RtfHeader(this, writer);
listTableContainer = new RtfContainer(this, writer);
return header;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
public RtfListTable startListTable(RtfAttributes attr)
throws IOException {
listNum++;
if (listTable != null) {
return listTable;
} else {
listTable = new RtfListTable(this, writer, new Integer(listNum), attr);
listTableContainer.addChild(listTable);
}
return listTable;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
public RtfPageArea startPageArea()
throws IOException, RtfStructureException {
if (pageArea != null) {
throw new RtfStructureException("startPageArea called more than once");
}
// create an empty header if there was none
if (header == null) {
startHeader();
}
header.close();
pageArea = new RtfPageArea(this, writer);
addChild(pageArea);
return pageArea;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
public RtfPageArea getPageArea()
throws IOException, RtfStructureException {
if (pageArea == null) {
return startPageArea();
}
return pageArea;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
public RtfDocumentArea startDocumentArea()
throws IOException, RtfStructureException {
if (docArea != null) {
throw new RtfStructureException("startDocumentArea called more than once");
}
// create an empty header if there was none
if (header == null) {
startHeader();
}
header.close();
docArea = new RtfDocumentArea(this, writer);
addChild(docArea);
return docArea;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
public RtfDocumentArea getDocumentArea()
throws IOException, RtfStructureException {
if (docArea == null) {
return startDocumentArea();
}
return docArea;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
protected void writeRtfPrefix() throws IOException {
writeGroupMark(true);
writeControlWord("rtf1");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
protected void writeRtfSuffix() throws IOException {
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFile.java
public synchronized void flush() throws IOException {
writeRtf();
writer.flush();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfText.java
public void writeRtfContent() throws IOException {
writeChars: {
//these lines were added by Boris Pouderous
if (attr != null) {
writeAttributes(attr, new String[] {RtfText.SPACE_BEFORE});
writeAttributes(attr, new String[] {RtfText.SPACE_AFTER});
}
if (isTab()) {
writeControlWord("tab");
} else if (isNewLine()) {
break writeChars;
} else if (isBold(true)) {
writeControlWord("b");
} else if (isBold(false)) {
writeControlWord("b0");
// TODO not optimal, consecutive RtfText with same attributes
// could be written without group marks
} else {
writeGroupMark(true);
if (attr != null && mustWriteAttributes()) {
writeAttributes(attr, RtfText.ATTR_NAMES);
}
RtfStringConverter.getInstance().writeRtfString(writer, text);
writeGroupMark(false);
}
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
public RtfParagraph newParagraph() throws IOException {
closeAll();
para = new RtfParagraph(this, writer);
return para;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
public RtfParagraph newParagraph(RtfAttributes attrs) throws IOException {
closeAll();
para = new RtfParagraph(this, writer, attrs);
return para;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
public RtfExternalGraphic newImage() throws IOException {
closeAll();
externalGraphic = new RtfExternalGraphic(this, writer);
return externalGraphic;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
private void closeCurrentParagraph() throws IOException {
if (para != null) {
para.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
private void closeCurrentExternalGraphic() throws IOException {
if (externalGraphic != null) {
externalGraphic.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
private void closeCurrentTable() throws IOException {
if (table != null) {
table.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
protected void writeRtfPrefix() throws IOException {
writeGroupMark(true);
writeMyAttributes();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
protected void writeRtfSuffix() throws IOException {
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
public void closeAll() throws IOException {
closeCurrentParagraph();
closeCurrentExternalGraphic();
closeCurrentTable();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
public RtfTable newTable(RtfAttributes attrs, ITableColumnsInfo tc) throws IOException {
closeAll();
table = new RtfTable(this, writer, attrs, tc);
return table;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
public RtfTable newTable(ITableColumnsInfo tc) throws IOException {
closeAll();
table = new RtfTable(this, writer, tc);
return table;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfterBeforeBase.java
public RtfTextrun getTextrun()
throws IOException {
return RtfTextrun.getTextrun(this, writer, null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyle.java
public void writeListPrefix(RtfListItem item)
throws IOException {
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyle.java
public void writeParagraphPrefix(RtfElement element)
throws IOException {
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyle.java
public void writeLevelGroup(RtfElement element)
throws IOException {
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfExternalGraphic newImage() throws IOException {
closeAll();
externalGraphic = new RtfExternalGraphic(this, writer);
return externalGraphic;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfParagraph newParagraph(RtfAttributes attrs) throws IOException {
closeAll();
paragraph = new RtfParagraph(this, writer, attrs);
return paragraph;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfParagraph newParagraph() throws IOException {
return newParagraph(null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfParagraphKeepTogether newParagraphKeepTogether() throws IOException {
return new RtfParagraphKeepTogether(this, writer);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfTable newTable(ITableColumnsInfo tc) throws IOException {
closeAll();
table = new RtfTable(this, writer, tc);
return table;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfTable newTable(RtfAttributes attrs, ITableColumnsInfo tc) throws IOException {
closeAll();
table = new RtfTable(this, writer, attrs, tc);
return table;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfList newList(RtfAttributes attrs) throws IOException {
closeAll();
list = new RtfList(this, writer, attrs);
return list;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfBefore newBefore(RtfAttributes attrs) throws IOException {
closeAll();
before = new RtfBefore(this, writer, attrs);
return before;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfAfter newAfter(RtfAttributes attrs) throws IOException {
closeAll();
after = new RtfAfter(this, writer, attrs);
return after;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfJforCmd newJforCmd(RtfAttributes attrs) throws IOException {
jforCmd = new RtfJforCmd(this, writer, attrs);
return jforCmd;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
protected void writeRtfPrefix() throws IOException {
writeAttributes(attrib, RtfPage.PAGE_ATTR);
newLine();
writeControlWord("sectd");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
protected void writeRtfSuffix() throws IOException {
// write suffix /sect only if this section is not last section (see bug #51484)
List siblings = parent.getChildren();
if ( ( siblings.indexOf ( this ) + 1 ) < siblings.size() ) {
writeControlWord("sect");
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
private void closeCurrentTable() throws IOException {
if (table != null) {
table.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
private void closeCurrentParagraph() throws IOException {
if (paragraph != null) {
paragraph.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
private void closeCurrentList() throws IOException {
if (list != null) {
list.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
private void closeCurrentExternalGraphic() throws IOException {
if (externalGraphic != null) {
externalGraphic.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
private void closeCurrentBefore() throws IOException {
if (before != null) {
before.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
private void closeAll()
throws IOException {
closeCurrentTable();
closeCurrentParagraph();
closeCurrentList();
closeCurrentExternalGraphic();
closeCurrentBefore();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfSection.java
public RtfTextrun getTextrun()
throws IOException {
return RtfTextrun.getTextrun(this, writer, null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfLeader.java
protected void writeRtfContent() throws IOException {
int thickness = LEADER_STANDARD_WIDTH;
String tablead = null;
String tabwidth = null;
for (Iterator it = attrs.nameIterator(); it.hasNext();) {
final String name = (String)it.next();
if (attrs.isSet(name)) {
if (name.equals(LEADER_TABLEAD)) {
tablead = attrs.getValue(LEADER_TABLEAD).toString();
} else if (name.equals(LEADER_WIDTH)) {
tabwidth = attrs.getValue(LEADER_WIDTH).toString();
}
}
}
if (attrs.getValue(LEADER_RULE_THICKNESS) != null) {
thickness += Integer.parseInt(attrs.getValue(LEADER_RULE_THICKNESS).toString())
/ 1000 * 2;
attrs.unset(LEADER_RULE_THICKNESS);
}
//Remove private attributes
attrs.unset(LEADER_WIDTH);
attrs.unset(LEADER_TABLEAD);
// If leader is 100% we use a tabulator, because its more
// comfortable, specially for the table of content
if (attrs.getValue(LEADER_USETAB) != null) {
attrs.unset(LEADER_USETAB);
writeControlWord(LEADER_TAB_RIGHT);
if (tablead != null) {
writeControlWord(tablead);
}
writeControlWord(LEADER_TAB_WIDTH + tabwidth);
writeGroupMark(true);
writeControlWord(LEADER_IGNORE_STYLE);
writeAttributes(attrs, null);
writeControlWord(LEADER_EXPAND);
writeControlWord(LEADER_TAB_VALUE);
writeGroupMark(false);
} else { // Using white spaces with different underline formats
writeControlWord(LEADER_IGNORE_STYLE);
writeControlWord(LEADER_ZERO_WIDTH);
writeGroupMark(true);
writeControlWord(LEADER_RULE_THICKNESS + thickness);
writeControlWord(LEADER_UP);
super.writeAttributes(attrs, null);
if (tablead != null) {
writeControlWord(tablead);
}
// Calculation for the necessary amount of white spaces
// Depending on font-size 15 -> 1cm = 7,5 spaces
// TODO for rule-thickness this has to be done better
for (double d = (Integer.parseInt(tabwidth) / 560) * 7.5; d >= 1; d--) {
RtfStringConverter.getInstance().writeRtfString(writer, " ");
}
writeGroupMark(false);
writeControlWord(LEADER_ZERO_WIDTH);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfContainer.java
protected void writeRtfContent()
throws IOException {
for (Iterator it = children.iterator(); it.hasNext();) {
final RtfElement e = (RtfElement)it.next();
e.writeRtf();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfContainer.java
void dump(Writer w, int indent)
throws IOException {
super.dump(w, indent);
for (Iterator it = children.iterator(); it.hasNext();) {
final RtfElement e = (RtfElement)it.next();
e.dump(w, indent + 1);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFontTable.java
protected void writeRtfContent() throws IOException {
RtfFontManager.getInstance ().writeFonts ((RtfHeader)parent);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleBullet.java
public void writeListPrefix(RtfListItem item) throws IOException {
// bulleted list
item.writeControlWord("pnlvlblt");
item.writeControlWord("ilvl0");
item.writeOneAttribute(RtfListTable.LIST_NUMBER, new Integer(item.getNumber()));
item.writeOneAttribute("pnindent",
item.getParentList().attrib.getValue(RtfListTable.LIST_INDENT));
item.writeControlWord("pnf1");
item.writeGroupMark(true);
item.writeControlWord("pndec");
item.writeOneAttribute(RtfListTable.LIST_FONT_TYPE, "2");
item.writeControlWord("pntxtb");
item.writeControlWord("'b7");
item.writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleBullet.java
public void writeParagraphPrefix(RtfElement element) throws IOException {
element.writeGroupMark(true);
element.writeControlWord("pntext");
element.writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleBullet.java
public void writeLevelGroup(RtfElement element) throws IOException {
element.attrib.set(RtfListTable.LIST_NUMBER_TYPE, 23);
element.writeGroupMark(true);
element.writeOneAttributeNS(RtfListTable.LIST_TEXT_FORM, "\\'01\\'b7");
element.writeGroupMark(false);
element.writeGroupMark(true);
element.writeOneAttributeNS(RtfListTable.LIST_NUM_POSITION, null);
element.writeGroupMark(false);
element.attrib.set(RtfListTable.LIST_FONT_TYPE, 2);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfAfter.java
protected void writeMyAttributes() throws IOException {
writeAttributes(attrib, FOOTER_ATTR);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfDocumentArea.java
public RtfSection newSection() throws IOException {
if (currentSection != null) {
currentSection.close();
}
currentSection = new RtfSection(this, writer);
return currentSection;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFontManager.java
public void writeFonts (RtfHeader header) throws IOException {
if (fontTable == null || fontTable.size () == 0) {
return;
}
header.newLine();
header.writeGroupMark(true);
header.writeControlWord("fonttbl");
int len = fontTable.size ();
for (int i = 0; i < len; i++) {
header.writeGroupMark(true);
header.newLine();
header.write("\\f" + i);
header.write(" " + (String) fontTable.elementAt (i));
header.write(";");
header.writeGroupMark(false);
}
header.newLine();
header.writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
protected void writeRtfContent() throws IOException {
writeGroupMark(true);
writeAttributes(getRtfAttributes(), null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
protected void writeRtfContent() throws IOException {
writeGroupMark(false);
boolean bHasTableCellParent = this.getParentOfClass(RtfTableCell.class) != null;
//Unknown behavior when a table starts a new section,
//Word may crash
if (breakType != BREAK_NONE) {
if (!bHasTableCellParent) {
writeControlWord("sect");
/* The following modifiers don't seem to appear in the right place */
switch (breakType) {
case BREAK_EVEN_PAGE:
writeControlWord("sbkeven");
break;
case BREAK_ODD_PAGE:
writeControlWord("sbkodd");
break;
case BREAK_COLUMN:
writeControlWord("sbkcol");
break;
default:
writeControlWord("sbkpage");
}
} else {
log.warn("Cannot create break-after for a paragraph inside a table.");
}
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
private void addOpenGroupMark(RtfAttributes attrs) throws IOException {
RtfOpenGroupMark r = new RtfOpenGroupMark(this, writer, attrs);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
private void addCloseGroupMark(int breakType) throws IOException {
RtfCloseGroupMark r = new RtfCloseGroupMark(this, writer, breakType);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
private void addCloseGroupMark() throws IOException {
RtfCloseGroupMark r = new RtfCloseGroupMark(this, writer, BREAK_NONE);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void pushBlockAttributes(RtfAttributes attrs) throws IOException {
rtfSpaceManager.stopUpdatingSpaceBefore();
RtfSpaceSplitter splitter = rtfSpaceManager.pushRtfSpaceSplitter(attrs);
addOpenGroupMark(splitter.getCommonAttributes());
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void popBlockAttributes(int breakType) throws IOException {
rtfSpaceManager.popRtfSpaceSplitter();
rtfSpaceManager.stopUpdatingSpaceBefore();
addCloseGroupMark(breakType);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void pushInlineAttributes(RtfAttributes attrs) throws IOException {
rtfSpaceManager.pushInlineAttributes(attrs);
addOpenGroupMark(attrs);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void addPageNumberCitation(String refId) throws IOException {
RtfPageNumberCitation r = new RtfPageNumberCitation(this, writer, refId);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void popInlineAttributes() throws IOException {
rtfSpaceManager.popInlineAttributes();
addCloseGroupMark();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void addString(String s) throws IOException {
if (s.equals("")) {
return;
}
RtfAttributes attrs = rtfSpaceManager.getLastInlineAttribute();
//add RtfSpaceSplitter to inherit accumulated space
rtfSpaceManager.pushRtfSpaceSplitter(attrs);
rtfSpaceManager.setCandidate(attrs);
// create a string and add it as a child
new RtfString(this, writer, s);
rtfSpaceManager.popRtfSpaceSplitter();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public RtfFootnote addFootnote() throws IOException {
return new RtfFootnote(this, writer);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public RtfParagraphBreak addParagraphBreak() throws IOException {
// get copy of children list
List children = getChildren();
Stack tmp = new Stack();
RtfParagraphBreak par = null;
// delete all previous CloseGroupMark
int deletedCloseGroupCount = 0;
ListIterator lit = children.listIterator(children.size());
while (lit.hasPrevious()
&& (lit.previous() instanceof RtfCloseGroupMark)) {
tmp.push(Integer.valueOf(((RtfCloseGroupMark)lit.next()).getBreakType()));
lit.remove();
deletedCloseGroupCount++;
}
if (children.size() != 0) {
// add paragraph break and restore all deleted close group marks
setChildren(children);
par = new RtfParagraphBreak(this, writer);
for (int i = 0; i < deletedCloseGroupCount; i++) {
addCloseGroupMark(((Integer)tmp.pop()).intValue());
}
}
return par;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void addLeader(RtfAttributes attrs) throws IOException {
new RtfLeader(this, writer, attrs);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void addPageNumber(RtfAttributes attr) throws IOException {
RtfPageNumber r = new RtfPageNumber(this, writer, attr);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public RtfHyperLink addHyperlink(RtfAttributes attr) throws IOException {
return new RtfHyperLink(this, writer, attr);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public void addBookmark(String id) throws IOException {
if (id != "") {
// if id is not empty, add boormark
new RtfBookmark(this, writer, id);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public RtfExternalGraphic newImage() throws IOException {
return new RtfExternalGraphic(this, writer);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
public static RtfTextrun getTextrun(RtfContainer container, Writer writer, RtfAttributes attrs)
throws IOException {
List list = container.getChildren();
if (list.size() == 0) {
//add a new RtfTextrun
RtfTextrun textrun = new RtfTextrun(container, writer, attrs);
list.add(textrun);
return textrun;
}
Object obj = list.get(list.size() - 1);
if (obj instanceof RtfTextrun) {
//if the last child is a RtfTextrun, return it
return (RtfTextrun) obj;
}
//add a new RtfTextrun as the last child
RtfTextrun textrun = new RtfTextrun(container, writer, attrs);
list.add(textrun);
return textrun;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
protected void writeRtfContent() throws IOException {
/**
*TODO: The textrun's children are iterated twice:
* 1. To determine the last RtfParagraphBreak
* 2. To write the children
* Maybe this can be done more efficient.
*/
boolean bHasTableCellParent
= this.getParentOfClass(RtfTableCell.class) != null;
RtfAttributes attrBlockLevel = new RtfAttributes();
//determine, if this RtfTextrun is the last child of its parent
boolean bLast = false;
for (Iterator it = parent.getChildren().iterator(); it.hasNext();) {
if (it.next() == this) {
bLast = !it.hasNext();
break;
}
}
//get last RtfParagraphBreak, which is not followed by any visible child
RtfParagraphBreak lastParagraphBreak = null;
if (bLast) {
RtfElement aBefore = null;
for (Iterator it = getChildren().iterator(); it.hasNext();) {
final RtfElement e = (RtfElement)it.next();
if (e instanceof RtfParagraphBreak) {
//If the element before was a paragraph break or a bookmark
//they will be hidden and are therefore not considered as visible
if (!(aBefore instanceof RtfParagraphBreak)
&& !(aBefore instanceof RtfBookmark)) {
lastParagraphBreak = (RtfParagraphBreak)e;
}
} else {
if (!(e instanceof RtfOpenGroupMark)
&& !(e instanceof RtfCloseGroupMark)
&& e.isEmpty()) {
lastParagraphBreak = null;
}
}
aBefore = e;
}
}
//may contain for example \intbl
writeAttributes(attrib, null);
if (rtfListItem != null) {
rtfListItem.getRtfListStyle().writeParagraphPrefix(this);
}
//write all children
boolean bPrevPar = false;
boolean bBookmark = false;
boolean bFirst = true;
for (Iterator it = getChildren().iterator(); it.hasNext();) {
final RtfElement e = (RtfElement)it.next();
final boolean bRtfParagraphBreak = (e instanceof RtfParagraphBreak);
if (bHasTableCellParent) {
attrBlockLevel.set(e.getRtfAttributes());
}
/**
* -Write RtfParagraphBreak only, if the previous visible child
* was't also a RtfParagraphBreak.
* -Write RtfParagraphBreak only, if it is not the first visible
* child.
* -If the RtfTextrun is the last child of its parent, write a
* RtfParagraphBreak only, if it is not the last child.
* -If the RtfParagraphBreak can not be hidden (e.g. a table cell requires it)
* it is also written
*/
boolean bHide = false;
bHide = bRtfParagraphBreak;
bHide = bHide
&& (bPrevPar
|| bFirst
|| (bSuppressLastPar && bLast && lastParagraphBreak != null
&& e == lastParagraphBreak)
|| bBookmark)
&& ((RtfParagraphBreak)e).canHide();
if (!bHide) {
newLine();
e.writeRtf();
if (rtfListItem != null && e instanceof RtfParagraphBreak) {
rtfListItem.getRtfListStyle().writeParagraphPrefix(this);
}
}
if (e instanceof RtfParagraphBreak) {
bPrevPar = true;
} else if (e instanceof RtfBookmark) {
bBookmark = true;
} else if (e instanceof RtfCloseGroupMark) {
//do nothing
} else if (e instanceof RtfOpenGroupMark) {
//do nothing
} else {
bPrevPar = bPrevPar && e.isEmpty();
bFirst = bFirst && e.isEmpty();
bBookmark = false;
}
} //for (Iterator it = ...)
//
if (bHasTableCellParent) {
writeAttributes(attrBlockLevel, null);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfLineBreak.java
protected void writeRtfContent() throws IOException {
writeControlWord("line");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleText.java
public void writeListPrefix(RtfListItem item)
throws IOException {
// bulleted list
item.writeControlWord("pnlvlblt");
item.writeControlWord("ilvl0");
item.writeOneAttribute(RtfListTable.LIST_NUMBER, new Integer(item.getNumber()));
item.writeOneAttribute("pnindent",
item.getParentList().attrib.getValue(RtfListTable.LIST_INDENT));
item.writeControlWord("pnf1");
item.writeGroupMark(true);
//item.writeControlWord("pndec");
item.writeOneAttribute(RtfListTable.LIST_FONT_TYPE, "2");
item.writeControlWord("pntxtb");
RtfStringConverter.getInstance().writeRtfString(item.writer, text);
item.writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleText.java
public void writeParagraphPrefix(RtfElement element)
throws IOException {
element.writeGroupMark(true);
element.writeControlWord("pntext");
element.writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleText.java
public void writeLevelGroup(RtfElement element)
throws IOException {
element.attrib.set(RtfListTable.LIST_NUMBER_TYPE, 23);
element.writeGroupMark(true);
String sCount;
if (text.length() < 10) {
sCount = "0" + String.valueOf(text.length());
} else {
sCount = String.valueOf(Integer.toHexString(text.length()));
if (sCount.length() == 1) {
sCount = "0" + sCount;
}
}
element.writeOneAttributeNS(
RtfListTable.LIST_TEXT_FORM, "\\'" + sCount
+ RtfStringConverter.getInstance().escape(text));
element.writeGroupMark(false);
element.writeGroupMark(true);
element.writeOneAttributeNS(RtfListTable.LIST_NUM_POSITION, null);
element.writeGroupMark(false);
element.attrib.set(RtfListTable.LIST_FONT_TYPE, 2);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTemplate.java
public void setTemplateFilePath(String templateFilePath) throws IOException {
// no validity checks here - leave this to the RTF client
if (templateFilePath == null) {
this.templateFilePath = null;
} else {
this.templateFilePath = templateFilePath.trim();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTemplate.java
public void writeTemplate (RtfHeader header) throws IOException {
if (templateFilePath == null || templateFilePath.length() == 0) {
return;
}
header.writeGroupMark (true);
header.writeControlWord ("template");
header.writeRtfString(this.templateFilePath);
header.writeGroupMark (false);
header.writeGroupMark (true);
header.writeControlWord ("linkstyles");
header.writeGroupMark (false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleNumber.java
public void writeListPrefix(RtfListItem item)
throws IOException {
item.writeControlWord("pnlvlbody");
item.writeControlWord("ilvl0");
item.writeOneAttribute(RtfListTable.LIST_NUMBER, "0");
item.writeControlWord("pndec");
item.writeOneAttribute("pnstart", new Integer(1));
item.writeOneAttribute("pnindent",
item.attrib.getValue(RtfListTable.LIST_INDENT));
item.writeControlWord("pntxta.");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleNumber.java
public void writeParagraphPrefix(RtfElement element)
throws IOException {
element.writeGroupMark(true);
element.writeControlWord("pntext");
element.writeControlWord("f" + RtfFontManager.getInstance().getFontNumber("Symbol"));
element.writeControlWord("'b7");
element.writeControlWord("tab");
element.writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListStyleNumber.java
public void writeLevelGroup(RtfElement element)
throws IOException {
element.writeOneAttributeNS(
RtfListTable.LIST_START_AT, new Integer(1));
element.attrib.set(RtfListTable.LIST_NUMBER_TYPE, 0);
element.writeGroupMark(true);
element.writeOneAttributeNS(
RtfListTable.LIST_TEXT_FORM, "\\'03\\\'00. ;");
element.writeGroupMark(false);
element.writeGroupMark(true);
element.writeOneAttributeNS(
RtfListTable.LIST_NUM_POSITION, "\\'01;");
element.writeGroupMark(false);
element.writeOneAttribute(RtfListTable.LIST_FONT_TYPE, new Integer(0));
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExtraRowSet.java
RtfTableCell createExtraCell(int rowIndex, int xOffset, int cellWidth,
RtfAttributes parentCellAttributes)
throws IOException {
final RtfTableCell c = new RtfTableCell(null, writer, cellWidth,
parentCellAttributes, DEFAULT_IDNUM);
cells.add(new PositionedCell(c, rowIndex, xOffset));
return c;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExtraRowSet.java
protected void writeRtfContent() throws IOException {
// sort cells by rowIndex and xOffset
Collections.sort(cells);
// process all extra cells by rendering them into extra rows
List rowCells = null;
int rowIndex = -1;
for (Iterator it = cells.iterator(); it.hasNext();) {
final PositionedCell pc = (PositionedCell)it.next();
if (pc.rowIndex != rowIndex) {
// starting a new row, render previous one
if (rowCells != null) {
writeRow(rowCells);
}
rowIndex = pc.rowIndex;
rowCells = new LinkedList();
}
rowCells.add(pc);
}
// render last row
if (rowCells != null) {
writeRow(rowCells);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExtraRowSet.java
private void writeRow(List cells)
throws IOException {
if (allCellsEmpty(cells)) {
return;
}
final RtfTableRow row = new RtfTableRow(null, writer, DEFAULT_IDNUM);
int cellIndex = 0;
// Get the context of the table that holds the nested table
ITableColumnsInfo parentITableColumnsInfo = getParentITableColumnsInfo();
parentITableColumnsInfo.selectFirstColumn();
// X offset of the current empty cell to add
float xOffset = 0;
float xOffsetOfLastPositionedCell = 0;
for (Iterator it = cells.iterator(); it.hasNext();) {
final PositionedCell pc = (PositionedCell)it.next();
// if first cell is not at offset 0, add placeholder cell
// TODO should be merged with the cell that is above it
if (cellIndex == 0 && pc.xOffset > 0) {
/**
* Added by Boris Poudérous
*/
// Add empty cells merged vertically with the cells above and with the same widths
// (BEFORE the cell that contains the nested table)
for (int i = 0; (xOffset < pc.xOffset)
&& (i < parentITableColumnsInfo.getNumberOfColumns()); i++) {
// Get the width of the cell above
xOffset += parentITableColumnsInfo.getColumnWidth();
// Create the empty cell merged vertically
row.newTableCellMergedVertically((int)parentITableColumnsInfo.getColumnWidth(),
pc.cell.attrib);
// Select next column in order to have its width
parentITableColumnsInfo.selectNextColumn();
}
}
row.addChild(pc.cell);
// Line added by Boris Poudérous
xOffsetOfLastPositionedCell = pc.xOffset + pc.cell.getCellWidth();
cellIndex++;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
protected void writeRtfPrefix() throws IOException {
super.writeRtfPrefix();
getRtfListStyle().writeParagraphPrefix(this);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
public RtfTextrun getTextrun() throws IOException {
return this;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
public void addString(String s) throws IOException {
final String label = s.trim();
if (label.length() > 0 && Character.isDigit(label.charAt(0))) {
rtfListItem.setRtfListStyle(new RtfListStyleNumber());
} else {
rtfListItem.setRtfListStyle(new RtfListStyleText(label));
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
public RtfParagraph newParagraph(RtfAttributes attrs) throws IOException {
if (paragraph != null) {
paragraph.close();
}
paragraph = new RtfListItemParagraph(this, attrs);
return paragraph;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
public RtfParagraph newParagraph() throws IOException {
return newParagraph(null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
public RtfTextrun getTextrun() throws IOException {
RtfTextrun textrun = RtfTextrun.getTextrun(this, writer, null);
textrun.setRtfListItem(this);
return textrun;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
public RtfList newList(RtfAttributes attrs) throws IOException {
RtfList list = new RtfList(this, writer, attrs);
return list;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
protected void writeRtfPrefix() throws IOException {
// pard causes word97 (and sometimes 2000 too) to crash if the list is nested in a table
if (!parentList.getHasTableParent()) {
writeControlWord("pard");
}
writeOneAttribute(RtfText.LEFT_INDENT_FIRST,
"360"); //attrib.getValue(RtfListTable.LIST_INDENT));
writeOneAttribute(RtfText.LEFT_INDENT_BODY,
attrib.getValue(RtfText.LEFT_INDENT_BODY));
// group for list setup info
writeGroupMark(true);
writeStarControlWord("pn");
//Modified by Chris Scott
//fixes second line indentation
getRtfListStyle().writeListPrefix(this);
writeGroupMark(false);
writeOneAttribute(RtfListTable.LIST_NUMBER, new Integer(number));
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListItem.java
protected void writeRtfSuffix() throws IOException {
super.writeRtfSuffix();
/* reset paragraph defaults to make sure list ends
* but pard causes word97 (and sometimes 2000 too) to crash if the list
* is nested in a table
*/
if (!parentList.getHasTableParent()) {
writeControlWord("pard");
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfPage.java
protected void writeRtfContent() throws IOException {
writeAttributes(attrib, PAGE_ATTR);
if (attrib != null) {
Object widthRaw = attrib.getValue(PAGE_WIDTH);
Object heightRaw = attrib.getValue(PAGE_HEIGHT);
if ((widthRaw instanceof Integer) && (heightRaw instanceof Integer)
&& ((Integer) widthRaw).intValue() > ((Integer) heightRaw).intValue()) {
writeControlWord(LANDSCAPE);
}
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHeader.java
protected void writeRtfContent() throws IOException {
writeControlWord(charset);
writeUserProperties();
RtfColorTable.getInstance().writeColors(this);
super.writeRtfContent();
RtfTemplate.getInstance().writeTemplate(this);
RtfStyleSheetTable.getInstance().writeStyleSheet(this);
writeFootnoteProperties();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHeader.java
private void writeUserProperties() throws IOException {
if (userProperties.size() > 0) {
writeGroupMark(true);
writeStarControlWord("userprops");
for (Iterator it = userProperties.entrySet().iterator(); it.hasNext();) {
final Map.Entry entry = (Map.Entry)it.next();
writeGroupMark(true);
writeControlWord("propname");
RtfStringConverter.getInstance().writeRtfString(writer,
entry.getKey().toString());
writeGroupMark(false);
writeControlWord("proptype30");
writeGroupMark(true);
writeControlWord("staticval");
RtfStringConverter.getInstance().writeRtfString(writer,
entry.getValue().toString());
writeGroupMark(false);
}
writeGroupMark(false);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHeader.java
void write(String toWrite) throws IOException {
writer.write(toWrite);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHeader.java
void writeRtfString(String toWrite) throws IOException {
RtfStringConverter.getInstance().writeRtfString(writer, toWrite);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHeader.java
private void writeFootnoteProperties() throws IOException {
newLine();
writeControlWord("fet0"); //footnotes, not endnotes
writeControlWord("ftnbj"); //place footnotes at the end of the
//page (should be the default, but
//Word 2000 thinks otherwise)
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
protected void writeRtfContent() throws IOException {
try {
writeRtfContentWithException();
} catch (ExternalGraphicException ie) {
writeExceptionInRtf(ie);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
protected void writeRtfContentWithException() throws IOException {
if (writer == null) {
return;
}
if (url == null && imagedata == null) {
throw new ExternalGraphicException(
"No image data is available (neither URL, nor in-memory)");
}
String linkToRoot = System.getProperty("jfor_link_to_root");
if (url != null && linkToRoot != null) {
writer.write("{\\field {\\* \\fldinst { INCLUDEPICTURE \"");
writer.write(linkToRoot);
File urlFile = new File(url.getFile());
writer.write(urlFile.getName());
writer.write("\" \\\\* MERGEFORMAT \\\\d }}}");
return;
}
// getRtfFile ().getLog ().logInfo ("Writing image '" + url + "'.");
if (imagedata == null) {
try {
final InputStream in = url.openStream();
try {
imagedata = IOUtils.toByteArray(url.openStream());
} finally {
IOUtils.closeQuietly(in);
}
} catch (Exception e) {
throw new ExternalGraphicException("The attribute 'src' of "
+ "<fo:external-graphic> has a invalid value: '"
+ url + "' (" + e + ")");
}
}
if (imagedata == null) {
return;
}
// Determine image file format
String file = (url != null ? url.getFile() : "<unknown>");
imageformat = FormatBase.determineFormat(imagedata);
if (imageformat != null) {
imageformat = imageformat.convert(imageformat, imagedata);
}
if (imageformat == null
|| imageformat.getType() == ImageConstants.I_NOT_SUPPORTED
|| "".equals(imageformat.getRtfTag())) {
throw new ExternalGraphicException("The tag <fo:external-graphic> "
+ "does not support "
+ file.substring(file.lastIndexOf(".") + 1)
+ " - image type.");
}
// Writes the beginning of the rtf image
writeGroupMark(true);
writeStarControlWord("shppict");
writeGroupMark(true);
writeControlWord("pict");
StringBuffer buf = new StringBuffer(imagedata.length * 3);
writeControlWord(imageformat.getRtfTag());
computeImageSize();
writeSizeInfo();
writeAttributes(getRtfAttributes(), null);
for (int i = 0; i < imagedata.length; i++) {
int iData = imagedata [i];
// Make positive byte
if (iData < 0) {
iData += 256;
}
if (iData < 16) {
// Set leading zero and append
buf.append('0');
}
buf.append(Integer.toHexString(iData));
}
int len = buf.length();
char[] chars = new char[len];
buf.getChars(0, len, chars, 0);
writer.write(chars);
// Writes the end of RTF image
writeGroupMark(false);
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
private void writeSizeInfo () throws IOException {
// Set image size
if (width != -1) {
writeControlWord("picw" + width);
}
if (height != -1) {
writeControlWord("pich" + height);
}
if (widthDesired != -1) {
if (perCentW) {
writeControlWord("picscalex" + widthDesired);
} else {
//writeControlWord("picscalex" + widthDesired * 100 / width);
writeControlWord("picwgoal" + widthDesired);
}
} else if (scaleUniform && heightDesired != -1) {
if (perCentH) {
writeControlWord("picscalex" + heightDesired);
} else {
writeControlWord("picscalex" + heightDesired * 100 / height);
}
}
if (heightDesired != -1) {
if (perCentH) {
writeControlWord("picscaley" + heightDesired);
} else {
//writeControlWord("picscaley" + heightDesired * 100 / height);
writeControlWord("pichgoal" + heightDesired);
}
} else if (scaleUniform && widthDesired != -1) {
if (perCentW) {
writeControlWord("picscaley" + widthDesired);
} else {
writeControlWord("picscaley" + widthDesired * 100 / width);
}
}
if (this.cropValues[0] != 0) {
writeOneAttribute("piccropl", new Integer(this.cropValues[0]));
}
if (this.cropValues[1] != 0) {
writeOneAttribute("piccropt", new Integer(this.cropValues[1]));
}
if (this.cropValues[2] != 0) {
writeOneAttribute("piccropr", new Integer(this.cropValues[2]));
}
if (this.cropValues[3] != 0) {
writeOneAttribute("piccropb", new Integer(this.cropValues[3]));
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
public void setImageData(byte[] data) throws IOException {
this.imagedata = data;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
public void setURL(String urlString) throws IOException {
URL tmpUrl = null;
try {
tmpUrl = new URL (urlString);
} catch (MalformedURLException e) {
try {
tmpUrl = new File (urlString).toURI().toURL ();
} catch (MalformedURLException ee) {
throw new ExternalGraphicException("The attribute 'src' of "
+ "<fo:external-graphic> has a invalid value: '"
+ urlString + "' (" + ee + ")");
}
}
this.url = tmpUrl;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfGenerator.java
protected void writeRtfContent() throws IOException {
newLine();
writeGroupMark(true);
writeStarControlWord("generator");
writer.write("Apache XML Graphics RTF Library");
writer.write(";");
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListTable.java
public void writeRtfContent() throws IOException {
newLine();
if (lists != null) {
//write '\listtable'
writeGroupMark(true);
writeStarControlWordNS(LIST_TABLE);
newLine();
for (Iterator it = lists.iterator(); it.hasNext();) {
final RtfList list = (RtfList)it.next();
writeListTableEntry(list);
newLine();
}
writeGroupMark(false);
newLine();
//write '\listoveridetable'
writeGroupMark(true);
writeStarControlWordNS(LIST_OVR_TABLE);
int z = 1;
newLine();
for (Iterator it = styles.iterator(); it.hasNext();) {
final RtfListStyle style = (RtfListStyle)it.next();
writeGroupMark(true);
writeStarControlWordNS(LIST_OVR);
writeGroupMark(true);
writeOneAttributeNS(LIST_ID, style.getRtfList().getListId().toString());
writeOneAttributeNS(LIST_OVR_COUNT, new Integer(0));
writeOneAttributeNS(LIST_NUMBER, new Integer(z++));
writeGroupMark(false);
writeGroupMark(false);
newLine();
}
writeGroupMark(false);
newLine();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfListTable.java
private void writeListTableEntry(RtfList list)
throws IOException {
//write list-specific attributes
writeGroupMark(true);
writeControlWordNS(LIST);
writeOneAttributeNS(LIST_TEMPLATE_ID, list.getListTemplateId().toString());
writeOneAttributeNS(LIST, attrib.getValue(LIST));
// write level-specific attributes
writeGroupMark(true);
writeControlWordNS(LIST_LEVEL);
writeOneAttributeNS(LIST_JUSTIFICATION, attrib.getValue(LIST_JUSTIFICATION));
writeOneAttributeNS(LIST_FOLLOWING_CHAR, attrib.getValue(LIST_FOLLOWING_CHAR));
writeOneAttributeNS(LIST_SPACE, new Integer(0));
writeOneAttributeNS(LIST_INDENT, attrib.getValue(LIST_INDENT));
RtfListItem item = (RtfListItem)list.getChildren().get(0);
if (item != null) {
item.getRtfListStyle().writeLevelGroup(this);
}
writeGroupMark(false);
writeGroupMark(true);
writeControlWordNS(LIST_NAME);
writeGroupMark(false);
writeOneAttributeNS(LIST_ID, list.getListId().toString());
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFootnote.java
public RtfTextrun getTextrun() throws IOException {
if (bBody) {
RtfTextrun textrun = RtfTextrun.getTextrun(body, writer, null);
textrun.setSuppressLastPar(true);
return textrun;
} else {
return textrunInline;
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFootnote.java
protected void writeRtfContent() throws IOException {
textrunInline.writeRtfContent();
writeGroupMark(true);
writeControlWord("footnote");
writeControlWord("ftnalt");
body.writeRtfContent();
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfFootnote.java
public RtfList newList(RtfAttributes attrs) throws IOException {
if (list != null) {
list.close();
}
list = new RtfList(body, writer, attrs);
return list;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
public final void close() throws IOException {
closed = true;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
public final void writeRtf() throws IOException {
if (!written) {
written = true;
if (okToWriteRtf()) {
writeRtfPrefix();
writeRtfContent();
writeRtfSuffix();
}
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
public void newLine() throws IOException {
writer.write("\n");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected final void writeControlWord(String word)
throws IOException {
writer.write('\\');
writer.write(word);
writer.write(' ');
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected final void writeStarControlWord(String word)
throws IOException {
writer.write("\\*\\");
writer.write(word);
writer.write(' ');
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected final void writeStarControlWordNS(String word)
throws IOException {
writer.write("\\*\\");
writer.write(word);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected final void writeControlWordNS(String word)
throws IOException {
writer.write('\\');
writer.write(word);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected void writeRtfPrefix() throws IOException {
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected void writeRtfSuffix() throws IOException {
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected final void writeGroupMark(boolean isStart)
throws IOException {
writer.write(isStart ? "{" : "}");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected void writeAttributes(RtfAttributes attr, String [] nameList)
throws IOException {
if (attr == null) {
return;
}
if (nameList != null) {
// process only given attribute names
for (int i = 0; i < nameList.length; i++) {
final String name = nameList[i];
if (attr.isSet(name)) {
writeOneAttribute(name, attr.getValue(name));
}
}
} else {
// process all defined attributes
for (Iterator it = attr.nameIterator(); it.hasNext();) {
final String name = (String)it.next();
if (attr.isSet(name)) {
writeOneAttribute(name, attr.getValue(name));
}
}
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected void writeOneAttribute(String name, Object value)
throws IOException {
String cw = name;
if (value instanceof Integer) {
// attribute has integer value, must write control word + value
cw += value;
} else if (value instanceof String) {
cw += value;
} else if (value instanceof RtfAttributes) {
writeControlWord(cw);
writeAttributes((RtfAttributes) value, null);
return;
}
writeControlWord(cw);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected void writeOneAttributeNS(String name, Object value)
throws IOException {
String cw = name;
if (value instanceof Integer) {
// attribute has integer value, must write control word + value
cw += value;
} else if (value instanceof String) {
cw += value;
} else if (value instanceof RtfAttributes) {
writeControlWord(cw);
writeAttributes((RtfAttributes) value, null);
return;
}
writeControlWordNS(cw);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
void dump(Writer w, int indent)
throws IOException {
for (int i = 0; i < indent; i++) {
w.write(' ');
}
w.write(this.toString());
w.write('\n');
w.flush();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfElement.java
protected void writeExceptionInRtf(Exception ie)
throws IOException {
writeGroupMark(true);
writeControlWord("par");
// make the exception message stand out so that the problem is visible
writeControlWord("fs48");
// RtfStringConverter.getInstance().writeRtfString(m_writer,
// JForVersionInfo.getShortVersionInfo() + ": ");
RtfStringConverter.getInstance().writeRtfString(writer, ie.getClass().getName());
writeControlWord("fs20");
RtfStringConverter.getInstance().writeRtfString(writer, " " + ie.toString());
writeControlWord("par");
writeGroupMark(false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfStyleSheetTable.java
public void writeStyleSheet (RtfHeader header) throws IOException {
if (styles == null || styles.size () == 0) {
return;
}
header.writeGroupMark (true);
header.writeControlWord ("stylesheet");
int number = nameTable.size ();
for (int i = 0; i < number; i++) {
String name = (String) nameTable.elementAt (i);
header.writeGroupMark (true);
header.writeControlWord ("*\\" + this.getRtfStyleReference (name));
Object o = attrTable.get (name);
if (o != null) {
header.writeAttributes ((RtfAttributes) o, RtfText.ATTR_NAMES);
header.writeAttributes ((RtfAttributes) o, RtfText.ALIGNMENT);
}
header.write (name + ";");
header.writeGroupMark (false);
}
header.writeGroupMark (false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBookmark.java
public void writeRtfPrefix () throws IOException {
startBookmark ();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBookmark.java
public void writeRtfContent () throws IOException {
// this.getRtfFile ().getLog ().logInfo ("Write bookmark '" + bookmark + "'.");
// No content to write
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBookmark.java
public void writeRtfSuffix () throws IOException {
endBookmark ();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBookmark.java
private void startBookmark () throws IOException {
// {\*\bkmkstart test}
writeRtfBookmark ("bkmkstart");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBookmark.java
private void endBookmark () throws IOException {
// {\*\bkmkend test}
writeRtfBookmark ("bkmkend");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBookmark.java
private void writeRtfBookmark (String tag) throws IOException {
if (bookmark == null) {
return;
}
this.writeGroupMark (true);
//changed. Now using writeStarControlWord
this.writeStarControlWord (tag);
writer.write (bookmark);
this.writeGroupMark (false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraphKeepTogether.java
protected void writeRtfContent() throws IOException {
//First reet paragraph properties
// create a new one with keepn
if (status == STATUS_OPEN_PARAGRAPH) {
writeControlWord("pard");
writeControlWord("par");
writeControlWord("keepn");
writeGroupMark(true);
status = STATUS_NULL;
}
if (status == STATUS_CLOSE_PARAGRAPH) {
writeGroupMark(false);
status = STATUS_NULL;
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfColorTable.java
public void writeColors (RtfHeader header) throws IOException {
if (colorTable == null || colorTable.size () == 0) {
return;
}
header.newLine();
header.writeGroupMark (true);
//Don't use writeControlWord, because it appends a blank,
//which may confuse Wordpad.
//This also implicitly writes the first color (=index 0), which
//is reserved for auto-colored.
header.write ("\\colortbl;");
int len = colorTable.size ();
for (int i = 0; i < len; i++) {
int identifier = ((Integer) colorTable.get (i)).intValue ();
header.newLine();
header.write ("\\red" + determineColorLevel (identifier, RED));
header.write ("\\green" + determineColorLevel (identifier, GREEN));
header.write ("\\blue" + determineColorLevel (identifier, BLUE) + ";");
}
header.newLine();
header.writeGroupMark (false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfString.java
protected void writeRtfContent() throws IOException {
RtfStringConverter.getInstance().writeRtfString(writer, text);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfPageNumberCitation.java
protected void writeRtfContent() throws IOException {
// If we have a valid ID
if (isValid()) {
// Build page reference field
String pageRef = RTF_FIELD_PAGEREF_MODEL;
final int insertionIndex = pageRef.indexOf("}");
pageRef = pageRef.substring(0, insertionIndex)
+ "\"" + id
+ "\"" + " "
+ pageRef.substring(insertionIndex, pageRef.length());
id = null;
// Write RTF content
writeGroupMark(true);
writeControlWord(RTF_FIELD);
writeGroupMark(true);
writeAttributes(attrib, RtfText.ATTR_NAMES); // Added by Boris Poudérous
writeStarControlWord(pageRef);
writeGroupMark(false);
writeGroupMark(true);
writeControlWord(RTF_FIELD_RESULT + '#'); //To see where the page-number would be
writeGroupMark(false);
writeGroupMark(false);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfList.java
public RtfListItem newListItem() throws IOException {
if (item != null) {
item.close();
}
item = new RtfListItem(this, writer);
return item;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfStringConverter.java
public void writeRtfString(Writer w, String str) throws IOException {
if (str == null) {
return;
}
w.write(escape(str));
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBookmarkContainerImpl.java
public RtfBookmark newBookmark (String bookmark) throws IOException {
if (mBookmark != null) {
mBookmark.close ();
}
mBookmark = new RtfBookmark (this, writer, bookmark);
return mBookmark;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfBefore.java
protected void writeMyAttributes() throws IOException {
writeAttributes(attrib, HEADER_ATTR);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
protected void writeRtfPrefix() throws IOException {
//Reset paragraph properties if needed
if (resetProperties) {
writeControlWord("pard");
}
/*
* Original comment said "do not write text attributes here, they are
* handled by RtfText." However, the text attributes appear to be
* relevant to paragraphs as well.
*/
writeAttributes(attrib, RtfText.ATTR_NAMES);
writeAttributes(attrib, PARA_ATTRIBUTES);
// Added by Normand Masse
// Write alignment attributes after \intbl for cells
if (attrib.isSet("intbl") && mustWriteAttributes()) {
writeAttributes(attrib, RtfText.ALIGNMENT);
}
//Set keepn if needed (Keep paragraph with the next paragraph)
if (keepn) {
writeControlWord("keepn");
}
// start a group for this paragraph and write our own attributes if needed
if (mustWriteGroupMark()) {
writeGroupMark(true);
}
if (mustWriteAttributes()) {
// writeAttributes(m_attrib, new String [] {"cs"});
// Added by Normand Masse
// If \intbl then attributes have already been written (see higher in method)
if (!attrib.isSet("intbl")) {
writeAttributes(attrib, RtfText.ALIGNMENT);
}
//this line added by Chris Scott, Westinghouse
writeAttributes(attrib, RtfText.BORDER);
writeAttributes(attrib, RtfText.INDENT);
writeAttributes(attrib, RtfText.TABS);
if (writeForBreak) {
writeControlWord("pard\\par");
}
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
protected void writeRtfSuffix() throws IOException {
// sometimes the end of paragraph mark must be suppressed in table cells
boolean writeMark = true;
if (parent instanceof RtfTableCell) {
writeMark = ((RtfTableCell)parent).paragraphNeedsPar(this);
}
if (writeMark) {
writeControlWord("par");
}
if (mustWriteGroupMark()) {
writeGroupMark(false);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public RtfText newText(String str) throws IOException {
return newText(str, null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public RtfText newText(String str, RtfAttributes attr) throws IOException {
closeAll();
text = new RtfText(this, writer, str, attr);
return text;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public void newPageBreak() throws IOException {
writeForBreak = true;
new RtfPageBreak(this, writer);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public void newLineBreak() throws IOException {
new RtfLineBreak(this, writer);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public RtfPageNumber newPageNumber()throws IOException {
pageNumber = new RtfPageNumber(this, writer);
return pageNumber;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public RtfPageNumberCitation newPageNumberCitation(String id) throws IOException {
pageNumberCitation = new RtfPageNumberCitation(this, writer, id);
return pageNumberCitation;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public RtfHyperLink newHyperLink(String str, RtfAttributes attr) throws IOException {
hyperlink = new RtfHyperLink(this, writer, str, attr);
return hyperlink;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
public RtfExternalGraphic newImage() throws IOException {
closeAll();
externalGraphic = new RtfExternalGraphic(this, writer);
return externalGraphic;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
private void closeCurrentText() throws IOException {
if (text != null) {
text.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
private void closeCurrentHyperLink() throws IOException {
if (hyperlink != null) {
hyperlink.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraph.java
private void closeAll() throws IOException {
closeCurrentText();
closeCurrentHyperLink();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfParagraphBreak.java
protected void writeRtfContent() throws IOException {
if (controlWord != null ) {
writeControlWord(controlWord);
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfPageBreak.java
protected void writeRtfContent() throws IOException {
writeControlWord("page");
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
public RtfParagraph newParagraph(RtfAttributes attrs) throws IOException {
closeAll();
// in tables, RtfParagraph must have the intbl attribute
if (attrs == null) {
attrs = new RtfAttributes();
}
attrs.set("intbl");
paragraph = new RtfParagraph(this, writer, attrs);
if (paragraph.attrib.isSet("qc")) {
setCenter = true;
attrs.set("qc");
} else if (paragraph.attrib.isSet("qr")) {
setRight = true;
attrs.set("qr");
} else {
attrs.set("ql");
}
attrs.set("intbl");
//lines modified by Chris Scott, Westinghouse
return paragraph;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
public RtfExternalGraphic newImage() throws IOException {
closeAll();
externalGraphic = new RtfExternalGraphic(this, writer);
return externalGraphic;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
public RtfParagraph newParagraph() throws IOException {
return newParagraph(null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
public RtfList newList(RtfAttributes attrib) throws IOException {
closeAll();
list = new RtfList(this, writer, attrib);
return list;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
public RtfTable newTable(ITableColumnsInfo tc) throws IOException {
closeAll();
table = new RtfTable(this, writer, tc);
return table;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
public RtfTable newTable(RtfAttributes attrs, ITableColumnsInfo tc) throws IOException {
closeAll();
table = new RtfTable(this, writer, attrs, tc); // Added tc Boris Poudérous 07/22/2002
return table;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
int writeCellDef(int offset) throws IOException {
/*
* Don't write \clmgf or \clmrg. Instead add the widths
* of all spanned columns and create a single wider cell,
* because \clmgf and \clmrg won't work in last row of a
* table (Word2000 seems to do the same).
* Cause of this, dont't write horizontally merged cells.
* They just exist as placeholders in TableContext class,
* and are never written to RTF file.
*/
// horizontal cell merge codes
if (hMerge == MERGE_WITH_PREVIOUS) {
return offset;
}
newLine();
this.widthOffset = offset;
// vertical cell merge codes
if (vMerge == MERGE_START) {
writeControlWord("clvmgf");
} else if (vMerge == MERGE_WITH_PREVIOUS) {
writeControlWord("clvmrg");
}
/**
* Added by Boris POUDEROUS on 2002/06/26
*/
// Cell background color processing :
writeAttributes (attrib, ITableAttributes.CELL_COLOR);
/** - end - */
writeAttributes (attrib, ITableAttributes.ATTRIB_CELL_PADDING);
writeAttributes (attrib, ITableAttributes.CELL_BORDER);
writeAttributes (attrib, IBorderAttributes.BORDERS);
// determine cell width
int iCurrentWidth = this.cellWidth;
if (attrib.getValue("number-columns-spanned") != null) {
// Get the number of columns spanned
int nbMergedCells = ((Integer)attrib.getValue("number-columns-spanned")).intValue();
RtfTable tab = getRow().getTable();
// Get the context of the current table in order to get the width of each column
ITableColumnsInfo tableColumnsInfo
= tab.getITableColumnsInfo();
tableColumnsInfo.selectFirstColumn();
// Reach the column index in table context corresponding to the current column cell
// id is the index of the current cell (it begins at 1)
// getColumnIndex() is the index of the current column in table context (it begins at 0)
// => so we must withdraw 1 when comparing these two variables.
while ((this.id - 1) != tableColumnsInfo.getColumnIndex()) {
tableColumnsInfo.selectNextColumn();
}
// We withdraw one cell because the first cell is already created
// (it's the current cell) !
int i = nbMergedCells - 1;
while (i > 0) {
tableColumnsInfo.selectNextColumn();
iCurrentWidth += (int)tableColumnsInfo.getColumnWidth();
i--;
}
}
final int xPos = offset + iCurrentWidth;
//these lines added by Chris Scott, Westinghouse
//some attributes need to be written before opening block
if (setCenter) {
writeControlWord("trqc");
} else if (setRight) {
writeControlWord("trqr");
} else {
writeControlWord("trql");
}
writeAttributes (attrib, ITableAttributes.CELL_VERT_ALIGN);
writeControlWord("cellx" + xPos);
return xPos;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
protected void writeRtfContent() throws IOException {
// Never write horizontally merged cells.
if (hMerge == MERGE_WITH_PREVIOUS) {
return;
}
super.writeRtfContent();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
protected void writeRtfPrefix() throws IOException {
// Never write horizontally merged cells.
if (hMerge == MERGE_WITH_PREVIOUS) {
return;
}
super.writeRtfPrefix();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
protected void writeRtfSuffix() throws IOException {
// Never write horizontally merged cells.
if (hMerge == MERGE_WITH_PREVIOUS) {
return;
}
if (getRow().getTable().isNestedTable()) {
//nested table
if (lastBreak == null) {
writeControlWordNS("nestcell");
}
writeGroupMark(true);
writeControlWord("nonesttables");
writeControlWord("par");
writeGroupMark(false);
} else {
// word97 hangs if cell does not contain at least one "par" control word
// TODO this is what causes the extra spaces in nested table of test
// 004-spacing-in-tables.fo,
// but if is not here we generate invalid RTF for word97
if (setCenter) {
writeControlWord("qc");
} else if (setRight) {
writeControlWord("qr");
} else {
RtfElement lastChild = null;
if (getChildren().size() > 0) {
lastChild = (RtfElement) getChildren().get(getChildren().size() - 1);
}
if (lastChild != null
&& lastChild instanceof RtfTextrun) {
//Don't write \ql in order to allow for example a right aligned paragraph
//in a not right aligned table-cell to write its \qr.
} else {
writeControlWord("ql");
}
}
if (!containsText()) {
writeControlWord("intbl");
//R.Marra this create useless paragraph
//Seem working into Word97 with the "intbl" only
//writeControlWord("par");
}
if (lastBreak == null) {
writeControlWord("cell");
}
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
private void closeCurrentParagraph() throws IOException {
if (paragraph != null) {
paragraph.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
private void closeCurrentList() throws IOException {
if (list != null) {
list.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
private void closeCurrentTable() throws IOException {
if (table != null) {
table.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
private void closeCurrentExternalGraphic() throws IOException {
if (externalGraphic != null) {
externalGraphic.close();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
private void closeAll()
throws IOException {
closeCurrentTable();
closeCurrentParagraph();
closeCurrentList();
closeCurrentExternalGraphic();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTableCell.java
public RtfTextrun getTextrun() throws IOException {
RtfAttributes attrs = new RtfAttributes();
if (!getRow().getTable().isNestedTable()) {
attrs.set("intbl");
}
RtfTextrun textrun = RtfTextrun.getTextrun(this, writer, attrs);
//Suppress the very last \par, because the closing \cell applies the
//paragraph attributes.
textrun.setSuppressLastPar(true);
return textrun;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
public void writeRtfPrefix () throws IOException {
super.writeGroupMark (true);
super.writeControlWord ("field");
super.writeGroupMark (true);
super.writeStarControlWord ("fldinst");
writer.write ("HYPERLINK \"" + url + "\" ");
super.writeGroupMark (false);
super.writeGroupMark (true);
super.writeControlWord ("fldrslt");
// start a group for this paragraph and write our own attributes if needed
if (attrib != null && attrib.isSet ("cs")) {
writeGroupMark (true);
writeAttributes(attrib, new String [] {"cs"});
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
public void writeRtfSuffix () throws IOException {
if (attrib != null && attrib.isSet ("cs")) {
writeGroupMark (false);
}
super.writeGroupMark (false);
super.writeGroupMark (false);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
public RtfText newText (String str) throws IOException {
return newText (str, null);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
public RtfText newText (String str, RtfAttributes attr) throws IOException {
closeAll ();
mText = new RtfText (this, writer, str, attr);
return mText;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
public void newLineBreak () throws IOException {
new RtfLineBreak (this, writer);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
private void closeCurrentText () throws IOException {
if (mText != null) {
mText.close ();
}
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
private void closeAll () throws IOException {
closeCurrentText();
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfHyperLink.java
public RtfTextrun getTextrun() throws IOException {
RtfTextrun textrun = RtfTextrun.getTextrun(this, writer, null);
return textrun;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfPageArea.java
public RtfPage newPage(RtfAttributes attr) throws IOException {
if (currentPage != null) {
currentPage.close();
}
currentPage = new RtfPage(this, writer, attr);
return currentPage;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTable.java
public RtfTableRow newTableRow() throws IOException {
if (row != null) {
row.close();
}
highestRow++;
row = new RtfTableRow(this, writer, attrib, highestRow);
return row;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTable.java
public RtfTableRow newTableRow(RtfAttributes attrs) throws IOException, FOPException {
RtfAttributes attr = null;
if (attrib != null) {
try {
attr = (RtfAttributes) attrib.clone ();
} catch (CloneNotSupportedException e) {
throw new FOPException(e);
}
attr.set (attrs);
} else {
attr = attrs;
}
if (row != null) {
row.close();
}
highestRow++;
row = new RtfTableRow(this, writer, attr, highestRow);
return row;
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTable.java
protected void writeRtfPrefix() throws IOException {
if (isNestedTable()) {
writeControlWordNS("pard");
}
writeGroupMark(true);
}
// in src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTable.java
protected void writeRtfSuffix() throws IOException {
writeGroupMark(false);
if (isNestedTable()) {
getRow().writeRowAndCellsDefintions();
}
}
// in src/java/org/apache/fop/render/rtf/RTFHandler.java
private void putGraphic(AbstractGraphics abstractGraphic, ImageInfo info)
throws IOException {
try {
FOUserAgent userAgent = abstractGraphic.getUserAgent();
ImageManager manager = userAgent.getFactory().getImageManager();
ImageSessionContext sessionContext = userAgent.getImageSessionContext();
Map hints = ImageUtil.getDefaultHints(sessionContext);
Image image = manager.getImage(info, FLAVORS, hints, sessionContext);
putGraphic(abstractGraphic, image);
} catch (ImageException ie) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageError(this, null, ie, null);
}
}
// in src/java/org/apache/fop/render/rtf/RTFHandler.java
private void putGraphic(AbstractGraphics abstractGraphic, Image image)
throws IOException {
byte[] rawData = null;
final ImageInfo info = image.getInfo();
if (image instanceof ImageRawStream) {
ImageRawStream rawImage = (ImageRawStream)image;
InputStream in = rawImage.createInputStream();
try {
rawData = IOUtils.toByteArray(in);
} finally {
IOUtils.closeQuietly(in);
}
}
if (rawData == null) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageWritingError(this, null);
return;
}
//Set up percentage calculations
this.percentManager.setDimension(abstractGraphic);
PercentBaseContext pContext = new PercentBaseContext() {
public int getBaseLength(int lengthBase, FObj fobj) {
switch (lengthBase) {
case LengthBase.IMAGE_INTRINSIC_WIDTH:
return info.getSize().getWidthMpt();
case LengthBase.IMAGE_INTRINSIC_HEIGHT:
return info.getSize().getHeightMpt();
default:
return percentManager.getBaseLength(lengthBase, fobj);
}
}
};
ImageLayout layout = new ImageLayout(abstractGraphic, pContext,
image.getInfo().getSize().getDimensionMpt());
final IRtfTextrunContainer c
= (IRtfTextrunContainer)builderContext.getContainer(
IRtfTextrunContainer.class, true, this);
final RtfExternalGraphic rtfGraphic = c.getTextrun().newImage();
//set URL
if (info.getOriginalURI() != null) {
rtfGraphic.setURL(info.getOriginalURI());
}
rtfGraphic.setImageData(rawData);
FoUnitsConverter converter = FoUnitsConverter.getInstance();
Dimension viewport = layout.getViewportSize();
Rectangle placement = layout.getPlacement();
int cropLeft = Math.round(converter.convertMptToTwips(-placement.x));
int cropTop = Math.round(converter.convertMptToTwips(-placement.y));
int cropRight = Math.round(converter.convertMptToTwips(
-1 * (viewport.width - placement.x - placement.width)));
int cropBottom = Math.round(converter.convertMptToTwips(
-1 * (viewport.height - placement.y - placement.height)));
rtfGraphic.setCropping(cropLeft, cropTop, cropRight, cropBottom);
int width = Math.round(converter.convertMptToTwips(viewport.width));
int height = Math.round(converter.convertMptToTwips(viewport.height));
width += cropLeft + cropRight;
height += cropTop + cropBottom;
rtfGraphic.setWidthTwips(width);
rtfGraphic.setHeightTwips(height);
//TODO: make this configurable:
// int compression = m_context.m_options.getRtfExternalGraphicCompressionRate ();
int compression = 0;
if (compression != 0) {
if (!rtfGraphic.setCompressionRate(compression)) {
log.warn("The compression rate " + compression
+ " is invalid. The value has to be between 1 and 100 %.");
}
}
}
// in src/java/org/apache/fop/render/bitmap/PNGRenderer.java
public void startRenderer(OutputStream outputStream) throws IOException {
log.info("rendering areas to PNG");
multiFileUtil = new MultiFileRenderingUtil(PNG_FILE_EXTENSION,
getUserAgent().getOutputFile());
this.firstOutputStream = outputStream;
}
// in src/java/org/apache/fop/render/bitmap/PNGRenderer.java
public void stopRenderer() throws IOException {
super.stopRenderer();
for (int i = 0; i < pageViewportList.size(); i++) {
OutputStream os = getCurrentOutputStream(i);
if (os == null) {
BitmapRendererEventProducer eventProducer
= BitmapRendererEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.stoppingAfterFirstPageNoFilename(this);
break;
}
try {
// Do the rendering: get the image for this page
PageViewport pv = (PageViewport)pageViewportList.get(i);
RenderedImage image = (RenderedImage)getPageImage(pv);
// Encode this image
if (log.isDebugEnabled()) {
log.debug("Encoding page " + (i + 1));
}
writeImage(os, image);
} finally {
//Only close self-created OutputStreams
if (os != firstOutputStream) {
IOUtils.closeQuietly(os);
}
}
}
}
// in src/java/org/apache/fop/render/bitmap/PNGRenderer.java
private void writeImage(OutputStream os, RenderedImage image) throws IOException {
ImageWriterParams params = new ImageWriterParams();
params.setResolution(Math.round(userAgent.getTargetResolution()));
// Encode PNG image
ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor(getMimeType());
if (writer == null) {
BitmapRendererEventProducer eventProducer
= BitmapRendererEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.noImageWriterFound(this, getMimeType());
}
if (log.isDebugEnabled()) {
log.debug("Writing image using " + writer.getClass().getName());
}
writer.writeImage(image, os, params);
}
// in src/java/org/apache/fop/render/bitmap/PNGRenderer.java
protected OutputStream getCurrentOutputStream(int pageNumber) throws IOException {
if (pageNumber == 0) {
return firstOutputStream;
} else {
return multiFileUtil.createOutputStream(pageNumber);
}
}
// in src/java/org/apache/fop/render/bitmap/MultiFileRenderingUtil.java
public OutputStream createOutputStream(int pageNumber) throws IOException {
if (filePrefix == null) {
return null;
} else {
File f = new File(outputDir,
filePrefix + (pageNumber + 1) + "." + fileExtension);
OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
return os;
}
}
// in src/java/org/apache/fop/render/bitmap/TIFFRenderer.java
public void startRenderer(OutputStream outputStream) throws IOException {
this.outputStream = outputStream;
super.startRenderer(outputStream);
}
// in src/java/org/apache/fop/render/bitmap/TIFFRenderer.java
public void stopRenderer() throws IOException {
super.stopRenderer();
log.debug("Starting TIFF encoding ...");
// Creates lazy iterator over generated page images
Iterator pageImagesItr = new LazyPageImagesIterator(getNumberOfPages(), log);
// Creates writer
ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor(getMimeType());
if (writer == null) {
BitmapRendererEventProducer eventProducer
= BitmapRendererEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.noImageWriterFound(this, getMimeType());
}
if (writer.supportsMultiImageWriter()) {
MultiImageWriter multiWriter = writer.createMultiImageWriter(outputStream);
try {
// Write all pages/images
while (pageImagesItr.hasNext()) {
RenderedImage img = (RenderedImage) pageImagesItr.next();
multiWriter.writeImage(img, writerParams);
}
} finally {
multiWriter.close();
}
} else {
RenderedImage renderedImage = null;
if (pageImagesItr.hasNext()) {
renderedImage = (RenderedImage) pageImagesItr.next();
}
writer.writeImage(renderedImage, outputStream, writerParams);
if (pageImagesItr.hasNext()) {
BitmapRendererEventProducer eventProducer
= BitmapRendererEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.stoppingAfterFirstPageNoFilename(this);
}
}
// Cleaning
outputStream.flush();
clearViewportList();
log.debug("TIFF encoding done.");
}
// in src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
private AFPFont fontFromType(String type, String codepage, String encoding,
ResourceAccessor accessor, Configuration afpFontCfg) throws ConfigurationException,
IOException {
if ("raster".equalsIgnoreCase(type)) {
String name = afpFontCfg.getAttribute("name", "Unknown");
// Create a new font object
RasterFont font = new RasterFont(name);
Configuration[] rasters = afpFontCfg.getChildren("afp-raster-font");
if (rasters.length == 0) {
eventProducer.fontConfigMissing(this, "<afp-raster-font...",
afpFontCfg.getLocation());
return null;
}
for (int j = 0; j < rasters.length; j++) {
Configuration rasterCfg = rasters[j];
String characterset = rasterCfg.getAttribute("characterset");
if (characterset == null) {
eventProducer.fontConfigMissing(this, "characterset attribute",
afpFontCfg.getLocation());
return null;
}
float size = rasterCfg.getAttributeAsFloat("size");
int sizeMpt = (int) (size * 1000);
String base14 = rasterCfg.getAttribute("base14-font", null);
if (base14 != null) {
try {
Class<? extends Typeface> clazz = Class.forName(
"org.apache.fop.fonts.base14." + base14).asSubclass(Typeface.class);
try {
Typeface tf = clazz.newInstance();
font.addCharacterSet(sizeMpt,
CharacterSetBuilder.getSingleByteInstance()
.build(characterset, codepage, encoding, tf,
eventProducer));
} catch (Exception ie) {
String msg = "The base 14 font class " + clazz.getName()
+ " could not be instantiated";
log.error(msg);
}
} catch (ClassNotFoundException cnfe) {
String msg = "The base 14 font class for " + characterset
+ " could not be found";
log.error(msg);
}
} else {
font.addCharacterSet(sizeMpt, CharacterSetBuilder.getSingleByteInstance()
.buildSBCS(characterset, codepage, encoding, accessor, eventProducer));
}
}
return font;
} else if ("outline".equalsIgnoreCase(type)) {
String characterset = afpFontCfg.getAttribute("characterset");
if (characterset == null) {
eventProducer.fontConfigMissing(this, "characterset attribute",
afpFontCfg.getLocation());
return null;
}
String name = afpFontCfg.getAttribute("name", characterset);
CharacterSet characterSet = null;
String base14 = afpFontCfg.getAttribute("base14-font", null);
if (base14 != null) {
try {
Class<? extends Typeface> clazz = Class.forName("org.apache.fop.fonts.base14."
+ base14).asSubclass(Typeface.class);
try {
Typeface tf = clazz.newInstance();
characterSet = CharacterSetBuilder.getSingleByteInstance()
.build(characterset, codepage, encoding, tf, eventProducer);
} catch (Exception ie) {
String msg = "The base 14 font class " + clazz.getName()
+ " could not be instantiated";
log.error(msg);
}
} catch (ClassNotFoundException cnfe) {
String msg = "The base 14 font class for " + characterset
+ " could not be found";
log.error(msg);
}
} else {
characterSet = CharacterSetBuilder.getSingleByteInstance().buildSBCS(
characterset, codepage, encoding, accessor, eventProducer);
}
// Return new font object
return new OutlineFont(name, characterSet);
} else if ("CIDKeyed".equalsIgnoreCase(type)) {
String characterset = afpFontCfg.getAttribute("characterset");
if (characterset == null) {
eventProducer.fontConfigMissing(this, "characterset attribute",
afpFontCfg.getLocation());
return null;
}
String name = afpFontCfg.getAttribute("name", characterset);
CharacterSet characterSet = null;
CharacterSetType charsetType = afpFontCfg.getAttributeAsBoolean("ebcdic-dbcs", false)
? CharacterSetType.DOUBLE_BYTE_LINE_DATA : CharacterSetType.DOUBLE_BYTE;
characterSet = CharacterSetBuilder.getDoubleByteInstance().buildDBCS(characterset,
codepage, encoding, charsetType, accessor, eventProducer);
// Create a new font object
DoubleByteFont font = new DoubleByteFont(name, characterSet);
return font;
} else {
log.error("No or incorrect type attribute: " + type);
}
return null;
}
// in src/java/org/apache/fop/render/afp/AFPSVGHandler.java
protected void renderSVGDocument(final RendererContext rendererContext,
final Document doc) throws IOException {
AFPRendererContext afpRendererContext = (AFPRendererContext)rendererContext;
AFPInfo afpInfo = afpRendererContext.getInfo();
this.paintAsBitmap = afpInfo.paintAsBitmap();
FOUserAgent userAgent = rendererContext.getUserAgent();
// fallback paint as bitmap
String uri = getDocumentURI(doc);
if (paintAsBitmap) {
try {
super.renderSVGDocument(rendererContext, doc);
} catch (IOException ioe) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
userAgent.getEventBroadcaster());
eventProducer.svgRenderingError(this, ioe, uri);
}
return;
}
// Create a new AFPGraphics2D
final boolean textAsShapes = afpInfo.strokeText();
AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes);
AFPPaintingState paintingState = g2d.getPaintingState();
paintingState.setImageUri(uri);
// Create an AFPBridgeContext
BridgeContext bridgeContext = createBridgeContext(userAgent, g2d);
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
//to it.
Document clonedDoc = BatikUtil.cloneSVGDocument(doc);
// Build the SVG DOM and provide the painter with it
GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc);
// Create Graphics2DImagePainter
final RendererContextWrapper wrappedContext
= RendererContext.wrapRendererContext(rendererContext);
Dimension imageSize = getImageSize(wrappedContext);
Graphics2DImagePainter painter
= createGraphics2DImagePainter(bridgeContext, root, imageSize);
// Create AFPObjectAreaInfo
RendererContextWrapper rctx = RendererContext.wrapRendererContext(rendererContext);
int x = rctx.getCurrentXPosition();
int y = rctx.getCurrentYPosition();
int width = afpInfo.getWidth();
int height = afpInfo.getHeight();
int resolution = afpInfo.getResolution();
paintingState.save(); // save
AFPObjectAreaInfo objectAreaInfo
= createObjectAreaInfo(paintingState, x, y, width, height, resolution);
// Create AFPGraphicsObjectInfo
AFPResourceInfo resourceInfo = afpInfo.getResourceInfo();
AFPGraphicsObjectInfo graphicsObjectInfo = createGraphicsObjectInfo(
paintingState, painter, userAgent, resourceInfo, g2d);
graphicsObjectInfo.setObjectAreaInfo(objectAreaInfo);
// Create the GOCA GraphicsObject in the DataStream
AFPResourceManager resourceManager = afpInfo.getResourceManager();
resourceManager.createObject(graphicsObjectInfo);
paintingState.restore(); // resume
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
protected void clip() throws IOException {
//not supported by AFP
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
protected void closePath() throws IOException {
//used for clipping only, so not implemented
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
protected void moveTo(int x, int y) throws IOException {
//used for clipping only, so not implemented
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
protected void lineTo(int x, int y) throws IOException {
//used for clipping only, so not implemented
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
protected void saveGraphicsState() throws IOException {
//used for clipping only, so not implemented
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
protected void restoreGraphicsState() throws IOException {
//used for clipping only, so not implemented
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
protected void drawBorderLine( // CSOK: ParameterNumber
int x1, int y1, int x2, int y2, boolean horz,
boolean startOrBefore, int style, Color color) throws IOException {
BorderPaintingInfo borderPaintInfo = new BorderPaintingInfo(
toPoints(x1), toPoints(y1), toPoints(x2), toPoints(y2),
horz, style, color);
delegate.paint(borderPaintInfo);
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
Override
public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
throws IOException {
if (start.y != end.y) {
//TODO Support arbitrary lines if necessary
throw new UnsupportedOperationException(
"Can only deal with horizontal lines right now");
}
//Simply delegates to drawBorderLine() as AFP line painting is not very sophisticated.
int halfWidth = width / 2;
drawBorderLine(start.x, start.y - halfWidth, end.x, start.y + halfWidth,
true, true, style.getEnumValue(), color);
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
public void drawText( // CSOK: MethodLength
int x, int y, final int letterSpacing, final int wordSpacing,
final int[][] dp, final String text) throws IFException {
final int fontSize = this.state.getFontSize();
getPaintingState().setFontSize(fontSize);
FontTriplet triplet = new FontTriplet(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
//TODO Ignored: state.getFontVariant()
String fontKey = getFontInfo().getInternalFontKey(triplet);
if (fontKey == null) {
triplet = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL);
fontKey = getFontInfo().getInternalFontKey(triplet);
}
// register font as necessary
Map<String, Typeface> fontMetricMap = documentHandler.getFontInfo().getFonts();
final AFPFont afpFont = (AFPFont)fontMetricMap.get(fontKey);
final Font font = getFontInfo().getFontInstance(triplet, fontSize);
AFPPageFonts pageFonts = getPaintingState().getPageFonts();
AFPFontAttributes fontAttributes = pageFonts.registerFont(fontKey, afpFont, fontSize);
final int fontReference = fontAttributes.getFontReference();
final int[] coords = unitConv.mpts2units(new float[] {x, y} );
final CharacterSet charSet = afpFont.getCharacterSet(fontSize);
if (afpFont.isEmbeddable()) {
try {
documentHandler.getResourceManager().embedFont(afpFont, charSet);
} catch (IOException ioe) {
throw new IFException("Error while embedding font resources", ioe);
}
}
AbstractPageObject page = getDataStream().getCurrentPage();
PresentationTextObject pto = page.getPresentationTextObject();
try {
pto.createControlSequences(new PtocaProducer() {
public void produce(PtocaBuilder builder) throws IOException {
Point p = getPaintingState().getPoint(coords[X], coords[Y]);
builder.setTextOrientation(getPaintingState().getRotation());
builder.absoluteMoveBaseline(p.y);
builder.absoluteMoveInline(p.x);
builder.setExtendedTextColor(state.getTextColor());
builder.setCodedFont((byte)fontReference);
int l = text.length();
int[] dx = IFUtil.convertDPToDX ( dp );
int dxl = (dx != null ? dx.length : 0);
StringBuffer sb = new StringBuffer();
if (dxl > 0 && dx[0] != 0) {
int dxu = Math.round(unitConv.mpt2units(dx[0]));
builder.relativeMoveInline(-dxu);
}
//Following are two variants for glyph placement.
//SVI does not seem to be implemented in the same way everywhere, so
//a fallback alternative is preserved here.
final boolean usePTOCAWordSpacing = true;
if (usePTOCAWordSpacing) {
int interCharacterAdjustment = 0;
if (letterSpacing != 0) {
interCharacterAdjustment = Math.round(unitConv.mpt2units(
letterSpacing));
}
builder.setInterCharacterAdjustment(interCharacterAdjustment);
int spaceWidth = font.getCharWidth(CharUtilities.SPACE);
int fixedSpaceCharacterIncrement = Math.round(unitConv.mpt2units(
spaceWidth + letterSpacing));
int varSpaceCharacterIncrement = fixedSpaceCharacterIncrement;
if (wordSpacing != 0) {
varSpaceCharacterIncrement = Math.round(unitConv.mpt2units(
spaceWidth + wordSpacing + letterSpacing));
}
builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement);
boolean fixedSpaceMode = false;
for (int i = 0; i < l; i++) {
char orgChar = text.charAt(i);
float glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
fixedSpaceCharacterIncrement);
fixedSpaceMode = true;
sb.append(CharUtilities.SPACE);
int charWidth = font.getCharWidth(orgChar);
glyphAdjust += (charWidth - spaceWidth);
} else {
if (fixedSpaceMode) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
varSpaceCharacterIncrement);
fixedSpaceMode = false;
}
char ch;
if (orgChar == CharUtilities.NBSPACE) {
ch = ' '; //converted to normal space to allow word spacing
} else {
ch = orgChar;
}
sb.append(ch);
}
if (i < dxl - 1) {
glyphAdjust += dx[i + 1];
}
if (glyphAdjust != 0) {
flushText(builder, sb, charSet);
int increment = Math.round(unitConv.mpt2units(glyphAdjust));
builder.relativeMoveInline(increment);
}
}
} else {
for (int i = 0; i < l; i++) {
char orgChar = text.charAt(i);
float glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
sb.append(CharUtilities.SPACE);
int spaceWidth = font.getCharWidth(CharUtilities.SPACE);
int charWidth = font.getCharWidth(orgChar);
glyphAdjust += (charWidth - spaceWidth);
} else {
sb.append(orgChar);
}
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
glyphAdjust += wordSpacing;
}
glyphAdjust += letterSpacing;
if (i < dxl - 1) {
glyphAdjust += dx[i + 1];
}
if (glyphAdjust != 0) {
flushText(builder, sb, charSet);
int increment = Math.round(unitConv.mpt2units(glyphAdjust));
builder.relativeMoveInline(increment);
}
}
}
flushText(builder, sb, charSet);
}
private void flushText(PtocaBuilder builder, StringBuffer sb,
final CharacterSet charSet) throws IOException {
if (sb.length() > 0) {
builder.addTransparentData(charSet.encodeChars(sb));
sb.setLength(0);
}
}
});
} catch (IOException ioe) {
throw new IFException("I/O error in drawText()", ioe);
}
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
public void produce(PtocaBuilder builder) throws IOException {
Point p = getPaintingState().getPoint(coords[X], coords[Y]);
builder.setTextOrientation(getPaintingState().getRotation());
builder.absoluteMoveBaseline(p.y);
builder.absoluteMoveInline(p.x);
builder.setExtendedTextColor(state.getTextColor());
builder.setCodedFont((byte)fontReference);
int l = text.length();
int[] dx = IFUtil.convertDPToDX ( dp );
int dxl = (dx != null ? dx.length : 0);
StringBuffer sb = new StringBuffer();
if (dxl > 0 && dx[0] != 0) {
int dxu = Math.round(unitConv.mpt2units(dx[0]));
builder.relativeMoveInline(-dxu);
}
//Following are two variants for glyph placement.
//SVI does not seem to be implemented in the same way everywhere, so
//a fallback alternative is preserved here.
final boolean usePTOCAWordSpacing = true;
if (usePTOCAWordSpacing) {
int interCharacterAdjustment = 0;
if (letterSpacing != 0) {
interCharacterAdjustment = Math.round(unitConv.mpt2units(
letterSpacing));
}
builder.setInterCharacterAdjustment(interCharacterAdjustment);
int spaceWidth = font.getCharWidth(CharUtilities.SPACE);
int fixedSpaceCharacterIncrement = Math.round(unitConv.mpt2units(
spaceWidth + letterSpacing));
int varSpaceCharacterIncrement = fixedSpaceCharacterIncrement;
if (wordSpacing != 0) {
varSpaceCharacterIncrement = Math.round(unitConv.mpt2units(
spaceWidth + wordSpacing + letterSpacing));
}
builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement);
boolean fixedSpaceMode = false;
for (int i = 0; i < l; i++) {
char orgChar = text.charAt(i);
float glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
fixedSpaceCharacterIncrement);
fixedSpaceMode = true;
sb.append(CharUtilities.SPACE);
int charWidth = font.getCharWidth(orgChar);
glyphAdjust += (charWidth - spaceWidth);
} else {
if (fixedSpaceMode) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
varSpaceCharacterIncrement);
fixedSpaceMode = false;
}
char ch;
if (orgChar == CharUtilities.NBSPACE) {
ch = ' '; //converted to normal space to allow word spacing
} else {
ch = orgChar;
}
sb.append(ch);
}
if (i < dxl - 1) {
glyphAdjust += dx[i + 1];
}
if (glyphAdjust != 0) {
flushText(builder, sb, charSet);
int increment = Math.round(unitConv.mpt2units(glyphAdjust));
builder.relativeMoveInline(increment);
}
}
} else {
for (int i = 0; i < l; i++) {
char orgChar = text.charAt(i);
float glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
sb.append(CharUtilities.SPACE);
int spaceWidth = font.getCharWidth(CharUtilities.SPACE);
int charWidth = font.getCharWidth(orgChar);
glyphAdjust += (charWidth - spaceWidth);
} else {
sb.append(orgChar);
}
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
glyphAdjust += wordSpacing;
}
glyphAdjust += letterSpacing;
if (i < dxl - 1) {
glyphAdjust += dx[i + 1];
}
if (glyphAdjust != 0) {
flushText(builder, sb, charSet);
int increment = Math.round(unitConv.mpt2units(glyphAdjust));
builder.relativeMoveInline(increment);
}
}
}
flushText(builder, sb, charSet);
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
private void flushText(PtocaBuilder builder, StringBuffer sb,
final CharacterSet charSet) throws IOException {
if (sb.length() > 0) {
builder.addTransparentData(charSet.encodeChars(sb));
sb.setLength(0);
}
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
protected void saveGraphicsState() throws IOException {
getPaintingState().save();
}
// in src/java/org/apache/fop/render/afp/AFPPainter.java
protected void restoreGraphicsState() throws IOException {
getPaintingState().restore();
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
AFPRenderingContext afpContext = (AFPRenderingContext)context;
AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo();
AFPPaintingState paintingState = afpContext.getPaintingState();
// set resource information
setResourceInformation(imageObjectInfo,
image.getInfo().getOriginalURI(),
afpContext.getForeignAttributes());
setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager());
// Positioning
imageObjectInfo.setObjectAreaInfo(createObjectAreaInfo(paintingState, pos));
Dimension targetSize = pos.getSize();
// Image content
ImageRendered imageRend = (ImageRendered)image;
RenderedImageEncoder encoder = new RenderedImageEncoder(imageRend, targetSize);
encoder.prepareEncoding(imageObjectInfo, paintingState);
boolean included = afpContext.getResourceManager().tryIncludeObject(imageObjectInfo);
if (!included) {
long start = System.currentTimeMillis();
//encode only if the same image has not been encoded, yet
encoder.encodeImage(imageObjectInfo, paintingState);
if (log.isDebugEnabled()) {
long duration = System.currentTimeMillis() - start;
log.debug("Image encoding took " + duration + "ms.");
}
// Create image
afpContext.getResourceManager().createObject(imageObjectInfo);
}
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
private AFPDataObjectInfo encodeImage
(AFPImageObjectInfo imageObjectInfo,
AFPPaintingState paintingState)
throws IOException {
RenderedImage renderedImage = imageRendered.getRenderedImage();
FunctionSet functionSet = useFS10 ? FunctionSet.FS10 : FunctionSet.FS11;
if (usePageSegments) {
assert resampledDim != null;
//Resize, optionally resample and convert image
imageObjectInfo.setCreatePageSegment(true);
float ditheringQuality = paintingState.getDitheringQuality();
if (this.resample) {
if (log.isDebugEnabled()) {
log.debug("Resample from " + intrinsicSize.getDimensionPx()
+ " to " + resampledDim);
}
renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage,
resampledDim, ditheringQuality);
} else if (ditheringQuality >= 0.5f) {
renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage,
intrinsicSize.getDimensionPx(), ditheringQuality);
}
}
//TODO To reduce AFP file size, investigate using a compression scheme.
//Currently, all image data is uncompressed.
ColorModel cm = renderedImage.getColorModel();
if (log.isTraceEnabled()) {
log.trace("ColorModel: " + cm);
}
int pixelSize = cm.getPixelSize();
if (cm.hasAlpha()) {
pixelSize -= 8;
}
byte[] imageData = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
boolean allowDirectEncoding = true;
if (allowDirectEncoding && (pixelSize <= maxPixelSize)) {
//Attempt to encode without resampling the image
ImageEncodingHelper helper = new ImageEncodingHelper(renderedImage,
pixelSize == 32);
ColorModel encodedColorModel = helper.getEncodedColorModel();
boolean directEncode = true;
if (helper.getEncodedColorModel().getPixelSize() > maxPixelSize) {
directEncode = false; //pixel size needs to be reduced
}
if (BitmapImageUtil.getColorIndexSize(renderedImage) > 2) {
directEncode = false; //Lookup tables are not implemented, yet
}
if (useFS10
&& BitmapImageUtil.isMonochromeImage(renderedImage)
&& BitmapImageUtil.isZeroBlack(renderedImage)) {
directEncode = false;
//need a special method to invert the bit-stream since setting the
//subtractive mode in AFP alone doesn't seem to do the trick.
if (encodeInvertedBilevel(helper, imageObjectInfo, baos)) {
imageData = baos.toByteArray();
}
}
if (directEncode) {
log.debug("Encoding image directly...");
imageObjectInfo.setBitsPerPixel(encodedColorModel.getPixelSize());
if (pixelSize == 32) {
functionSet = FunctionSet.FS45; //IOCA FS45 required for CMYK
}
//Lossy or loss-less?
if (!paintingState.canEmbedJpeg()
&& paintingState.getBitmapEncodingQuality() < 1.0f) {
try {
if (log.isDebugEnabled()) {
log.debug("Encoding using baseline DCT (JPEG, q="
+ paintingState.getBitmapEncodingQuality() + ")...");
}
encodeToBaselineDCT(renderedImage,
paintingState.getBitmapEncodingQuality(),
paintingState.getResolution(),
baos);
imageObjectInfo.setCompression(ImageContent.COMPID_JPEG);
} catch (IOException ioe) {
//Some JPEG codecs cannot encode CMYK
helper.encode(baos);
}
} else {
helper.encode(baos);
}
imageData = baos.toByteArray();
}
}
if (imageData == null) {
log.debug("Encoding image via RGB...");
imageData = encodeViaRGB(renderedImage, imageObjectInfo, paintingState, baos);
}
// Should image be FS45?
if (paintingState.getFS45()) {
functionSet = FunctionSet.FS45;
}
//Wrapping 300+ resolution FS11 IOCA in a page segment is apparently necessary(?)
imageObjectInfo.setCreatePageSegment(
(functionSet.equals(FunctionSet.FS11) || functionSet.equals(FunctionSet.FS45))
&& paintingState.getWrapPSeg()
);
imageObjectInfo.setMimeType(functionSet.getMimeType());
imageObjectInfo.setData(imageData);
return imageObjectInfo;
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
private byte[] encodeViaRGB(RenderedImage renderedImage,
AFPImageObjectInfo imageObjectInfo, AFPPaintingState paintingState,
ByteArrayOutputStream baos) throws IOException {
byte[] imageData;
//Convert image to 24bit RGB
ImageEncodingHelper.encodeRenderedImageAsRGB(renderedImage, baos);
imageData = baos.toByteArray();
imageObjectInfo.setBitsPerPixel(24);
boolean colorImages = paintingState.isColorImages();
imageObjectInfo.setColor(colorImages);
// convert to grayscale
if (!colorImages) {
log.debug("Converting RGB image to grayscale...");
baos.reset();
int bitsPerPixel = paintingState.getBitsPerPixel();
imageObjectInfo.setBitsPerPixel(bitsPerPixel);
//TODO this should be done off the RenderedImage to avoid buffering the
//intermediate 24bit image
ImageEncodingHelper.encodeRGBAsGrayScale(
imageData, renderedImage.getWidth(), renderedImage.getHeight(),
bitsPerPixel, baos);
imageData = baos.toByteArray();
if (bitsPerPixel == 1) {
imageObjectInfo.setSubtractive(true);
}
}
return imageData;
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
private boolean encodeInvertedBilevel(ImageEncodingHelper helper,
AFPImageObjectInfo imageObjectInfo, OutputStream out) throws IOException {
RenderedImage renderedImage = helper.getImage();
if (!BitmapImageUtil.isMonochromeImage(renderedImage)) {
throw new IllegalStateException("This method only supports binary images!");
}
int tiles = renderedImage.getNumXTiles() * renderedImage.getNumYTiles();
if (tiles > 1) {
return false;
}
SampleModel sampleModel = renderedImage.getSampleModel();
SampleModel expectedSampleModel = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
renderedImage.getWidth(), renderedImage.getHeight(), 1);
if (!expectedSampleModel.equals(sampleModel)) {
return false; //Pixels are not packed
}
imageObjectInfo.setBitsPerPixel(1);
Raster raster = renderedImage.getTile(0, 0);
DataBuffer buffer = raster.getDataBuffer();
if (buffer instanceof DataBufferByte) {
DataBufferByte byteBuffer = (DataBufferByte)buffer;
log.debug("Encoding image as inverted bi-level...");
byte[] rawData = byteBuffer.getData();
int remaining = rawData.length;
int pos = 0;
byte[] data = new byte[4096];
while (remaining > 0) {
int size = Math.min(remaining, data.length);
for (int i = 0; i < size; i++) {
data[i] = (byte)~rawData[pos]; //invert bits
pos++;
}
out.write(data, 0, size);
remaining -= size;
}
return true;
}
return false;
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
private void encodeToBaselineDCT(RenderedImage image,
float quality, int resolution, OutputStream out) throws IOException {
ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor("image/jpeg");
ImageWriterParams params = new ImageWriterParams();
params.setJPEGQuality(quality, true);
params.setResolution(resolution);
writer.writeImage(image, out, params);
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java
Override
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
log.debug("Embedding undecoded CCITT data as data container...");
super.handleImage(context, image, pos);
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
AFPRenderingContext afpContext = (AFPRenderingContext)context;
AFPGraphicsObjectInfo graphicsObjectInfo = (AFPGraphicsObjectInfo)createDataObjectInfo();
// set resource information
setResourceInformation(graphicsObjectInfo,
image.getInfo().getOriginalURI(),
afpContext.getForeignAttributes());
// Positioning
graphicsObjectInfo.setObjectAreaInfo(
createObjectAreaInfo(afpContext.getPaintingState(), pos));
setDefaultResourceLevel(graphicsObjectInfo, afpContext.getResourceManager());
AFPPaintingState paintingState = afpContext.getPaintingState();
paintingState.save(); // save
AffineTransform placement = new AffineTransform();
placement.translate(pos.x, pos.y);
paintingState.concatenate(placement);
// Image content
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
final boolean textAsShapes = paintingState.isStrokeGOCAText();
AFPGraphics2D g2d = new AFPGraphics2D(
textAsShapes,
afpContext.getPaintingState(),
afpContext.getResourceManager(),
graphicsObjectInfo.getResourceInfo(),
(textAsShapes ? null : afpContext.getFontInfo()));
g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
graphicsObjectInfo.setGraphics2D(g2d);
graphicsObjectInfo.setPainter(imageG2D.getGraphics2DImagePainter());
// Create image
afpContext.getResourceManager().createObject(graphicsObjectInfo);
paintingState.restore(); // resume
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java
Override
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
if (log.isDebugEnabled()) {
log.debug("Embedding undecoded image data (" + image.getInfo().getMimeType()
+ ") as data container...");
}
super.handleImage(context, image, pos);
}
// in src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java
private void updateDataObjectInfo(AFPDataObjectInfo dataObjectInfo,
ImageRawStream rawStream, AFPResourceManager resourceManager) throws IOException {
dataObjectInfo.setMimeType(rawStream.getFlavor().getMimeType());
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
if (!resourceInfo.levelChanged()) {
resourceInfo.setLevel(resourceManager.getResourceLevelDefaults()
.getDefaultResourceLevel(ResourceObject.TYPE_IMAGE));
}
InputStream inputStream = rawStream.createInputStream();
try {
dataObjectInfo.setData(IOUtils.toByteArray(inputStream));
} finally {
IOUtils.closeQuietly(inputStream);
}
int dataHeight = rawStream.getSize().getHeightPx();
dataObjectInfo.setDataHeight(dataHeight);
int dataWidth = rawStream.getSize().getWidthPx();
dataObjectInfo.setDataWidth(dataWidth);
ImageSize imageSize = rawStream.getSize();
dataObjectInfo.setDataHeightRes((int) (imageSize.getDpiHorizontal() * 10));
dataObjectInfo.setDataWidthRes((int) (imageSize.getDpiVertical() * 10));
}
// in src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
AFPRenderingContext afpContext = (AFPRenderingContext)context;
AFPDataObjectInfo dataObjectInfo = createDataObjectInfo();
// set resource information
setResourceInformation(dataObjectInfo,
image.getInfo().getOriginalURI(),
afpContext.getForeignAttributes());
// Positioning
dataObjectInfo.setObjectAreaInfo(createObjectAreaInfo(afpContext.getPaintingState(), pos));
// set object area info
//AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo();
AFPPaintingState paintingState = afpContext.getPaintingState();
int resolution = paintingState.getResolution();
AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo();
objectAreaInfo.setResolution(resolution);
// Image content
ImageRawStream imageStream = (ImageRawStream)image;
updateDataObjectInfo(dataObjectInfo, imageStream, afpContext.getResourceManager());
setAdditionalParameters(dataObjectInfo, imageStream);
// Create image
afpContext.getResourceManager().createObject(dataObjectInfo);
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
AFPRenderingContext afpContext = (AFPRenderingContext)context;
AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo();
AFPPaintingState paintingState = afpContext.getPaintingState();
// set resource information
setResourceInformation(imageObjectInfo,
image.getInfo().getOriginalURI(),
afpContext.getForeignAttributes());
setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager());
// Positioning
imageObjectInfo.setObjectAreaInfo(createObjectAreaInfo(paintingState, pos));
updateIntrinsicSize(imageObjectInfo, paintingState, image.getSize());
// Image content
ImageRawJPEG jpeg = (ImageRawJPEG)image;
imageObjectInfo.setCompression(ImageContent.COMPID_JPEG);
ColorSpace cs = jpeg.getColorSpace();
switch (cs.getType()) {
case ColorSpace.TYPE_GRAY:
imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11);
imageObjectInfo.setColor(false);
imageObjectInfo.setBitsPerPixel(8);
break;
case ColorSpace.TYPE_RGB:
imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11);
imageObjectInfo.setColor(true);
imageObjectInfo.setBitsPerPixel(24);
break;
case ColorSpace.TYPE_CMYK:
imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45);
imageObjectInfo.setColor(true);
imageObjectInfo.setBitsPerPixel(32);
break;
default:
throw new IllegalStateException(
"Color space of JPEG image not supported: " + cs);
}
boolean included = afpContext.getResourceManager().tryIncludeObject(imageObjectInfo);
if (!included) {
log.debug("Embedding undecoded JPEG as IOCA image...");
InputStream inputStream = jpeg.createInputStream();
try {
imageObjectInfo.setData(IOUtils.toByteArray(inputStream));
} finally {
IOUtils.closeQuietly(inputStream);
}
// Create image
afpContext.getResourceManager().createObject(imageObjectInfo);
}
}
// in src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java
public void paintImage(Graphics2DImagePainter painter,
RendererContext rendererContext,
int x, int y, int width, int height) throws IOException {
AFPRendererContext afpRendererContext = (AFPRendererContext)rendererContext;
AFPInfo afpInfo = afpRendererContext.getInfo();
final boolean textAsShapes = false;
AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes);
paintingState.save();
//Fallback solution: Paint to a BufferedImage
if (afpInfo.paintAsBitmap()) {
// paint image
RendererContextWrapper rendererContextWrapper
= RendererContext.wrapRendererContext(rendererContext);
float targetResolution = rendererContext.getUserAgent().getTargetResolution();
int resolution = Math.round(targetResolution);
boolean colorImages = afpInfo.isColorSupported();
BufferedImage bufferedImage = paintToBufferedImage(
painter, rendererContextWrapper, resolution, !colorImages, false);
// draw image
AffineTransform at = paintingState.getData().getTransform();
at.translate(x, y);
g2d.drawImage(bufferedImage, at, null);
} else {
AFPGraphicsObjectInfo graphicsObjectInfo = new AFPGraphicsObjectInfo();
graphicsObjectInfo.setPainter(painter);
graphicsObjectInfo.setGraphics2D(g2d);
// get the 'width' and 'height' attributes of the SVG document
Dimension imageSize = painter.getImageSize();
float imw = (float)imageSize.getWidth() / 1000f;
float imh = (float)imageSize.getHeight() / 1000f;
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
graphicsObjectInfo.setArea(area);
AFPResourceManager resourceManager = afpInfo.getResourceManager();
resourceManager.createObject(graphicsObjectInfo);
}
paintingState.restore();
}
// in src/java/org/apache/fop/render/afp/AFPImageHandlerSVG.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
AFPRenderingContext afpContext = (AFPRenderingContext)context;
ImageXMLDOM imageSVG = (ImageXMLDOM)image;
FOUserAgent userAgent = afpContext.getUserAgent();
AFPGraphicsObjectInfo graphicsObjectInfo = (AFPGraphicsObjectInfo)createDataObjectInfo();
AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo();
setDefaultToInlineResourceLevel(graphicsObjectInfo);
// Create a new AFPGraphics2D
AFPPaintingState paintingState = afpContext.getPaintingState();
final boolean textAsShapes = paintingState.isStrokeGOCAText();
AFPGraphics2D g2d = new AFPGraphics2D(
textAsShapes,
afpContext.getPaintingState(),
afpContext.getResourceManager(),
resourceInfo,
(textAsShapes ? null : afpContext.getFontInfo()));
g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
paintingState.setImageUri(image.getInfo().getOriginalURI());
// Create an AFPBridgeContext
BridgeContext bridgeContext = AFPSVGHandler.createBridgeContext(userAgent, g2d);
// Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
// to it.
Document clonedDoc = BatikUtil.cloneSVGDocument(imageSVG.getDocument());
// Build the SVG DOM and provide the painter with it
GraphicsNode root;
try {
GVTBuilder builder = new GVTBuilder();
root = builder.build(bridgeContext, clonedDoc);
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI());
return;
}
// Image positioning
AFPObjectAreaInfo objectAreaInfo = AFPImageHandler.createObjectAreaInfo(paintingState, pos);
graphicsObjectInfo.setObjectAreaInfo(objectAreaInfo);
paintingState.save(); // save
AffineTransform placement = new AffineTransform();
placement.translate(pos.x, pos.y);
paintingState.concatenate(placement);
//Set up painter and target
graphicsObjectInfo.setGraphics2D(g2d);
// Create Graphics2DImagePainter
Dimension imageSize = image.getSize().getDimensionMpt();
Graphics2DImagePainter painter = new Graphics2DImagePainterImpl(
root, bridgeContext, imageSize);
graphicsObjectInfo.setPainter(painter);
// Create the GOCA GraphicsObject in the DataStream
AFPResourceManager resourceManager = afpContext.getResourceManager();
resourceManager.createObject(graphicsObjectInfo);
paintingState.restore(); // resume
}
// in src/java/org/apache/fop/render/awt/AWTRenderer.java
public void renderPage(PageViewport pageViewport) throws IOException, FOPException {
super.renderPage(pageViewport);
if (statusListener != null) {
statusListener.notifyPageRendered();
}
}
// in src/java/org/apache/fop/render/awt/AWTRenderer.java
public void stopRenderer() throws IOException {
super.stopRenderer();
if (statusListener != null) {
statusListener.notifyRendererStopped(); // Refreshes view of page
}
}
// in src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java
public void paintImage(Graphics2DImagePainter painter,
RendererContext context,
int x, int y, int width, int height) throws IOException {
//TODO Deprecated method to be removed once Barcode4J 2.1 is released.
paintImage((org.apache.xmlgraphics.java2d.Graphics2DImagePainter)painter,
context, x, y, width, height);
}
// in src/java/org/apache/fop/render/ps/PSRenderingUtil.java
public static void writeSetupCodeList(PSGenerator gen, List setupCodeList, String type)
throws IOException {
if (setupCodeList != null) {
Iterator i = setupCodeList.iterator();
while (i.hasNext()) {
PSSetupCode setupCode = (PSSetupCode)i.next();
gen.commentln("%FOPBegin" + type + ": ("
+ (setupCode.getName() != null ? setupCode.getName() : "")
+ ")");
LineNumberReader reader = new LineNumberReader(
new java.io.StringReader(setupCode.getContent()));
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.length() > 0) {
gen.writeln(line.trim());
}
}
gen.commentln("%FOPEnd" + type);
i.remove();
}
}
}
// in src/java/org/apache/fop/render/ps/PSRenderingUtil.java
public static void writeEnclosedExtensionAttachments(PSGenerator gen,
Collection attachmentCollection) throws IOException {
Iterator iter = attachmentCollection.iterator();
while (iter.hasNext()) {
PSExtensionAttachment attachment = (PSExtensionAttachment)iter.next();
if (attachment != null) {
writeEnclosedExtensionAttachment(gen, attachment);
}
iter.remove();
}
}
// in src/java/org/apache/fop/render/ps/PSRenderingUtil.java
public static void writeEnclosedExtensionAttachment(PSGenerator gen,
PSExtensionAttachment attachment) throws IOException {
if (attachment instanceof PSCommentBefore) {
gen.commentln("%" + attachment.getContent());
} else if (attachment instanceof PSCommentAfter) {
gen.commentln("%" + attachment.getContent());
} else {
String info = "";
if (attachment instanceof PSSetupCode) {
PSSetupCode setupCodeAttach = (PSSetupCode)attachment;
String name = setupCodeAttach.getName();
if (name != null) {
info += ": (" + name + ")";
}
}
String type = attachment.getType();
gen.commentln("%FOPBegin" + type + info);
LineNumberReader reader = new LineNumberReader(
new java.io.StringReader(attachment.getContent()));
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.length() > 0) {
gen.writeln(line);
}
}
gen.commentln("%FOPEnd" + type);
}
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo)
throws IOException {
return writeFontDict(gen, fontInfo, fontInfo.getFonts(), true);
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo,
Map<String, Typeface> fonts)
throws IOException {
return writeFontDict(gen, fontInfo, fonts, false);
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
private static Map writeFontDict(PSGenerator gen, FontInfo fontInfo,
Map<String, Typeface> fonts, boolean encodeAllCharacters) throws IOException {
gen.commentln("%FOPBeginFontDict");
Map fontResources = new java.util.HashMap();
for (String key : fonts.keySet()) {
Typeface tf = getTypeFace(fontInfo, fonts, key);
PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getFontName());
fontResources.put(key, fontRes);
embedFont(gen, tf, fontRes);
if (tf instanceof SingleByteFont) {
SingleByteFont sbf = (SingleByteFont)tf;
if (encodeAllCharacters) {
sbf.encodeAllUnencodedCharacters();
}
for (int i = 0, c = sbf.getAdditionalEncodingCount(); i < c; i++) {
SingleByteEncoding encoding = sbf.getAdditionalEncoding(i);
defineEncoding(gen, encoding);
String postFix = "_" + (i + 1);
PSResource derivedFontRes = defineDerivedFont(gen, tf.getFontName(),
tf.getFontName() + postFix, encoding.getName());
fontResources.put(key + postFix, derivedFontRes);
}
}
}
gen.commentln("%FOPEndFontDict");
reencodeFonts(gen, fonts);
return fontResources;
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
private static void reencodeFonts(PSGenerator gen, Map<String, Typeface> fonts)
throws IOException {
ResourceTracker tracker = gen.getResourceTracker();
if (!tracker.isResourceSupplied(WINANSI_ENCODING_RESOURCE)) {
//Only out Base 14 fonts still use that
defineWinAnsiEncoding(gen);
}
gen.commentln("%FOPBeginFontReencode");
//Rewrite font encodings
for (String key : fonts.keySet()) {
Typeface tf = fonts.get(key);
if (tf instanceof LazyFont) {
tf = ((LazyFont)tf).getRealFont();
if (tf == null) {
continue;
}
}
if (null == tf.getEncodingName()) {
//ignore (ZapfDingbats and Symbol used to run through here, kept for safety reasons)
} else if ("SymbolEncoding".equals(tf.getEncodingName())) {
//ignore (no encoding redefinition)
} else if ("ZapfDingbatsEncoding".equals(tf.getEncodingName())) {
//ignore (no encoding redefinition)
} else {
if (tf instanceof Base14Font) {
//Our Base 14 fonts don't use the default encoding
redefineFontEncoding(gen, tf.getFontName(), tf.getEncodingName());
} else if (tf instanceof SingleByteFont) {
SingleByteFont sbf = (SingleByteFont)tf;
if (!sbf.isUsingNativeEncoding()) {
//Font has been configured to use an encoding other than the default one
redefineFontEncoding(gen, tf.getFontName(), tf.getEncodingName());
}
}
}
}
gen.commentln("%FOPEndFontReencode");
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
public static void embedFont(PSGenerator gen, Typeface tf, PSResource fontRes)
throws IOException {
boolean embeddedFont = false;
if (FontType.TYPE1 == tf.getFontType()) {
if (tf instanceof CustomFont) {
CustomFont cf = (CustomFont)tf;
if (isEmbeddable(cf)) {
InputStream in = getInputStreamOnFont(gen, cf);
if (in != null) {
gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE,
fontRes);
embedType1Font(gen, in);
gen.writeDSCComment(DSCConstants.END_RESOURCE);
gen.getResourceTracker().registerSuppliedResource(fontRes);
embeddedFont = true;
} else {
gen.commentln("%WARNING: Could not embed font: " + cf.getFontName());
log.warn("Font " + cf.getFontName() + " is marked as supplied in the"
+ " PostScript file but could not be embedded!");
}
}
}
}
if (!embeddedFont) {
gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes);
}
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
private static InputStream getInputStreamOnFont(PSGenerator gen, CustomFont font)
throws IOException {
if (isEmbeddable(font)) {
Source source = font.getEmbedFileSource();
if (source == null && font.getEmbedResourceName() != null) {
source = new StreamSource(PSFontUtils.class
.getResourceAsStream(font.getEmbedResourceName()));
}
if (source == null) {
return null;
}
InputStream in = null;
if (source instanceof StreamSource) {
in = ((StreamSource) source).getInputStream();
}
if (in == null && source.getSystemId() != null) {
try {
in = new java.net.URL(source.getSystemId()).openStream();
} catch (MalformedURLException e) {
new FileNotFoundException(
"File not found. URL could not be resolved: "
+ e.getMessage());
}
}
if (in == null) {
return null;
}
//Make sure the InputStream is decorated with a BufferedInputStream
if (!(in instanceof java.io.BufferedInputStream)) {
in = new java.io.BufferedInputStream(in);
}
return in;
} else {
return null;
}
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
public static PSResource defineEncoding(PSGenerator gen, SingleByteEncoding encoding)
throws IOException {
PSResource res = new PSResource(PSResource.TYPE_ENCODING, encoding.getName());
gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res);
gen.writeln("/" + encoding.getName() + " [");
String[] charNames = encoding.getCharNameMap();
for (int i = 0; i < 256; i++) {
if (i > 0) {
if ((i % 5) == 0) {
gen.newLine();
} else {
gen.write(" ");
}
}
String glyphname = null;
if (i < charNames.length) {
glyphname = charNames[i];
}
if (glyphname == null || "".equals(glyphname)) {
glyphname = Glyphs.NOTDEF;
}
gen.write("/");
gen.write(glyphname);
}
gen.newLine();
gen.writeln("] def");
gen.writeDSCComment(DSCConstants.END_RESOURCE);
gen.getResourceTracker().registerSuppliedResource(res);
return res;
}
// in src/java/org/apache/fop/render/ps/PSFontUtils.java
public static PSResource defineDerivedFont
(PSGenerator gen, String baseFontName, String fontName, String encoding)
throws IOException {
PSResource res = new PSResource(PSResource.TYPE_FONT, fontName);
gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res);
gen.commentln("%XGCDependencies: font " + baseFontName);
gen.commentln("%XGC+ encoding " + encoding);
gen.writeln("/" + baseFontName + " findfont");
gen.writeln("dup length dict begin");
gen.writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall");
gen.writeln(" /Encoding " + encoding + " def");
gen.writeln(" currentdict");
gen.writeln("end");
gen.writeln("/" + fontName + " exch definefont pop");
gen.writeDSCComment(DSCConstants.END_RESOURCE);
gen.getResourceTracker().registerSuppliedResource(res);
return res;
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawJPEG jpeg = (ImageRawJPEG)image;
float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
Rectangle2D targetRect = new Rectangle2D.Float(
x, y, w, h);
ImageInfo info = image.getInfo();
ImageEncoder encoder = new ImageEncoderJPEG(jpeg);
PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
info.getOriginalURI(), targetRect,
jpeg.getColorSpace(), 8, jpeg.isInverted(), gen);
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerRawJPEG.java
public void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawJPEG jpeg = (ImageRawJPEG)image;
ImageInfo info = image.getInfo();
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();
ImageEncoder encoder = new ImageEncoderJPEG(jpeg);
FormGenerator formGen = new ImageFormGenerator(
form.getName(), imageDescription,
info.getSize().getDimensionPt(),
info.getSize().getDimensionPx(),
encoder,
jpeg.getColorSpace(), jpeg.isInverted());
formGen.generate(gen);
}
// in src/java/org/apache/fop/render/ps/ResourceHandler.java
public void process(InputStream in, OutputStream out,
int pageCount, Rectangle2D documentBoundingBox)
throws DSCException, IOException {
DSCParser parser = new DSCParser(in);
PSGenerator gen = new PSGenerator(out);
parser.addListener(new DefaultNestedDocumentHandler(gen));
parser.addListener(new IncludeResourceListener(gen));
//Skip DSC header
DSCHeaderComment header = DSCTools.checkAndSkipDSC30Header(parser);
header.generate(gen);
parser.setFilter(new DSCFilter() {
private final Set filtered = new java.util.HashSet();
{
//We rewrite those as part of the processing
filtered.add(DSCConstants.PAGES);
filtered.add(DSCConstants.BBOX);
filtered.add(DSCConstants.HIRES_BBOX);
filtered.add(DSCConstants.DOCUMENT_NEEDED_RESOURCES);
filtered.add(DSCConstants.DOCUMENT_SUPPLIED_RESOURCES);
}
public boolean accept(DSCEvent event) {
if (event.isDSCComment()) {
//Filter %%Pages which we add manually from a parameter
return !(filtered.contains(event.asDSCComment().getName()));
} else {
return true;
}
}
});
//Get PostScript language level (may be missing)
while (true) {
DSCEvent event = parser.nextEvent();
if (event == null) {
reportInvalidDSC();
}
if (DSCTools.headerCommentsEndHere(event)) {
//Set number of pages
DSCCommentPages pages = new DSCCommentPages(pageCount);
pages.generate(gen);
new DSCCommentBoundingBox(documentBoundingBox).generate(gen);
new DSCCommentHiResBoundingBox(documentBoundingBox).generate(gen);
PSFontUtils.determineSuppliedFonts(resTracker, fontInfo, fontInfo.getUsedFonts());
registerSuppliedForms(resTracker, globalFormResources);
//Supplied Resources
DSCCommentDocumentSuppliedResources supplied
= new DSCCommentDocumentSuppliedResources(
resTracker.getDocumentSuppliedResources());
supplied.generate(gen);
//Needed Resources
DSCCommentDocumentNeededResources needed
= new DSCCommentDocumentNeededResources(
resTracker.getDocumentNeededResources());
needed.generate(gen);
//Write original comment that ends the header comments
event.generate(gen);
break;
}
if (event.isDSCComment()) {
DSCComment comment = event.asDSCComment();
if (DSCConstants.LANGUAGE_LEVEL.equals(comment.getName())) {
DSCCommentLanguageLevel level = (DSCCommentLanguageLevel)comment;
gen.setPSLevel(level.getLanguageLevel());
}
}
event.generate(gen);
}
//Skip to the FOPFontSetup
PostScriptComment fontSetupPlaceholder = parser.nextPSComment("FOPFontSetup", gen);
if (fontSetupPlaceholder == null) {
throw new DSCException("Didn't find %FOPFontSetup comment in stream");
}
PSFontUtils.writeFontDict(gen, fontInfo, fontInfo.getUsedFonts());
generateForms(globalFormResources, gen);
//Skip the prolog and to the first page
DSCComment pageOrTrailer = parser.nextDSCComment(DSCConstants.PAGE, gen);
if (pageOrTrailer == null) {
throw new DSCException("Page expected, but none found");
}
//Process individual pages (and skip as necessary)
while (true) {
DSCCommentPage page = (DSCCommentPage)pageOrTrailer;
page.generate(gen);
pageOrTrailer = DSCTools.nextPageOrTrailer(parser, gen);
if (pageOrTrailer == null) {
reportInvalidDSC();
} else if (!DSCConstants.PAGE.equals(pageOrTrailer.getName())) {
pageOrTrailer.generate(gen);
break;
}
}
//Write the rest
while (parser.hasNext()) {
DSCEvent event = parser.nextEvent();
event.generate(gen);
}
gen.flush();
}
// in src/java/org/apache/fop/render/ps/ResourceHandler.java
private static void registerSuppliedForms(ResourceTracker resTracker, Map formResources)
throws IOException {
if (formResources == null) {
return;
}
Iterator iter = formResources.values().iterator();
while (iter.hasNext()) {
PSImageFormResource form = (PSImageFormResource)iter.next();
resTracker.registerSuppliedResource(form);
}
}
// in src/java/org/apache/fop/render/ps/ResourceHandler.java
private void generateForms(Map formResources, PSGenerator gen) throws IOException {
if (formResources == null) {
return;
}
Iterator iter = formResources.values().iterator();
while (iter.hasNext()) {
PSImageFormResource form = (PSImageFormResource)iter.next();
generateFormForImage(gen, form);
}
}
// in src/java/org/apache/fop/render/ps/ResourceHandler.java
private void generateFormForImage(PSGenerator gen, PSImageFormResource form)
throws IOException {
final String uri = form.getImageURI();
ImageManager manager = userAgent.getFactory().getImageManager();
ImageInfo info = null;
try {
ImageSessionContext sessionContext = userAgent.getImageSessionContext();
info = manager.getImageInfo(uri, sessionContext);
//Create a rendering context for form creation
PSRenderingContext formContext = new PSRenderingContext(
userAgent, gen, fontInfo, true);
ImageFlavor[] flavors;
ImageHandlerRegistry imageHandlerRegistry
= userAgent.getFactory().getImageHandlerRegistry();
flavors = imageHandlerRegistry.getSupportedFlavors(formContext);
Map hints = ImageUtil.getDefaultHints(sessionContext);
org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
info, flavors, hints, sessionContext);
ImageHandler basicHandler = imageHandlerRegistry.getHandler(formContext, img);
if (basicHandler == null) {
throw new UnsupportedOperationException(
"No ImageHandler available for image: "
+ img.getInfo() + " (" + img.getClass().getName() + ")");
}
if (!(basicHandler instanceof PSImageHandler)) {
throw new IllegalStateException(
"ImageHandler implementation doesn't behave properly."
+ " It should have returned false in isCompatible(). Class: "
+ basicHandler.getClass().getName());
}
PSImageHandler handler = (PSImageHandler)basicHandler;
if (log.isTraceEnabled()) {
log.trace("Using ImageHandler: " + handler.getClass().getName());
}
handler.generateForm(formContext, img, form);
} catch (ImageException ie) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
userAgent.getEventBroadcaster());
eventProducer.imageError(resTracker, (info != null ? info.toString() : uri),
ie, null);
}
}
// in src/java/org/apache/fop/render/ps/ResourceHandler.java
private static FormGenerator createMissingForm(String formName, final Dimension2D dimensions) {
FormGenerator formGen = new FormGenerator(formName, null, dimensions) {
protected void generatePaintProc(PSGenerator gen) throws IOException {
gen.writeln("0 setgray");
gen.writeln("0 setlinewidth");
String w = gen.formatDouble(dimensions.getWidth());
String h = gen.formatDouble(dimensions.getHeight());
gen.writeln(w + " " + h + " scale");
gen.writeln("0 0 1 1 rectstroke");
gen.writeln("newpath");
gen.writeln("0 0 moveto");
gen.writeln("1 1 lineto");
gen.writeln("stroke");
gen.writeln("newpath");
gen.writeln("0 1 moveto");
gen.writeln("1 0 lineto");
gen.writeln("stroke");
}
};
return formGen;
}
// in src/java/org/apache/fop/render/ps/ResourceHandler.java
protected void generatePaintProc(PSGenerator gen) throws IOException {
gen.writeln("0 setgray");
gen.writeln("0 setlinewidth");
String w = gen.formatDouble(dimensions.getWidth());
String h = gen.formatDouble(dimensions.getHeight());
gen.writeln(w + " " + h + " scale");
gen.writeln("0 0 1 1 rectstroke");
gen.writeln("newpath");
gen.writeln("0 0 moveto");
gen.writeln("1 1 lineto");
gen.writeln("stroke");
gen.writeln("newpath");
gen.writeln("0 1 moveto");
gen.writeln("1 0 lineto");
gen.writeln("stroke");
}
// in src/java/org/apache/fop/render/ps/ResourceHandler.java
public void processEvent(DSCEvent event, DSCParser parser)
throws IOException, DSCException {
if (event.isDSCComment() && event instanceof DSCCommentIncludeResource) {
DSCCommentIncludeResource include = (DSCCommentIncludeResource)event;
PSResource res = include.getResource();
if (res.getType().equals(PSResource.TYPE_FORM)) {
if (inlineFormResources.containsValue(res)) {
PSImageFormResource form = (PSImageFormResource)
inlineFormResources.get(res);
//Create an inline form
//Wrap in save/restore pair to release memory
gen.writeln("save");
generateFormForImage(gen, form);
boolean execformFound = false;
DSCEvent next = parser.nextEvent();
if (next.isLine()) {
PostScriptLine line = next.asLine();
if (line.getLine().endsWith(" execform")) {
line.generate(gen);
execformFound = true;
}
}
if (!execformFound) {
throw new IOException(
"Expected a PostScript line in the form: <form> execform");
}
gen.writeln("restore");
} else {
//Do nothing
}
parser.next();
}
}
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
Graphics2DImagePainter painter = imageG2D.getGraphics2DImagePainter();
float fx = (float)pos.getX() / 1000f;
float fy = (float)pos.getY() / 1000f;
float fwidth = (float)pos.getWidth() / 1000f;
float fheight = (float)pos.getHeight() / 1000f;
// get the 'width' and 'height' attributes of the SVG document
Dimension dim = painter.getImageSize();
float imw = (float)dim.getWidth() / 1000f;
float imh = (float)dim.getHeight() / 1000f;
float sx = fwidth / (float)imw;
float sy = fheight / (float)imh;
gen.commentln("%FOPBeginGraphics2D");
gen.saveGraphicsState();
final boolean clip = false;
if (clip) {
// Clip to the image area.
gen.writeln("newpath");
gen.defineRect(fx, fy, fwidth, fheight);
gen.writeln("clip");
}
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
gen.concatMatrix(sx, 0, 0, sy, fx, fy);
final boolean textAsShapes = false;
PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
AffineTransform transform = new AffineTransform();
// scale to viewbox
transform.translate(fx, fy);
gen.getCurrentState().concatMatrix(transform);
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
painter.paint(graphics, area);
gen.restoreGraphicsState();
gen.commentln("%FOPEndGraphics2D");
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
public void generateForm(RenderingContext context, Image image, final PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
final ImageGraphics2D imageG2D = (ImageGraphics2D)image;
ImageInfo info = image.getInfo();
FormGenerator formGen = buildFormGenerator(gen.getPSLevel(), form, info, imageG2D);
formGen.generate(gen);
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
private FormGenerator buildFormGenerator(int psLanguageLevel, final PSImageFormResource form,
final ImageInfo info, final ImageGraphics2D imageG2D) {
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();
final Dimension2D dimensionsPt = info.getSize().getDimensionPt();
final Dimension2D dimensionsMpt = info.getSize().getDimensionMpt();
FormGenerator formGen;
if (psLanguageLevel <= 2) {
formGen = new EPSFormGenerator(form.getName(), imageDescription, dimensionsPt) {
@Override
void doGeneratePaintProc(PSGenerator gen) throws IOException {
paintImageG2D(imageG2D, dimensionsMpt, gen);
}
};
} else {
formGen = new EPSFormGenerator(form.getName(), imageDescription, dimensionsPt) {
@Override
protected void generateAdditionalDataStream(PSGenerator gen) throws IOException {
gen.writeln("/" + form.getName() + ":Data currentfile <<");
gen.writeln(" /Filter /SubFileDecode");
gen.writeln(" /DecodeParms << /EODCount 0 /EODString (%FOPEndOfData) >>");
gen.writeln(">> /ReusableStreamDecode filter");
paintImageG2D(imageG2D, dimensionsMpt, gen);
gen.writeln("%FOPEndOfData");
gen.writeln("def");
}
@Override
void doGeneratePaintProc(PSGenerator gen) throws IOException {
gen.writeln(form.getName() + ":Data 0 setfileposition");
gen.writeln(form.getName() + ":Data cvx exec");
}
};
}
return formGen;
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
Override
void doGeneratePaintProc(PSGenerator gen) throws IOException {
paintImageG2D(imageG2D, dimensionsMpt, gen);
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
Override
protected void generateAdditionalDataStream(PSGenerator gen) throws IOException {
gen.writeln("/" + form.getName() + ":Data currentfile <<");
gen.writeln(" /Filter /SubFileDecode");
gen.writeln(" /DecodeParms << /EODCount 0 /EODString (%FOPEndOfData) >>");
gen.writeln(">> /ReusableStreamDecode filter");
paintImageG2D(imageG2D, dimensionsMpt, gen);
gen.writeln("%FOPEndOfData");
gen.writeln("def");
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
Override
void doGeneratePaintProc(PSGenerator gen) throws IOException {
gen.writeln(form.getName() + ":Data 0 setfileposition");
gen.writeln(form.getName() + ":Data cvx exec");
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
protected void paintImageG2D(final ImageGraphics2D imageG2D, Dimension2D dimensionsMpt,
PSGenerator gen) throws IOException {
PSGraphics2DAdapter adapter = new PSGraphics2DAdapter(gen, false);
adapter.paintImage(imageG2D.getGraphics2DImagePainter(),
null,
0, 0,
(int) Math.round(dimensionsMpt.getWidth()),
(int) Math.round(dimensionsMpt.getHeight()));
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerGraphics2D.java
Override
protected final void generatePaintProc(PSGenerator gen) throws IOException {
gen.getResourceTracker().notifyResourceUsageOnPage(
PSProcSets.EPS_PROCSET);
gen.writeln("BeginEPSF");
doGeneratePaintProc(gen);
gen.writeln("EndEPSF");
}
// in src/java/org/apache/fop/render/ps/PSDocumentHandler.java
private void writeHeader() throws IOException {
//PostScript Header
gen.writeln(DSCConstants.PS_ADOBE_30);
gen.writeDSCComment(DSCConstants.CREATOR, new String[] {getUserAgent().getProducer()});
gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()});
gen.writeDSCComment(DSCConstants.LANGUAGE_LEVEL, new Integer(gen.getPSLevel()));
gen.writeDSCComment(DSCConstants.PAGES, new Object[] {DSCConstants.ATEND});
gen.writeDSCComment(DSCConstants.BBOX, DSCConstants.ATEND);
gen.writeDSCComment(DSCConstants.HIRES_BBOX, DSCConstants.ATEND);
gen.writeDSCComment(DSCConstants.DOCUMENT_SUPPLIED_RESOURCES,
new Object[] {DSCConstants.ATEND});
writeExtensions(COMMENT_DOCUMENT_HEADER);
gen.writeDSCComment(DSCConstants.END_COMMENTS);
//Defaults
gen.writeDSCComment(DSCConstants.BEGIN_DEFAULTS);
gen.writeDSCComment(DSCConstants.END_DEFAULTS);
//Prolog and Setup written right before the first page-sequence, see startPageSequence()
//Do this only once, as soon as we have all the content for the Setup section!
//Prolog
gen.writeDSCComment(DSCConstants.BEGIN_PROLOG);
PSProcSets.writeStdProcSet(gen);
PSProcSets.writeEPSProcSet(gen);
FOPProcSet.INSTANCE.writeTo(gen);
gen.writeDSCComment(DSCConstants.END_PROLOG);
//Setup
gen.writeDSCComment(DSCConstants.BEGIN_SETUP);
PSRenderingUtil.writeSetupCodeList(gen, setupCodeList, "SetupCode");
if (!psUtil.isOptimizeResources()) {
this.fontResources.addAll(PSFontUtils.writeFontDict(gen, fontInfo));
} else {
gen.commentln("%FOPFontSetup"); //Place-holder, will be replaced in the second pass
}
gen.writeDSCComment(DSCConstants.END_SETUP);
}
// in src/java/org/apache/fop/render/ps/PSDocumentHandler.java
private void rewritePostScriptFile() throws IOException {
log.debug("Processing PostScript resources...");
long startTime = System.currentTimeMillis();
ResourceTracker resTracker = gen.getResourceTracker();
InputStream in = new java.io.FileInputStream(this.tempFile);
in = new java.io.BufferedInputStream(in);
try {
try {
ResourceHandler handler = new ResourceHandler(getUserAgent(), this.fontInfo,
resTracker, this.formResources);
handler.process(in, this.outputStream,
this.currentPageNumber, this.documentBoundingBox);
this.outputStream.flush();
} catch (DSCException e) {
throw new RuntimeException(e.getMessage());
}
} finally {
IOUtils.closeQuietly(in);
if (!this.tempFile.delete()) {
this.tempFile.deleteOnExit();
log.warn("Could not delete temporary file: " + this.tempFile);
}
}
if (log.isDebugEnabled()) {
long duration = System.currentTimeMillis() - startTime;
log.debug("Resource Processing complete in " + duration + " ms.");
}
}
// in src/java/org/apache/fop/render/ps/PSDocumentHandler.java
private void writeExtensions(int which) throws IOException {
Collection extensions = comments[which];
if (extensions != null) {
PSRenderingUtil.writeEnclosedExtensionAttachments(gen, extensions);
extensions.clear();
}
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image;
float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
Rectangle2D targetRect = new Rectangle2D.Float(
x, y, w, h);
ImageInfo info = image.getInfo();
ImageEncoder encoder = new ImageEncoderCCITTFax(ccitt);
PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
info.getOriginalURI(), targetRect,
ccitt.getColorSpace(), 1, false, gen);
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerRawCCITTFax.java
public void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image;
ImageInfo info = image.getInfo();
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();
ImageEncoder encoder = new ImageEncoderCCITTFax(ccitt);
FormGenerator formGen = new ImageFormGenerator(
form.getName(), imageDescription,
info.getSize().getDimensionPt(),
info.getSize().getDimensionPx(),
encoder,
ccitt.getColorSpace(), 1, false);
formGen.generate(gen);
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageXMLDOM imageSVG = (ImageXMLDOM)image;
//Controls whether text painted by Batik is generated using text or path operations
boolean strokeText = false;
//TODO Configure text stroking
SVGUserAgent ua
= new SVGUserAgent(context.getUserAgent(), new AffineTransform());
PSGraphics2D graphics = new PSGraphics2D(strokeText, gen);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
BridgeContext ctx = new PSBridgeContext(ua,
(strokeText ? null : psContext.getFontInfo()),
context.getUserAgent().getFactory().getImageManager(),
context.getUserAgent().getImageSessionContext());
//Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
//to it.
Document clonedDoc = BatikUtil.cloneSVGDocument(imageSVG.getDocument());
GraphicsNode root;
try {
GVTBuilder builder = new GVTBuilder();
root = builder.build(ctx, clonedDoc);
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgNotBuilt(this, e, image.getInfo().getOriginalURI());
return;
}
// get the 'width' and 'height' attributes of the SVG document
float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
float sx = pos.width / w;
float sy = pos.height / h;
ctx = null;
gen.commentln("%FOPBeginSVG");
gen.saveGraphicsState();
final boolean clip = false;
if (clip) {
/*
* Clip to the svg area.
* Note: To have the svg overlay (under) a text area then use
* an fo:block-container
*/
gen.writeln("newpath");
gen.defineRect(pos.getMinX() / 1000f, pos.getMinY() / 1000f,
pos.width / 1000f, pos.height / 1000f);
gen.writeln("clip");
}
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
gen.concatMatrix(sx, 0, 0, sy, pos.getMinX() / 1000f, pos.getMinY() / 1000f);
AffineTransform transform = new AffineTransform();
// scale to viewbox
transform.translate(pos.getMinX(), pos.getMinY());
gen.getCurrentState().concatMatrix(transform);
try {
root.paint(graphics);
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
}
gen.restoreGraphicsState();
gen.commentln("%FOPEndSVG");
}
// in src/java/org/apache/fop/render/ps/FOPProcSet.java
public void writeTo(PSGenerator gen) throws IOException {
gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE,
new Object[] {TYPE_PROCSET, getName(),
Float.toString(getVersion()), Integer.toString(getRevision())});
gen.writeDSCComment(DSCConstants.VERSION,
new Object[] {Float.toString(getVersion()), Integer.toString(getRevision())});
gen.writeDSCComment(DSCConstants.COPYRIGHT, "Copyright 2009 "
+ "The Apache Software Foundation. "
+ "License terms: http://www.apache.org/licenses/LICENSE-2.0");
gen.writeDSCComment(DSCConstants.TITLE,
"Basic set of procedures used by Apache FOP");
gen.writeln("/TJ { % Similar but not equal to PDF's TJ operator");
gen.writeln(" {");
gen.writeln(" dup type /stringtype eq");
gen.writeln(" { show }"); //normal text show
gen.writeln(" { neg 1000 div 0 rmoveto }"); //negative X movement
gen.writeln(" ifelse");
gen.writeln(" } forall");
gen.writeln("} bd");
gen.writeln("/ATJ { % As TJ but adds letter-spacing");
gen.writeln(" /ATJls exch def");
gen.writeln(" {");
gen.writeln(" dup type /stringtype eq");
gen.writeln(" { ATJls 0 3 2 roll ashow }"); //normal text show
gen.writeln(" { neg 1000 div 0 rmoveto }"); //negative X movement
gen.writeln(" ifelse");
gen.writeln(" } forall");
gen.writeln("} bd");
gen.writeDSCComment(DSCConstants.END_RESOURCE);
gen.getResourceTracker().registerSuppliedResource(this);
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerEPS.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRawEPS eps = (ImageRawEPS)image;
float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
ImageInfo info = image.getInfo();
Rectangle2D bbox = eps.getBoundingBox();
if (bbox == null) {
bbox = new Rectangle2D.Double();
bbox.setFrame(new Point2D.Double(), info.getSize().getDimensionPt());
}
InputStream in = eps.createInputStream();
try {
String resourceName = info.getOriginalURI();
if (resourceName == null) {
resourceName = "inline image";
}
PSImageUtils.renderEPS(in, resourceName,
new Rectangle2D.Float(x, y, w, h),
bbox,
gen);
} finally {
IOUtils.closeQuietly(in);
}
}
// in src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java
public void writeTo(OutputStream out) throws IOException {
jpeg.writeTo(out);
}
// in src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java
public void writeTo(OutputStream out) throws IOException {
ccitt.writeTo(out);
}
// in src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java
public void paintImage(Graphics2DImagePainter painter,
RendererContext context,
int x, int y, int width, int height) throws IOException {
float fwidth = width / 1000f;
float fheight = height / 1000f;
float fx = x / 1000f;
float fy = y / 1000f;
// get the 'width' and 'height' attributes of the SVG document
Dimension dim = painter.getImageSize();
float imw = (float)dim.getWidth() / 1000f;
float imh = (float)dim.getHeight() / 1000f;
boolean paintAsBitmap = false;
if (context != null) {
Map foreign = (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES);
paintAsBitmap = (foreign != null
&& ImageHandlerUtil.isConversionModeBitmap(foreign));
}
float sx = paintAsBitmap ? 1.0f : (fwidth / (float)imw);
float sy = paintAsBitmap ? 1.0f : (fheight / (float)imh);
gen.commentln("%FOPBeginGraphics2D");
gen.saveGraphicsState();
if (clip) {
// Clip to the image area.
gen.writeln("newpath");
gen.defineRect(fx, fy, fwidth, fheight);
gen.writeln("clip");
}
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
gen.concatMatrix(sx, 0, 0, sy, fx, fy);
final boolean textAsShapes = false;
PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen);
graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
AffineTransform transform = new AffineTransform();
// scale to viewbox
transform.translate(fx, fy);
gen.getCurrentState().concatMatrix(transform);
if (paintAsBitmap) {
//Fallback solution: Paint to a BufferedImage
int resolution = (int)Math.round(context.getUserAgent().getTargetResolution());
RendererContextWrapper ctx = RendererContext.wrapRendererContext(context);
BufferedImage bi = paintToBufferedImage(painter, ctx, resolution, false, false);
float scale = PDFFactory.DEFAULT_PDF_RESOLUTION
/ context.getUserAgent().getTargetResolution();
graphics.drawImage(bi, new AffineTransform(scale, 0, 0, scale, 0, 0), null);
} else {
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
painter.paint(graphics, area);
}
gen.restoreGraphicsState();
gen.commentln("%FOPEndGraphics2D");
}
// in src/java/org/apache/fop/render/ps/PSPainter.java
protected void drawImageUsingImageHandler(ImageInfo info, Rectangle rect)
throws ImageException, IOException {
if (!getPSUtil().isOptimizeResources()
|| PSImageUtils.isImageInlined(info,
(PSRenderingContext)createRenderingContext())) {
super.drawImageUsingImageHandler(info, rect);
} else {
if (log.isDebugEnabled()) {
log.debug("Image " + info + " is embedded as a form later");
}
//Don't load image at this time, just put a form placeholder in the stream
PSResource form = documentHandler.getFormForImage(info.getOriginalURI());
PSImageUtils.drawForm(form, info, rect, getGenerator());
}
}
// in src/java/org/apache/fop/render/ps/PSPainter.java
protected void saveGraphicsState() throws IOException {
endTextObject();
getGenerator().saveGraphicsState();
}
// in src/java/org/apache/fop/render/ps/PSPainter.java
protected void restoreGraphicsState() throws IOException {
endTextObject();
getGenerator().restoreGraphicsState();
}
// in src/java/org/apache/fop/render/ps/PSPainter.java
protected void beginTextObject() throws IOException {
if (!inTextMode) {
PSGenerator generator = getGenerator();
generator.saveGraphicsState();
generator.writeln("BT");
inTextMode = true;
}
}
// in src/java/org/apache/fop/render/ps/PSPainter.java
protected void endTextObject() throws IOException {
if (inTextMode) {
inTextMode = false;
PSGenerator generator = getGenerator();
generator.writeln("ET");
generator.restoreGraphicsState();
}
}
// in src/java/org/apache/fop/render/ps/PSPainter.java
private void writeText( // CSOK: ParameterNumber
String text, int start, int len,
int letterSpacing, int wordSpacing, int[][] dp,
Font font, Typeface tf) throws IOException {
PSGenerator generator = getGenerator();
int end = start + len;
int initialSize = len;
initialSize += initialSize / 2;
boolean hasLetterSpacing = (letterSpacing != 0);
boolean needTJ = false;
int lineStart = 0;
StringBuffer accText = new StringBuffer(initialSize);
StringBuffer sb = new StringBuffer(initialSize);
int[] dx = IFUtil.convertDPToDX ( dp );
int dxl = (dx != null ? dx.length : 0);
for (int i = start; i < end; i++) {
char orgChar = text.charAt(i);
char ch;
int cw;
int glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
//Fixed width space are rendered as spaces so copy/paste works in a reader
ch = font.mapChar(CharUtilities.SPACE);
cw = font.getCharWidth(orgChar);
glyphAdjust = font.getCharWidth(ch) - cw;
} else {
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
glyphAdjust -= wordSpacing;
}
ch = font.mapChar(orgChar);
cw = font.getCharWidth(orgChar);
}
if (dx != null && i < dxl - 1) {
glyphAdjust -= dx[i + 1];
}
char codepoint = (char)(ch % 256);
PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text
if (glyphAdjust != 0) {
needTJ = true;
if (sb.length() == 0) {
sb.append('['); //Need to start TJ
}
if (accText.length() > 0) {
if ((sb.length() - lineStart + accText.length()) > 200) {
sb.append(PSGenerator.LF);
lineStart = sb.length();
}
sb.append('(');
sb.append(accText);
sb.append(") ");
accText.setLength(0); //reset accumulated text
}
sb.append(Integer.toString(glyphAdjust)).append(' ');
}
}
if (needTJ) {
if (accText.length() > 0) {
sb.append('(');
sb.append(accText);
sb.append(')');
}
if (hasLetterSpacing) {
sb.append("] " + formatMptAsPt(generator, letterSpacing) + " ATJ");
} else {
sb.append("] TJ");
}
} else {
sb.append('(').append(accText).append(")");
if (hasLetterSpacing) {
StringBuffer spb = new StringBuffer();
spb.append(formatMptAsPt(generator, letterSpacing))
.append(" 0 ");
sb.insert(0, spb.toString());
sb.append(" " + generator.mapCommand("ashow"));
} else {
sb.append(" " + generator.mapCommand("show"));
}
}
generator.writeln(sb.toString());
}
// in src/java/org/apache/fop/render/ps/PSPainter.java
private void useFont(String key, int size) throws IOException {
PSResource res = this.documentHandler.getPSResourceForFontKey(key);
PSGenerator generator = getGenerator();
generator.useFont("/" + res.getName(), size / 1000f);
generator.getResourceTracker().notifyResourceUsageOnPage(res);
}
// in src/java/org/apache/fop/render/ps/PSImageUtils.java
public static void drawForm(PSResource form, ImageInfo info, Rectangle rect,
PSGenerator generator) throws IOException {
Rectangle2D targetRect = new Rectangle2D.Double(
rect.getMinX() / 1000.0,
rect.getMinY() / 1000.0,
rect.getWidth() / 1000.0,
rect.getHeight() / 1000.0);
generator.saveGraphicsState();
translateAndScale(generator,
info.getSize().getDimensionPt(), targetRect);
//The following %%IncludeResource marker is needed later by ResourceHandler!
generator.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, form);
generator.getResourceTracker().notifyResourceUsageOnPage(form);
generator.writeln(form.getName() + " execform");
generator.restoreGraphicsState();
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRendered imageRend = (ImageRendered)image;
float x = (float)pos.getX() / 1000f;
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
RenderedImage ri = imageRend.getRenderedImage();
PSImageUtils.renderBitmapImage(ri, x, y, w, h, gen);
}
// in src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
public void generateForm(RenderingContext context, Image image, PSImageFormResource form)
throws IOException {
PSRenderingContext psContext = (PSRenderingContext)context;
PSGenerator gen = psContext.getGenerator();
ImageRendered imageRend = (ImageRendered)image;
ImageInfo info = image.getInfo();
String imageDescription = info.getMimeType() + " " + info.getOriginalURI();
RenderedImage ri = imageRend.getRenderedImage();
FormGenerator formGen = new ImageFormGenerator(
form.getName(), imageDescription,
info.getSize().getDimensionPt(),
ri, false);
formGen.generate(gen);
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
protected void paintTextRun(TextRun textRun, Graphics2D g2d) throws IOException {
AttributedCharacterIterator runaci = textRun.getACI();
runaci.first();
TextPaintInfo tpi = (TextPaintInfo)runaci.getAttribute(PAINT_INFO);
if (tpi == null || !tpi.visible) {
return;
}
if ((tpi != null) && (tpi.composite != null)) {
g2d.setComposite(tpi.composite);
}
//------------------------------------
TextSpanLayout layout = textRun.getLayout();
logTextRun(runaci, layout);
CharSequence chars = collectCharacters(runaci);
runaci.first(); //Reset ACI
final PSGraphics2D ps = (PSGraphics2D)g2d;
final PSGenerator gen = ps.getPSGenerator();
ps.preparePainting();
if (DEBUG) {
log.debug("Text: " + chars);
gen.commentln("%Text: " + chars);
}
GeneralPath debugShapes = null;
if (DEBUG) {
debugShapes = new GeneralPath();
}
TextUtil textUtil = new TextUtil(gen);
textUtil.setupFonts(runaci);
if (!textUtil.hasFonts()) {
//Draw using Java2D when no native fonts are available
textRun.getLayout().draw(g2d);
return;
}
gen.saveGraphicsState();
gen.concatMatrix(g2d.getTransform());
Shape imclip = g2d.getClip();
clip(ps, imclip);
gen.writeln("BT"); //beginTextObject()
AffineTransform localTransform = new AffineTransform();
Point2D prevPos = null;
GVTGlyphVector gv = layout.getGlyphVector();
PSTextRun psRun = new PSTextRun(); //Used to split a text run into smaller runs
for (int index = 0, c = gv.getNumGlyphs(); index < c; index++) {
char ch = chars.charAt(index);
boolean visibleChar = gv.isGlyphVisible(index)
|| (CharUtilities.isAnySpace(ch) && !CharUtilities.isZeroWidthSpace(ch));
logCharacter(ch, layout, index, visibleChar);
if (!visibleChar) {
continue;
}
Point2D glyphPos = gv.getGlyphPosition(index);
AffineTransform glyphTransform = gv.getGlyphTransform(index);
if (log.isTraceEnabled()) {
log.trace("pos " + glyphPos + ", transform " + glyphTransform);
}
if (DEBUG) {
Shape sh = gv.getGlyphLogicalBounds(index);
if (sh == null) {
sh = new Ellipse2D.Double(glyphPos.getX(), glyphPos.getY(), 2, 2);
}
debugShapes.append(sh, false);
}
//Exact position of the glyph
localTransform.setToIdentity();
localTransform.translate(glyphPos.getX(), glyphPos.getY());
if (glyphTransform != null) {
localTransform.concatenate(glyphTransform);
}
localTransform.scale(1, -1);
boolean flushCurrentRun = false;
//Try to optimize by combining characters using the same font and on the same line.
if (glyphTransform != null) {
//Happens for text-on-a-path
flushCurrentRun = true;
}
if (psRun.getRunLength() >= 128) {
//Don't let a run get too long
flushCurrentRun = true;
}
//Note the position of the glyph relative to the previous one
Point2D relPos;
if (prevPos == null) {
relPos = new Point2D.Double(0, 0);
} else {
relPos = new Point2D.Double(
glyphPos.getX() - prevPos.getX(),
glyphPos.getY() - prevPos.getY());
}
if (psRun.vertChanges == 0
&& psRun.getHorizRunLength() > 2
&& relPos.getY() != 0) {
//new line
flushCurrentRun = true;
}
//Select the actual character to paint
char paintChar = (CharUtilities.isAnySpace(ch) ? ' ' : ch);
//Select (sub)font for character
Font f = textUtil.selectFontForChar(paintChar);
char mapped = f.mapChar(ch);
boolean fontChanging = textUtil.isFontChanging(f, mapped);
if (fontChanging) {
flushCurrentRun = true;
}
if (flushCurrentRun) {
//Paint the current run and reset for the next run
psRun.paint(ps, textUtil, tpi);
psRun.reset();
}
//Track current run
psRun.addCharacter(paintChar, relPos);
psRun.noteStartingTransformation(localTransform);
//Change font if necessary
if (fontChanging) {
textUtil.setCurrentFont(f, mapped);
}
//Update last position
prevPos = glyphPos;
}
psRun.paint(ps, textUtil, tpi);
gen.writeln("ET"); //endTextObject()
gen.restoreGraphicsState();
if (DEBUG) {
//Paint debug shapes
g2d.setStroke(new BasicStroke(0));
g2d.setColor(Color.LIGHT_GRAY);
g2d.draw(debugShapes);
}
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
private void applyColor(Paint paint, final PSGenerator gen) throws IOException {
if (paint == null) {
return;
} else if (paint instanceof Color) {
Color col = (Color)paint;
gen.useColor(col);
} else {
log.warn("Paint not supported: " + paint.toString());
}
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
private void clip(PSGraphics2D ps, Shape shape) throws IOException {
if (shape == null) {
return;
}
ps.getPSGenerator().writeln("newpath");
PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
ps.processPathIterator(iter);
ps.getPSGenerator().writeln("clip");
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
public void writeTextMatrix(AffineTransform transform) throws IOException {
double[] matrix = new double[6];
transform.getMatrix(matrix);
gen.writeln(gen.formatDouble5(matrix[0]) + " "
+ gen.formatDouble5(matrix[1]) + " "
+ gen.formatDouble5(matrix[2]) + " "
+ gen.formatDouble5(matrix[3]) + " "
+ gen.formatDouble5(matrix[4]) + " "
+ gen.formatDouble5(matrix[5]) + " Tm");
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
public void selectFont(Font f, char mapped) throws IOException {
int encoding = mapped / 256;
String postfix = (encoding == 0 ? null : Integer.toString(encoding));
PSResource res = getResourceForFont(f, postfix);
gen.useFont("/" + res.getName(), f.getFontSize() / 1000f);
gen.getResourceTracker().notifyResourceUsageOnPage(res);
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
public void paint(PSGraphics2D g2d, TextUtil textUtil, TextPaintInfo tpi)
throws IOException {
if (getRunLength() > 0) {
if (log.isDebugEnabled()) {
log.debug("Text run: " + currentChars);
}
textUtil.writeTextMatrix(this.textTransform);
if (isXShow()) {
log.debug("Horizontal text: xshow");
paintXYShow(g2d, textUtil, tpi.fillPaint, true, false);
} else if (isYShow()) {
log.debug("Vertical text: yshow");
paintXYShow(g2d, textUtil, tpi.fillPaint, false, true);
} else {
log.debug("Arbitrary text: xyshow");
paintXYShow(g2d, textUtil, tpi.fillPaint, true, true);
}
boolean stroke = (tpi.strokePaint != null) && (tpi.strokeStroke != null);
if (stroke) {
log.debug("Stroked glyph outlines");
paintStrokedGlyphs(g2d, textUtil, tpi.strokePaint, tpi.strokeStroke);
}
}
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
private void paintXYShow(PSGraphics2D g2d, TextUtil textUtil, Paint paint,
boolean x, boolean y) throws IOException {
PSGenerator gen = textUtil.gen;
char firstChar = this.currentChars.charAt(0);
//Font only has to be setup up before the first character
Font f = textUtil.selectFontForChar(firstChar);
char mapped = f.mapChar(firstChar);
textUtil.selectFont(f, mapped);
textUtil.setCurrentFont(f, mapped);
applyColor(paint, gen);
StringBuffer sb = new StringBuffer();
sb.append('(');
for (int i = 0, c = this.currentChars.length(); i < c; i++) {
char ch = this.currentChars.charAt(i);
mapped = f.mapChar(ch);
char codepoint = (char) (mapped % 256);
PSGenerator.escapeChar(codepoint, sb);
}
sb.append(')');
if (x || y) {
sb.append("\n[");
int idx = 0;
Iterator iter = this.relativePositions.iterator();
while (iter.hasNext()) {
Point2D pt = (Point2D)iter.next();
if (idx > 0) {
if (x) {
sb.append(format(gen, pt.getX()));
}
if (y) {
if (x) {
sb.append(' ');
}
sb.append(format(gen, -pt.getY()));
}
if (idx % 8 == 0) {
sb.append('\n');
} else {
sb.append(' ');
}
}
idx++;
}
if (x) {
sb.append('0');
}
if (y) {
if (x) {
sb.append(' ');
}
sb.append('0');
}
sb.append(']');
}
sb.append(' ');
if (x) {
sb.append('x');
}
if (y) {
sb.append('y');
}
sb.append("show"); // --> xshow, yshow or xyshow
gen.writeln(sb.toString());
}
// in src/java/org/apache/fop/render/ps/PSTextPainter.java
private void paintStrokedGlyphs(PSGraphics2D g2d, TextUtil textUtil,
Paint strokePaint, Stroke stroke) throws IOException {
PSGenerator gen = textUtil.gen;
applyColor(strokePaint, gen);
PSGraphics2D.applyStroke(stroke, gen);
Font f = null;
Iterator iter = this.relativePositions.iterator();
iter.next();
Point2D pos = new Point2D.Double(0, 0);
gen.writeln("0 0 M");
for (int i = 0, c = this.currentChars.length(); i < c; i++) {
char ch = this.currentChars.charAt(0);
if (i == 0) {
//Font only has to be setup up before the first character
f = textUtil.selectFontForChar(ch);
}
char mapped = f.mapChar(ch);
if (i == 0) {
textUtil.selectFont(f, mapped);
textUtil.setCurrentFont(f, mapped);
}
mapped = f.mapChar(this.currentChars.charAt(i));
//add glyph outlines to current path
char codepoint = (char)(mapped % 256);
gen.write("(" + codepoint + ")");
gen.writeln(" false charpath");
if (iter.hasNext()) {
//Position for the next character
Point2D pt = (Point2D)iter.next();
pos.setLocation(pos.getX() + pt.getX(), pos.getY() - pt.getY());
gen.writeln(gen.formatDouble5(pos.getX()) + " "
+ gen.formatDouble5(pos.getY()) + " M");
}
}
gen.writeln("stroke"); //paints all accumulated glyph outlines
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
protected void drawBorderLine( // CSOK: ParameterNumber
int x1, int y1, int x2, int y2, boolean horz,
boolean startOrBefore, int style, Color col) throws IOException {
drawBorderLine(generator, toPoints(x1), toPoints(y1), toPoints(x2), toPoints(y2),
horz, startOrBefore, style, col);
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
private static void drawLine(PSGenerator gen,
float startx, float starty, float endx, float endy) throws IOException {
gen.writeln(gen.formatDouble(startx) + " "
+ gen.formatDouble(starty) + " " + gen.mapCommand("moveto") + " "
+ gen.formatDouble(endx) + " "
+ gen.formatDouble(endy) + " " + gen.mapCommand("lineto") + " "
+ gen.mapCommand("stroke") + " " + gen.mapCommand("newpath"));
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
public static void drawBorderLine( // CSOK: ParameterNumber
PSGenerator gen,
float x1, float y1, float x2, float y2, boolean horz, // CSOK: JavadocMethod
boolean startOrBefore, int style, Color col) // CSOK: JavadocMethod
throws IOException { // CSOK: JavadocMethod
float w = x2 - x1;
float h = y2 - y1;
if ((w < 0) || (h < 0)) {
log.error("Negative extent received. Border won't be painted.");
return;
}
switch (style) {
case Constants.EN_DASHED:
gen.useColor(col);
if (horz) {
float unit = Math.abs(2 * h);
int rep = (int)(w / unit);
if (rep % 2 == 0) {
rep++;
}
unit = w / rep;
gen.useDash("[" + unit + "] 0");
gen.useLineCap(0);
gen.useLineWidth(h);
float ym = y1 + (h / 2);
drawLine(gen, x1, ym, x2, ym);
} else {
float unit = Math.abs(2 * w);
int rep = (int)(h / unit);
if (rep % 2 == 0) {
rep++;
}
unit = h / rep;
gen.useDash("[" + unit + "] 0");
gen.useLineCap(0);
gen.useLineWidth(w);
float xm = x1 + (w / 2);
drawLine(gen, xm, y1, xm, y2);
}
break;
case Constants.EN_DOTTED:
gen.useColor(col);
gen.useLineCap(1); //Rounded!
if (horz) {
float unit = Math.abs(2 * h);
int rep = (int)(w / unit);
if (rep % 2 == 0) {
rep++;
}
unit = w / rep;
gen.useDash("[0 " + unit + "] 0");
gen.useLineWidth(h);
float ym = y1 + (h / 2);
drawLine(gen, x1, ym, x2, ym);
} else {
float unit = Math.abs(2 * w);
int rep = (int)(h / unit);
if (rep % 2 == 0) {
rep++;
}
unit = h / rep;
gen.useDash("[0 " + unit + "] 0");
gen.useLineWidth(w);
float xm = x1 + (w / 2);
drawLine(gen, xm, y1, xm, y2);
}
break;
case Constants.EN_DOUBLE:
gen.useColor(col);
gen.useDash(null);
if (horz) {
float h3 = h / 3;
gen.useLineWidth(h3);
float ym1 = y1 + (h3 / 2);
float ym2 = ym1 + h3 + h3;
drawLine(gen, x1, ym1, x2, ym1);
drawLine(gen, x1, ym2, x2, ym2);
} else {
float w3 = w / 3;
gen.useLineWidth(w3);
float xm1 = x1 + (w3 / 2);
float xm2 = xm1 + w3 + w3;
drawLine(gen, xm1, y1, xm1, y2);
drawLine(gen, xm2, y1, xm2, y2);
}
break;
case Constants.EN_GROOVE:
case Constants.EN_RIDGE:
float colFactor = (style == Constants.EN_GROOVE ? 0.4f : -0.4f);
gen.useDash(null);
if (horz) {
Color uppercol = ColorUtil.lightenColor(col, -colFactor);
Color lowercol = ColorUtil.lightenColor(col, colFactor);
float h3 = h / 3;
gen.useLineWidth(h3);
float ym1 = y1 + (h3 / 2);
gen.useColor(uppercol);
drawLine(gen, x1, ym1, x2, ym1);
gen.useColor(col);
drawLine(gen, x1, ym1 + h3, x2, ym1 + h3);
gen.useColor(lowercol);
drawLine(gen, x1, ym1 + h3 + h3, x2, ym1 + h3 + h3);
} else {
Color leftcol = ColorUtil.lightenColor(col, -colFactor);
Color rightcol = ColorUtil.lightenColor(col, colFactor);
float w3 = w / 3;
gen.useLineWidth(w3);
float xm1 = x1 + (w3 / 2);
gen.useColor(leftcol);
drawLine(gen, xm1, y1, xm1, y2);
gen.useColor(col);
drawLine(gen, xm1 + w3, y1, xm1 + w3, y2);
gen.useColor(rightcol);
drawLine(gen, xm1 + w3 + w3, y1, xm1 + w3 + w3, y2);
}
break;
case Constants.EN_INSET:
case Constants.EN_OUTSET:
colFactor = (style == Constants.EN_OUTSET ? 0.4f : -0.4f);
gen.useDash(null);
if (horz) {
Color c = ColorUtil.lightenColor(col, (startOrBefore ? 1 : -1) * colFactor);
gen.useLineWidth(h);
float ym1 = y1 + (h / 2);
gen.useColor(c);
drawLine(gen, x1, ym1, x2, ym1);
} else {
Color c = ColorUtil.lightenColor(col, (startOrBefore ? 1 : -1) * colFactor);
gen.useLineWidth(w);
float xm1 = x1 + (w / 2);
gen.useColor(c);
drawLine(gen, xm1, y1, xm1, y2);
}
break;
case Constants.EN_HIDDEN:
break;
default:
gen.useColor(col);
gen.useDash(null);
gen.useLineCap(0);
if (horz) {
gen.useLineWidth(h);
float ym = y1 + (h / 2);
drawLine(gen, x1, ym, x2, ym);
} else {
gen.useLineWidth(w);
float xm = x1 + (w / 2);
drawLine(gen, xm, y1, xm, y2);
}
}
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
public void drawLine(Point start, Point end,
int width, Color color, RuleStyle style) throws IOException {
if (start.y != end.y) {
//TODO Support arbitrary lines if necessary
throw new UnsupportedOperationException(
"Can only deal with horizontal lines right now");
}
saveGraphicsState();
int half = width / 2;
int starty = start.y - half;
//Rectangle boundingRect = new Rectangle(start.x, start.y - half, end.x - start.x, width);
switch (style.getEnumValue()) {
case Constants.EN_SOLID:
case Constants.EN_DASHED:
case Constants.EN_DOUBLE:
drawBorderLine(start.x, starty, end.x, starty + width,
true, true, style.getEnumValue(), color);
break;
case Constants.EN_DOTTED:
clipRect(start.x, starty, end.x - start.x, width);
//This displaces the dots to the right by half a dot's width
//TODO There's room for improvement here
generator.concatMatrix(1, 0, 0, 1, toPoints(half), 0);
drawBorderLine(start.x, starty, end.x, starty + width,
true, true, style.getEnumValue(), color);
break;
case Constants.EN_GROOVE:
case Constants.EN_RIDGE:
generator.useColor(ColorUtil.lightenColor(color, 0.6f));
moveTo(start.x, starty);
lineTo(end.x, starty);
lineTo(end.x, starty + 2 * half);
lineTo(start.x, starty + 2 * half);
closePath();
generator.write(" " + generator.mapCommand("fill"));
generator.writeln(" " + generator.mapCommand("newpath"));
generator.useColor(color);
if (style == RuleStyle.GROOVE) {
moveTo(start.x, starty);
lineTo(end.x, starty);
lineTo(end.x, starty + half);
lineTo(start.x + half, starty + half);
lineTo(start.x, starty + 2 * half);
} else {
moveTo(end.x, starty);
lineTo(end.x, starty + 2 * half);
lineTo(start.x, starty + 2 * half);
lineTo(start.x, starty + half);
lineTo(end.x - half, starty + half);
}
closePath();
generator.write(" " + generator.mapCommand("fill"));
generator.writeln(" " + generator.mapCommand("newpath"));
break;
default:
throw new UnsupportedOperationException("rule style not supported");
}
restoreGraphicsState();
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
protected void moveTo(int x, int y) throws IOException {
generator.writeln(generator.formatDouble(toPoints(x)) + " "
+ generator.formatDouble(toPoints(y)) + " " + generator.mapCommand("moveto"));
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
protected void lineTo(int x, int y) throws IOException {
generator.writeln(generator.formatDouble(toPoints(x)) + " "
+ generator.formatDouble(toPoints(y)) + " " + generator.mapCommand("lineto"));
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
protected void closePath() throws IOException {
generator.writeln("cp");
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
private void clipRect(int x, int y, int width, int height) throws IOException {
generator.defineRect(toPoints(x), toPoints(y), toPoints(width), toPoints(height));
clip();
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
protected void clip() throws IOException {
generator.writeln(generator.mapCommand("clip") + " " + generator.mapCommand("newpath"));
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
protected void saveGraphicsState() throws IOException {
generator.saveGraphicsState();
}
// in src/java/org/apache/fop/render/ps/PSBorderPainter.java
protected void restoreGraphicsState() throws IOException {
generator.restoreGraphicsState();
}
// in src/java/org/apache/fop/render/ps/NativeTextHandler.java
public void writeSetup() throws IOException {
if (fontInfo != null) {
PSFontUtils.writeFontDict(getPSGenerator(), fontInfo);
}
}
// in src/java/org/apache/fop/render/ps/NativeTextHandler.java
public void writePageSetup() throws IOException {
//nop
}
// in src/java/org/apache/fop/render/ps/NativeTextHandler.java
public void drawString(String text, float x, float y) throws IOException {
// TODO Remove me after removing the deprecated method in TextHandler.
throw new UnsupportedOperationException("Deprecated method!");
}
// in src/java/org/apache/fop/render/ps/NativeTextHandler.java
public void drawString(Graphics2D g, String s, float x, float y) throws IOException {
PSGraphics2D g2d = (PSGraphics2D)g;
g2d.preparePainting();
if (this.overrideFont == null) {
java.awt.Font awtFont = g2d.getFont();
this.font = createFont(awtFont);
} else {
this.font = this.overrideFont;
this.overrideFont = null;
}
//Color and Font state
g2d.establishColor(g2d.getColor());
establishCurrentFont();
PSGenerator gen = getPSGenerator();
gen.saveGraphicsState();
//Clip
Shape imclip = g2d.getClip();
g2d.writeClip(imclip);
//Prepare correct transformation
AffineTransform trans = g2d.getTransform();
gen.concatMatrix(trans);
gen.writeln(gen.formatDouble(x) + " "
+ gen.formatDouble(y) + " moveto ");
gen.writeln("1 -1 scale");
StringBuffer sb = new StringBuffer("(");
escapeText(s, sb);
sb.append(") t ");
gen.writeln(sb.toString());
gen.restoreGraphicsState();
}
// in src/java/org/apache/fop/render/ps/NativeTextHandler.java
private void establishCurrentFont() throws IOException {
if ((currentFontName != this.font.getFontName())
|| (currentFontSize != this.font.getFontSize())) {
PSGenerator gen = getPSGenerator();
gen.writeln("/" + this.font.getFontTriplet().getName() + " "
+ gen.formatDouble(font.getFontSize() / 1000f) + " F");
currentFontName = this.font.getFontName();
currentFontSize = this.font.getFontSize();
}
}
// in src/java/org/apache/fop/render/java2d/Java2DImageHandlerRenderedImage.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
Java2DRenderingContext java2dContext = (Java2DRenderingContext)context;
ImageInfo info = image.getInfo();
ImageRendered imageRend = (ImageRendered)image;
Graphics2D g2d = java2dContext.getGraphics2D();
AffineTransform at = new AffineTransform();
at.translate(pos.x, pos.y);
//scaling based on layout instructions
double sx = pos.getWidth() / (double)info.getSize().getWidthMpt();
double sy = pos.getHeight() / (double)info.getSize().getHeightMpt();
//scaling because of image resolution
//float sourceResolution = java2dContext.getUserAgent().getSourceResolution();
//source resolution seems to be a bad idea, not sure why
float sourceResolution = GraphicsConstants.DEFAULT_DPI;
sourceResolution *= 1000; //we're working in the millipoint area
sx *= sourceResolution / info.getSize().getDpiHorizontal();
sy *= sourceResolution / info.getSize().getDpiVertical();
at.scale(sx, sy);
RenderedImage rend = imageRend.getRenderedImage();
if (imageRend.getTransparentColor() != null && !rend.getColorModel().hasAlpha()) {
int transCol = imageRend.getTransparentColor().getRGB();
BufferedImage bufImage = makeTransparentImage(rend);
WritableRaster alphaRaster = bufImage.getAlphaRaster();
//TODO Masked images: Does anyone know a more efficient method to do this?
final int[] transparent = new int[] {0x00};
for (int y = 0, maxy = bufImage.getHeight(); y < maxy; y++) {
for (int x = 0, maxx = bufImage.getWidth(); x < maxx; x++) {
int col = bufImage.getRGB(x, y);
if (col == transCol) {
//Mask out all pixels that match the transparent color
alphaRaster.setPixel(x, y, transparent);
}
}
}
g2d.drawRenderedImage(bufImage, at);
} else {
g2d.drawRenderedImage(rend, at);
}
}
// in src/java/org/apache/fop/render/java2d/Java2DPainter.java
private void concatenateTransformationMatrix(AffineTransform transform) throws IOException {
g2dState.transform(transform);
}
// in src/java/org/apache/fop/render/java2d/Java2DImageHandlerGraphics2D.java
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
Java2DRenderingContext java2dContext = (Java2DRenderingContext)context;
ImageInfo info = image.getInfo();
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
Dimension dim = info.getSize().getDimensionMpt();
Graphics2D g2d = (Graphics2D)java2dContext.getGraphics2D().create();
g2d.translate(pos.x, pos.y);
double sx = pos.width / dim.getWidth();
double sy = pos.height / dim.getHeight();
g2d.scale(sx, sy);
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, dim.getWidth(), dim.getHeight());
imageG2D.getGraphics2DImagePainter().paint(g2d, area);
g2d.dispose();
}
// in src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java
public void paintImage(Graphics2DImagePainter painter,
RendererContext context,
int x, int y, int width, int height) throws IOException {
float fwidth = width / 1000f;
float fheight = height / 1000f;
float fx = x / 1000f;
float fy = y / 1000f;
// get the 'width' and 'height' attributes of the SVG document
Dimension dim = painter.getImageSize();
float imw = (float)dim.getWidth() / 1000f;
float imh = (float)dim.getHeight() / 1000f;
float sx = fwidth / (float)imw;
float sy = fheight / (float)imh;
Java2DRenderer renderer = (Java2DRenderer)context.getRenderer();
Java2DGraphicsState state = renderer.state;
//Create copy and paint on that
Graphics2D g2d = (Graphics2D)state.getGraph().create();
g2d.setColor(Color.black);
g2d.setBackground(Color.black);
//TODO Clip to the image area.
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
g2d.translate(fx, fy);
AffineTransform at = AffineTransform.getScaleInstance(sx, sy);
if (!at.isIdentity()) {
g2d.transform(at);
}
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
painter.paint(g2d, area);
g2d.dispose();
}
// in src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java
private void initialize(final Source source)
throws FontFormatException, IOException {
int type = Font.TRUETYPE_FONT;
if (FontType.TYPE1.equals(typeface.getFontType())) {
type = TYPE1_FONT; //Font.TYPE1_FONT; only available in Java 1.5
}
InputStream is = null;
if (source instanceof StreamSource) {
is = ((StreamSource) source).getInputStream();
} else if (source.getSystemId() != null) {
is = new java.net.URL(source.getSystemId()).openStream();
} else {
throw new IllegalArgumentException("No font source provided.");
}
this.font = Font.createFont(type, is);
is.close();
}
// in src/java/org/apache/fop/render/java2d/Java2DRenderer.java
public void startRenderer(OutputStream out) throws IOException {
super.startRenderer(out);
// do nothing by default
}
// in src/java/org/apache/fop/render/java2d/Java2DRenderer.java
public void stopRenderer() throws IOException {
log.debug("Java2DRenderer stopped");
renderingDone = true;
int numberOfPages = currentPageNumber;
// TODO set all vars to null for gc
if (numberOfPages == 0) {
new FOPException("No page could be rendered");
}
}
// in src/java/org/apache/fop/render/java2d/Java2DRenderer.java
public void renderPage(PageViewport pageViewport) throws IOException, FOPException {
try {
rememberPage((PageViewport)pageViewport.clone());
} catch (CloneNotSupportedException e) {
throw new FOPException(e);
}
//The clone() call is necessary as we store the page for later. Otherwise, the
//RenderPagesModel calls PageViewport.clear() to release memory as early as possible.
currentPageNumber++;
}
// in src/java/org/apache/fop/afp/apps/FontPatternExtractor.java
public void extract(File file, File targetDir) throws IOException {
InputStream in = new java.io.FileInputStream(file);
try {
MODCAParser parser = new MODCAParser(in);
ByteArrayOutputStream baout = new ByteArrayOutputStream();
UnparsedStructuredField strucField;
while ((strucField = parser.readNextStructuredField()) != null) {
if (strucField.getSfTypeID() == 0xD3EE89) {
byte[] sfData = strucField.getData();
println(strucField.toString());
HexDump.dump(sfData, 0, printStream, 0);
baout.write(sfData);
}
}
ByteArrayInputStream bin = new ByteArrayInputStream(baout.toByteArray());
DataInputStream din = new DataInputStream(bin);
long len = din.readInt() & 0xFFFFFFFFL;
println("Length: " + len);
din.skip(4); //checksum
int tidLen = din.readUnsignedShort() - 2;
byte[] tid = new byte[tidLen];
din.readFully(tid);
String filename = new String(tid, "ISO-8859-1");
int asciiCount1 = countUSAsciiCharacters(filename);
String filenameEBCDIC = new String(tid, "Cp1146");
int asciiCount2 = countUSAsciiCharacters(filenameEBCDIC);
println("TID: " + filename + " " + filenameEBCDIC);
if (asciiCount2 > asciiCount1) {
//Haven't found an indicator if the name is encoded in EBCDIC or not
//so we use a trick.
filename = filenameEBCDIC;
}
if (!filename.toLowerCase().endsWith(".pfb")) {
filename = filename + ".pfb";
}
println("Output filename: " + filename);
File out = new File(targetDir, filename);
OutputStream fout = new java.io.FileOutputStream(out);
try {
IOUtils.copyLarge(din, fout);
} finally {
IOUtils.closeQuietly(fout);
}
} finally {
IOUtils.closeQuietly(in);
}
}
// in src/java/org/apache/fop/afp/ptoca/TextDataInfoProducer.java
public void produce(PtocaBuilder builder) throws IOException {
builder.setTextOrientation(textDataInfo.getRotation());
builder.absoluteMoveBaseline(textDataInfo.getY());
builder.absoluteMoveInline(textDataInfo.getX());
builder.setVariableSpaceCharacterIncrement(
textDataInfo.getVariableSpaceCharacterIncrement());
builder.setInterCharacterAdjustment(
textDataInfo.getInterCharacterAdjustment());
builder.setExtendedTextColor(textDataInfo.getColor());
builder.setCodedFont((byte)textDataInfo.getFontReference());
// Add transparent data
String textString = textDataInfo.getString();
String encoding = textDataInfo.getEncoding();
builder.addTransparentData(CharactersetEncoder.encodeSBCS(textString, encoding));
}
// in src/java/org/apache/fop/afp/ptoca/TransparentDataControlSequence.java
void writeTo(OutputStream outStream) throws IOException {
encodedChars.writeTo(outStream, offset, length);
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
private void commit(byte functionType) throws IOException {
int length = baout.size() + 2;
assert length < 256;
OutputStream out = getOutputStreamForControlSequence(length);
out.write(length);
out.write(functionType);
baout.writeTo(out);
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void writeIntroducer() throws IOException {
OutputStream out = getOutputStreamForControlSequence(ESCAPE.length);
out.write(ESCAPE);
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void setCodedFont(byte font) throws IOException {
// Avoid unnecessary specification of the font
if (currentFont == font) {
return;
} else {
currentFont = font;
}
newControlSequence();
writeBytes(font);
commit(chained(SCFL));
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void absoluteMoveInline(int coordinate) throws IOException {
if (coordinate == this.currentX) {
return;
}
newControlSequence();
writeShort(coordinate);
commit(chained(AMI));
currentX = coordinate;
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void relativeMoveInline(int increment) throws IOException {
newControlSequence();
writeShort(increment);
commit(chained(RMI));
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void absoluteMoveBaseline(int coordinate) throws IOException {
if (coordinate == this.currentY) {
return;
}
newControlSequence();
writeShort(coordinate);
commit(chained(AMB));
currentY = coordinate;
currentX = -1;
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void addTransparentData(EncodedChars encodedChars) throws IOException {
for (TransparentData trn : new TransparentDataControlSequence(encodedChars)) {
newControlSequence();
trn.writeTo(baout);
commit(chained(TRN));
}
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void drawBaxisRule(int length, int width) throws IOException {
newControlSequence();
writeShort(length); // Rule length
writeShort(width); // Rule width
writeBytes(0); // Rule width fraction is always null. enough?
commit(chained(DBR));
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void drawIaxisRule(int length, int width) throws IOException {
newControlSequence();
writeShort(length); // Rule length
writeShort(width); // Rule width
writeBytes(0); // Rule width fraction is always null. enough?
commit(chained(DIR));
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void setTextOrientation(int orientation) throws IOException {
if (orientation == this.currentOrientation) {
return;
}
newControlSequence();
AxisOrientation.getRightHandedAxisOrientationFor(orientation).writeTo(baout);
commit(chained(STO));
this.currentOrientation = orientation;
currentX = -1;
currentY = -1;
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void setExtendedTextColor(Color col) throws IOException {
if (ColorUtil.isSameColor(col, currentColor)) {
return;
}
if (col instanceof ColorWithAlternatives) {
ColorWithAlternatives cwa = (ColorWithAlternatives)col;
Color alt = cwa.getFirstAlternativeOfType(ColorSpace.TYPE_CMYK);
if (alt != null) {
col = alt;
}
}
ColorSpace cs = col.getColorSpace();
newControlSequence();
if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) {
// Color space - 0x04 = CMYK, all else are reserved and must be zero
writeBytes(0x00, 0x04, 0x00, 0x00, 0x00, 0x00);
writeBytes(8, 8, 8, 8); // Number of bits in component 1, 2, 3 & 4 respectively
float[] comps = col.getColorComponents(null);
assert comps.length == 4;
for (int i = 0; i < 4; i++) {
int component = Math.round(comps[i] * 255);
writeBytes(component);
}
} else if (cs instanceof CIELabColorSpace) {
// Color space - 0x08 = CIELAB, all else are reserved and must be zero
writeBytes(0x00, 0x08, 0x00, 0x00, 0x00, 0x00);
writeBytes(8, 8, 8, 0); // Number of bits in component 1,2,3 & 4
//Sadly, 16 bit components don't seem to work
float[] colorComponents = col.getColorComponents(null);
int l = Math.round(colorComponents[0] * 255f);
int a = Math.round(colorComponents[1] * 255f) - 128;
int b = Math.round(colorComponents[2] * 255f) - 128;
writeBytes(l, a, b); // l*, a* and b*
} else {
// Color space - 0x01 = RGB, all else are reserved and must be zero
writeBytes(0x00, 0x01, 0x00, 0x00, 0x00, 0x00);
writeBytes(8, 8, 8, 0); // Number of bits in component 1, 2, 3 & 4 respectively
writeBytes(col.getRed(), col.getGreen(), col.getBlue()); // RGB intensity
}
commit(chained(SEC));
this.currentColor = col;
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void setVariableSpaceCharacterIncrement(int incr) throws IOException {
if (incr == this.currentVariableSpaceCharacterIncrement) {
return;
}
assert incr >= 0 && incr < (1 << 16);
newControlSequence();
writeShort(Math.abs(incr)); //Increment
commit(chained(SVI));
this.currentVariableSpaceCharacterIncrement = incr;
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void setInterCharacterAdjustment(int incr) throws IOException {
if (incr == this.currentInterCharacterAdjustment) {
return;
}
assert incr >= Short.MIN_VALUE && incr <= Short.MAX_VALUE;
newControlSequence();
writeShort(Math.abs(incr)); //Increment
writeBytes(incr >= 0 ? 0 : 1); // Direction
commit(chained(SIA));
this.currentInterCharacterAdjustment = incr;
}
// in src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
public void endChainedControlSequence() throws IOException {
newControlSequence();
commit(NOP);
}
// in src/java/org/apache/fop/afp/ptoca/LineDataInfoProducer.java
public void produce(PtocaBuilder builder) throws IOException {
builder.setTextOrientation(lineDataInfo.getRotation());
int x1 = ensurePositive(lineDataInfo.getX1());
int y1 = ensurePositive(lineDataInfo.getY1());
builder.absoluteMoveBaseline(y1);
builder.absoluteMoveInline(x1);
builder.setExtendedTextColor(lineDataInfo.getColor());
int x2 = ensurePositive(lineDataInfo.getX2());
int y2 = ensurePositive(lineDataInfo.getY2());
int thickness = lineDataInfo.getThickness();
if (y1 == y2) {
builder.drawIaxisRule(x2 - x1, thickness);
} else if (x1 == x2) {
builder.drawBaxisRule(y2 - y1, thickness);
} else {
LOG.error("Invalid axis rule: unable to draw line");
return;
}
}
// in src/java/org/apache/fop/afp/DataStream.java
public void endDocument() throws IOException {
if (complete) {
String msg = "Invalid state - document already ended.";
LOG.warn("endDocument():: " + msg);
throw new IllegalStateException(msg);
}
if (currentPageObject != null) {
// End the current page if necessary
endPage();
}
if (currentPageGroup != null) {
// End the current page group if necessary
endPageGroup();
}
// Write out document
if (document != null) {
document.endDocument();
document.writeToStream(this.outputStream);
}
this.outputStream.flush();
this.complete = true;
this.document = null;
this.outputStream = null;
}
// in src/java/org/apache/fop/afp/DataStream.java
public void endOverlay() throws IOException {
if (currentOverlay != null) {
currentOverlay.endPage();
currentOverlay = null;
currentPage = currentPageObject;
}
}
// in src/java/org/apache/fop/afp/DataStream.java
public void endPage() throws IOException {
if (currentPageObject != null) {
currentPageObject.endPage();
if (currentPageGroup != null) {
currentPageGroup.addPage(currentPageObject);
currentPageGroup.writeToStream(this.outputStream);
} else {
document.addPage(currentPageObject);
document.writeToStream(this.outputStream);
}
currentPageObject = null;
currentPage = null;
}
}
// in src/java/org/apache/fop/afp/DataStream.java
public void createText(final AFPTextDataInfo textDataInfo, final int letterSpacing,
final int wordSpacing, final Font font, final CharacterSet charSet)
throws UnsupportedEncodingException {
int rotation = paintingState.getRotation();
if (rotation != 0) {
textDataInfo.setRotation(rotation);
Point p = getPoint(textDataInfo.getX(), textDataInfo.getY());
textDataInfo.setX(p.x);
textDataInfo.setY(p.y);
}
// use PtocaProducer to create PTX records
PtocaProducer producer = new PtocaProducer() {
public void produce(PtocaBuilder builder) throws IOException {
builder.setTextOrientation(textDataInfo.getRotation());
builder.absoluteMoveBaseline(textDataInfo.getY());
builder.absoluteMoveInline(textDataInfo.getX());
builder.setExtendedTextColor(textDataInfo.getColor());
builder.setCodedFont((byte)textDataInfo.getFontReference());
int l = textDataInfo.getString().length();
StringBuffer sb = new StringBuffer();
int interCharacterAdjustment = 0;
AFPUnitConverter unitConv = paintingState.getUnitConverter();
if (letterSpacing != 0) {
interCharacterAdjustment = Math.round(unitConv.mpt2units(letterSpacing));
}
builder.setInterCharacterAdjustment(interCharacterAdjustment);
int spaceWidth = font.getCharWidth(CharUtilities.SPACE);
int spacing = spaceWidth + letterSpacing;
int fixedSpaceCharacterIncrement = Math.round(unitConv.mpt2units(spacing));
int varSpaceCharacterIncrement = fixedSpaceCharacterIncrement;
if (wordSpacing != 0) {
varSpaceCharacterIncrement = Math.round(unitConv.mpt2units(
spaceWidth + wordSpacing + letterSpacing));
}
builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement);
boolean fixedSpaceMode = false;
for (int i = 0; i < l; i++) {
char orgChar = textDataInfo.getString().charAt(i);
float glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
fixedSpaceCharacterIncrement);
fixedSpaceMode = true;
sb.append(CharUtilities.SPACE);
int charWidth = font.getCharWidth(orgChar);
glyphAdjust += (charWidth - spaceWidth);
} else {
if (fixedSpaceMode) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
varSpaceCharacterIncrement);
fixedSpaceMode = false;
}
char ch;
if (orgChar == CharUtilities.NBSPACE) {
ch = ' '; //converted to normal space to allow word spacing
} else {
ch = orgChar;
}
sb.append(ch);
}
if (glyphAdjust != 0) {
flushText(builder, sb, charSet);
int increment = Math.round(unitConv.mpt2units(glyphAdjust));
builder.relativeMoveInline(increment);
}
}
flushText(builder, sb, charSet);
}
private void flushText(PtocaBuilder builder, StringBuffer sb,
final CharacterSet charSet) throws IOException {
if (sb.length() > 0) {
builder.addTransparentData(charSet.encodeChars(sb));
sb.setLength(0);
}
}
};
currentPage.createText(producer);
}
// in src/java/org/apache/fop/afp/DataStream.java
public void produce(PtocaBuilder builder) throws IOException {
builder.setTextOrientation(textDataInfo.getRotation());
builder.absoluteMoveBaseline(textDataInfo.getY());
builder.absoluteMoveInline(textDataInfo.getX());
builder.setExtendedTextColor(textDataInfo.getColor());
builder.setCodedFont((byte)textDataInfo.getFontReference());
int l = textDataInfo.getString().length();
StringBuffer sb = new StringBuffer();
int interCharacterAdjustment = 0;
AFPUnitConverter unitConv = paintingState.getUnitConverter();
if (letterSpacing != 0) {
interCharacterAdjustment = Math.round(unitConv.mpt2units(letterSpacing));
}
builder.setInterCharacterAdjustment(interCharacterAdjustment);
int spaceWidth = font.getCharWidth(CharUtilities.SPACE);
int spacing = spaceWidth + letterSpacing;
int fixedSpaceCharacterIncrement = Math.round(unitConv.mpt2units(spacing));
int varSpaceCharacterIncrement = fixedSpaceCharacterIncrement;
if (wordSpacing != 0) {
varSpaceCharacterIncrement = Math.round(unitConv.mpt2units(
spaceWidth + wordSpacing + letterSpacing));
}
builder.setVariableSpaceCharacterIncrement(varSpaceCharacterIncrement);
boolean fixedSpaceMode = false;
for (int i = 0; i < l; i++) {
char orgChar = textDataInfo.getString().charAt(i);
float glyphAdjust = 0;
if (CharUtilities.isFixedWidthSpace(orgChar)) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
fixedSpaceCharacterIncrement);
fixedSpaceMode = true;
sb.append(CharUtilities.SPACE);
int charWidth = font.getCharWidth(orgChar);
glyphAdjust += (charWidth - spaceWidth);
} else {
if (fixedSpaceMode) {
flushText(builder, sb, charSet);
builder.setVariableSpaceCharacterIncrement(
varSpaceCharacterIncrement);
fixedSpaceMode = false;
}
char ch;
if (orgChar == CharUtilities.NBSPACE) {
ch = ' '; //converted to normal space to allow word spacing
} else {
ch = orgChar;
}
sb.append(ch);
}
if (glyphAdjust != 0) {
flushText(builder, sb, charSet);
int increment = Math.round(unitConv.mpt2units(glyphAdjust));
builder.relativeMoveInline(increment);
}
}
flushText(builder, sb, charSet);
}
// in src/java/org/apache/fop/afp/DataStream.java
private void flushText(PtocaBuilder builder, StringBuffer sb,
final CharacterSet charSet) throws IOException {
if (sb.length() > 0) {
builder.addTransparentData(charSet.encodeChars(sb));
sb.setLength(0);
}
}
// in src/java/org/apache/fop/afp/DataStream.java
public void startDocument() throws IOException {
this.document = factory.createDocument();
document.writeToStream(this.outputStream);
}
// in src/java/org/apache/fop/afp/DataStream.java
public void startPageGroup() throws IOException {
endPageGroup();
this.currentPageGroup = factory.createPageGroup(tleSequence);
}
// in src/java/org/apache/fop/afp/DataStream.java
public void endPageGroup() throws IOException {
if (currentPageGroup != null) {
currentPageGroup.endPageGroup();
tleSequence = currentPageGroup.getTleSequence();
document.addPageGroup(currentPageGroup);
currentPageGroup = null;
}
document.writeToStream(outputStream); //Flush objects
}
// in src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java
public void paint(PaintingInfo paintInfo) throws IOException {
RectanglePaintingInfo rectanglePaintInfo = (RectanglePaintingInfo)paintInfo;
if (rectanglePaintInfo.getWidth() <= 0 || rectanglePaintInfo.getHeight() <= 0) {
return;
}
int ditherMatrix = DitherUtil.DITHER_MATRIX_8X8;
Dimension ditherSize = new Dimension(ditherMatrix, ditherMatrix);
//Prepare an FS10 bi-level image
AFPImageObjectInfo imageObjectInfo = new AFPImageObjectInfo();
imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10);
//imageObjectInfo.setCreatePageSegment(true);
imageObjectInfo.getResourceInfo().setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE));
imageObjectInfo.getResourceInfo().setImageDimension(ditherSize);
imageObjectInfo.setBitsPerPixel(1);
imageObjectInfo.setColor(false);
//Note: the following may not be supported by older implementations
imageObjectInfo.setMappingOption(MappingOptionTriplet.REPLICATE_AND_TRIM);
//Dither image size
int resolution = paintingState.getResolution();
ImageSize ditherBitmapSize = new ImageSize(
ditherSize.width, ditherSize.height, resolution);
imageObjectInfo.setDataHeightRes((int)Math.round(
ditherBitmapSize.getDpiHorizontal() * 10));
imageObjectInfo.setDataWidthRes((int)Math.round(
ditherBitmapSize.getDpiVertical() * 10));
imageObjectInfo.setDataWidth(ditherSize.width);
imageObjectInfo.setDataHeight(ditherSize.height);
//Create dither image
Color col = paintingState.getColor();
byte[] dither = DitherUtil.getBayerDither(ditherMatrix, col, false);
imageObjectInfo.setData(dither);
//Positioning
int rotation = paintingState.getRotation();
AffineTransform at = paintingState.getData().getTransform();
Point2D origin = at.transform(new Point2D.Float(
rectanglePaintInfo.getX() * 1000,
rectanglePaintInfo.getY() * 1000), null);
AFPUnitConverter unitConv = paintingState.getUnitConverter();
float width = unitConv.pt2units(rectanglePaintInfo.getWidth());
float height = unitConv.pt2units(rectanglePaintInfo.getHeight());
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(
(int) Math.round(origin.getX()),
(int) Math.round(origin.getY()),
Math.round(width), Math.round(height), resolution, rotation);
imageObjectInfo.setObjectAreaInfo(objectAreaInfo);
//Create rectangle
resourceManager.createObject(imageObjectInfo);
}
// in src/java/org/apache/fop/afp/parser/MODCAParser.java
public UnparsedStructuredField readNextStructuredField() throws IOException {
//Find the SF delimiter
do {
//Exhausted streams and so no next SF
// - null return represents this case
// TODO should this happen?
if (din.available() == 0) {
return null;
}
} while (din.readByte() != CARRIAGE_CONTROL_CHAR);
//Read introducer as byte array to preserve any data not parsed below
byte[] introducerData = new byte[INTRODUCER_LENGTH]; //Length of introducer
din.readFully(introducerData);
Introducer introducer = new Introducer(introducerData);
int dataLength = introducer.getLength() - INTRODUCER_LENGTH;
//Handle optional extension
byte[] extData = null;
if (introducer.isExtensionPresent()) {
short extLength = 0;
extLength = (short)((din.readByte()) & 0xFF);
if (extLength > 0) {
extData = new byte[extLength - 1];
din.readFully(extData);
dataLength -= extLength;
}
}
//Read payload
byte[] data = new byte[dataLength];
din.readFully(data);
UnparsedStructuredField sf = new UnparsedStructuredField(introducer, data, extData);
if (LOG.isTraceEnabled()) {
LOG.trace(sf);
}
return sf;
}
// in src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java
public void writeTo(OutputStream out) throws IOException {
out.write(introducer.introducerData);
if (isSfiExtensionPresent()) {
out.write(this.extData.length + 1);
out.write(this.extData);
}
out.write(this.data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsSetCharacterSet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
getOrderCode(), // GSCS order code
BinaryUtils.convert(fontReference)[0]
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsFullArc.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
// integer portion of multiplier
data[6] = BinaryUtils.convert(mh, 1)[0];
// fractional portion of multiplier
data[7] = BinaryUtils.convert(mhr, 1)[0];
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
byte[] strData = getStringAsBytes();
System.arraycopy(strData, 0, data, 6, strData.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsSetFractionalLineWidth.java
public void writeToStream(OutputStream os) throws IOException {
int integral = (int) multiplier;
int fractional = (int) ((multiplier - (float) integral) * 256);
byte[] data = new byte[] {
getOrderCode(), // GSLW order code
0x02, // two bytes next
(byte) integral, // integral line with
(byte) fractional // and fractional
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsSetLineType.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
getOrderCode(), // GSLW order code
type // line type
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsSetPatternSymbol.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
getOrderCode(), // GSPT order code
pattern
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/AbstractGraphicsCoord.java
public void writeToStream(OutputStream os) throws IOException {
os.write(getData());
}
// in src/java/org/apache/fop/afp/goca/GraphicsData.java
Override
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[9];
copySF(data, SF_CLASS, Type.DATA, Category.GRAPHICS);
int dataLength = getDataLength();
byte[] len = BinaryUtils.convert(dataLength, 2);
data[1] = len[0]; // Length byte 1
data[2] = len[1]; // Length byte 2
if (this.segmentedData) {
data[6] |= 32; //Data is segmented
}
os.write(data);
writeObjects(objects, os);
}
// in src/java/org/apache/fop/afp/goca/GraphicsSetLineWidth.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
getOrderCode(), // GSLW order code
(byte) multiplier // MH (line-width)
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java
public void writeToStream(OutputStream os) throws IOException {
float[] colorComponents = color.getColorComponents(null);
// COLSPCE
byte colspace;
ColorSpace cs = color.getColorSpace();
int colSpaceType = cs.getType();
ByteArrayOutputStream baout = new ByteArrayOutputStream();
byte[] colsizes;
if (colSpaceType == ColorSpace.TYPE_CMYK) {
colspace = CMYK;
colsizes = new byte[] {0x08, 0x08, 0x08, 0x08};
for (int i = 0; i < colorComponents.length; i++) {
baout.write(Math.round(colorComponents[i] * 255));
}
} else if (colSpaceType == ColorSpace.TYPE_RGB) {
colspace = RGB;
colsizes = new byte[] {0x08, 0x08, 0x08, 0x00};
for (int i = 0; i < colorComponents.length; i++) {
baout.write(Math.round(colorComponents[i] * 255));
}
} else if (cs instanceof CIELabColorSpace) {
colspace = CIELAB;
colsizes = new byte[] {0x08, 0x08, 0x08, 0x00};
DataOutput dout = new java.io.DataOutputStream(baout);
//According to GOCA, I'd expect the multiplicator below to be 255f, not 100f
//But only IBM AFP Workbench seems to support Lab colors and it requires "c * 100f"
int l = Math.round(colorComponents[0] * 100f);
int a = Math.round(colorComponents[1] * 255f) - 128;
int b = Math.round(colorComponents[2] * 255f) - 128;
dout.writeByte(l);
dout.writeByte(a);
dout.writeByte(b);
} else {
throw new IllegalStateException();
}
int len = getDataLength();
byte[] data = new byte[12];
data[0] = getOrderCode(); // GSPCOL order code
data[1] = (byte) (len - 2); // LEN
data[2] = 0x00; // reserved; must be zero
data[3] = colspace; // COLSPCE
data[4] = 0x00; // reserved; must be zero
data[5] = 0x00; // reserved; must be zero
data[6] = 0x00; // reserved; must be zero
data[7] = 0x00; // reserved; must be zero
data[8] = colsizes[0]; // COLSIZE(S)
data[9] = colsizes[1];
data[10] = colsizes[2];
data[11] = colsizes[3];
os.write(data);
baout.writeTo(os);
}
// in src/java/org/apache/fop/afp/goca/GraphicsImage.java
public void writeToStream(OutputStream os) throws IOException {
byte[] xcoord = BinaryUtils.convert(x, 2);
byte[] ycoord = BinaryUtils.convert(y, 2);
byte[] w = BinaryUtils.convert(width, 2);
byte[] h = BinaryUtils.convert(height, 2);
byte[] startData = new byte[] {
getOrderCode(), // GBIMG order code
(byte) 0x0A, // LENGTH
xcoord[0],
xcoord[1],
ycoord[0],
ycoord[1],
0x00, // FORMAT
0x00, // RES
w[0], // WIDTH
w[1], //
h[0], // HEIGHT
h[1] //
};
os.write(startData);
byte[] dataHeader = new byte[] {
(byte) 0x92 // GIMD
};
final int lengthOffset = 1;
writeChunksToStream(imageData, dataHeader, lengthOffset, MAX_DATA_LEN, os);
byte[] endData = new byte[] {
(byte) 0x93, // GEIMG order code
0x00 // LENGTH
};
os.write(endData);
}
// in src/java/org/apache/fop/afp/goca/GraphicsBox.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = (byte)0x20; // CONTROL draw control flags
data[3] = 0x00; // reserved
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsAreaEnd.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
getOrderCode(), // GEAR order code
0x00, // LENGTH
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsChainedSegment.java
Override
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[14];
data[0] = getOrderCode(); // BEGIN_SEGMENT
data[1] = 0x0C; // Length of following parameters
// segment name
byte[] nameBytes = getNameBytes();
System.arraycopy(nameBytes, 0, data, 2, NAME_LENGTH);
data[6] = 0x00; // FLAG1 (ignored)
//FLAG2
data[7] |= this.appended ? APPEND_TO_EXISING : APPEND_NEW_SEGMENT;
if (this.prologPresent) {
data[7] |= PROLOG;
}
int dataLength = super.getDataLength();
byte[] len = BinaryUtils.convert(dataLength, 2);
data[8] = len[0]; // SEGL
data[9] = len[1];
// P/S NAME (predecessor name)
if (predecessorNameBytes != null) {
System.arraycopy(predecessorNameBytes, 0, data, 10, NAME_LENGTH);
}
os.write(data);
writeObjects(objects, os);
}
// in src/java/org/apache/fop/afp/goca/GraphicsLine.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsAreaBegin.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
getOrderCode(), // GBAR order code
(byte)(RES1 + (drawBoundary ? BOUNDARY : NO_BOUNDARY))
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrderContainer.java
protected void writeStart(OutputStream os) throws IOException {
setStarted(true);
}
// in src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrderContainer.java
protected void writeContent(OutputStream os) throws IOException {
writeObjects(objects, os);
}
// in src/java/org/apache/fop/afp/goca/GraphicsEndProlog.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
getOrderCode(), // GEPROL order code
0x00, // Reserved
};
os.write(data);
}
// in src/java/org/apache/fop/afp/goca/GraphicsSetMix.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
0x0C, // GSMX order code
mode // MODE (mix mode value)
};
os.write(data);
}
// in src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java
public void writeTo(OutputStream out, int offset, int length) throws IOException {
if (offset < 0 || length < 0 || offset + length > bytes.length) {
throw new IllegalArgumentException();
}
out.write(bytes, this.offset + offset, length);
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected InputStream openInputStream(ResourceAccessor accessor, String filename,
AFPEventProducer eventProducer)
throws IOException {
URI uri;
try {
uri = new URI(filename.trim());
} catch (URISyntaxException e) {
throw new FileNotFoundException("Invalid filename: "
+ filename + " (" + e.getMessage() + ")");
}
if (LOG.isDebugEnabled()) {
LOG.debug("Opening " + uri);
}
InputStream inputStream = accessor.createInputStream(uri);
return inputStream;
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
public CharacterSet buildSBCS(String characterSetName, String codePageName, String encoding,
ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException {
return processFont(characterSetName, codePageName, encoding, CharacterSetType.SINGLE_BYTE,
accessor, eventProducer);
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
public CharacterSet buildDBCS(String characterSetName, String codePageName, String encoding,
CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer)
throws IOException {
return processFont(characterSetName, codePageName, encoding, charsetType, accessor,
eventProducer);
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
public CharacterSet build(String characterSetName, String codePageName, String encoding,
Typeface typeface, AFPEventProducer eventProducer) throws IOException {
return new FopCharacterSet(codePageName, encoding, characterSetName, typeface,
eventProducer);
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
private CharacterSet processFont(String characterSetName, String codePageName, String encoding,
CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer)
throws IOException {
// check for cached version of the characterset
String descriptor = characterSetName + "_" + encoding + "_" + codePageName;
CharacterSet characterSet = (CharacterSet) characterSetsCache.get(descriptor);
if (characterSet != null) {
return characterSet;
}
// characterset not in the cache, so recreating
characterSet = new CharacterSet(codePageName, encoding, charsetType, characterSetName,
accessor, eventProducer);
InputStream inputStream = null;
try {
/**
* Get the code page which contains the character mapping
* information to map the unicode character id to the graphic
* chracter global identifier.
*/
Map<String, String> codePage;
synchronized (codePagesCache) {
codePage = codePagesCache.get(codePageName);
if (codePage == null) {
codePage = loadCodePage(codePageName, encoding, accessor, eventProducer);
codePagesCache.put(codePageName, codePage);
}
}
inputStream = openInputStream(accessor, characterSetName, eventProducer);
StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream);
// Process D3A689 Font Descriptor
FontDescriptor fontDescriptor = processFontDescriptor(structuredFieldReader);
characterSet.setNominalVerticalSize(fontDescriptor.getNominalFontSizeInMillipoints());
// Process D3A789 Font Control
FontControl fontControl = processFontControl(structuredFieldReader);
if (fontControl != null) {
//process D3AE89 Font Orientation
CharacterSetOrientation[] characterSetOrientations
= processFontOrientation(structuredFieldReader);
double metricNormalizationFactor;
if (fontControl.isRelative()) {
metricNormalizationFactor = 1;
} else {
int dpi = fontControl.getDpi();
metricNormalizationFactor = 1000.0d * 72000.0d
/ fontDescriptor.getNominalFontSizeInMillipoints() / dpi;
}
//process D3AC89 Font Position
processFontPosition(structuredFieldReader, characterSetOrientations,
metricNormalizationFactor);
//process D38C89 Font Index (per orientation)
for (int i = 0; i < characterSetOrientations.length; i++) {
processFontIndex(structuredFieldReader,
characterSetOrientations[i], codePage, metricNormalizationFactor);
characterSet.addCharacterSetOrientation(characterSetOrientations[i]);
}
} else {
throw new IOException("Missing D3AE89 Font Control structured field.");
}
} finally {
closeInputStream(inputStream);
}
characterSetsCache.put(descriptor, characterSet);
return characterSet;
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected Map<String, String> loadCodePage(String codePage, String encoding,
ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException {
// Create the HashMap to store code page information
Map<String, String> codePages = new HashMap<String, String>();
InputStream inputStream = null;
try {
inputStream = openInputStream(accessor, codePage.trim(), eventProducer);
StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream);
byte[] data = structuredFieldReader.getNext(CHARACTER_TABLE_SF);
int position = 0;
byte[] gcgiBytes = new byte[8];
byte[] charBytes = new byte[1];
// Read data, ignoring bytes 0 - 2
for (int index = 3; index < data.length; index++) {
if (position < 8) {
// Build the graphic character global identifier key
gcgiBytes[position] = data[index];
position++;
} else if (position == 9) {
position = 0;
// Set the character
charBytes[0] = data[index];
String gcgiString = new String(gcgiBytes,
AFPConstants.EBCIDIC_ENCODING);
//Use the 8-bit char index to find the Unicode character using the Java encoding
//given in the configuration. If the code page and the Java encoding don't
//match, a wrong Unicode character will be associated with the AFP GCGID.
//Idea: we could use IBM's GCGID to Unicode map and build code pages ourselves.
String charString = new String(charBytes, encoding);
codePages.put(gcgiString, charString);
} else {
position++;
}
}
} catch (FileNotFoundException e) {
eventProducer.codePageNotFound(this, e);
} finally {
closeInputStream(inputStream);
}
return codePages;
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected static FontDescriptor processFontDescriptor(
StructuredFieldReader structuredFieldReader)
throws IOException {
byte[] fndData = structuredFieldReader.getNext(FONT_DESCRIPTOR_SF);
return new FontDescriptor(fndData);
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected FontControl processFontControl(StructuredFieldReader structuredFieldReader)
throws IOException {
byte[] fncData = structuredFieldReader.getNext(FONT_CONTROL_SF);
FontControl fontControl = null;
if (fncData != null) {
fontControl = new FontControl();
if (fncData[7] == (byte) 0x02) {
fontControl.setRelative(true);
}
int metricResolution = getUBIN(fncData, 9);
if (metricResolution == 1000) {
//Special case: 1000 units per em (rather than dpi)
fontControl.setUnitsPerEm(1000);
} else {
fontControl.setDpi(metricResolution / 10);
}
}
return fontControl;
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected CharacterSetOrientation[] processFontOrientation(
StructuredFieldReader structuredFieldReader) throws IOException {
byte[] data = structuredFieldReader.getNext(FONT_ORIENTATION_SF);
int position = 0;
byte[] fnoData = new byte[26];
List<CharacterSetOrientation> orientations = new ArrayList<CharacterSetOrientation>();
// Read data, ignoring bytes 0 - 2
for (int index = 3; index < data.length; index++) {
// Build the font orientation record
fnoData[position] = data[index];
position++;
if (position == 26) {
position = 0;
int orientation = determineOrientation(fnoData[2]);
// Space Increment
int space = ((fnoData[8] & 0xFF ) << 8) + (fnoData[9] & 0xFF);
// Em-Space Increment
int em = ((fnoData[14] & 0xFF ) << 8) + (fnoData[15] & 0xFF);
CharacterSetOrientation cso = new CharacterSetOrientation(orientation);
cso.setSpaceIncrement(space);
cso.setEmSpaceIncrement(em);
orientations.add(cso);
}
}
return orientations.toArray(EMPTY_CSO_ARRAY);
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected void processFontPosition(StructuredFieldReader structuredFieldReader,
CharacterSetOrientation[] characterSetOrientations, double metricNormalizationFactor)
throws IOException {
byte[] data = structuredFieldReader.getNext(FONT_POSITION_SF);
int position = 0;
byte[] fpData = new byte[26];
int characterSetOrientationIndex = 0;
// Read data, ignoring bytes 0 - 2
for (int index = 3; index < data.length; index++) {
if (position < 22) {
// Build the font orientation record
fpData[position] = data[index];
if (position == 9) {
CharacterSetOrientation characterSetOrientation
= characterSetOrientations[characterSetOrientationIndex];
int xHeight = getSBIN(fpData, 2);
int capHeight = getSBIN(fpData, 4);
int ascHeight = getSBIN(fpData, 6);
int dscHeight = getSBIN(fpData, 8);
dscHeight = dscHeight * -1;
characterSetOrientation.setXHeight(
(int)Math.round(xHeight * metricNormalizationFactor));
characterSetOrientation.setCapHeight(
(int)Math.round(capHeight * metricNormalizationFactor));
characterSetOrientation.setAscender(
(int)Math.round(ascHeight * metricNormalizationFactor));
characterSetOrientation.setDescender(
(int)Math.round(dscHeight * metricNormalizationFactor));
}
} else if (position == 22) {
position = 0;
characterSetOrientationIndex++;
fpData[position] = data[index];
}
position++;
}
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected void processFontIndex(StructuredFieldReader structuredFieldReader,
CharacterSetOrientation cso, Map<String, String> codepage,
double metricNormalizationFactor)
throws IOException {
byte[] data = structuredFieldReader.getNext(FONT_INDEX_SF);
int position = 0;
byte[] gcgid = new byte[8];
byte[] fiData = new byte[20];
char lowest = 255;
char highest = 0;
String firstABCMismatch = null;
// Read data, ignoring bytes 0 - 2
for (int index = 3; index < data.length; index++) {
if (position < 8) {
gcgid[position] = data[index];
position++;
} else if (position < 27) {
fiData[position - 8] = data[index];
position++;
} else if (position == 27) {
fiData[position - 8] = data[index];
position = 0;
String gcgiString = new String(gcgid, AFPConstants.EBCIDIC_ENCODING);
String idx = codepage.get(gcgiString);
if (idx != null) {
char cidx = idx.charAt(0);
int width = getUBIN(fiData, 0);
int a = getSBIN(fiData, 10);
int b = getUBIN(fiData, 12);
int c = getSBIN(fiData, 14);
int abc = a + b + c;
int diff = Math.abs(abc - width);
if (diff != 0 && width != 0) {
double diffPercent = 100 * diff / (double)width;
if (diffPercent > 2) {
if (LOG.isTraceEnabled()) {
LOG.trace(gcgiString + ": "
+ a + " + " + b + " + " + c + " = " + (a + b + c)
+ " but found: " + width);
}
if (firstABCMismatch == null) {
firstABCMismatch = gcgiString;
}
}
}
if (cidx < lowest) {
lowest = cidx;
}
if (cidx > highest) {
highest = cidx;
}
int normalizedWidth = (int)Math.round(width * metricNormalizationFactor);
cso.setWidth(cidx, normalizedWidth);
}
}
}
cso.setFirstChar(lowest);
cso.setLastChar(highest);
if (LOG.isDebugEnabled() && firstABCMismatch != null) {
//Debug level because it usually is no problem.
LOG.debug("Font has metrics inconsitencies where A+B+C doesn't equal the"
+ " character increment. The first such character found: "
+ firstABCMismatch);
}
}
// in src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
protected Map<String, String> loadCodePage(String codePage, String encoding,
ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException {
// Create the HashMap to store code page information
Map<String, String> codePages = new HashMap<String, String>();
InputStream inputStream = null;
try {
inputStream = openInputStream(accessor, codePage.trim(), eventProducer);
StructuredFieldReader structuredFieldReader
= new StructuredFieldReader(inputStream);
byte[] data;
while ((data = structuredFieldReader.getNext(CHARACTER_TABLE_SF)) != null) {
int position = 0;
byte[] gcgiBytes = new byte[8];
byte[] charBytes = new byte[2];
// Read data, ignoring bytes 0 - 2
for (int index = 3; index < data.length; index++) {
if (position < 8) {
// Build the graphic character global identifier key
gcgiBytes[position] = data[index];
position++;
} else if (position == 9) {
// Set the character
charBytes[0] = data[index];
position++;
} else if (position == 10) {
position = 0;
// Set the character
charBytes[1] = data[index];
String gcgiString = new String(gcgiBytes,
AFPConstants.EBCIDIC_ENCODING);
String charString = new String(charBytes, encoding);
codePages.put(gcgiString, charString);
} else {
position++;
}
}
}
} catch (FileNotFoundException e) {
eventProducer.codePageNotFound(this, e);
} finally {
closeInputStream(inputStream);
}
return codePages;
}
// in src/java/org/apache/fop/afp/AFPStreamer.java
public DataStream createDataStream(AFPPaintingState paintingState) throws IOException {
this.tempFile = File.createTempFile(AFPDATASTREAM_TEMP_FILE_PREFIX, null);
this.documentFile = new RandomAccessFile(tempFile, "rw");
this.documentOutputStream = new BufferedOutputStream(
new FileOutputStream(documentFile.getFD()));
this.dataStream = factory.createDataStream(paintingState, documentOutputStream);
return dataStream;
}
// in src/java/org/apache/fop/afp/AFPStreamer.java
public void close() throws IOException {
Iterator it = pathResourceGroupMap.values().iterator();
while (it.hasNext()) {
StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next();
resourceGroup.close();
}
// close any open print-file resource group
if (printFileResourceGroup != null) {
printFileResourceGroup.close();
}
// write out document
writeToStream(outputStream);
outputStream.close();
if (documentOutputStream != null) {
documentOutputStream.close();
}
if (documentFile != null) {
documentFile.close();
}
// delete temporary file
tempFile.delete();
}
// in src/java/org/apache/fop/afp/AFPStreamer.java
public void writeToStream(OutputStream os) throws IOException {
// long start = System.currentTimeMillis();
int len = (int)documentFile.length();
int numChunks = len / BUFFER_SIZE;
int remainingChunkSize = len % BUFFER_SIZE;
byte[] buffer;
documentFile.seek(0);
if (numChunks > 0) {
buffer = new byte[BUFFER_SIZE];
for (int i = 0; i < numChunks; i++) {
documentFile.read(buffer, 0, BUFFER_SIZE);
os.write(buffer, 0, BUFFER_SIZE);
}
} else {
buffer = new byte[remainingChunkSize];
}
if (remainingChunkSize > 0) {
documentFile.read(buffer, 0, remainingChunkSize);
os.write(buffer, 0, remainingChunkSize);
}
os.flush();
// long end = System.currentTimeMillis();
// log.debug("writing time " + (end - start) + "ms");
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public DataStream createDataStream(AFPPaintingState paintingState, OutputStream outputStream)
throws IOException {
this.dataStream = streamer.createDataStream(paintingState);
streamer.setOutputStream(outputStream);
return this.dataStream;
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public void writeToStream() throws IOException {
streamer.close();
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public boolean tryIncludeObject(AFPDataObjectInfo dataObjectInfo) throws IOException {
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
updateResourceInfoUri(resourceInfo);
String objectName = includeNameMap.get(resourceInfo);
if (objectName != null) {
// an existing data resource so reference it by adding an include to the current page
includeObject(dataObjectInfo, objectName);
return true;
}
objectName = pageSegmentMap.get(resourceInfo);
if (objectName != null) {
// an existing data resource so reference it by adding an include to the current page
includePageSegment(dataObjectInfo, objectName);
return true;
}
return false;
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public void createObject(AFPDataObjectInfo dataObjectInfo) throws IOException {
if (tryIncludeObject(dataObjectInfo)) {
//Object has already been produced and is available by inclusion, so return early.
return;
}
AbstractNamedAFPObject namedObj = null;
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
boolean useInclude = true;
Registry.ObjectType objectType = null;
// new resource so create
if (dataObjectInfo instanceof AFPImageObjectInfo) {
AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo;
namedObj = dataObjectFactory.createImage(imageObjectInfo);
} else if (dataObjectInfo instanceof AFPGraphicsObjectInfo) {
AFPGraphicsObjectInfo graphicsObjectInfo = (AFPGraphicsObjectInfo)dataObjectInfo;
namedObj = dataObjectFactory.createGraphic(graphicsObjectInfo);
} else {
// natively embedded data object
namedObj = dataObjectFactory.createObjectContainer(dataObjectInfo);
objectType = dataObjectInfo.getObjectType();
useInclude = objectType != null && objectType.isIncludable();
}
AFPResourceLevel resourceLevel = resourceInfo.getLevel();
ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
useInclude &= resourceGroup != null;
if (useInclude) {
boolean usePageSegment = dataObjectInfo.isCreatePageSegment();
// if it is to reside within a resource group at print-file or external level
if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) {
if (usePageSegment) {
String pageSegmentName = "S10" + namedObj.getName().substring(3);
namedObj.setName(pageSegmentName);
PageSegment seg = new PageSegment(pageSegmentName);
seg.addObject(namedObj);
namedObj = seg;
}
// wrap newly created data object in a resource object
namedObj = dataObjectFactory.createResource(namedObj, resourceInfo, objectType);
}
// add data object into its resource group destination
resourceGroup.addObject(namedObj);
// create the include object
String objectName = namedObj.getName();
if (usePageSegment) {
includePageSegment(dataObjectInfo, objectName);
pageSegmentMap.put(resourceInfo, objectName);
} else {
includeObject(dataObjectInfo, objectName);
// record mapping of resource info to data object resource name
includeNameMap.put(resourceInfo, objectName);
}
} else {
// not to be included so inline data object directly into the current page
dataStream.getCurrentPage().addObject(namedObj);
}
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public void embedFont(AFPFont afpFont, CharacterSet charSet)
throws IOException {
if (afpFont.isEmbeddable()) {
//Embed fonts (char sets and code pages)
if (charSet.getResourceAccessor() != null) {
ResourceAccessor accessor = charSet.getResourceAccessor();
createIncludedResource(
charSet.getName(), accessor,
ResourceObject.TYPE_FONT_CHARACTER_SET);
createIncludedResource(
charSet.getCodePage(), accessor,
ResourceObject.TYPE_CODE_PAGE);
}
}
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public void createIncludedResource(String resourceName, ResourceAccessor accessor,
byte resourceObjectType) throws IOException {
URI uri;
try {
uri = new URI(resourceName.trim());
} catch (URISyntaxException e) {
throw new IOException("Could not create URI from resource name: " + resourceName
+ " (" + e.getMessage() + ")");
}
createIncludedResource(resourceName, uri, accessor, resourceObjectType);
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public void createIncludedResource(String resourceName, URI uri, ResourceAccessor accessor,
byte resourceObjectType) throws IOException {
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE);
AFPResourceInfo resourceInfo = new AFPResourceInfo();
resourceInfo.setLevel(resourceLevel);
resourceInfo.setName(resourceName);
resourceInfo.setUri(uri.toASCIIString());
String objectName = includeNameMap.get(resourceInfo);
if (objectName == null) {
if (log.isDebugEnabled()) {
log.debug("Adding included resource: " + resourceName);
}
IncludedResourceObject resourceContent = new IncludedResourceObject(
resourceName, accessor, uri);
ResourceObject resourceObject = factory.createResource(resourceName);
resourceObject.setDataObject(resourceContent);
resourceObject.setType(resourceObjectType);
ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
resourceGroup.addObject(resourceObject);
// record mapping of resource info to data object resource name
includeNameMap.put(resourceInfo, resourceName);
} else {
//skip, already created
}
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
public void createIncludedResourceFromExternal(final String resourceName,
final URI uri, final ResourceAccessor accessor) throws IOException {
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE);
AFPResourceInfo resourceInfo = new AFPResourceInfo();
resourceInfo.setLevel(resourceLevel);
resourceInfo.setName(resourceName);
resourceInfo.setUri(uri.toASCIIString());
String resource = includeNameMap.get(resourceInfo);
if (resource == null) {
ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
//resourceObject delegates write commands to copyNamedResource()
//The included resource may already be wrapped in a resource object
AbstractNamedAFPObject resourceObject = new AbstractNamedAFPObject(null) {
@Override
protected void writeContent(OutputStream os) throws IOException {
InputStream inputStream = null;
try {
inputStream = accessor.createInputStream(uri);
BufferedInputStream bin = new BufferedInputStream(inputStream);
AFPResourceUtil.copyNamedResource(resourceName, bin, os);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
//bypass super.writeStart
@Override
protected void writeStart(OutputStream os) throws IOException { }
//bypass super.writeEnd
@Override
protected void writeEnd(OutputStream os) throws IOException { }
};
resourceGroup.addObject(resourceObject);
includeNameMap.put(resourceInfo, resourceName);
}
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
Override
protected void writeContent(OutputStream os) throws IOException {
InputStream inputStream = null;
try {
inputStream = accessor.createInputStream(uri);
BufferedInputStream bin = new BufferedInputStream(inputStream);
AFPResourceUtil.copyNamedResource(resourceName, bin, os);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
// in src/java/org/apache/fop/afp/AFPResourceManager.java
Override
protected void writeStart(OutputStream os) throws IOException { }
// in src/java/org/apache/fop/afp/AFPResourceManager.java
Override
protected void writeEnd(OutputStream os) throws IOException { }
// in src/java/org/apache/fop/afp/modca/MapImageObject.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[11];
copySF(data, Type.MAP, Category.IMAGE);
int tripletLen = getTripletDataLength();
byte[] len = BinaryUtils.convert(10 + tripletLen, 2);
data[1] = len[0];
data[2] = len[1];
len = BinaryUtils.convert(2 + tripletLen, 2);
data[9] = len[0];
data[10] = len[1];
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/MapPageSegment.java
public void writeToStream(OutputStream os) throws IOException {
int count = getPageSegments().size();
byte groupLength = 0x0C;
int groupsLength = count * groupLength;
byte[] data = new byte[groupsLength + 12 + 1];
data[0] = 0x5A;
// Set the total record length
byte[] rl1 = BinaryUtils.convert(data.length - 1, 2); //Ignore the
// first byte in
// the length
data[1] = rl1[0];
data[2] = rl1[1];
// Structured field ID for a MPS
data[3] = (byte) 0xD3;
data[4] = Type.MIGRATION;
data[5] = Category.PAGE_SEGMENT;
data[6] = 0x00; // Flags
data[7] = 0x00; // Reserved
data[8] = 0x00; // Reserved
data[9] = groupLength;
data[10] = 0x00; // Reserved
data[11] = 0x00; // Reserved
data[12] = 0x00; // Reserved
int pos = 13;
Iterator iter = this.pageSegments.iterator();
while (iter.hasNext()) {
pos += 4;
String name = (String)iter.next();
try {
byte[] nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
System.arraycopy(nameBytes, 0, data, pos, nameBytes.length);
} catch (UnsupportedEncodingException usee) {
LOG.error("UnsupportedEncodingException translating the name "
+ name);
}
pos += 8;
}
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/InvokeMediumMap.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.MAP, Category.MEDIUM_MAP);
// Set the total record length
byte[] len = BinaryUtils.convert(16, 2); //Ignore first byte
data[1] = len[0];
data[2] = len[1];
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/StreamedResourceGroup.java
public void addObject(AbstractNamedAFPObject namedObject) throws IOException {
if (!started) {
writeStart(os);
started = true;
}
try {
namedObject.writeToStream(os);
} finally {
os.flush();
}
}
// in src/java/org/apache/fop/afp/modca/StreamedResourceGroup.java
public void close() throws IOException {
writeEnd(os);
complete = true;
}
// in src/java/org/apache/fop/afp/modca/GraphicsObject.java
Override
protected void writeStart(OutputStream os) throws IOException {
super.writeStart(os);
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.GRAPHICS);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/GraphicsObject.java
Override
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
writeObjects(objects, os);
}
// in src/java/org/apache/fop/afp/modca/GraphicsObject.java
Override
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.GRAPHICS);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PreprocessPresentationObject.java
public void writeStart(OutputStream os) throws IOException {
super.writeStart(os);
byte[] data = new byte[9];
copySF(data, Type.PROCESS, Category.DATA_RESOURCE);
byte[] l = BinaryUtils.convert(19 + getTripletDataLength(), 2);
data[1] = l[0]; // Length byte 1
data[2] = l[1]; // Length byte 1
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PreprocessPresentationObject.java
public void writeContent(OutputStream os) throws IOException {
byte[] data = new byte[12];
byte[] l = BinaryUtils.convert(12 + getTripletDataLength(), 2);
data[0] = l[0]; // RGLength
data[1] = l[1]; // RGLength
data[2] = objType; // ObjType
data[3] = 0x00; // Reserved
data[4] = 0x00; // Reserved
data[5] = objOrent; // ObjOrent
if (objXOffset > 0) {
byte[] xOff = BinaryUtils.convert(objYOffset, 3);
data[6] = xOff[0]; // XocaOset (not specified)
data[7] = xOff[1]; // XocaOset
data[8] = xOff[2]; // XocaOset
} else {
data[6] = (byte)0xFF; // XocaOset (not specified)
data[7] = (byte)0xFF; // XocaOset
data[8] = (byte)0xFF; // XocaOset
}
if (objYOffset > 0) {
byte[] yOff = BinaryUtils.convert(objYOffset, 3);
data[9] = yOff[0]; // YocaOset (not specified)
data[10] = yOff[1]; // YocaOset
data[11] = yOff[2]; // YocaOset
} else {
data[9] = (byte)0xFF; // YocaOset (not specified)
data[10] = (byte)0xFF; // YocaOset
data[11] = (byte)0xFF; // YocaOset
}
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/ResourceObject.java
protected void writeStart(OutputStream os) throws IOException {
super.writeStart(os);
byte[] data = new byte[19];
copySF(data, Type.BEGIN, Category.NAME_RESOURCE);
// Set the total record length
int tripletDataLength = getTripletDataLength();
byte[] len = BinaryUtils.convert(18 + tripletDataLength, 2);
data[1] = len[0]; // Length byte 1
data[2] = len[1]; // Length byte 2
// Set reserved bits
data[17] = 0x00; // Reserved
data[18] = 0x00; // Reserved
os.write(data);
// Write triplets
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/ResourceObject.java
protected void writeContent(OutputStream os) throws IOException {
if (namedObject != null) {
namedObject.writeToStream(os);
}
}
// in src/java/org/apache/fop/afp/modca/ResourceObject.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.NAME_RESOURCE);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/IMImageObject.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
if (imageOutputControl != null) {
imageOutputControl.writeToStream(os);
}
if (imageInputDescriptor != null) {
imageInputDescriptor.writeToStream(os);
}
if (imageCellPosition != null) {
imageCellPosition.writeToStream(os);
}
if (imageRasterData != null) {
imageRasterData.writeToStream(os);
}
}
// in src/java/org/apache/fop/afp/modca/IMImageObject.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.IM_IMAGE);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/IMImageObject.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.IM_IMAGE);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/IncludePageSegment.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[23]; //(9 +14)
copySF(data, Type.INCLUDE, Category.PAGE_SEGMENT);
// Set the total record length
byte[] len = BinaryUtils.convert(22, 2); //Ignore first byte
data[1] = len[0];
data[2] = len[1];
byte[] xPos = BinaryUtils.convert(x, 3);
data[17] = xPos[0]; // x coordinate
data[18] = xPos[1];
data[19] = xPos[2];
byte[] yPos = BinaryUtils.convert(y, 3);
data[20] = yPos[0]; // y coordinate
data[21] = yPos[1];
data[22] = yPos[2];
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/MapContainerData.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[11];
copySF(data, Type.MAP, Category.OBJECT_CONTAINER);
int tripletLen = getTripletDataLength();
byte[] len = BinaryUtils.convert(10 + tripletLen, 2);
data[1] = len[0];
data[2] = len[1];
len = BinaryUtils.convert(2 + tripletLen, 2);
data[9] = len[0];
data[10] = len[1];
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/TagLogicalElement.java
public void writeToStream(OutputStream os) throws IOException {
setFullyQualifiedName(
FullyQualifiedNameTriplet.TYPE_ATTRIBUTE_GID,
FullyQualifiedNameTriplet.FORMAT_CHARSTR,
name);
setAttributeValue(value);
setAttributeQualifier(tleID, 1);
byte[] data = new byte[SF_HEADER_LENGTH];
copySF(data, Type.ATTRIBUTE, Category.PROCESS_ELEMENT);
int tripletDataLength = getTripletDataLength();
byte[] l = BinaryUtils.convert(data.length + tripletDataLength - 1, 2);
data[1] = l[0];
data[2] = l[1];
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/PresentationEnvironmentControl.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[11];
copySF(data, Type.CONTROL, Category.DOCUMENT);
int tripletDataLen = getTripletDataLength();
byte[] len = BinaryUtils.convert(10 + tripletDataLen);
data[1] = len[0];
data[2] = len[1];
data[9] = 0x00; // Reserved; must be zero
data[10] = 0x00; // Reserved; must be zero
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/ResourceGroup.java
public void addObject(AbstractNamedAFPObject namedObject) throws IOException {
resourceSet.add(namedObject);
}
// in src/java/org/apache/fop/afp/modca/ResourceGroup.java
public void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.RESOURCE_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ResourceGroup.java
public void writeContent(OutputStream os) throws IOException {
Iterator it = resourceSet.iterator();
while (it.hasNext()) {
Object object = it.next();
if (object instanceof Streamable) {
Streamable streamableObject = (Streamable)object;
streamableObject.writeToStream(os);
}
}
}
// in src/java/org/apache/fop/afp/modca/ResourceGroup.java
public void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.RESOURCE_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PresentationTextObject.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.PRESENTATION_TEXT);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PresentationTextObject.java
protected void writeContent(OutputStream os) throws IOException {
writeObjects(this.presentationTextDataList, os);
}
// in src/java/org/apache/fop/afp/modca/PresentationTextObject.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.PRESENTATION_TEXT);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ObjectEnvironmentGroup.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.OBJECT_ENVIRONMENT_GROUP);
int tripletDataLength = getTripletDataLength();
int sfLen = data.length + tripletDataLength - 1;
byte[] len = BinaryUtils.convert(sfLen, 2);
data[1] = len[0];
data[2] = len[1];
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/ObjectEnvironmentGroup.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
if (presentationEnvironmentControl != null) {
presentationEnvironmentControl.writeToStream(os);
}
if (objectAreaDescriptor != null) {
objectAreaDescriptor.writeToStream(os);
}
if (objectAreaPosition != null) {
objectAreaPosition.writeToStream(os);
}
if (mapImageObject != null) {
mapImageObject.writeToStream(os);
}
if (mapContainerData != null) {
mapContainerData.writeToStream(os);
}
if (mapDataResource != null) {
mapDataResource.writeToStream(os);
}
if (dataDescriptor != null) {
dataDescriptor.writeToStream(os);
}
}
// in src/java/org/apache/fop/afp/modca/ObjectEnvironmentGroup.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.OBJECT_ENVIRONMENT_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/IncludeObject.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[36];
super.copySF(data, Type.INCLUDE, Category.DATA_RESOURCE);
// Set the total record length
int tripletDataLength = getTripletDataLength();
byte[] len = BinaryUtils.convert(35 + tripletDataLength, 2); //Ignore first byte
data[1] = len[0];
data[2] = len[1];
data[17] = 0x00; // reserved
data[18] = objectType;
writeOsetTo(data, 19, xoaOset);
writeOsetTo(data, 22, yoaOset);
oaOrent.writeTo(data, 25);
writeOsetTo(data, 29, xocaOset);
writeOsetTo(data, 32, yocaOset);
// RefCSys (Reference coordinate system)
data[35] = 0x01; // Page or overlay coordinate system
// Write structured field data
os.write(data);
// Write triplet for FQN internal/external object reference
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/ImageObject.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.IMAGE);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ImageObject.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
if (imageSegment != null) {
final byte[] dataHeader = new byte[9];
copySF(dataHeader, SF_CLASS, Type.DATA, Category.IMAGE);
final int lengthOffset = 1;
// TODO save memory!
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageSegment.writeToStream(baos);
byte[] data = baos.toByteArray();
writeChunksToStream(data, dataHeader, lengthOffset, MAX_DATA_LEN, os);
}
}
// in src/java/org/apache/fop/afp/modca/ImageObject.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.IMAGE);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java
public void writeToStream(OutputStream os) throws IOException {
byte[] headerData = new byte[9];
copySF(headerData, Type.DESCRIPTOR, Category.GRAPHICS);
byte[] drawingOrderSubsetData = getDrawingOrderSubset();
byte[] windowSpecificationData = getWindowSpecification();
byte[] len = BinaryUtils.convert(headerData.length
+ drawingOrderSubsetData.length
+ windowSpecificationData.length - 1, 2);
headerData[1] = len[0];
headerData[2] = len[1];
os.write(headerData);
os.write(drawingOrderSubsetData);
os.write(windowSpecificationData);
}
// in src/java/org/apache/fop/afp/modca/ObjectAreaDescriptor.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[9];
copySF(data, Type.DESCRIPTOR, Category.OBJECT_AREA);
addTriplet(new DescriptorPositionTriplet(OBJECT_AREA_POSITION_ID));
addTriplet(new MeasurementUnitsTriplet(widthRes, heightRes));
addTriplet(new ObjectAreaSizeTriplet(width, height));
/* not allowed in Presentation Interchange Set 1
addTriplet(new PresentationSpaceResetMixingTriplet(
PresentationSpaceResetMixingTriplet.NOT_RESET));
*/
int tripletDataLength = getTripletDataLength();
byte[] len = BinaryUtils.convert(data.length + tripletDataLength - 1, 2);
data[1] = len[0]; // Length
data[2] = len[1];
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[22];
copySF(data, Type.DESCRIPTOR, Category.IMAGE);
// SF length
byte[] len = BinaryUtils.convert(data.length - 1, 2);
data[1] = len[0];
data[2] = len[1];
byte[] x = BinaryUtils.convert(widthRes, 2);
data[10] = x[0];
data[11] = x[1];
byte[] y = BinaryUtils.convert(heightRes, 2);
data[12] = y[0];
data[13] = y[1];
byte[] w = BinaryUtils.convert(width, 2);
data[14] = w[0];
data[15] = w[1];
byte[] h = BinaryUtils.convert(height, 2);
data[16] = h[0];
data[17] = h[1];
//IOCA Function Set Field
data[18] = (byte)0xF7; // ID = Set IOCA Function Set
data[19] = 0x02; // Length
data[20] = 0x01; // Category = Function set identifier
data[21] = functionSet;
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ResourceEnvironmentGroup.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.RESOURCE_ENVIROMENT_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ResourceEnvironmentGroup.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.RESOURCE_ENVIROMENT_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ResourceEnvironmentGroup.java
protected void writeContent(OutputStream os) throws IOException {
writeObjects(mapDataResources, os);
writeObjects(mapPageOverlays, os);
writeObjects(preProcessPresentationObjects, os);
}
// in src/java/org/apache/fop/afp/modca/AbstractResourceEnvironmentGroupContainer.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
if (resourceEnvironmentGroup != null) {
resourceEnvironmentGroup.writeToStream(os);
}
}
// in src/java/org/apache/fop/afp/modca/AxisOrientation.java
public void writeTo(OutputStream stream) throws IOException {
byte[] data = new byte[4];
writeTo(data, 0);
stream.write(data);
}
// in src/java/org/apache/fop/afp/modca/Document.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.DOCUMENT);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/Document.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.DOCUMENT);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/AbstractResourceGroupContainer.java
Override
public void writeToStream(OutputStream os) throws IOException {
if (!started) {
writeStart(os);
started = true;
}
writeContent(os);
if (complete) {
writeEnd(os);
}
}
// in src/java/org/apache/fop/afp/modca/AbstractResourceGroupContainer.java
Override
protected void writeObjects(Collection/*<AbstractAFPObject>*/ objects, OutputStream os)
throws IOException {
writeObjects(objects, os, false);
}
// in src/java/org/apache/fop/afp/modca/AbstractResourceGroupContainer.java
protected void writeObjects(Collection/*<AbstractAFPObject>*/ objects, OutputStream os,
boolean forceWrite) throws IOException {
if (objects != null && objects.size() > 0) {
Iterator it = objects.iterator();
while (it.hasNext()) {
AbstractAFPObject ao = (AbstractAFPObject)it.next();
if (forceWrite || canWrite(ao)) {
ao.writeToStream(os);
it.remove();
} else {
break;
}
}
}
}
// in src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[21];
copySF(data, Type.DESCRIPTOR, Category.OBJECT_CONTAINER);
// SF length
byte[] len = BinaryUtils.convert(data.length - 1, 2);
data[1] = len[0];
data[2] = len[1];
// XocBase = 10 inches
data[9] = 0x00;
// YocBase = 10 inches
data[10] = 0x00;
// XocUnits
byte[] xdpi = BinaryUtils.convert(widthRes * 10, 2);
data[11] = xdpi[0];
data[12] = xdpi[1];
// YocUnits
byte[] ydpi = BinaryUtils.convert(heightRes * 10, 2);
data[13] = ydpi[0];
data[14] = ydpi[1];
// XocSize
byte[] xsize = BinaryUtils.convert(width, 3);
data[15] = xsize[0];
data[16] = xsize[1];
data[17] = xsize[2];
// YocSize
byte[] ysize = BinaryUtils.convert(height, 3);
data[18] = ysize[0];
data[19] = ysize[1];
data[20] = ysize[2];
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/AbstractDataObject.java
protected void writeStart(OutputStream os) throws IOException {
setStarted(true);
}
// in src/java/org/apache/fop/afp/modca/AbstractDataObject.java
protected void writeContent(OutputStream os) throws IOException {
writeTriplets(os);
if (objectEnvironmentGroup != null) {
objectEnvironmentGroup.writeToStream(os);
}
}
// in src/java/org/apache/fop/afp/modca/PresentationTextDescriptor.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[23];
copySF(data, Type.MIGRATION, Category.PRESENTATION_TEXT);
data[1] = 0x00; // length
data[2] = 0x16;
data[9] = 0x00;
data[10] = 0x00;
byte[] xdpi = BinaryUtils.convert(widthRes * 10, 2);
data[11] = xdpi[0]; // xdpi
data[12] = xdpi[1];
byte[] ydpi = BinaryUtils.convert(heightRes * 10, 2);
data[13] = ydpi[0]; // ydpi
data[14] = ydpi[1];
byte[] x = BinaryUtils.convert(width, 3);
data[15] = x[0];
data[16] = x[1];
data[17] = x[2];
byte[] y = BinaryUtils.convert(height, 3);
data[18] = y[0];
data[19] = y[1];
data[20] = y[2];
data[21] = 0x00;
data[22] = 0x00;
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ActiveEnvironmentGroup.java
public void writeContent(OutputStream os) throws IOException {
super.writeTriplets(os);
writeObjects(mapCodedFonts, os);
writeObjects(mapDataResources, os);
writeObjects(mapPageOverlays, os);
writeObjects(mapPageSegments, os);
if (pageDescriptor != null) {
pageDescriptor.writeToStream(os);
}
if (objectAreaDescriptor != null && objectAreaPosition != null) {
objectAreaDescriptor.writeToStream(os);
objectAreaPosition.writeToStream(os);
}
if (presentationTextDataDescriptor != null) {
presentationTextDataDescriptor.writeToStream(os);
}
}
// in src/java/org/apache/fop/afp/modca/ActiveEnvironmentGroup.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.ACTIVE_ENVIRONMENT_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ActiveEnvironmentGroup.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.ACTIVE_ENVIRONMENT_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/Overlay.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.OVERLAY);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/Overlay.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
getActiveEnvironmentGroup().writeToStream(os);
writeObjects(objects, os);
}
// in src/java/org/apache/fop/afp/modca/Overlay.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.OVERLAY);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/IncludePageOverlay.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[25]; //(9 +16)
copySF(data, Type.INCLUDE, Category.PAGE_OVERLAY);
// Set the total record length
byte[] len = BinaryUtils.convert(24, 2); //Ignore first byte
data[1] = len[0];
data[2] = len[1];
byte[] xPos = BinaryUtils.convert(x, 3);
data[17] = xPos[0]; // x coordinate
data[18] = xPos[1];
data[19] = xPos[2];
byte[] yPos = BinaryUtils.convert(y, 3);
data[20] = yPos[0]; // y coordinate
data[21] = yPos[1];
data[22] = yPos[2];
switch (orientation) {
case 90:
data[23] = 0x2D;
data[24] = 0x00;
break;
case 180:
data[23] = 0x5A;
data[24] = 0x00;
break;
case 270:
data[23] = (byte) 0x87;
data[24] = 0x00;
break;
default:
data[23] = 0x00;
data[24] = 0x00;
break;
}
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
public void writeToStream(OutputStream os) throws IOException {
InputStream in = resourceAccessor.createInputStream(this.uri);
try {
AFPResourceUtil.copyResourceFile(in, os);
} finally {
IOUtils.closeQuietly(in);
}
}
// in src/java/org/apache/fop/afp/modca/AbstractPageObject.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
writeObjects(this.objects, os);
}
// in src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java
protected void writeTriplets(OutputStream os) throws IOException {
if (hasTriplets()) {
writeObjects(triplets, os);
triplets = null; // gc
}
}
// in src/java/org/apache/fop/afp/modca/PresentationTextData.java
public void writeToStream(OutputStream os) throws IOException {
assert getBytesAvailable() >= 0;
byte[] data = baos.toByteArray();
byte[] size = BinaryUtils.convert(data.length - 1, 2);
data[1] = size[0];
data[2] = size[1];
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/NoOperation.java
public void writeToStream(OutputStream os) throws IOException {
byte[] contentData = content.getBytes(AFPConstants.EBCIDIC_ENCODING);
int contentLen = contentData.length;
// packet maximum of 32759 bytes
if (contentLen > MAX_DATA_LEN) {
contentLen = MAX_DATA_LEN;
}
byte[] data = new byte[9 + contentLen];
data[0] = 0x5A;
// Set the total record length
byte[] rl1 = BinaryUtils.convert(8 + contentLen, 2);
//Ignore first byte
data[1] = rl1[0];
data[2] = rl1[1];
// Structured field ID for a NOP
data[3] = (byte) 0xD3;
data[4] = (byte) 0xEE;
data[5] = (byte) 0xEE;
data[6] = 0x00; // Reserved
data[7] = 0x00; // Reserved
data[8] = 0x00; // Reserved
int pos = 9;
for (int i = 0; i < contentLen; i++) {
data[pos++] = contentData[i];
}
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/MeasurementUnitsTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = TEN_INCHES; // XoaBase
data[3] = TEN_INCHES; // YoaBase
byte[] xUnits = BinaryUtils.convert(xRes * 10, 2);
data[4] = xUnits[0]; // XoaUnits (x units per unit base)
data[5] = xUnits[1];
byte[] yUnits = BinaryUtils.convert(yRes * 10, 2);
data[6] = yUnits[0]; // YoaUnits (y units per unit base)
data[7] = yUnits[1];
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/AttributeValueTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = super.getData();
data[2] = 0x00; // Reserved
data[3] = 0x00; // Reserved
// convert name and value to ebcdic
byte[] tleByteValue = null;
try {
tleByteValue = attVal.getBytes(AFPConstants.EBCIDIC_ENCODING);
} catch (UnsupportedEncodingException usee) {
tleByteValue = attVal.getBytes();
throw new IllegalArgumentException(attVal + " encoding failed");
}
System.arraycopy(tleByteValue, 0, data, 4, tleByteValue.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/ObjectAreaSizeTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = type; // SizeType
byte[] xOASize = BinaryUtils.convert(x, 3);
data[3] = xOASize[0]; // XoaSize - Object area extent for X axis
data[4] = xOASize[1];
data[5] = xOASize[2];
byte[] yOASize = BinaryUtils.convert(y, 3);
data[6] = yOASize[0]; // YoaSize - Object area extent for Y axis
data[7] = yOASize[1];
data[8] = yOASize[2];
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/CommentTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
byte[] strData = commentString.getBytes(AFPConstants.EBCIDIC_ENCODING);
System.arraycopy(strData, 0, data, 2, strData.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/DescriptorPositionTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = oapId;
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/ResourceObjectTypeTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = objectType;
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/ObjectByteExtentTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
byte[] extData = BinaryUtils.convert(byteExt, 4);
System.arraycopy(extData, 0, data, 2, extData.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/ObjectClassificationTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = 0x00; // reserved (must be zero)
data[3] = objectClass; // ObjClass
data[4] = 0x00; // reserved (must be zero)
data[5] = 0x00; // reserved (must be zero)
// StrucFlgs - Information on the structure of the object container
byte[] structureFlagsBytes
= getStructureFlagsAsBytes(dataInContainer, containerHasOEG, dataInOCD);
data[6] = structureFlagsBytes[0];
data[7] = structureFlagsBytes[1];
byte[] objectIdBytes = objectType.getOID();
// RegObjId - MOD:CA-registered ASN.1 OID for object type (8-23)
System.arraycopy(objectIdBytes, 0, data, 8, objectIdBytes.length);
// ObjTpName - name of object type (24-55)
byte[] objectTypeNameBytes;
objectTypeNameBytes
= StringUtils.rpad(objectType.getName(), ' ', OBJECT_TYPE_NAME_LEN).getBytes(
AFPConstants.EBCIDIC_ENCODING);
System.arraycopy(objectTypeNameBytes, 0, data, 24, objectTypeNameBytes.length);
// ObjLev - release level or version number of object type (56-63)
byte[] objectLevelBytes;
objectLevelBytes = StringUtils.rpad(objectLevel, ' ', OBJECT_LEVEL_LEN).getBytes(
AFPConstants.EBCIDIC_ENCODING);
System.arraycopy(objectLevelBytes, 0, data, 56, objectLevelBytes.length);
// CompName - name of company or organization that owns object definition (64-95)
byte[] companyNameBytes;
companyNameBytes = StringUtils.rpad(companyName, ' ', COMPANY_NAME_LEN).getBytes(
AFPConstants.EBCIDIC_ENCODING);
System.arraycopy(companyNameBytes, 0, data, 64, companyNameBytes.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceMixingRulesTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
System.arraycopy(rules, 0, data, 2, rules.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/MappingOptionTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = mapValue;
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceResetMixingTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = backgroundMixFlag;
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/AttributeQualifierTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
byte[] id = BinaryUtils.convert(seqNumber, 4);
System.arraycopy(id, 0, data, 2, id.length);
byte[] level = BinaryUtils.convert(levNumber, 4);
System.arraycopy(level, 0, data, 6, level.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/ExtendedResourceLocalIdentifierTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = type;
byte[] resLID = BinaryUtils.convert(localId, 4); // 4 bytes
System.arraycopy(resLID, 0, data, 3, resLID.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/triplets/FullyQualifiedNameTriplet.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = getData();
data[2] = type;
data[3] = format;
// FQName
byte[] fqNameBytes;
String encoding = AFPConstants.EBCIDIC_ENCODING;
if (format == FORMAT_URL) {
encoding = AFPConstants.US_ASCII_ENCODING;
}
try {
fqNameBytes = fqName.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException(
encoding + " encoding failed");
}
System.arraycopy(fqNameBytes, 0, data, 4, fqNameBytes.length);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PageDescriptor.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[24];
copySF(data, Type.DESCRIPTOR, Category.PAGE);
data[2] = 0x17;
// XpgBase
data[9] = 0x00; // XpgBase = 10 inches
// YpgBase
data[10] = 0x00; // YpgBase = 10 inches
// XpgUnits
byte[] xdpi = BinaryUtils.convert(widthRes * 10, 2);
data[11] = xdpi[0];
data[12] = xdpi[1];
// YpgUnits
byte[] ydpi = BinaryUtils.convert(heightRes * 10, 2);
data[13] = ydpi[0];
data[14] = ydpi[1];
// XpgSize
byte[] x = BinaryUtils.convert(width, 3);
data[15] = x[0];
data[16] = x[1];
data[17] = x[2];
// YpgSize
byte[] y = BinaryUtils.convert(height, 3);
data[18] = y[0];
data[19] = y[1];
data[20] = y[2];
data[21] = 0x00; // Reserved
data[22] = 0x00; // Reserved
data[23] = 0x00; // Reserved
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/MapCodedFont.java
public void writeToStream(OutputStream os) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] startData = new byte[9];
copySF(startData, Type.MAP, Category.CODED_FONT);
baos.write(startData);
Iterator iter = fontList.iterator();
while (iter.hasNext()) {
FontDefinition fd = (FontDefinition) iter.next();
// Start of repeating groups (occurs 1 to 254)
baos.write(0x00);
if (fd.scale == 0) {
// Raster Font
baos.write(0x22); // Length of 34
} else {
// Outline Font
baos.write(0x3A); // Length of 58
}
// Font Character Set Name Reference
baos.write(0x0C); //TODO Relax requirement for 8 chars in the name
baos.write(0x02);
baos.write((byte) 0x86);
baos.write(0x00);
baos.write(fd.characterSet);
// Font Code Page Name Reference
baos.write(0x0C); //TODO Relax requirement for 8 chars in the name
baos.write(0x02);
baos.write((byte) 0x85);
baos.write(0x00);
baos.write(fd.codePage);
//TODO idea: for CIDKeyed fonts, maybe hint at Unicode encoding with X'50' triplet
//to allow font substitution.
// Character Rotation
baos.write(0x04);
baos.write(0x26);
baos.write(fd.orientation);
baos.write(0x00);
// Resource Local Identifier
baos.write(0x04);
baos.write(0x24);
baos.write(0x05);
baos.write(fd.fontReferenceKey);
if (fd.scale != 0) {
// Outline Font (triplet '1F')
baos.write(0x14);
baos.write(0x1F);
baos.write(0x00);
baos.write(0x00);
baos.write(BinaryUtils.convert(fd.scale, 2)); // Height
baos.write(new byte[] {0x00, 0x00}); // Width
baos.write(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00});
baos.write(0x60);
// Outline Font (triplet '5D')
baos.write(0x04);
baos.write(0x5D);
baos.write(BinaryUtils.convert(fd.scale, 2));
}
}
byte[] data = baos.toByteArray();
// Set the total record length
byte[] rl1 = BinaryUtils.convert(data.length - 1, 2);
data[1] = rl1[0];
data[2] = rl1[1];
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/AbstractEnvironmentGroup.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
}
// in src/java/org/apache/fop/afp/modca/ObjectContainer.java
protected void writeStart(OutputStream os) throws IOException {
byte[] headerData = new byte[17];
copySF(headerData, Type.BEGIN, Category.OBJECT_CONTAINER);
// Set the total record length
int containerLen = headerData.length + getTripletDataLength() - 1;
byte[] len = BinaryUtils.convert(containerLen, 2);
headerData[1] = len[0]; // Length byte 1
headerData[2] = len[1]; // Length byte 2
os.write(headerData);
}
// in src/java/org/apache/fop/afp/modca/ObjectContainer.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os); // write triplets and OEG
// write OCDs
byte[] dataHeader = new byte[9];
copySF(dataHeader, SF_CLASS, Type.DATA, Category.OBJECT_CONTAINER);
final int lengthOffset = 1;
if (data != null) {
writeChunksToStream(data, dataHeader, lengthOffset, MAX_DATA_LEN, os);
}
}
// in src/java/org/apache/fop/afp/modca/ObjectContainer.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.OBJECT_CONTAINER);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PageGroup.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.PAGE_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PageGroup.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.PAGE_GROUP);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/ObjectAreaPosition.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[33];
copySF(data, Type.POSITION, Category.OBJECT_AREA);
byte[] len = BinaryUtils.convert(32, 2);
data[1] = len[0]; // Length
data[2] = len[1];
data[9] = 0x01; // OAPosID = 1
data[10] = 0x17; // RGLength = 23
byte[] xcoord = BinaryUtils.convert(x, 3);
data[11] = xcoord[0]; // XoaOSet
data[12] = xcoord[1];
data[13] = xcoord[2];
byte[] ycoord = BinaryUtils.convert(y, 3);
data[14] = ycoord[0]; // YoaOSet
data[15] = ycoord[1];
data[16] = ycoord[2];
byte xorient = (byte)(rotation / 2);
data[17] = xorient; // XoaOrent
byte yorient = (byte)(rotation / 2 + 45);
data[19] = yorient; // YoaOrent
byte[] xoffset = BinaryUtils.convert(xOffset, 3);
data[22] = xoffset[0]; // XocaOSet
data[23] = xoffset[1];
data[24] = xoffset[2];
byte[] yoffset = BinaryUtils.convert(yOffset, 3);
data[25] = yoffset[0]; // YocaOSet
data[26] = yoffset[1];
data[27] = yoffset[2];
data[28] = 0x00; // XocaOrent
data[29] = 0x00;
data[30] = 0x2D; // YocaOrent
data[31] = 0x00;
data[32] = this.refCSys; // RefCSys
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PageSegment.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.PAGE_SEGMENT);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PageSegment.java
protected void writeContent(OutputStream os) throws IOException {
super.writeContent(os);
writeObjects(objects, os);
}
// in src/java/org/apache/fop/afp/modca/PageSegment.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.PAGE_SEGMENT);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/AbstractAFPObject.java
protected <S extends Streamable> void writeObjects(Collection<S> objects, OutputStream os)
throws IOException {
if (objects != null) {
Iterator<S> it = objects.iterator();
while (it.hasNext()) {
Streamable s = it.next();
s.writeToStream(os);
it.remove(); // once written, immediately remove the object
}
}
}
// in src/java/org/apache/fop/afp/modca/AbstractAFPObject.java
protected static void writeChunksToStream(byte[] data, byte[] dataHeader,
int lengthOffset, int maxChunkLength, OutputStream os) throws IOException {
int dataLength = data.length;
int numFullChunks = dataLength / maxChunkLength;
int lastChunkLength = dataLength % maxChunkLength;
int headerLen = dataHeader.length - lengthOffset;
// length field is just before data so do not include in data length
if (headerLen == 2) {
headerLen = 0;
}
byte[] len;
int off = 0;
if (numFullChunks > 0) {
// write out full data chunks
len = BinaryUtils.convert(headerLen + maxChunkLength, 2);
dataHeader[lengthOffset] = len[0]; // Length byte 1
dataHeader[lengthOffset + 1] = len[1]; // Length byte 2
for (int i = 0; i < numFullChunks; i++, off += maxChunkLength) {
os.write(dataHeader);
os.write(data, off, maxChunkLength);
}
}
if (lastChunkLength > 0) {
// write last data chunk
len = BinaryUtils.convert(headerLen + lastChunkLength, 2);
dataHeader[lengthOffset] = len[0]; // Length byte 1
dataHeader[lengthOffset + 1] = len[1]; // Length byte 2
os.write(dataHeader);
os.write(data, off, lastChunkLength);
}
}
// in src/java/org/apache/fop/afp/modca/AbstractStructuredObject.java
protected void writeStart(OutputStream os) throws IOException {
}
// in src/java/org/apache/fop/afp/modca/AbstractStructuredObject.java
protected void writeEnd(OutputStream os) throws IOException {
}
// in src/java/org/apache/fop/afp/modca/AbstractStructuredObject.java
protected void writeContent(OutputStream os) throws IOException {
}
// in src/java/org/apache/fop/afp/modca/AbstractStructuredObject.java
public void writeToStream(OutputStream os) throws IOException {
writeStart(os);
writeContent(os);
writeEnd(os);
}
// in src/java/org/apache/fop/afp/modca/MapPageOverlay.java
public void writeToStream(OutputStream os) throws IOException {
int oLayCount = getOverlays().size();
int recordlength = oLayCount * 18;
byte[] data = new byte[recordlength + 9];
data[0] = 0x5A;
// Set the total record length
byte[] rl1 = BinaryUtils.convert(recordlength + 8, 2); //Ignore the
// first byte in
// the length
data[1] = rl1[0];
data[2] = rl1[1];
// Structured field ID for a MPO
data[3] = (byte) 0xD3;
data[4] = (byte) Type.MAP;
data[5] = (byte) Category.PAGE_OVERLAY;
data[6] = 0x00; // Reserved
data[7] = 0x00; // Reserved
data[8] = 0x00; // Reserved
int pos = 8;
//For each overlay
byte olayref = 0x00;
for (int i = 0; i < oLayCount; i++) {
olayref = (byte) (olayref + 1);
data[++pos] = 0x00;
data[++pos] = 0x12; //the length of repeating group
data[++pos] = 0x0C; //Fully Qualified Name
data[++pos] = 0x02;
data[++pos] = (byte) 0x84;
data[++pos] = 0x00;
//now add the name
byte[] name = (byte[]) overLays.get(i);
for (int j = 0; j < name.length; j++) {
data[++pos] = name[j];
}
data[++pos] = 0x04; //Resource Local Identifier (RLI)
data[++pos] = 0x24;
data[++pos] = 0x02;
//now add the unique id to the RLI
data[++pos] = olayref;
}
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/MapDataResource.java
public void writeToStream(OutputStream os) throws IOException {
super.writeStart(os);
byte[] data = new byte[11];
copySF(data, Type.MAP, Category.DATA_RESOURCE);
int tripletDataLen = getTripletDataLength();
byte[] len = BinaryUtils.convert(10 + tripletDataLen, 2);
data[1] = len[0];
data[2] = len[1];
len = BinaryUtils.convert(2 + tripletDataLen, 2);
data[9] = len[0];
data[10] = len[1];
os.write(data);
writeTriplets(os);
}
// in src/java/org/apache/fop/afp/modca/PageObject.java
protected void writeStart(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.BEGIN, Category.PAGE);
os.write(data);
}
// in src/java/org/apache/fop/afp/modca/PageObject.java
protected void writeContent(OutputStream os) throws IOException {
writeTriplets(os);
getActiveEnvironmentGroup().writeToStream(os);
writeObjects(objects, os);
}
// in src/java/org/apache/fop/afp/modca/PageObject.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[17];
copySF(data, Type.END, Category.PAGE);
os.write(data);
}
// in src/java/org/apache/fop/afp/util/StructuredFieldReader.java
public byte[] getNext(byte[] identifier) throws IOException {
byte[] bytes = AFPResourceUtil.getNext(identifier, this.inputStream);
if (bytes != null) {
//Users of this class expect the field data without length and identifier
int srcPos = 2 + identifier.length;
byte[] tmp = new byte[bytes.length - srcPos];
System.arraycopy(bytes, srcPos, tmp, 0, tmp.length);
bytes = tmp;
}
return bytes;
}
// in src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java
public InputStream createInputStream(URI uri) throws IOException {
URI resolved = resolveAgainstBase(uri);
URL url = resolved.toURL();
return url.openStream();
}
// in src/java/org/apache/fop/afp/util/DTDEntityResolver.java
public InputSource resolveEntity(String publicId, String systemId)
throws IOException {
URL resource = null;
if ( AFP_DTD_1_2_ID.equals(publicId) ) {
resource = getResource( AFP_DTD_1_2_RESOURCE );
} else if ( AFP_DTD_1_1_ID.equals(publicId) ) {
resource = getResource( AFP_DTD_1_1_RESOURCE );
} else if ( AFP_DTD_1_0_ID.equals(publicId) ) {
throw new FontRuntimeException(
"The AFP Installed Font Definition 1.0 DTD is not longer supported" );
} else if (systemId != null && systemId.indexOf("afp-fonts.dtd") >= 0 ) {
throw new FontRuntimeException(
"The AFP Installed Font Definition DTD must be specified using the public id" );
} else {
return null;
}
InputSource inputSource = new InputSource( resource.openStream() );
inputSource.setPublicId( publicId );
inputSource.setSystemId( systemId );
return inputSource;
}
// in src/java/org/apache/fop/afp/util/AFPResourceUtil.java
public static byte[] getNext(byte[] identifier, InputStream inputStream) throws IOException {
MODCAParser parser = new MODCAParser(inputStream);
while (true) {
UnparsedStructuredField field = parser.readNextStructuredField();
if (field == null) {
return null;
}
if (field.getSfClassCode() == identifier[0]
&& field.getSfTypeCode() == identifier[1]
&& field.getSfCategoryCode() == identifier[2]) {
return field.getCompleteFieldAsBytes();
}
}
}
// in src/java/org/apache/fop/afp/util/AFPResourceUtil.java
public static void copyResourceFile(final InputStream in, OutputStream out)
throws IOException {
MODCAParser parser = new MODCAParser(in);
while (true) {
UnparsedStructuredField field = parser.readNextStructuredField();
if (field == null) {
break;
}
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
field.writeTo(out);
}
}
// in src/java/org/apache/fop/afp/util/AFPResourceUtil.java
public static void copyNamedResource(String name,
final InputStream in, final OutputStream out) throws IOException {
final MODCAParser parser = new MODCAParser(in);
Collection<String> resourceNames = new java.util.HashSet<String>();
//Find matching "Begin" field
final UnparsedStructuredField fieldBegin;
while (true) {
final UnparsedStructuredField field = parser.readNextStructuredField();
if (field == null) {
throw new IOException("Requested resource '" + name
+ "' not found. Encountered resource names: " + resourceNames);
}
if (field.getSfTypeCode() != TYPE_CODE_BEGIN) { //0xA8=Begin
continue; //Not a "Begin" field
}
final String resourceName = getResourceName(field);
resourceNames.add(resourceName);
if (resourceName.equals(name)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Start of requested structured field found:\n"
+ field);
}
fieldBegin = field;
break; //Name doesn't match
}
}
//Decide whether the resource file has to be wrapped in a resource object
boolean wrapInResource;
if (fieldBegin.getSfCategoryCode() == Category.PAGE_SEGMENT) {
//A naked page segment must be wrapped in a resource object
wrapInResource = true;
} else if (fieldBegin.getSfCategoryCode() == Category.NAME_RESOURCE) {
//A resource object can be copied directly
wrapInResource = false;
} else {
throw new IOException("Cannot handle resource: " + fieldBegin);
}
//Copy structured fields (wrapped or as is)
if (wrapInResource) {
ResourceObject resourceObject = new ResourceObject(name) {
protected void writeContent(OutputStream os) throws IOException {
copyNamedStructuredFields(name, fieldBegin, parser, out);
}
};
resourceObject.setType(ResourceObject.TYPE_PAGE_SEGMENT);
resourceObject.writeToStream(out);
} else {
copyNamedStructuredFields(name, fieldBegin, parser, out);
}
}
// in src/java/org/apache/fop/afp/util/AFPResourceUtil.java
protected void writeContent(OutputStream os) throws IOException {
copyNamedStructuredFields(name, fieldBegin, parser, out);
}
// in src/java/org/apache/fop/afp/util/AFPResourceUtil.java
private static void copyNamedStructuredFields(final String name,
UnparsedStructuredField fieldBegin, MODCAParser parser,
OutputStream out) throws IOException {
UnparsedStructuredField field = fieldBegin;
while (true) {
if (field == null) {
throw new IOException("Ending structured field not found for resource " + name);
}
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
field.writeTo(out);
if (field.getSfTypeCode() == TYPE_CODE_END
&& fieldBegin.getSfCategoryCode() == field.getSfCategoryCode()
&& name.equals(getResourceName(field))) {
break;
}
field = parser.readNextStructuredField();
}
}
// in src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java
public InputStream createInputStream(URI uri) throws IOException {
//Step 1: resolve against local base URI --> URI
URI resolved = resolveAgainstBase(uri);
//Step 2: resolve against the user agent --> stream
String base = (this.categoryBaseURI != null
? this.categoryBaseURI
: this.userAgent.getBaseURL());
Source src = userAgent.resolveURI(resolved.toASCIIString(), base);
if (src == null) {
throw new FileNotFoundException("Resource not found: " + uri.toASCIIString());
} else if (src instanceof StreamSource) {
StreamSource ss = (StreamSource)src;
InputStream in = ss.getInputStream();
if (in != null) {
return in;
}
if (ss.getReader() != null) {
//Don't support reader, retry using system ID below
IOUtils.closeQuietly(ss.getReader());
}
}
URL url = new URL(src.getSystemId());
return url.openStream();
}
// in src/java/org/apache/fop/afp/ioca/ImageInputDescriptor.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[45];
copySF(data, Type.DESCRIPTOR, Category.IM_IMAGE);
data[1] = 0x00; // length
data[2] = 0x2C;
// Constant data.
data[9] = 0x00;
data[10] = 0x00;
data[11] = 0x09;
data[12] = 0x60;
data[13] = 0x09;
data[14] = 0x60;
data[15] = 0x00;
data[16] = 0x00;
data[17] = 0x00;
data[18] = 0x00;
data[19] = 0x00;
data[20] = 0x00;
// X Base (Fixed x00)
data[21] = 0x00;
// Y Base (Fixed x00)
data[22] = 0x00;
byte[] imagepoints = BinaryUtils.convert(resolution * 10, 2);
/**
* Specifies the number of image points per unit base for the X axis
* of the image. This value is ten times the resolution of the image
* in the X direction.
*/
data[23] = imagepoints[0];
data[24] = imagepoints[1];
/**
* Specifies the number of image points per unit base for the Y axis
* of the image. This value is ten times the resolution of the image
* in the Y direction.
*/
data[25] = imagepoints[0];
data[26] = imagepoints[1];
/**
* Specifies the extent in the X direction, in image points, of an
* non-celled (simple) image.
*/
data[27] = 0x00;
data[28] = 0x01;
/**
* Specifies the extent in the Y direction, in image points, of an
* non-celled (simple) image.
*/
data[29] = 0x00;
data[30] = 0x01;
// Constant Data
data[31] = 0x00;
data[32] = 0x00;
data[33] = 0x00;
data[34] = 0x00;
data[35] = 0x2D;
data[36] = 0x00;
// Default size of image cell in X direction
data[37] = 0x00;
data[38] = 0x01;
// Default size of image cell in Y direction
data[39] = 0x00;
data[40] = 0x01;
// Constant Data
data[41] = 0x00;
data[42] = 0x01;
// Image Color
data[43] = (byte)0xFF;
data[44] = (byte)0xFF;
os.write(data);
}
// in src/java/org/apache/fop/afp/ioca/IDEStructureParameter.java
public void writeToStream(OutputStream os) throws IOException {
int length = 7 + bitsPerIDE.length;
byte flags = 0x00;
if (subtractive) {
flags |= 1 << 7;
}
if (grayCoding) {
flags |= 1 << 6;
}
DataOutputStream dout = new DataOutputStream(os);
dout.writeByte(0x9B); //ID
dout.writeByte(length - 2); //LENGTH
dout.writeByte(flags); //FLAGS
dout.writeByte(this.colorModel); //FORMAT
for (int i = 0; i < 3; i++) {
dout.writeByte(0); //RESERVED
}
dout.write(this.bitsPerIDE); //component sizes
}
// in src/java/org/apache/fop/afp/ioca/ImageContent.java
Override
protected void writeContent(OutputStream os) throws IOException {
if (imageSizeParameter != null) {
imageSizeParameter.writeToStream(os);
}
// TODO convert to triplet/parameter class
os.write(getImageEncodingParameter());
os.write(getImageIDESizeParameter());
if (getIDEStructureParameter() != null) {
getIDEStructureParameter().writeToStream(os);
}
boolean useFS10 = (this.ideSize == 1);
if (!useFS10) {
os.write(getExternalAlgorithmParameter());
}
final byte[] dataHeader = new byte[] {
(byte)0xFE, // ID
(byte)0x92, // ID
0x00, // length
0x00 // length
};
final int lengthOffset = 2;
// Image Data
if (data != null) {
writeChunksToStream(data, dataHeader, lengthOffset, MAX_DATA_LEN, os);
}
}
// in src/java/org/apache/fop/afp/ioca/ImageContent.java
Override
protected void writeStart(OutputStream os) throws IOException {
final byte[] startData = new byte[] {
(byte)0x91, // ID
0x01, // Length
(byte)0xff, // Object Type = IOCA Image Object
};
os.write(startData);
}
// in src/java/org/apache/fop/afp/ioca/ImageContent.java
Override
protected void writeEnd(OutputStream os) throws IOException {
final byte[] endData = new byte[] {
(byte)0x93, // ID
0x00, // Length
};
os.write(endData);
}
// in src/java/org/apache/fop/afp/ioca/ImageSizeParameter.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] {
(byte)0x94, // ID = Image Size Parameter
0x09, // Length
0x00, // Unit base - 10 Inches
0x00, // HRESOL
0x00, //
0x00, // VRESOL
0x00, //
0x00, // HSIZE
0x00, //
0x00, // VSIZE
0x00, //
};
byte[] x = BinaryUtils.convert(hRes, 2);
data[3] = x[0];
data[4] = x[1];
byte[] y = BinaryUtils.convert(vRes, 2);
data[5] = y[0];
data[6] = y[1];
byte[] w = BinaryUtils.convert(hSize, 2);
data[7] = w[0];
data[8] = w[1];
byte[] h = BinaryUtils.convert(vSize, 2);
data[9] = h[0];
data[10] = h[1];
os.write(data);
}
// in src/java/org/apache/fop/afp/ioca/ImageOutputControl.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[33];
data[0] = 0x5A;
data[1] = 0x00;
data[2] = 0x20;
data[3] = (byte) 0xD3;
data[4] = (byte) 0xA7;
data[5] = (byte) 0x7B;
data[6] = 0x00;
data[7] = 0x00;
data[8] = 0x00;
// XoaOset
byte[] x1 = BinaryUtils.convert(xCoord, 3);
data[9] = x1[0];
data[10] = x1[1];
data[11] = x1[2];
// YoaOset
byte[] x2 = BinaryUtils.convert(yCoord, 3);
data[12] = x2[0];
data[13] = x2[1];
data[14] = x2[2];
switch (orientation) {
case 0:
// 0 and 90 degrees respectively
data[15] = 0x00;
data[16] = 0x00;
data[17] = 0x2D;
data[18] = 0x00;
break;
case 90:
// 90 and 180 degrees respectively
data[15] = 0x2D;
data[16] = 0x00;
data[17] = 0x5A;
data[18] = 0x00;
break;
case 180:
// 180 and 270 degrees respectively
data[15] = 0x5A;
data[16] = 0x00;
data[17] = (byte) 0x87;
data[18] = 0x00;
break;
case 270:
// 270 and 0 degrees respectively
data[15] = (byte) 0x87;
data[16] = 0x00;
data[17] = 0x00;
data[18] = 0x00;
break;
default:
// 0 and 90 degrees respectively
data[15] = 0x00;
data[16] = 0x00;
data[17] = 0x2D;
data[18] = 0x00;
break;
}
// Constant Data
data[19] = 0x00;
data[20] = 0x00;
data[21] = 0x00;
data[22] = 0x00;
data[23] = 0x00;
data[24] = 0x00;
data[25] = 0x00;
data[26] = 0x00;
if (singlePoint) {
data[27] = 0x03;
data[28] = (byte) 0xE8;
data[29] = 0x03;
data[30] = (byte) 0xE8;
} else {
data[27] = 0x07;
data[28] = (byte) 0xD0;
data[29] = 0x07;
data[30] = (byte) 0xD0;
}
// Constant Data
data[31] = (byte) 0xFF;
data[32] = (byte) 0xFF;
os.write(data);
}
// in src/java/org/apache/fop/afp/ioca/ImageCellPosition.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[21];
copySF(data, Type.POSITION, Category.IM_IMAGE);
data[1] = 0x00; // length
data[2] = 0x14;
/**
* Specifies the offset along the Xp direction, in image points,
* of this image cell from the IM image object area origin.
*/
byte[] x1 = BinaryUtils.convert(xOffset, 2);
data[9] = x1[0];
data[10] = x1[1];
/**
* Specifies the offset along the Yp direction, in image points,
* of this image cell from the IM image object area origin.
*/
byte[] x2 = BinaryUtils.convert(yOffset, 2);
data[11] = x2[0];
data[12] = x2[1];
data[13] = xSize[0];
data[14] = xSize[1];
data[15] = ySize[0];
data[16] = ySize[1];
data[17] = xFillSize[0];
data[18] = xFillSize[1];
data[19] = yFillSize[0];
data[20] = yFillSize[1];
os.write(data);
}
// in src/java/org/apache/fop/afp/ioca/ImageRasterData.java
public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[9];
copySF(data, Type.DATA, Category.IM_IMAGE);
// The size of the structured field
byte[] len = BinaryUtils.convert(rasterData.length + 8, 2);
data[1] = len[0];
data[2] = len[1];
os.write(data);
os.write(rasterData);
}
// in src/java/org/apache/fop/afp/ioca/ImageSegment.java
public void writeContent(OutputStream os) throws IOException {
if (imageContent != null) {
imageContent.writeToStream(os);
}
}
// in src/java/org/apache/fop/afp/ioca/ImageSegment.java
protected void writeStart(OutputStream os) throws IOException {
//Name disabled, it's optional and not referenced by our code
//byte[] nameBytes = getNameBytes();
byte[] data = new byte[] {
0x70, // ID
0x00, // Length
/*
nameBytes[0], // Name byte 1
nameBytes[1], // Name byte 2
nameBytes[2], // Name byte 3
nameBytes[3], // Name byte 4
*/
};
os.write(data);
}
// in src/java/org/apache/fop/afp/ioca/ImageSegment.java
protected void writeEnd(OutputStream os) throws IOException {
byte[] data = new byte[] {
0x71, // ID
0x00, // Length
};
os.write(data);
}
// in src/java/org/apache/fop/events/model/EventModel.java
private void writeXMLizable(XMLizable object, File outputFile) throws IOException {
//These two approaches do not seem to work in all environments:
//Result res = new StreamResult(outputFile);
//Result res = new StreamResult(outputFile.toURI().toURL().toExternalForm());
//With an old Xalan version: file:/C:/.... --> file:\C:\.....
OutputStream out = new java.io.FileOutputStream(outputFile);
out = new java.io.BufferedOutputStream(out);
Result res = new StreamResult(out);
try {
SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
TransformerHandler handler = tFactory.newTransformerHandler();
Transformer transformer = handler.getTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
handler.setResult(res);
handler.startDocument();
object.toSAX(handler);
handler.endDocument();
} catch (TransformerConfigurationException e) {
throw new IOException(e.getMessage());
} catch (TransformerFactoryConfigurationError e) {
throw new IOException(e.getMessage());
} catch (SAXException e) {
throw new IOException(e.getMessage());
} finally {
IOUtils.closeQuietly(out);
}
}
// in src/java/org/apache/fop/events/model/EventModel.java
public void saveToXML(File modelFile) throws IOException {
writeXMLizable(this, modelFile);
}
// in src/java/org/apache/fop/area/PageViewport.java
public void savePage(ObjectOutputStream out) throws IOException {
// set the unresolved references so they are serialized
page.setUnresolvedReferences(unresolvedIDRefs);
out.writeObject(page);
page = null;
}
// in src/java/org/apache/fop/area/PageViewport.java
public void loadPage(ObjectInputStream in) throws IOException, ClassNotFoundException {
page = (Page) in.readObject();
unresolvedIDRefs = page.getUnresolvedReferences();
if (unresolvedIDRefs != null && pendingResolved != null) {
for (String id : pendingResolved.keySet()) {
resolveIDRef(id, pendingResolved.get(id));
}
pendingResolved = null;
}
}
// in src/java/org/apache/fop/area/inline/InlineViewport.java
private void writeObject(java.io.ObjectOutputStream out)
throws IOException {
out.writeBoolean(contentPosition != null);
if (contentPosition != null) {
out.writeFloat((float) contentPosition.getX());
out.writeFloat((float) contentPosition.getY());
out.writeFloat((float) contentPosition.getWidth());
out.writeFloat((float) contentPosition.getHeight());
}
out.writeBoolean(clip);
out.writeObject((TreeMap)traits);
out.writeObject(content);
}
// in src/java/org/apache/fop/area/inline/InlineViewport.java
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
if (in.readBoolean()) {
contentPosition = new Rectangle2D.Float(in.readFloat(),
in.readFloat(),
in.readFloat(),
in.readFloat());
}
this.clip = in.readBoolean();
this.traits = (TreeMap) in.readObject();
this.content = (Area) in.readObject();
}
// in src/java/org/apache/fop/area/RegionViewport.java
private void writeObject(java.io.ObjectOutputStream out)
throws IOException {
out.writeFloat((float) viewArea.getX());
out.writeFloat((float) viewArea.getY());
out.writeFloat((float) viewArea.getWidth());
out.writeFloat((float) viewArea.getHeight());
out.writeBoolean(clip);
out.writeObject((TreeMap)traits);
out.writeObject(regionReference);
}
// in src/java/org/apache/fop/area/RegionViewport.java
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
viewArea = new Rectangle2D.Float(in.readFloat(), in.readFloat(),
in.readFloat(), in.readFloat());
clip = in.readBoolean();
traits = (TreeMap)in.readObject();
setRegionReference((RegionReference) in.readObject());
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readLangSysTable(String tableTag, long langSysTable, String langSysTag) throws IOException {
in.seekSet(langSysTable);
if (log.isDebugEnabled()) {
log.debug(tableTag + " lang sys table: " + langSysTag );
}
// read lookup order (reorder) table offset
int lo = in.readTTFUShort();
// read required feature index
int rf = in.readTTFUShort();
String rfi;
if ( rf != 65535 ) {
rfi = "f" + rf;
} else {
rfi = null;
}
// read (non-required) feature count
int nf = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " lang sys table reorder table: " + lo );
log.debug(tableTag + " lang sys table required feature index: " + rf );
log.debug(tableTag + " lang sys table non-required feature count: " + nf );
}
// read (non-required) feature indices
int[] fia = new int[nf];
List fl = new java.util.ArrayList();
for ( int i = 0; i < nf; i++ ) {
int fi = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " lang sys table non-required feature index: " + fi );
}
fia[i] = fi;
fl.add ( "f" + fi );
}
if ( seLanguages == null ) {
seLanguages = new java.util.LinkedHashMap();
}
seLanguages.put ( langSysTag, new Object[] { rfi, fl } );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readScriptTable(String tableTag, long scriptTable, String scriptTag) throws IOException {
in.seekSet(scriptTable);
if (log.isDebugEnabled()) {
log.debug(tableTag + " script table: " + scriptTag );
}
// read default language system table offset
int dl = in.readTTFUShort();
String dt = defaultTag;
if ( dl > 0 ) {
if (log.isDebugEnabled()) {
log.debug(tableTag + " default lang sys tag: " + dt );
log.debug(tableTag + " default lang sys table offset: " + dl );
}
}
// read language system record count
int nl = in.readTTFUShort();
List ll = new java.util.ArrayList();
if ( nl > 0 ) {
String[] lta = new String[nl];
int[] loa = new int[nl];
// read language system records
for ( int i = 0, n = nl; i < n; i++ ) {
String lt = in.readTTFString(4);
int lo = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " lang sys tag: " + lt );
log.debug(tableTag + " lang sys table offset: " + lo );
}
lta[i] = lt;
loa[i] = lo;
if ( dl == lo ) {
dl = 0;
dt = lt;
}
ll.add ( lt );
}
// read non-default language system tables
for ( int i = 0, n = nl; i < n; i++ ) {
readLangSysTable ( tableTag, scriptTable + loa [ i ], lta [ i ] );
}
}
// read default language system table (if specified)
if ( dl > 0 ) {
readLangSysTable ( tableTag, scriptTable + dl, dt );
} else if ( dt != null ) {
if (log.isDebugEnabled()) {
log.debug(tableTag + " lang sys default: " + dt );
}
}
seScripts.put ( scriptTag, new Object[] { dt, ll, seLanguages } );
seLanguages = null;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readScriptList(String tableTag, long scriptList) throws IOException {
in.seekSet(scriptList);
// read script record count
int ns = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " script list record count: " + ns );
}
if ( ns > 0 ) {
String[] sta = new String[ns];
int[] soa = new int[ns];
// read script records
for ( int i = 0, n = ns; i < n; i++ ) {
String st = in.readTTFString(4);
int so = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " script tag: " + st );
log.debug(tableTag + " script table offset: " + so );
}
sta[i] = st;
soa[i] = so;
}
// read script tables
for ( int i = 0, n = ns; i < n; i++ ) {
seLanguages = null;
readScriptTable ( tableTag, scriptList + soa [ i ], sta [ i ] );
}
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readFeatureTable(String tableTag, long featureTable, String featureTag, int featureIndex) throws IOException {
in.seekSet(featureTable);
if (log.isDebugEnabled()) {
log.debug(tableTag + " feature table: " + featureTag );
}
// read feature params offset
int po = in.readTTFUShort();
// read lookup list indices count
int nl = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " feature table parameters offset: " + po );
log.debug(tableTag + " feature table lookup list index count: " + nl );
}
// read lookup table indices
int[] lia = new int[nl];
List lul = new java.util.ArrayList();
for ( int i = 0; i < nl; i++ ) {
int li = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " feature table lookup index: " + li );
}
lia[i] = li;
lul.add ( "lu" + li );
}
seFeatures.put ( "f" + featureIndex, new Object[] { featureTag, lul } );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readFeatureList(String tableTag, long featureList) throws IOException {
in.seekSet(featureList);
// read feature record count
int nf = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " feature list record count: " + nf );
}
if ( nf > 0 ) {
String[] fta = new String[nf];
int[] foa = new int[nf];
// read feature records
for ( int i = 0, n = nf; i < n; i++ ) {
String ft = in.readTTFString(4);
int fo = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " feature tag: " + ft );
log.debug(tableTag + " feature table offset: " + fo );
}
fta[i] = ft;
foa[i] = fo;
}
// read feature tables
for ( int i = 0, n = nf; i < n; i++ ) {
if (log.isDebugEnabled()) {
log.debug(tableTag + " feature index: " + i );
}
readFeatureTable ( tableTag, featureList + foa [ i ], fta [ i ], i );
}
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphCoverageTable readCoverageTableFormat1(String label, long tableOffset, int coverageFormat) throws IOException {
List entries = new java.util.ArrayList();
in.seekSet(tableOffset);
// skip over format (already known)
in.skip ( 2 );
// read glyph count
int ng = in.readTTFUShort();
int[] ga = new int[ng];
for ( int i = 0, n = ng; i < n; i++ ) {
int g = in.readTTFUShort();
ga[i] = g;
entries.add ( Integer.valueOf(g) );
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(label + " glyphs: " + toString(ga) );
}
return GlyphCoverageTable.createCoverageTable ( entries );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphCoverageTable readCoverageTableFormat2(String label, long tableOffset, int coverageFormat) throws IOException {
List entries = new java.util.ArrayList();
in.seekSet(tableOffset);
// skip over format (already known)
in.skip ( 2 );
// read range record count
int nr = in.readTTFUShort();
for ( int i = 0, n = nr; i < n; i++ ) {
// read range start
int s = in.readTTFUShort();
// read range end
int e = in.readTTFUShort();
// read range coverage (mapping) index
int m = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(label + " range[" + i + "]: [" + s + "," + e + "]: " + m );
}
entries.add ( new GlyphCoverageTable.MappingRange ( s, e, m ) );
}
return GlyphCoverageTable.createCoverageTable ( entries );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphCoverageTable readCoverageTable(String label, long tableOffset) throws IOException {
GlyphCoverageTable gct;
long cp = in.getCurrentPos();
in.seekSet(tableOffset);
// read coverage table format
int cf = in.readTTFUShort();
if ( cf == 1 ) {
gct = readCoverageTableFormat1 ( label, tableOffset, cf );
} else if ( cf == 2 ) {
gct = readCoverageTableFormat2 ( label, tableOffset, cf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported coverage table format: " + cf );
}
in.seekSet ( cp );
return gct;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphClassTable readClassDefTableFormat1(String label, long tableOffset, int classFormat) throws IOException {
List entries = new java.util.ArrayList();
in.seekSet(tableOffset);
// skip over format (already known)
in.skip ( 2 );
// read start glyph
int sg = in.readTTFUShort();
entries.add ( Integer.valueOf(sg) );
// read glyph count
int ng = in.readTTFUShort();
// read glyph classes
int[] ca = new int[ng];
for ( int i = 0, n = ng; i < n; i++ ) {
int gc = in.readTTFUShort();
ca[i] = gc;
entries.add ( Integer.valueOf(gc) );
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(label + " glyph classes: " + toString(ca) );
}
return GlyphClassTable.createClassTable ( entries );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphClassTable readClassDefTableFormat2(String label, long tableOffset, int classFormat) throws IOException {
List entries = new java.util.ArrayList();
in.seekSet(tableOffset);
// skip over format (already known)
in.skip ( 2 );
// read range record count
int nr = in.readTTFUShort();
for ( int i = 0, n = nr; i < n; i++ ) {
// read range start
int s = in.readTTFUShort();
// read range end
int e = in.readTTFUShort();
// read range glyph class (mapping) index
int m = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(label + " range[" + i + "]: [" + s + "," + e + "]: " + m );
}
entries.add ( new GlyphClassTable.MappingRange ( s, e, m ) );
}
return GlyphClassTable.createClassTable ( entries );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphClassTable readClassDefTable(String label, long tableOffset) throws IOException {
GlyphClassTable gct;
long cp = in.getCurrentPos();
in.seekSet(tableOffset);
// read class table format
int cf = in.readTTFUShort();
if ( cf == 1 ) {
gct = readClassDefTableFormat1 ( label, tableOffset, cf );
} else if ( cf == 2 ) {
gct = readClassDefTableFormat2 ( label, tableOffset, cf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported class definition table format: " + cf );
}
in.seekSet ( cp );
return gct;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readSingleSubTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read delta glyph
int dg = in.readTTFShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " single substitution subtable format: " + subtableFormat + " (delta)" );
log.debug(tableTag + " single substitution coverage table offset: " + co );
log.debug(tableTag + " single substitution delta: " + dg );
}
// read coverage table
seMapping = readCoverageTable ( tableTag + " single substitution coverage", subtableOffset + co );
seEntries.add ( Integer.valueOf ( dg ) );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readSingleSubTableFormat2(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read glyph count
int ng = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " single substitution subtable format: " + subtableFormat + " (mapped)" );
log.debug(tableTag + " single substitution coverage table offset: " + co );
log.debug(tableTag + " single substitution glyph count: " + ng );
}
// read coverage table
seMapping = readCoverageTable ( tableTag + " single substitution coverage", subtableOffset + co );
// read glyph substitutions
int[] gsa = new int[ng];
for ( int i = 0, n = ng; i < n; i++ ) {
int gs = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " single substitution glyph[" + i + "]: " + gs );
}
gsa[i] = gs;
seEntries.add ( Integer.valueOf ( gs ) );
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readSingleSubTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readSingleSubTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 2 ) {
readSingleSubTableFormat2 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported single substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readMultipleSubTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read sequence count
int ns = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " multiple substitution subtable format: " + subtableFormat + " (mapped)" );
log.debug(tableTag + " multiple substitution coverage table offset: " + co );
log.debug(tableTag + " multiple substitution sequence count: " + ns );
}
// read coverage table
seMapping = readCoverageTable ( tableTag + " multiple substitution coverage", subtableOffset + co );
// read sequence table offsets
int[] soa = new int[ns];
for ( int i = 0, n = ns; i < n; i++ ) {
soa[i] = in.readTTFUShort();
}
// read sequence tables
int[][] gsa = new int [ ns ] [];
for ( int i = 0, n = ns; i < n; i++ ) {
int so = soa[i];
int[] ga;
if ( so > 0 ) {
in.seekSet(subtableOffset + so);
// read glyph count
int ng = in.readTTFUShort();
ga = new int[ng];
for ( int j = 0; j < ng; j++ ) {
ga[j] = in.readTTFUShort();
}
} else {
ga = null;
}
if (log.isDebugEnabled()) {
log.debug(tableTag + " multiple substitution sequence[" + i + "]: " + toString ( ga ) );
}
gsa [ i ] = ga;
}
seEntries.add ( gsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readMultipleSubTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readMultipleSubTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported multiple substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readAlternateSubTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read alternate set count
int ns = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " alternate substitution subtable format: " + subtableFormat + " (mapped)" );
log.debug(tableTag + " alternate substitution coverage table offset: " + co );
log.debug(tableTag + " alternate substitution alternate set count: " + ns );
}
// read coverage table
seMapping = readCoverageTable ( tableTag + " alternate substitution coverage", subtableOffset + co );
// read alternate set table offsets
int[] soa = new int[ns];
for ( int i = 0, n = ns; i < n; i++ ) {
soa[i] = in.readTTFUShort();
}
// read alternate set tables
for ( int i = 0, n = ns; i < n; i++ ) {
int so = soa[i];
in.seekSet(subtableOffset + so);
// read glyph count
int ng = in.readTTFUShort();
int[] ga = new int[ng];
for ( int j = 0; j < ng; j++ ) {
int gs = in.readTTFUShort();
ga[j] = gs;
}
if (log.isDebugEnabled()) {
log.debug(tableTag + " alternate substitution alternate set[" + i + "]: " + toString ( ga ) );
}
seEntries.add ( ga );
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readAlternateSubTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readAlternateSubTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported alternate substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readLigatureSubTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read ligature set count
int ns = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " ligature substitution subtable format: " + subtableFormat + " (mapped)" );
log.debug(tableTag + " ligature substitution coverage table offset: " + co );
log.debug(tableTag + " ligature substitution ligature set count: " + ns );
}
// read coverage table
seMapping = readCoverageTable ( tableTag + " ligature substitution coverage", subtableOffset + co );
// read ligature set table offsets
int[] soa = new int[ns];
for ( int i = 0, n = ns; i < n; i++ ) {
soa[i] = in.readTTFUShort();
}
// read ligature set tables
for ( int i = 0, n = ns; i < n; i++ ) {
int so = soa[i];
in.seekSet(subtableOffset + so);
// read ligature table count
int nl = in.readTTFUShort();
int[] loa = new int[nl];
for ( int j = 0; j < nl; j++ ) {
loa[j] = in.readTTFUShort();
}
List ligs = new java.util.ArrayList();
for ( int j = 0; j < nl; j++ ) {
int lo = loa[j];
in.seekSet(subtableOffset + so + lo);
// read ligature glyph id
int lg = in.readTTFUShort();
// read ligature (input) component count
int nc = in.readTTFUShort();
int[] ca = new int [ nc - 1 ];
// read ligature (input) component glyph ids
for ( int k = 0; k < nc - 1; k++ ) {
ca[k] = in.readTTFUShort();
}
if (log.isDebugEnabled()) {
log.debug(tableTag + " ligature substitution ligature set[" + i + "]: ligature(" + lg + "), components: " + toString ( ca ) );
}
ligs.add ( new GlyphSubstitutionTable.Ligature ( lg, ca ) );
}
seEntries.add ( new GlyphSubstitutionTable.LigatureSet ( ligs ) );
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readLigatureSubTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readLigatureSubTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported ligature substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphTable.RuleLookup[] readRuleLookups(int numLookups, String header) throws IOException {
GlyphTable.RuleLookup[] la = new GlyphTable.RuleLookup [ numLookups ];
for ( int i = 0, n = numLookups; i < n; i++ ) {
int sequenceIndex = in.readTTFUShort();
int lookupIndex = in.readTTFUShort();
la [ i ] = new GlyphTable.RuleLookup ( sequenceIndex, lookupIndex );
// dump info if debugging and header is non-null
if ( log.isDebugEnabled() && ( header != null ) ) {
log.debug(header + "lookup[" + i + "]: " + la[i]);
}
}
return la;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readContextualSubTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read rule set count
int nrs = in.readTTFUShort();
// read rule set offsets
int[] rsoa = new int [ nrs ];
for ( int i = 0; i < nrs; i++ ) {
rsoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " contextual substitution format: " + subtableFormat + " (glyphs)" );
log.debug(tableTag + " contextual substitution coverage table offset: " + co );
log.debug(tableTag + " contextual substitution rule set count: " + nrs );
for ( int i = 0; i < nrs; i++ ) {
log.debug(tableTag + " contextual substitution rule set offset[" + i + "]: " + rsoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " contextual substitution coverage", subtableOffset + co );
} else {
ct = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ nrs ];
String header = null;
for ( int i = 0; i < nrs; i++ ) {
GlyphTable.RuleSet rs;
int rso = rsoa [ i ];
if ( rso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + rso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
GlyphTable.GlyphSequenceRule r;
int ro = roa [ j ];
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + rso + ro );
// read glyph count
int ng = in.readTTFUShort();
// read rule lookup count
int nl = in.readTTFUShort();
// read glyphs
int[] glyphs = new int [ ng - 1 ];
for ( int k = 0, nk = glyphs.length; k < nk; k++ ) {
glyphs [ k ] = in.readTTFUShort();
}
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual substitution lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.GlyphSequenceRule ( lookups, ng, glyphs );
} else {
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readContextualSubTableFormat2(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read class def table offset
int cdo = in.readTTFUShort();
// read class rule set count
int ngc = in.readTTFUShort();
// read class rule set offsets
int[] csoa = new int [ ngc ];
for ( int i = 0; i < ngc; i++ ) {
csoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " contextual substitution format: " + subtableFormat + " (glyph classes)" );
log.debug(tableTag + " contextual substitution coverage table offset: " + co );
log.debug(tableTag + " contextual substitution class set count: " + ngc );
for ( int i = 0; i < ngc; i++ ) {
log.debug(tableTag + " contextual substitution class set offset[" + i + "]: " + csoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " contextual substitution coverage", subtableOffset + co );
} else {
ct = null;
}
// read class definition table
GlyphClassTable cdt;
if ( cdo > 0 ) {
cdt = readClassDefTable ( tableTag + " contextual substitution class definition", subtableOffset + cdo );
} else {
cdt = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ ngc ];
String header = null;
for ( int i = 0; i < ngc; i++ ) {
int cso = csoa [ i ];
GlyphTable.RuleSet rs;
if ( cso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + cso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
int ro = roa [ j ];
GlyphTable.ClassSequenceRule r;
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + cso + ro );
// read glyph count
int ng = in.readTTFUShort();
// read rule lookup count
int nl = in.readTTFUShort();
// read classes
int[] classes = new int [ ng - 1 ];
for ( int k = 0, nk = classes.length; k < nk; k++ ) {
classes [ k ] = in.readTTFUShort();
}
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual substitution lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.ClassSequenceRule ( lookups, ng, classes );
} else {
assert ro > 0 : "unexpected null subclass rule offset";
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( cdt );
seEntries.add ( Integer.valueOf ( ngc ) );
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readContextualSubTableFormat3(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read glyph (input sequence length) count
int ng = in.readTTFUShort();
// read substitution lookup count
int nl = in.readTTFUShort();
// read glyph coverage offsets, one per glyph input sequence length count
int[] gcoa = new int [ ng ];
for ( int i = 0; i < ng; i++ ) {
gcoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " contextual substitution format: " + subtableFormat + " (glyph sets)" );
log.debug(tableTag + " contextual substitution glyph input sequence length count: " + ng );
log.debug(tableTag + " contextual substitution lookup count: " + nl );
for ( int i = 0; i < ng; i++ ) {
log.debug(tableTag + " contextual substitution coverage table offset[" + i + "]: " + gcoa[i] );
}
}
// read coverage tables
GlyphCoverageTable[] gca = new GlyphCoverageTable [ ng ];
for ( int i = 0; i < ng; i++ ) {
int gco = gcoa [ i ];
GlyphCoverageTable gct;
if ( gco > 0 ) {
gct = readCoverageTable ( tableTag + " contextual substitution coverage[" + i + "]", subtableOffset + gco );
} else {
gct = null;
}
gca [ i ] = gct;
}
// read rule lookups
String header = null;
if (log.isDebugEnabled()) {
header = tableTag + " contextual substitution lookups: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
// construct rule, rule set, and rule set array
GlyphTable.Rule r = new GlyphTable.CoverageSequenceRule ( lookups, ng, gca );
GlyphTable.RuleSet rs = new GlyphTable.HomogeneousRuleSet ( new GlyphTable.Rule[] {r} );
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet[] {rs};
// store results
assert ( gca != null ) && ( gca.length > 0 );
seMapping = gca[0];
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readContextualSubTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readContextualSubTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 2 ) {
readContextualSubTableFormat2 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 3 ) {
readContextualSubTableFormat3 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported contextual substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readChainedContextualSubTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read rule set count
int nrs = in.readTTFUShort();
// read rule set offsets
int[] rsoa = new int [ nrs ];
for ( int i = 0; i < nrs; i++ ) {
rsoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " chained contextual substitution format: " + subtableFormat + " (glyphs)" );
log.debug(tableTag + " chained contextual substitution coverage table offset: " + co );
log.debug(tableTag + " chained contextual substitution rule set count: " + nrs );
for ( int i = 0; i < nrs; i++ ) {
log.debug(tableTag + " chained contextual substitution rule set offset[" + i + "]: " + rsoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " chained contextual substitution coverage", subtableOffset + co );
} else {
ct = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ nrs ];
String header = null;
for ( int i = 0; i < nrs; i++ ) {
GlyphTable.RuleSet rs;
int rso = rsoa [ i ];
if ( rso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + rso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
GlyphTable.ChainedGlyphSequenceRule r;
int ro = roa [ j ];
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + rso + ro );
// read backtrack glyph count
int nbg = in.readTTFUShort();
// read backtrack glyphs
int[] backtrackGlyphs = new int [ nbg ];
for ( int k = 0, nk = backtrackGlyphs.length; k < nk; k++ ) {
backtrackGlyphs [ k ] = in.readTTFUShort();
}
// read input glyph count
int nig = in.readTTFUShort();
// read glyphs
int[] glyphs = new int [ nig - 1 ];
for ( int k = 0, nk = glyphs.length; k < nk; k++ ) {
glyphs [ k ] = in.readTTFUShort();
}
// read lookahead glyph count
int nlg = in.readTTFUShort();
// read lookahead glyphs
int[] lookaheadGlyphs = new int [ nlg ];
for ( int k = 0, nk = lookaheadGlyphs.length; k < nk; k++ ) {
lookaheadGlyphs [ k ] = in.readTTFUShort();
}
// read rule lookup count
int nl = in.readTTFUShort();
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual substitution lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.ChainedGlyphSequenceRule ( lookups, nig, glyphs, backtrackGlyphs, lookaheadGlyphs );
} else {
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readChainedContextualSubTableFormat2(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read backtrack class def table offset
int bcdo = in.readTTFUShort();
// read input class def table offset
int icdo = in.readTTFUShort();
// read lookahead class def table offset
int lcdo = in.readTTFUShort();
// read class set count
int ngc = in.readTTFUShort();
// read class set offsets
int[] csoa = new int [ ngc ];
for ( int i = 0; i < ngc; i++ ) {
csoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " chained contextual substitution format: " + subtableFormat + " (glyph classes)" );
log.debug(tableTag + " chained contextual substitution coverage table offset: " + co );
log.debug(tableTag + " chained contextual substitution class set count: " + ngc );
for ( int i = 0; i < ngc; i++ ) {
log.debug(tableTag + " chained contextual substitution class set offset[" + i + "]: " + csoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " chained contextual substitution coverage", subtableOffset + co );
} else {
ct = null;
}
// read backtrack class definition table
GlyphClassTable bcdt;
if ( bcdo > 0 ) {
bcdt = readClassDefTable ( tableTag + " contextual substitution backtrack class definition", subtableOffset + bcdo );
} else {
bcdt = null;
}
// read input class definition table
GlyphClassTable icdt;
if ( icdo > 0 ) {
icdt = readClassDefTable ( tableTag + " contextual substitution input class definition", subtableOffset + icdo );
} else {
icdt = null;
}
// read lookahead class definition table
GlyphClassTable lcdt;
if ( lcdo > 0 ) {
lcdt = readClassDefTable ( tableTag + " contextual substitution lookahead class definition", subtableOffset + lcdo );
} else {
lcdt = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ ngc ];
String header = null;
for ( int i = 0; i < ngc; i++ ) {
int cso = csoa [ i ];
GlyphTable.RuleSet rs;
if ( cso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + cso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
int ro = roa [ j ];
GlyphTable.ChainedClassSequenceRule r;
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + cso + ro );
// read backtrack glyph class count
int nbc = in.readTTFUShort();
// read backtrack glyph classes
int[] backtrackClasses = new int [ nbc ];
for ( int k = 0, nk = backtrackClasses.length; k < nk; k++ ) {
backtrackClasses [ k ] = in.readTTFUShort();
}
// read input glyph class count
int nic = in.readTTFUShort();
// read input glyph classes
int[] classes = new int [ nic - 1 ];
for ( int k = 0, nk = classes.length; k < nk; k++ ) {
classes [ k ] = in.readTTFUShort();
}
// read lookahead glyph class count
int nlc = in.readTTFUShort();
// read lookahead glyph classes
int[] lookaheadClasses = new int [ nlc ];
for ( int k = 0, nk = lookaheadClasses.length; k < nk; k++ ) {
lookaheadClasses [ k ] = in.readTTFUShort();
}
// read rule lookup count
int nl = in.readTTFUShort();
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual substitution lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.ChainedClassSequenceRule ( lookups, nic, classes, backtrackClasses, lookaheadClasses );
} else {
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( icdt );
seEntries.add ( bcdt );
seEntries.add ( lcdt );
seEntries.add ( Integer.valueOf ( ngc ) );
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readChainedContextualSubTableFormat3(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read backtrack glyph count
int nbg = in.readTTFUShort();
// read backtrack glyph coverage offsets
int[] bgcoa = new int [ nbg ];
for ( int i = 0; i < nbg; i++ ) {
bgcoa [ i ] = in.readTTFUShort();
}
// read input glyph count
int nig = in.readTTFUShort();
// read input glyph coverage offsets
int[] igcoa = new int [ nig ];
for ( int i = 0; i < nig; i++ ) {
igcoa [ i ] = in.readTTFUShort();
}
// read lookahead glyph count
int nlg = in.readTTFUShort();
// read lookahead glyph coverage offsets
int[] lgcoa = new int [ nlg ];
for ( int i = 0; i < nlg; i++ ) {
lgcoa [ i ] = in.readTTFUShort();
}
// read substitution lookup count
int nl = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " chained contextual substitution format: " + subtableFormat + " (glyph sets)" );
log.debug(tableTag + " chained contextual substitution backtrack glyph count: " + nbg );
for ( int i = 0; i < nbg; i++ ) {
log.debug(tableTag + " chained contextual substitution backtrack coverage table offset[" + i + "]: " + bgcoa[i] );
}
log.debug(tableTag + " chained contextual substitution input glyph count: " + nig );
for ( int i = 0; i < nig; i++ ) {
log.debug(tableTag + " chained contextual substitution input coverage table offset[" + i + "]: " + igcoa[i] );
}
log.debug(tableTag + " chained contextual substitution lookahead glyph count: " + nlg );
for ( int i = 0; i < nlg; i++ ) {
log.debug(tableTag + " chained contextual substitution lookahead coverage table offset[" + i + "]: " + lgcoa[i] );
}
log.debug(tableTag + " chained contextual substitution lookup count: " + nl );
}
// read backtrack coverage tables
GlyphCoverageTable[] bgca = new GlyphCoverageTable[nbg];
for ( int i = 0; i < nbg; i++ ) {
int bgco = bgcoa [ i ];
GlyphCoverageTable bgct;
if ( bgco > 0 ) {
bgct = readCoverageTable ( tableTag + " chained contextual substitution backtrack coverage[" + i + "]", subtableOffset + bgco );
} else {
bgct = null;
}
bgca[i] = bgct;
}
// read input coverage tables
GlyphCoverageTable[] igca = new GlyphCoverageTable[nig];
for ( int i = 0; i < nig; i++ ) {
int igco = igcoa [ i ];
GlyphCoverageTable igct;
if ( igco > 0 ) {
igct = readCoverageTable ( tableTag + " chained contextual substitution input coverage[" + i + "]", subtableOffset + igco );
} else {
igct = null;
}
igca[i] = igct;
}
// read lookahead coverage tables
GlyphCoverageTable[] lgca = new GlyphCoverageTable[nlg];
for ( int i = 0; i < nlg; i++ ) {
int lgco = lgcoa [ i ];
GlyphCoverageTable lgct;
if ( lgco > 0 ) {
lgct = readCoverageTable ( tableTag + " chained contextual substitution lookahead coverage[" + i + "]", subtableOffset + lgco );
} else {
lgct = null;
}
lgca[i] = lgct;
}
// read rule lookups
String header = null;
if (log.isDebugEnabled()) {
header = tableTag + " chained contextual substitution lookups: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
// construct rule, rule set, and rule set array
GlyphTable.Rule r = new GlyphTable.ChainedCoverageSequenceRule ( lookups, nig, igca, bgca, lgca );
GlyphTable.RuleSet rs = new GlyphTable.HomogeneousRuleSet ( new GlyphTable.Rule[] {r} );
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet[] {rs};
// store results
assert ( igca != null ) && ( igca.length > 0 );
seMapping = igca[0];
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readChainedContextualSubTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readChainedContextualSubTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 2 ) {
readChainedContextualSubTableFormat2 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 3 ) {
readChainedContextualSubTableFormat3 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported chained contextual substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readExtensionSubTableFormat1(int lookupType, int lookupFlags, int lookupSequence, int subtableSequence, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read extension lookup type
int lt = in.readTTFUShort();
// read extension offset
long eo = in.readTTFULong();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " extension substitution subtable format: " + subtableFormat );
log.debug(tableTag + " extension substitution lookup type: " + lt );
log.debug(tableTag + " extension substitution lookup table offset: " + eo );
}
// read referenced subtable from extended offset
readGSUBSubtable ( lt, lookupFlags, lookupSequence, subtableSequence, subtableOffset + eo );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readExtensionSubTable(int lookupType, int lookupFlags, int lookupSequence, int subtableSequence, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readExtensionSubTableFormat1 ( lookupType, lookupFlags, lookupSequence, subtableSequence, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported extension substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readReverseChainedSingleSubTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GSUB";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read backtrack glyph count
int nbg = in.readTTFUShort();
// read backtrack glyph coverage offsets
int[] bgcoa = new int [ nbg ];
for ( int i = 0; i < nbg; i++ ) {
bgcoa [ i ] = in.readTTFUShort();
}
// read lookahead glyph count
int nlg = in.readTTFUShort();
// read backtrack glyph coverage offsets
int[] lgcoa = new int [ nlg ];
for ( int i = 0; i < nlg; i++ ) {
lgcoa [ i ] = in.readTTFUShort();
}
// read substitution (output) glyph count
int ng = in.readTTFUShort();
// read substitution (output) glyphs
int[] glyphs = new int [ ng ];
for ( int i = 0, n = ng; i < n; i++ ) {
glyphs [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " reverse chained contextual substitution format: " + subtableFormat );
log.debug(tableTag + " reverse chained contextual substitution coverage table offset: " + co );
log.debug(tableTag + " reverse chained contextual substitution backtrack glyph count: " + nbg );
for ( int i = 0; i < nbg; i++ ) {
log.debug(tableTag + " reverse chained contextual substitution backtrack coverage table offset[" + i + "]: " + bgcoa[i] );
}
log.debug(tableTag + " reverse chained contextual substitution lookahead glyph count: " + nlg );
for ( int i = 0; i < nlg; i++ ) {
log.debug(tableTag + " reverse chained contextual substitution lookahead coverage table offset[" + i + "]: " + lgcoa[i] );
}
log.debug(tableTag + " reverse chained contextual substitution glyphs: " + toString(glyphs) );
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " reverse chained contextual substitution coverage", subtableOffset + co );
// read backtrack coverage tables
GlyphCoverageTable[] bgca = new GlyphCoverageTable[nbg];
for ( int i = 0; i < nbg; i++ ) {
int bgco = bgcoa[i];
GlyphCoverageTable bgct;
if ( bgco > 0 ) {
bgct = readCoverageTable ( tableTag + " reverse chained contextual substitution backtrack coverage[" + i + "]", subtableOffset + bgco );
} else {
bgct = null;
}
bgca[i] = bgct;
}
// read lookahead coverage tables
GlyphCoverageTable[] lgca = new GlyphCoverageTable[nlg];
for ( int i = 0; i < nlg; i++ ) {
int lgco = lgcoa[i];
GlyphCoverageTable lgct;
if ( lgco > 0 ) {
lgct = readCoverageTable ( tableTag + " reverse chained contextual substitution lookahead coverage[" + i + "]", subtableOffset + lgco );
} else {
lgct = null;
}
lgca[i] = lgct;
}
// store results
seMapping = ct;
seEntries.add ( bgca );
seEntries.add ( lgca );
seEntries.add ( glyphs );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readReverseChainedSingleSubTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read substitution subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readReverseChainedSingleSubTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported reverse chained single substitution subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGSUBSubtable(int lookupType, int lookupFlags, int lookupSequence, int subtableSequence, long subtableOffset) throws IOException {
initATSubState();
int subtableFormat = -1;
switch ( lookupType ) {
case GSUBLookupType.SINGLE:
subtableFormat = readSingleSubTable ( lookupType, lookupFlags, subtableOffset );
break;
case GSUBLookupType.MULTIPLE:
subtableFormat = readMultipleSubTable ( lookupType, lookupFlags, subtableOffset );
break;
case GSUBLookupType.ALTERNATE:
subtableFormat = readAlternateSubTable ( lookupType, lookupFlags, subtableOffset );
break;
case GSUBLookupType.LIGATURE:
subtableFormat = readLigatureSubTable ( lookupType, lookupFlags, subtableOffset );
break;
case GSUBLookupType.CONTEXTUAL:
subtableFormat = readContextualSubTable ( lookupType, lookupFlags, subtableOffset );
break;
case GSUBLookupType.CHAINED_CONTEXTUAL:
subtableFormat = readChainedContextualSubTable ( lookupType, lookupFlags, subtableOffset );
break;
case GSUBLookupType.REVERSE_CHAINED_SINGLE:
subtableFormat = readReverseChainedSingleSubTable ( lookupType, lookupFlags, subtableOffset );
break;
case GSUBLookupType.EXTENSION:
subtableFormat = readExtensionSubTable ( lookupType, lookupFlags, lookupSequence, subtableSequence, subtableOffset );
break;
default:
break;
}
extractSESubState ( GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION, lookupType, lookupFlags, lookupSequence, subtableSequence, subtableFormat );
resetATSubState();
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphPositioningTable.DeviceTable readPosDeviceTable(long subtableOffset, long deviceTableOffset) throws IOException {
long cp = in.getCurrentPos();
in.seekSet(subtableOffset + deviceTableOffset);
// read start size
int ss = in.readTTFUShort();
// read end size
int es = in.readTTFUShort();
// read delta format
int df = in.readTTFUShort();
int s1;
int m1;
int dm;
int dd;
int s2;
if ( df == 1 ) {
s1 = 14;
m1 = 0x3;
dm = 1;
dd = 4;
s2 = 2;
} else if ( df == 2 ) {
s1 = 12;
m1 = 0xF;
dm = 7;
dd = 16;
s2 = 4;
} else if ( df == 3 ) {
s1 = 8;
m1 = 0xFF;
dm = 127;
dd = 256;
s2 = 8;
} else {
log.debug ( "unsupported device table delta format: " + df + ", ignoring device table" );
return null;
}
// read deltas
int n = ( es - ss ) + 1;
if ( n < 0 ) {
log.debug ( "invalid device table delta count: " + n + ", ignoring device table" );
return null;
}
int[] da = new int [ n ];
for ( int i = 0; ( i < n ) && ( s2 > 0 );) {
int p = in.readTTFUShort();
for ( int j = 0, k = 16 / s2; j < k; j++ ) {
int d = ( p >> s1 ) & m1;
if ( d > dm ) {
d -= dd;
}
if ( i < n ) {
da [ i++ ] = d;
} else {
break;
}
p <<= s2;
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphPositioningTable.Value readPosValue(long subtableOffset, int valueFormat) throws IOException {
// XPlacement
int xp;
if ( ( valueFormat & GlyphPositioningTable.Value.X_PLACEMENT ) != 0 ) {
xp = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
} else {
xp = 0;
}
// YPlacement
int yp;
if ( ( valueFormat & GlyphPositioningTable.Value.Y_PLACEMENT ) != 0 ) {
yp = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
} else {
yp = 0;
}
// XAdvance
int xa;
if ( ( valueFormat & GlyphPositioningTable.Value.X_ADVANCE ) != 0 ) {
xa = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
} else {
xa = 0;
}
// YAdvance
int ya;
if ( ( valueFormat & GlyphPositioningTable.Value.Y_ADVANCE ) != 0 ) {
ya = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
} else {
ya = 0;
}
// XPlaDevice
GlyphPositioningTable.DeviceTable xpd;
if ( ( valueFormat & GlyphPositioningTable.Value.X_PLACEMENT_DEVICE ) != 0 ) {
int xpdo = in.readTTFUShort();
xpd = readPosDeviceTable ( subtableOffset, xpdo );
} else {
xpd = null;
}
// YPlaDevice
GlyphPositioningTable.DeviceTable ypd;
if ( ( valueFormat & GlyphPositioningTable.Value.Y_PLACEMENT_DEVICE ) != 0 ) {
int ypdo = in.readTTFUShort();
ypd = readPosDeviceTable ( subtableOffset, ypdo );
} else {
ypd = null;
}
// XAdvDevice
GlyphPositioningTable.DeviceTable xad;
if ( ( valueFormat & GlyphPositioningTable.Value.X_ADVANCE_DEVICE ) != 0 ) {
int xado = in.readTTFUShort();
xad = readPosDeviceTable ( subtableOffset, xado );
} else {
xad = null;
}
// YAdvDevice
GlyphPositioningTable.DeviceTable yad;
if ( ( valueFormat & GlyphPositioningTable.Value.Y_ADVANCE_DEVICE ) != 0 ) {
int yado = in.readTTFUShort();
yad = readPosDeviceTable ( subtableOffset, yado );
} else {
yad = null;
}
return new GlyphPositioningTable.Value ( xp, yp, xa, ya, xpd, ypd, xad, yad );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readSinglePosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read value format
int vf = in.readTTFUShort();
// read value
GlyphPositioningTable.Value v = readPosValue ( subtableOffset, vf );
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " single positioning subtable format: " + subtableFormat + " (delta)" );
log.debug(tableTag + " single positioning coverage table offset: " + co );
log.debug(tableTag + " single positioning value: " + v );
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " single positioning coverage", subtableOffset + co );
// store results
seMapping = ct;
seEntries.add ( v );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readSinglePosTableFormat2(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read value format
int vf = in.readTTFUShort();
// read value count
int nv = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " single positioning subtable format: " + subtableFormat + " (mapped)" );
log.debug(tableTag + " single positioning coverage table offset: " + co );
log.debug(tableTag + " single positioning value count: " + nv );
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " single positioning coverage", subtableOffset + co );
// read positioning values
GlyphPositioningTable.Value[] pva = new GlyphPositioningTable.Value[nv];
for ( int i = 0, n = nv; i < n; i++ ) {
GlyphPositioningTable.Value pv = readPosValue ( subtableOffset, vf );
if (log.isDebugEnabled()) {
log.debug(tableTag + " single positioning value[" + i + "]: " + pv );
}
pva[i] = pv;
}
// store results
seMapping = ct;
seEntries.add ( pva );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readSinglePosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positionining subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readSinglePosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 2 ) {
readSinglePosTableFormat2 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported single positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphPositioningTable.PairValues readPosPairValues(long subtableOffset, boolean hasGlyph, int vf1, int vf2) throws IOException {
// read glyph (if present)
int glyph;
if ( hasGlyph ) {
glyph = in.readTTFUShort();
} else {
glyph = 0;
}
// read first value (if present)
GlyphPositioningTable.Value v1;
if ( vf1 != 0 ) {
v1 = readPosValue ( subtableOffset, vf1 );
} else {
v1 = null;
}
// read second value (if present)
GlyphPositioningTable.Value v2;
if ( vf2 != 0 ) {
v2 = readPosValue ( subtableOffset, vf2 );
} else {
v2 = null;
}
return new GlyphPositioningTable.PairValues ( glyph, v1, v2 );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphPositioningTable.PairValues[] readPosPairSetTable(long subtableOffset, int pairSetTableOffset, int vf1, int vf2) throws IOException {
String tableTag = "GPOS";
long cp = in.getCurrentPos();
in.seekSet(subtableOffset + pairSetTableOffset);
// read pair values count
int npv = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " pair set table offset: " + pairSetTableOffset );
log.debug(tableTag + " pair set table values count: " + npv );
}
// read pair values
GlyphPositioningTable.PairValues[] pva = new GlyphPositioningTable.PairValues [ npv ];
for ( int i = 0, n = npv; i < n; i++ ) {
GlyphPositioningTable.PairValues pv = readPosPairValues ( subtableOffset, true, vf1, vf2 );
pva [ i ] = pv;
if (log.isDebugEnabled()) {
log.debug(tableTag + " pair set table value[" + i + "]: " + pv);
}
}
in.seekSet(cp);
return pva;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readPairPosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read value format for first glyph
int vf1 = in.readTTFUShort();
// read value format for second glyph
int vf2 = in.readTTFUShort();
// read number (count) of pair sets
int nps = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " pair positioning subtable format: " + subtableFormat + " (glyphs)" );
log.debug(tableTag + " pair positioning coverage table offset: " + co );
log.debug(tableTag + " pair positioning value format #1: " + vf1 );
log.debug(tableTag + " pair positioning value format #2: " + vf2 );
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " pair positioning coverage", subtableOffset + co );
// read pair value matrix
GlyphPositioningTable.PairValues[][] pvm = new GlyphPositioningTable.PairValues [ nps ][];
for ( int i = 0, n = nps; i < n; i++ ) {
// read pair set offset
int pso = in.readTTFUShort();
// read pair set table at offset
pvm [ i ] = readPosPairSetTable ( subtableOffset, pso, vf1, vf2 );
}
// store results
seMapping = ct;
seEntries.add ( pvm );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readPairPosTableFormat2(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read value format for first glyph
int vf1 = in.readTTFUShort();
// read value format for second glyph
int vf2 = in.readTTFUShort();
// read class def 1 offset
int cd1o = in.readTTFUShort();
// read class def 2 offset
int cd2o = in.readTTFUShort();
// read number (count) of classes in class def 1 table
int nc1 = in.readTTFUShort();
// read number (count) of classes in class def 2 table
int nc2 = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " pair positioning subtable format: " + subtableFormat + " (glyph classes)" );
log.debug(tableTag + " pair positioning coverage table offset: " + co );
log.debug(tableTag + " pair positioning value format #1: " + vf1 );
log.debug(tableTag + " pair positioning value format #2: " + vf2 );
log.debug(tableTag + " pair positioning class def table #1 offset: " + cd1o );
log.debug(tableTag + " pair positioning class def table #2 offset: " + cd2o );
log.debug(tableTag + " pair positioning class #1 count: " + nc1 );
log.debug(tableTag + " pair positioning class #2 count: " + nc2 );
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " pair positioning coverage", subtableOffset + co );
// read class definition table #1
GlyphClassTable cdt1 = readClassDefTable ( tableTag + " pair positioning class definition #1", subtableOffset + cd1o );
// read class definition table #2
GlyphClassTable cdt2 = readClassDefTable ( tableTag + " pair positioning class definition #2", subtableOffset + cd2o );
// read pair value matrix
GlyphPositioningTable.PairValues[][] pvm = new GlyphPositioningTable.PairValues [ nc1 ] [ nc2 ];
for ( int i = 0; i < nc1; i++ ) {
for ( int j = 0; j < nc2; j++ ) {
GlyphPositioningTable.PairValues pv = readPosPairValues ( subtableOffset, false, vf1, vf2 );
pvm [ i ] [ j ] = pv;
if (log.isDebugEnabled()) {
log.debug(tableTag + " pair set table value[" + i + "][" + j + "]: " + pv);
}
}
}
// store results
seMapping = ct;
seEntries.add ( cdt1 );
seEntries.add ( cdt2 );
seEntries.add ( Integer.valueOf ( nc1 ) );
seEntries.add ( Integer.valueOf ( nc2 ) );
seEntries.add ( pvm );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readPairPosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readPairPosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 2 ) {
readPairPosTableFormat2 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported pair positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private GlyphPositioningTable.Anchor readPosAnchor(long anchorTableOffset) throws IOException {
GlyphPositioningTable.Anchor a;
long cp = in.getCurrentPos();
in.seekSet(anchorTableOffset);
// read anchor table format
int af = in.readTTFUShort();
if ( af == 1 ) {
// read x coordinate
int x = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
// read y coordinate
int y = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
a = new GlyphPositioningTable.Anchor ( x, y );
} else if ( af == 2 ) {
// read x coordinate
int x = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
// read y coordinate
int y = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
// read anchor point index
int ap = in.readTTFUShort();
a = new GlyphPositioningTable.Anchor ( x, y, ap );
} else if ( af == 3 ) {
// read x coordinate
int x = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
// read y coordinate
int y = ttf.convertTTFUnit2PDFUnit ( in.readTTFShort() );
// read x device table offset
int xdo = in.readTTFUShort();
// read y device table offset
int ydo = in.readTTFUShort();
// read x device table (if present)
GlyphPositioningTable.DeviceTable xd;
if ( xdo != 0 ) {
xd = readPosDeviceTable ( cp, xdo );
} else {
xd = null;
}
// read y device table (if present)
GlyphPositioningTable.DeviceTable yd;
if ( ydo != 0 ) {
yd = readPosDeviceTable ( cp, ydo );
} else {
yd = null;
}
a = new GlyphPositioningTable.Anchor ( x, y, xd, yd );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported positioning anchor format: " + af );
}
in.seekSet(cp);
return a;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readCursivePosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read entry/exit count
int ec = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " cursive positioning subtable format: " + subtableFormat );
log.debug(tableTag + " cursive positioning coverage table offset: " + co );
log.debug(tableTag + " cursive positioning entry/exit count: " + ec );
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " cursive positioning coverage", subtableOffset + co );
// read entry/exit records
GlyphPositioningTable.Anchor[] aa = new GlyphPositioningTable.Anchor [ ec * 2 ];
for ( int i = 0, n = ec; i < n; i++ ) {
// read entry anchor offset
int eno = in.readTTFUShort();
// read exit anchor offset
int exo = in.readTTFUShort();
// read entry anchor
GlyphPositioningTable.Anchor ena;
if ( eno > 0 ) {
ena = readPosAnchor ( subtableOffset + eno );
} else {
ena = null;
}
// read exit anchor
GlyphPositioningTable.Anchor exa;
if ( exo > 0 ) {
exa = readPosAnchor ( subtableOffset + exo );
} else {
exa = null;
}
aa [ ( i * 2 ) + 0 ] = ena;
aa [ ( i * 2 ) + 1 ] = exa;
if (log.isDebugEnabled()) {
if ( ena != null ) {
log.debug(tableTag + " cursive entry anchor [" + i + "]: " + ena );
}
if ( exa != null ) {
log.debug(tableTag + " cursive exit anchor [" + i + "]: " + exa );
}
}
}
// store results
seMapping = ct;
seEntries.add ( aa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readCursivePosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readCursivePosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported cursive positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readMarkToBasePosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read mark coverage offset
int mco = in.readTTFUShort();
// read base coverage offset
int bco = in.readTTFUShort();
// read mark class count
int nmc = in.readTTFUShort();
// read mark array offset
int mao = in.readTTFUShort();
// read base array offset
int bao = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-base positioning subtable format: " + subtableFormat );
log.debug(tableTag + " mark-to-base positioning mark coverage table offset: " + mco );
log.debug(tableTag + " mark-to-base positioning base coverage table offset: " + bco );
log.debug(tableTag + " mark-to-base positioning mark class count: " + nmc );
log.debug(tableTag + " mark-to-base positioning mark array offset: " + mao );
log.debug(tableTag + " mark-to-base positioning base array offset: " + bao );
}
// read mark coverage table
GlyphCoverageTable mct = readCoverageTable ( tableTag + " mark-to-base positioning mark coverage", subtableOffset + mco );
// read base coverage table
GlyphCoverageTable bct = readCoverageTable ( tableTag + " mark-to-base positioning base coverage", subtableOffset + bco );
// read mark anchor array
// seek to mark array
in.seekSet(subtableOffset + mao);
// read mark count
int nm = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-base positioning mark count: " + nm );
}
// read mark anchor array, where i:{0...markCount}
GlyphPositioningTable.MarkAnchor[] maa = new GlyphPositioningTable.MarkAnchor [ nm ];
for ( int i = 0; i < nm; i++ ) {
// read mark class
int mc = in.readTTFUShort();
// read mark anchor offset
int ao = in.readTTFUShort();
GlyphPositioningTable.Anchor a;
if ( ao > 0 ) {
a = readPosAnchor ( subtableOffset + mao + ao );
} else {
a = null;
}
GlyphPositioningTable.MarkAnchor ma;
if ( a != null ) {
ma = new GlyphPositioningTable.MarkAnchor ( mc, a );
} else {
ma = null;
}
maa [ i ] = ma;
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-base positioning mark anchor[" + i + "]: " + ma);
}
}
// read base anchor matrix
// seek to base array
in.seekSet(subtableOffset + bao);
// read base count
int nb = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-base positioning base count: " + nb );
}
// read anchor matrix, where i:{0...baseCount - 1}, j:{0...markClassCount - 1}
GlyphPositioningTable.Anchor[][] bam = new GlyphPositioningTable.Anchor [ nb ] [ nmc ];
for ( int i = 0; i < nb; i++ ) {
for ( int j = 0; j < nmc; j++ ) {
// read base anchor offset
int ao = in.readTTFUShort();
GlyphPositioningTable.Anchor a;
if ( ao > 0 ) {
a = readPosAnchor ( subtableOffset + bao + ao );
} else {
a = null;
}
bam [ i ] [ j ] = a;
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-base positioning base anchor[" + i + "][" + j + "]: " + a);
}
}
}
// store results
seMapping = mct;
seEntries.add ( bct );
seEntries.add ( Integer.valueOf ( nmc ) );
seEntries.add ( maa );
seEntries.add ( bam );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readMarkToBasePosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readMarkToBasePosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported mark-to-base positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readMarkToLigaturePosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read mark coverage offset
int mco = in.readTTFUShort();
// read ligature coverage offset
int lco = in.readTTFUShort();
// read mark class count
int nmc = in.readTTFUShort();
// read mark array offset
int mao = in.readTTFUShort();
// read ligature array offset
int lao = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-ligature positioning subtable format: " + subtableFormat );
log.debug(tableTag + " mark-to-ligature positioning mark coverage table offset: " + mco );
log.debug(tableTag + " mark-to-ligature positioning ligature coverage table offset: " + lco );
log.debug(tableTag + " mark-to-ligature positioning mark class count: " + nmc );
log.debug(tableTag + " mark-to-ligature positioning mark array offset: " + mao );
log.debug(tableTag + " mark-to-ligature positioning ligature array offset: " + lao );
}
// read mark coverage table
GlyphCoverageTable mct = readCoverageTable ( tableTag + " mark-to-ligature positioning mark coverage", subtableOffset + mco );
// read ligature coverage table
GlyphCoverageTable lct = readCoverageTable ( tableTag + " mark-to-ligature positioning ligature coverage", subtableOffset + lco );
// read mark anchor array
// seek to mark array
in.seekSet(subtableOffset + mao);
// read mark count
int nm = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-ligature positioning mark count: " + nm );
}
// read mark anchor array, where i:{0...markCount}
GlyphPositioningTable.MarkAnchor[] maa = new GlyphPositioningTable.MarkAnchor [ nm ];
for ( int i = 0; i < nm; i++ ) {
// read mark class
int mc = in.readTTFUShort();
// read mark anchor offset
int ao = in.readTTFUShort();
GlyphPositioningTable.Anchor a;
if ( ao > 0 ) {
a = readPosAnchor ( subtableOffset + mao + ao );
} else {
a = null;
}
GlyphPositioningTable.MarkAnchor ma;
if ( a != null ) {
ma = new GlyphPositioningTable.MarkAnchor ( mc, a );
} else {
ma = null;
}
maa [ i ] = ma;
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-ligature positioning mark anchor[" + i + "]: " + ma);
}
}
// read ligature anchor matrix
// seek to ligature array
in.seekSet(subtableOffset + lao);
// read ligature count
int nl = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-ligature positioning ligature count: " + nl );
}
// read ligature attach table offsets
int[] laoa = new int [ nl ];
for ( int i = 0; i < nl; i++ ) {
laoa [ i ] = in.readTTFUShort();
}
// iterate over ligature attach tables, recording maximum component count
int mxc = 0;
for ( int i = 0; i < nl; i++ ) {
int lato = laoa [ i ];
in.seekSet ( subtableOffset + lao + lato );
// read component count
int cc = in.readTTFUShort();
if ( cc > mxc ) {
mxc = cc;
}
}
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-ligature positioning maximum component count: " + mxc );
}
// read anchor matrix, where i:{0...ligatureCount - 1}, j:{0...maxComponentCount - 1}, k:{0...markClassCount - 1}
GlyphPositioningTable.Anchor[][][] lam = new GlyphPositioningTable.Anchor [ nl ][][];
for ( int i = 0; i < nl; i++ ) {
int lato = laoa [ i ];
// seek to ligature attach table for ligature[i]
in.seekSet ( subtableOffset + lao + lato );
// read component count
int cc = in.readTTFUShort();
GlyphPositioningTable.Anchor[][] lcm = new GlyphPositioningTable.Anchor [ cc ] [ nmc ];
for ( int j = 0; j < cc; j++ ) {
for ( int k = 0; k < nmc; k++ ) {
// read ligature anchor offset
int ao = in.readTTFUShort();
GlyphPositioningTable.Anchor a;
if ( ao > 0 ) {
a = readPosAnchor ( subtableOffset + lao + lato + ao );
} else {
a = null;
}
lcm [ j ] [ k ] = a;
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-ligature positioning ligature anchor[" + i + "][" + j + "][" + k + "]: " + a);
}
}
}
lam [ i ] = lcm;
}
// store results
seMapping = mct;
seEntries.add ( lct );
seEntries.add ( Integer.valueOf ( nmc ) );
seEntries.add ( Integer.valueOf ( mxc ) );
seEntries.add ( maa );
seEntries.add ( lam );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readMarkToLigaturePosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readMarkToLigaturePosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported mark-to-ligature positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readMarkToMarkPosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read mark #1 coverage offset
int m1co = in.readTTFUShort();
// read mark #2 coverage offset
int m2co = in.readTTFUShort();
// read mark class count
int nmc = in.readTTFUShort();
// read mark #1 array offset
int m1ao = in.readTTFUShort();
// read mark #2 array offset
int m2ao = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-mark positioning subtable format: " + subtableFormat );
log.debug(tableTag + " mark-to-mark positioning mark #1 coverage table offset: " + m1co );
log.debug(tableTag + " mark-to-mark positioning mark #2 coverage table offset: " + m2co );
log.debug(tableTag + " mark-to-mark positioning mark class count: " + nmc );
log.debug(tableTag + " mark-to-mark positioning mark #1 array offset: " + m1ao );
log.debug(tableTag + " mark-to-mark positioning mark #2 array offset: " + m2ao );
}
// read mark #1 coverage table
GlyphCoverageTable mct1 = readCoverageTable ( tableTag + " mark-to-mark positioning mark #1 coverage", subtableOffset + m1co );
// read mark #2 coverage table
GlyphCoverageTable mct2 = readCoverageTable ( tableTag + " mark-to-mark positioning mark #2 coverage", subtableOffset + m2co );
// read mark #1 anchor array
// seek to mark array
in.seekSet(subtableOffset + m1ao);
// read mark count
int nm1 = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-mark positioning mark #1 count: " + nm1 );
}
// read mark anchor array, where i:{0...mark1Count}
GlyphPositioningTable.MarkAnchor[] maa = new GlyphPositioningTable.MarkAnchor [ nm1 ];
for ( int i = 0; i < nm1; i++ ) {
// read mark class
int mc = in.readTTFUShort();
// read mark anchor offset
int ao = in.readTTFUShort();
GlyphPositioningTable.Anchor a;
if ( ao > 0 ) {
a = readPosAnchor ( subtableOffset + m1ao + ao );
} else {
a = null;
}
GlyphPositioningTable.MarkAnchor ma;
if ( a != null ) {
ma = new GlyphPositioningTable.MarkAnchor ( mc, a );
} else {
ma = null;
}
maa [ i ] = ma;
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-mark positioning mark #1 anchor[" + i + "]: " + ma);
}
}
// read mark #2 anchor matrix
// seek to mark #2 array
in.seekSet(subtableOffset + m2ao);
// read mark #2 count
int nm2 = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-mark positioning mark #2 count: " + nm2 );
}
// read anchor matrix, where i:{0...mark2Count - 1}, j:{0...markClassCount - 1}
GlyphPositioningTable.Anchor[][] mam = new GlyphPositioningTable.Anchor [ nm2 ] [ nmc ];
for ( int i = 0; i < nm2; i++ ) {
for ( int j = 0; j < nmc; j++ ) {
// read mark anchor offset
int ao = in.readTTFUShort();
GlyphPositioningTable.Anchor a;
if ( ao > 0 ) {
a = readPosAnchor ( subtableOffset + m2ao + ao );
} else {
a = null;
}
mam [ i ] [ j ] = a;
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark-to-mark positioning mark #2 anchor[" + i + "][" + j + "]: " + a);
}
}
}
// store results
seMapping = mct1;
seEntries.add ( mct2 );
seEntries.add ( Integer.valueOf ( nmc ) );
seEntries.add ( maa );
seEntries.add ( mam );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readMarkToMarkPosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readMarkToMarkPosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported mark-to-mark positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readContextualPosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read rule set count
int nrs = in.readTTFUShort();
// read rule set offsets
int[] rsoa = new int [ nrs ];
for ( int i = 0; i < nrs; i++ ) {
rsoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " contextual positioning subtable format: " + subtableFormat + " (glyphs)" );
log.debug(tableTag + " contextual positioning coverage table offset: " + co );
log.debug(tableTag + " contextual positioning rule set count: " + nrs );
for ( int i = 0; i < nrs; i++ ) {
log.debug(tableTag + " contextual positioning rule set offset[" + i + "]: " + rsoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " contextual positioning coverage", subtableOffset + co );
} else {
ct = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ nrs ];
String header = null;
for ( int i = 0; i < nrs; i++ ) {
GlyphTable.RuleSet rs;
int rso = rsoa [ i ];
if ( rso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + rso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
GlyphTable.GlyphSequenceRule r;
int ro = roa [ j ];
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + rso + ro );
// read glyph count
int ng = in.readTTFUShort();
// read rule lookup count
int nl = in.readTTFUShort();
// read glyphs
int[] glyphs = new int [ ng - 1 ];
for ( int k = 0, nk = glyphs.length; k < nk; k++ ) {
glyphs [ k ] = in.readTTFUShort();
}
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual positioning lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.GlyphSequenceRule ( lookups, ng, glyphs );
} else {
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readContextualPosTableFormat2(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read class def table offset
int cdo = in.readTTFUShort();
// read class rule set count
int ngc = in.readTTFUShort();
// read class rule set offsets
int[] csoa = new int [ ngc ];
for ( int i = 0; i < ngc; i++ ) {
csoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " contextual positioning subtable format: " + subtableFormat + " (glyph classes)" );
log.debug(tableTag + " contextual positioning coverage table offset: " + co );
log.debug(tableTag + " contextual positioning class set count: " + ngc );
for ( int i = 0; i < ngc; i++ ) {
log.debug(tableTag + " contextual positioning class set offset[" + i + "]: " + csoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " contextual positioning coverage", subtableOffset + co );
} else {
ct = null;
}
// read class definition table
GlyphClassTable cdt;
if ( cdo > 0 ) {
cdt = readClassDefTable ( tableTag + " contextual positioning class definition", subtableOffset + cdo );
} else {
cdt = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ ngc ];
String header = null;
for ( int i = 0; i < ngc; i++ ) {
int cso = csoa [ i ];
GlyphTable.RuleSet rs;
if ( cso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + cso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
int ro = roa [ j ];
GlyphTable.ClassSequenceRule r;
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + cso + ro );
// read glyph count
int ng = in.readTTFUShort();
// read rule lookup count
int nl = in.readTTFUShort();
// read classes
int[] classes = new int [ ng - 1 ];
for ( int k = 0, nk = classes.length; k < nk; k++ ) {
classes [ k ] = in.readTTFUShort();
}
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual positioning lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.ClassSequenceRule ( lookups, ng, classes );
} else {
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( cdt );
seEntries.add ( Integer.valueOf ( ngc ) );
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readContextualPosTableFormat3(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read glyph (input sequence length) count
int ng = in.readTTFUShort();
// read positioning lookup count
int nl = in.readTTFUShort();
// read glyph coverage offsets, one per glyph input sequence length count
int[] gcoa = new int [ ng ];
for ( int i = 0; i < ng; i++ ) {
gcoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " contextual positioning subtable format: " + subtableFormat + " (glyph sets)" );
log.debug(tableTag + " contextual positioning glyph input sequence length count: " + ng );
log.debug(tableTag + " contextual positioning lookup count: " + nl );
for ( int i = 0; i < ng; i++ ) {
log.debug(tableTag + " contextual positioning coverage table offset[" + i + "]: " + gcoa[i] );
}
}
// read coverage tables
GlyphCoverageTable[] gca = new GlyphCoverageTable [ ng ];
for ( int i = 0; i < ng; i++ ) {
int gco = gcoa [ i ];
GlyphCoverageTable gct;
if ( gco > 0 ) {
gct = readCoverageTable ( tableTag + " contextual positioning coverage[" + i + "]", subtableOffset + gcoa[i] );
} else {
gct = null;
}
gca [ i ] = gct;
}
// read rule lookups
String header = null;
if (log.isDebugEnabled()) {
header = tableTag + " contextual positioning lookups: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
// construct rule, rule set, and rule set array
GlyphTable.Rule r = new GlyphTable.CoverageSequenceRule ( lookups, ng, gca );
GlyphTable.RuleSet rs = new GlyphTable.HomogeneousRuleSet ( new GlyphTable.Rule[] {r} );
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet[] {rs};
// store results
assert ( gca != null ) && ( gca.length > 0 );
seMapping = gca[0];
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readContextualPosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readContextualPosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 2 ) {
readContextualPosTableFormat2 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 3 ) {
readContextualPosTableFormat3 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported contextual positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readChainedContextualPosTableFormat1(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read rule set count
int nrs = in.readTTFUShort();
// read rule set offsets
int[] rsoa = new int [ nrs ];
for ( int i = 0; i < nrs; i++ ) {
rsoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " chained contextual positioning subtable format: " + subtableFormat + " (glyphs)" );
log.debug(tableTag + " chained contextual positioning coverage table offset: " + co );
log.debug(tableTag + " chained contextual positioning rule set count: " + nrs );
for ( int i = 0; i < nrs; i++ ) {
log.debug(tableTag + " chained contextual positioning rule set offset[" + i + "]: " + rsoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " chained contextual positioning coverage", subtableOffset + co );
} else {
ct = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ nrs ];
String header = null;
for ( int i = 0; i < nrs; i++ ) {
GlyphTable.RuleSet rs;
int rso = rsoa [ i ];
if ( rso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + rso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
GlyphTable.ChainedGlyphSequenceRule r;
int ro = roa [ j ];
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + rso + ro );
// read backtrack glyph count
int nbg = in.readTTFUShort();
// read backtrack glyphs
int[] backtrackGlyphs = new int [ nbg ];
for ( int k = 0, nk = backtrackGlyphs.length; k < nk; k++ ) {
backtrackGlyphs [ k ] = in.readTTFUShort();
}
// read input glyph count
int nig = in.readTTFUShort();
// read glyphs
int[] glyphs = new int [ nig - 1 ];
for ( int k = 0, nk = glyphs.length; k < nk; k++ ) {
glyphs [ k ] = in.readTTFUShort();
}
// read lookahead glyph count
int nlg = in.readTTFUShort();
// read lookahead glyphs
int[] lookaheadGlyphs = new int [ nlg ];
for ( int k = 0, nk = lookaheadGlyphs.length; k < nk; k++ ) {
lookaheadGlyphs [ k ] = in.readTTFUShort();
}
// read rule lookup count
int nl = in.readTTFUShort();
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual positioning lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.ChainedGlyphSequenceRule ( lookups, nig, glyphs, backtrackGlyphs, lookaheadGlyphs );
} else {
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readChainedContextualPosTableFormat2(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read coverage offset
int co = in.readTTFUShort();
// read backtrack class def table offset
int bcdo = in.readTTFUShort();
// read input class def table offset
int icdo = in.readTTFUShort();
// read lookahead class def table offset
int lcdo = in.readTTFUShort();
// read class set count
int ngc = in.readTTFUShort();
// read class set offsets
int[] csoa = new int [ ngc ];
for ( int i = 0; i < ngc; i++ ) {
csoa [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " chained contextual positioning subtable format: " + subtableFormat + " (glyph classes)" );
log.debug(tableTag + " chained contextual positioning coverage table offset: " + co );
log.debug(tableTag + " chained contextual positioning class set count: " + ngc );
for ( int i = 0; i < ngc; i++ ) {
log.debug(tableTag + " chained contextual positioning class set offset[" + i + "]: " + csoa[i] );
}
}
// read coverage table
GlyphCoverageTable ct;
if ( co > 0 ) {
ct = readCoverageTable ( tableTag + " chained contextual positioning coverage", subtableOffset + co );
} else {
ct = null;
}
// read backtrack class definition table
GlyphClassTable bcdt;
if ( bcdo > 0 ) {
bcdt = readClassDefTable ( tableTag + " contextual positioning backtrack class definition", subtableOffset + bcdo );
} else {
bcdt = null;
}
// read input class definition table
GlyphClassTable icdt;
if ( icdo > 0 ) {
icdt = readClassDefTable ( tableTag + " contextual positioning input class definition", subtableOffset + icdo );
} else {
icdt = null;
}
// read lookahead class definition table
GlyphClassTable lcdt;
if ( lcdo > 0 ) {
lcdt = readClassDefTable ( tableTag + " contextual positioning lookahead class definition", subtableOffset + lcdo );
} else {
lcdt = null;
}
// read rule sets
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet [ ngc ];
String header = null;
for ( int i = 0; i < ngc; i++ ) {
int cso = csoa [ i ];
GlyphTable.RuleSet rs;
if ( cso > 0 ) {
// seek to rule set [ i ]
in.seekSet ( subtableOffset + cso );
// read rule count
int nr = in.readTTFUShort();
// read rule offsets
int[] roa = new int [ nr ];
GlyphTable.Rule[] ra = new GlyphTable.Rule [ nr ];
for ( int j = 0; j < nr; j++ ) {
roa [ j ] = in.readTTFUShort();
}
// read glyph sequence rules
for ( int j = 0; j < nr; j++ ) {
GlyphTable.ChainedClassSequenceRule r;
int ro = roa [ j ];
if ( ro > 0 ) {
// seek to rule [ j ]
in.seekSet ( subtableOffset + cso + ro );
// read backtrack glyph class count
int nbc = in.readTTFUShort();
// read backtrack glyph classes
int[] backtrackClasses = new int [ nbc ];
for ( int k = 0, nk = backtrackClasses.length; k < nk; k++ ) {
backtrackClasses [ k ] = in.readTTFUShort();
}
// read input glyph class count
int nic = in.readTTFUShort();
// read input glyph classes
int[] classes = new int [ nic - 1 ];
for ( int k = 0, nk = classes.length; k < nk; k++ ) {
classes [ k ] = in.readTTFUShort();
}
// read lookahead glyph class count
int nlc = in.readTTFUShort();
// read lookahead glyph classes
int[] lookaheadClasses = new int [ nlc ];
for ( int k = 0, nk = lookaheadClasses.length; k < nk; k++ ) {
lookaheadClasses [ k ] = in.readTTFUShort();
}
// read rule lookup count
int nl = in.readTTFUShort();
// read rule lookups
if (log.isDebugEnabled()) {
header = tableTag + " contextual positioning lookups @rule[" + i + "][" + j + "]: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
r = new GlyphTable.ChainedClassSequenceRule ( lookups, nic, classes, backtrackClasses, lookaheadClasses );
} else {
r = null;
}
ra [ j ] = r;
}
rs = new GlyphTable.HomogeneousRuleSet ( ra );
} else {
rs = null;
}
rsa [ i ] = rs;
}
// store results
seMapping = ct;
seEntries.add ( icdt );
seEntries.add ( bcdt );
seEntries.add ( lcdt );
seEntries.add ( Integer.valueOf ( ngc ) );
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readChainedContextualPosTableFormat3(int lookupType, int lookupFlags, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read backtrack glyph count
int nbg = in.readTTFUShort();
// read backtrack glyph coverage offsets
int[] bgcoa = new int [ nbg ];
for ( int i = 0; i < nbg; i++ ) {
bgcoa [ i ] = in.readTTFUShort();
}
// read input glyph count
int nig = in.readTTFUShort();
// read backtrack glyph coverage offsets
int[] igcoa = new int [ nig ];
for ( int i = 0; i < nig; i++ ) {
igcoa [ i ] = in.readTTFUShort();
}
// read lookahead glyph count
int nlg = in.readTTFUShort();
// read backtrack glyph coverage offsets
int[] lgcoa = new int [ nlg ];
for ( int i = 0; i < nlg; i++ ) {
lgcoa [ i ] = in.readTTFUShort();
}
// read positioning lookup count
int nl = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " chained contextual positioning subtable format: " + subtableFormat + " (glyph sets)" );
log.debug(tableTag + " chained contextual positioning backtrack glyph count: " + nbg );
for ( int i = 0; i < nbg; i++ ) {
log.debug(tableTag + " chained contextual positioning backtrack coverage table offset[" + i + "]: " + bgcoa[i] );
}
log.debug(tableTag + " chained contextual positioning input glyph count: " + nig );
for ( int i = 0; i < nig; i++ ) {
log.debug(tableTag + " chained contextual positioning input coverage table offset[" + i + "]: " + igcoa[i] );
}
log.debug(tableTag + " chained contextual positioning lookahead glyph count: " + nlg );
for ( int i = 0; i < nlg; i++ ) {
log.debug(tableTag + " chained contextual positioning lookahead coverage table offset[" + i + "]: " + lgcoa[i] );
}
log.debug(tableTag + " chained contextual positioning lookup count: " + nl );
}
// read backtrack coverage tables
GlyphCoverageTable[] bgca = new GlyphCoverageTable[nbg];
for ( int i = 0; i < nbg; i++ ) {
int bgco = bgcoa [ i ];
GlyphCoverageTable bgct;
if ( bgco > 0 ) {
bgct = readCoverageTable ( tableTag + " chained contextual positioning backtrack coverage[" + i + "]", subtableOffset + bgco );
} else {
bgct = null;
}
bgca[i] = bgct;
}
// read input coverage tables
GlyphCoverageTable[] igca = new GlyphCoverageTable[nig];
for ( int i = 0; i < nig; i++ ) {
int igco = igcoa [ i ];
GlyphCoverageTable igct;
if ( igco > 0 ) {
igct = readCoverageTable ( tableTag + " chained contextual positioning input coverage[" + i + "]", subtableOffset + igco );
} else {
igct = null;
}
igca[i] = igct;
}
// read lookahead coverage tables
GlyphCoverageTable[] lgca = new GlyphCoverageTable[nlg];
for ( int i = 0; i < nlg; i++ ) {
int lgco = lgcoa [ i ];
GlyphCoverageTable lgct;
if ( lgco > 0 ) {
lgct = readCoverageTable ( tableTag + " chained contextual positioning lookahead coverage[" + i + "]", subtableOffset + lgco );
} else {
lgct = null;
}
lgca[i] = lgct;
}
// read rule lookups
String header = null;
if (log.isDebugEnabled()) {
header = tableTag + " chained contextual positioning lookups: ";
}
GlyphTable.RuleLookup[] lookups = readRuleLookups ( nl, header );
// construct rule, rule set, and rule set array
GlyphTable.Rule r = new GlyphTable.ChainedCoverageSequenceRule ( lookups, nig, igca, bgca, lgca );
GlyphTable.RuleSet rs = new GlyphTable.HomogeneousRuleSet ( new GlyphTable.Rule[] {r} );
GlyphTable.RuleSet[] rsa = new GlyphTable.RuleSet[] {rs};
// store results
assert ( igca != null ) && ( igca.length > 0 );
seMapping = igca[0];
seEntries.add ( rsa );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readChainedContextualPosTable(int lookupType, int lookupFlags, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readChainedContextualPosTableFormat1 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 2 ) {
readChainedContextualPosTableFormat2 ( lookupType, lookupFlags, subtableOffset, sf );
} else if ( sf == 3 ) {
readChainedContextualPosTableFormat3 ( lookupType, lookupFlags, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported chained contextual positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readExtensionPosTableFormat1(int lookupType, int lookupFlags, int lookupSequence, int subtableSequence, long subtableOffset, int subtableFormat) throws IOException {
String tableTag = "GPOS";
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read extension lookup type
int lt = in.readTTFUShort();
// read extension offset
long eo = in.readTTFULong();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " extension positioning subtable format: " + subtableFormat );
log.debug(tableTag + " extension positioning lookup type: " + lt );
log.debug(tableTag + " extension positioning lookup table offset: " + eo );
}
// read referenced subtable from extended offset
readGPOSSubtable ( lt, lookupFlags, lookupSequence, subtableSequence, subtableOffset + eo );
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private int readExtensionPosTable(int lookupType, int lookupFlags, int lookupSequence, int subtableSequence, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read positioning subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readExtensionPosTableFormat1 ( lookupType, lookupFlags, lookupSequence, subtableSequence, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported extension positioning subtable format: " + sf );
}
return sf;
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGPOSSubtable(int lookupType, int lookupFlags, int lookupSequence, int subtableSequence, long subtableOffset) throws IOException {
initATSubState();
int subtableFormat = -1;
switch ( lookupType ) {
case GPOSLookupType.SINGLE:
subtableFormat = readSinglePosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.PAIR:
subtableFormat = readPairPosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.CURSIVE:
subtableFormat = readCursivePosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.MARK_TO_BASE:
subtableFormat = readMarkToBasePosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.MARK_TO_LIGATURE:
subtableFormat = readMarkToLigaturePosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.MARK_TO_MARK:
subtableFormat = readMarkToMarkPosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.CONTEXTUAL:
subtableFormat = readContextualPosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.CHAINED_CONTEXTUAL:
subtableFormat = readChainedContextualPosTable ( lookupType, lookupFlags, subtableOffset );
break;
case GPOSLookupType.EXTENSION:
subtableFormat = readExtensionPosTable ( lookupType, lookupFlags, lookupSequence, subtableSequence, subtableOffset );
break;
default:
break;
}
extractSESubState ( GlyphTable.GLYPH_TABLE_TYPE_POSITIONING, lookupType, lookupFlags, lookupSequence, subtableSequence, subtableFormat );
resetATSubState();
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readLookupTable(String tableTag, int lookupSequence, long lookupTable) throws IOException {
boolean isGSUB = tableTag.equals ( "GSUB" );
boolean isGPOS = tableTag.equals ( "GPOS" );
in.seekSet(lookupTable);
// read lookup type
int lt = in.readTTFUShort();
// read lookup flags
int lf = in.readTTFUShort();
// read sub-table count
int ns = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
String lts;
if ( isGSUB ) {
lts = GSUBLookupType.toString ( lt );
} else if ( isGPOS ) {
lts = GPOSLookupType.toString ( lt );
} else {
lts = "?";
}
log.debug(tableTag + " lookup table type: " + lt + " (" + lts + ")" );
log.debug(tableTag + " lookup table flags: " + lf + " (" + LookupFlag.toString ( lf ) + ")" );
log.debug(tableTag + " lookup table subtable count: " + ns );
}
// read subtable offsets
int[] soa = new int[ns];
for ( int i = 0; i < ns; i++ ) {
int so = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " lookup table subtable offset: " + so );
}
soa[i] = so;
}
// read mark filtering set
if ( ( lf & LookupFlag.USE_MARK_FILTERING_SET ) != 0 ) {
// read mark filtering set
int fs = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " lookup table mark filter set: " + fs );
}
}
// read subtables
for ( int i = 0; i < ns; i++ ) {
int so = soa[i];
if ( isGSUB ) {
readGSUBSubtable ( lt, lf, lookupSequence, i, lookupTable + so );
} else if ( isGPOS ) {
readGPOSSubtable ( lt, lf, lookupSequence, i, lookupTable + so );
}
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readLookupList(String tableTag, long lookupList) throws IOException {
in.seekSet(lookupList);
// read lookup record count
int nl = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " lookup list record count: " + nl );
}
if ( nl > 0 ) {
int[] loa = new int[nl];
// read lookup records
for ( int i = 0, n = nl; i < n; i++ ) {
int lo = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " lookup table offset: " + lo );
}
loa[i] = lo;
}
// read lookup tables
for ( int i = 0, n = nl; i < n; i++ ) {
if (log.isDebugEnabled()) {
log.debug(tableTag + " lookup index: " + i );
}
readLookupTable ( tableTag, i, lookupList + loa [ i ] );
}
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readCommonLayoutTables(String tableTag, long scriptList, long featureList, long lookupList) throws IOException {
if ( scriptList > 0 ) {
readScriptList ( tableTag, scriptList );
}
if ( featureList > 0 ) {
readFeatureList ( tableTag, featureList );
}
if ( lookupList > 0 ) {
readLookupList ( tableTag, lookupList );
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGDEFClassDefTable(String tableTag, int lookupSequence, long subtableOffset) throws IOException {
initATSubState();
in.seekSet(subtableOffset);
// subtable is a bare class definition table
GlyphClassTable ct = readClassDefTable ( tableTag + " glyph class definition table", subtableOffset );
// store results
seMapping = ct;
// extract subtable
extractSESubState ( GlyphTable.GLYPH_TABLE_TYPE_DEFINITION, GDEFLookupType.GLYPH_CLASS, 0, lookupSequence, 0, 1 );
resetATSubState();
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGDEFAttachmentTable(String tableTag, int lookupSequence, long subtableOffset) throws IOException {
initATSubState();
in.seekSet(subtableOffset);
// read coverage offset
int co = in.readTTFUShort();
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " attachment point coverage table offset: " + co );
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " attachment point coverage", subtableOffset + co );
// store results
seMapping = ct;
// extract subtable
extractSESubState ( GlyphTable.GLYPH_TABLE_TYPE_DEFINITION, GDEFLookupType.ATTACHMENT_POINT, 0, lookupSequence, 0, 1 );
resetATSubState();
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGDEFLigatureCaretTable(String tableTag, int lookupSequence, long subtableOffset) throws IOException {
initATSubState();
in.seekSet(subtableOffset);
// read coverage offset
int co = in.readTTFUShort();
// read ligature glyph count
int nl = in.readTTFUShort();
// read ligature glyph table offsets
int[] lgto = new int [ nl ];
for ( int i = 0; i < nl; i++ ) {
lgto [ i ] = in.readTTFUShort();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " ligature caret coverage table offset: " + co );
log.debug(tableTag + " ligature caret ligature glyph count: " + nl );
for ( int i = 0; i < nl; i++ ) {
log.debug(tableTag + " ligature glyph table offset[" + i + "]: " + lgto[i] );
}
}
// read coverage table
GlyphCoverageTable ct = readCoverageTable ( tableTag + " ligature caret coverage", subtableOffset + co );
// store results
seMapping = ct;
// extract subtable
extractSESubState ( GlyphTable.GLYPH_TABLE_TYPE_DEFINITION, GDEFLookupType.LIGATURE_CARET, 0, lookupSequence, 0, 1 );
resetATSubState();
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGDEFMarkAttachmentTable(String tableTag, int lookupSequence, long subtableOffset) throws IOException {
initATSubState();
in.seekSet(subtableOffset);
// subtable is a bare class definition table
GlyphClassTable ct = readClassDefTable ( tableTag + " glyph class definition table", subtableOffset );
// store results
seMapping = ct;
// extract subtable
extractSESubState ( GlyphTable.GLYPH_TABLE_TYPE_DEFINITION, GDEFLookupType.MARK_ATTACHMENT, 0, lookupSequence, 0, 1 );
resetATSubState();
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGDEFMarkGlyphsTableFormat1(String tableTag, int lookupSequence, long subtableOffset, int subtableFormat) throws IOException {
initATSubState();
in.seekSet(subtableOffset);
// skip over format (already known)
in.skip ( 2 );
// read mark set class count
int nmc = in.readTTFUShort();
long[] mso = new long [ nmc ];
// read mark set coverage offsets
for ( int i = 0; i < nmc; i++ ) {
mso [ i ] = in.readTTFULong();
}
// dump info if debugging
if (log.isDebugEnabled()) {
log.debug(tableTag + " mark set subtable format: " + subtableFormat + " (glyph sets)" );
log.debug(tableTag + " mark set class count: " + nmc );
for ( int i = 0; i < nmc; i++ ) {
log.debug(tableTag + " mark set coverage table offset[" + i + "]: " + mso[i] );
}
}
// read mark set coverage tables, one per class
GlyphCoverageTable[] msca = new GlyphCoverageTable[nmc];
for ( int i = 0; i < nmc; i++ ) {
msca[i] = readCoverageTable ( tableTag + " mark set coverage[" + i + "]", subtableOffset + mso[i] );
}
// create combined class table from per-class coverage tables
GlyphClassTable ct = GlyphClassTable.createClassTable ( Arrays.asList ( msca ) );
// store results
seMapping = ct;
// extract subtable
extractSESubState ( GlyphTable.GLYPH_TABLE_TYPE_DEFINITION, GDEFLookupType.MARK_ATTACHMENT, 0, lookupSequence, 0, 1 );
resetATSubState();
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGDEFMarkGlyphsTable(String tableTag, int lookupSequence, long subtableOffset) throws IOException {
in.seekSet(subtableOffset);
// read mark set subtable format
int sf = in.readTTFUShort();
if ( sf == 1 ) {
readGDEFMarkGlyphsTableFormat1 ( tableTag, lookupSequence, subtableOffset, sf );
} else {
throw new AdvancedTypographicTableFormatException ( "unsupported mark glyph sets subtable format: " + sf );
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGDEF() throws IOException {
String tableTag = "GDEF";
// Initialize temporary state
initATState();
// Read glyph definition (GDEF) table
TTFDirTabEntry dirTab = ttf.getDirectoryEntry ( tableTag );
if ( gdef != null ) {
if (log.isDebugEnabled()) {
log.debug(tableTag + ": ignoring duplicate table");
}
} else if (dirTab != null) {
ttf.seekTab(in, tableTag, 0);
long version = in.readTTFULong();
if (log.isDebugEnabled()) {
log.debug(tableTag + " version: " + ( version / 65536 ) + "." + ( version % 65536 ));
}
// glyph class definition table offset (may be null)
int cdo = in.readTTFUShort();
// attach point list offset (may be null)
int apo = in.readTTFUShort();
// ligature caret list offset (may be null)
int lco = in.readTTFUShort();
// mark attach class definition table offset (may be null)
int mao = in.readTTFUShort();
// mark glyph sets definition table offset (may be null)
int mgo;
if ( version >= 0x00010002 ) {
mgo = in.readTTFUShort();
} else {
mgo = 0;
}
if (log.isDebugEnabled()) {
log.debug(tableTag + " glyph class definition table offset: " + cdo );
log.debug(tableTag + " attachment point list offset: " + apo );
log.debug(tableTag + " ligature caret list offset: " + lco );
log.debug(tableTag + " mark attachment class definition table offset: " + mao );
log.debug(tableTag + " mark glyph set definitions table offset: " + mgo );
}
// initialize subtable sequence number
int seqno = 0;
// obtain offset to start of gdef table
long to = dirTab.getOffset();
// (optionally) read glyph class definition subtable
if ( cdo != 0 ) {
readGDEFClassDefTable ( tableTag, seqno++, to + cdo );
}
// (optionally) read glyph attachment point subtable
if ( apo != 0 ) {
readGDEFAttachmentTable ( tableTag, seqno++, to + apo );
}
// (optionally) read ligature caret subtable
if ( lco != 0 ) {
readGDEFLigatureCaretTable ( tableTag, seqno++, to + lco );
}
// (optionally) read mark attachment class subtable
if ( mao != 0 ) {
readGDEFMarkAttachmentTable ( tableTag, seqno++, to + mao );
}
// (optionally) read mark glyph sets subtable
if ( mgo != 0 ) {
readGDEFMarkGlyphsTable ( tableTag, seqno++, to + mgo );
}
GlyphDefinitionTable gdef;
if ( ( gdef = constructGDEF() ) != null ) {
this.gdef = gdef;
}
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGSUB() throws IOException {
String tableTag = "GSUB";
// Initialize temporary state
initATState();
// Read glyph substitution (GSUB) table
TTFDirTabEntry dirTab = ttf.getDirectoryEntry ( tableTag );
if ( gpos != null ) {
if (log.isDebugEnabled()) {
log.debug(tableTag + ": ignoring duplicate table");
}
} else if (dirTab != null) {
ttf.seekTab(in, tableTag, 0);
int version = in.readTTFLong();
if (log.isDebugEnabled()) {
log.debug(tableTag + " version: " + ( version / 65536 ) + "." + ( version % 65536 ));
}
int slo = in.readTTFUShort();
int flo = in.readTTFUShort();
int llo = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " script list offset: " + slo );
log.debug(tableTag + " feature list offset: " + flo );
log.debug(tableTag + " lookup list offset: " + llo );
}
long to = dirTab.getOffset();
readCommonLayoutTables ( tableTag, to + slo, to + flo, to + llo );
GlyphSubstitutionTable gsub;
if ( ( gsub = constructGSUB() ) != null ) {
this.gsub = gsub;
}
}
}
// in src/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
private void readGPOS() throws IOException {
String tableTag = "GPOS";
// Initialize temporary state
initATState();
// Read glyph positioning (GPOS) table
TTFDirTabEntry dirTab = ttf.getDirectoryEntry ( tableTag );
if ( gpos != null ) {
if (log.isDebugEnabled()) {
log.debug(tableTag + ": ignoring duplicate table");
}
} else if (dirTab != null) {
ttf.seekTab(in, tableTag, 0);
int version = in.readTTFLong();
if (log.isDebugEnabled()) {
log.debug(tableTag + " version: " + ( version / 65536 ) + "." + ( version % 65536 ));
}
int slo = in.readTTFUShort();
int flo = in.readTTFUShort();
int llo = in.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug(tableTag + " script list offset: " + slo );
log.debug(tableTag + " feature list offset: " + flo );
log.debug(tableTag + " lookup list offset: " + llo );
}
long to = dirTab.getOffset();
readCommonLayoutTables ( tableTag, to + slo, to + flo, to + llo );
GlyphPositioningTable gpos;
if ( ( gpos = constructGPOS() ) != null ) {
this.gpos = gpos;
}
}
}
// in src/java/org/apache/fop/util/DataURLUtil.java
public static String createDataURL(InputStream in, String mediatype)
throws IOException {
return org.apache.xmlgraphics.util.uri.DataURLUtil.createDataURL(in,
mediatype);
}
// in src/java/org/apache/fop/util/DataURLUtil.java
public static void writeDataURL(InputStream in, String mediatype,
Writer writer) throws IOException {
org.apache.xmlgraphics.util.uri.DataURLUtil.writeDataURL(in, mediatype,
writer);
}
// in src/java/org/apache/fop/util/WriterOutputStream.java
public void close() throws IOException {
writerOutputStream.close();
}
// in src/java/org/apache/fop/util/WriterOutputStream.java
public void flush() throws IOException {
writerOutputStream.flush();
}
// in src/java/org/apache/fop/util/WriterOutputStream.java
public void write(byte[] buf, int offset, int length) throws IOException {
writerOutputStream.write(buf, offset, length);
}
// in src/java/org/apache/fop/util/WriterOutputStream.java
public void write(byte[] buf) throws IOException {
writerOutputStream.write(buf);
}
// in src/java/org/apache/fop/util/WriterOutputStream.java
public void write(int b) throws IOException {
writerOutputStream.write(b);
}
// in src/java/org/apache/fop/util/DelegatingContentHandler.java
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
if (entityResolver != null) {
return entityResolver.resolveEntity(publicId, systemId);
} else {
return null;
}
}
// in src/java/org/apache/fop/util/CloseBlockerOutputStream.java
public void close() throws IOException {
try {
flush();
} catch (IOException ioe) {
//ignore
}
}
// in src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java
public ImageInfo preloadImage(String uri, Source src, ImageContext context)
throws IOException {
if (!ImageUtil.hasInputStream(src)) {
return null;
}
ImageInfo info = null;
if (batikAvailable) {
try {
Loader loader = new Loader();
info = loader.getImage(uri, src, context);
} catch (NoClassDefFoundError e) {
batikAvailable = false;
log.warn("Batik not in class path", e);
return null;
}
}
if (info != null) {
ImageUtil.closeQuietly(src); //Image is fully read
}
return info;
}
// in src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java
public Image loadImage(ImageInfo info, Map hints, ImageSessionContext session)
throws ImageException, IOException {
if (!MimeConstants.MIME_SVG.equals(info.getMimeType())) {
throw new IllegalArgumentException("ImageInfo must be from an SVG image");
}
Image img = info.getOriginalImage();
if (!(img instanceof ImageXMLDOM)) {
throw new IllegalArgumentException(
"ImageInfo was expected to contain the SVG document as DOM");
}
ImageXMLDOM svgImage = (ImageXMLDOM)img;
if (!SVGDOMImplementation.SVG_NAMESPACE_URI.equals(svgImage.getRootNamespace())) {
throw new IllegalArgumentException(
"The Image is not in the SVG namespace: " + svgImage.getRootNamespace());
}
return svgImage;
}
// in src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java
public Image loadImage(ImageInfo info, Map hints, ImageSessionContext session)
throws ImageException, IOException {
if (!ImageWMF.MIME_WMF.equals(info.getMimeType())) {
throw new IllegalArgumentException("ImageInfo must be from a WMF image");
}
Image img = info.getOriginalImage();
if (!(img instanceof ImageWMF)) {
throw new IllegalArgumentException(
"ImageInfo was expected to contain the Windows Metafile (WMF)");
}
ImageWMF wmfImage = (ImageWMF)img;
return wmfImage;
}
// in src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
public ImageInfo preloadImage(String uri, Source src, ImageContext context)
throws IOException {
ImageInfo info = null;
if (batikAvailable) {
try {
Loader loader = new Loader();
if (!loader.isSupportedSource(src)) {
return null;
}
info = loader.getImage(uri, src, context);
} catch (NoClassDefFoundError e) {
batikAvailable = false;
log.warn("Batik not in class path", e);
return null;
}
}
if (info != null) {
ImageUtil.closeQuietly(src); //Image is fully read
}
return info;
}
// in src/java/org/apache/fop/cli/CommandLineOptions.java
public boolean parse(String[] args)
throws FOPException, IOException {
boolean optionsParsed = true;
try {
optionsParsed = parseOptions(args);
if (optionsParsed) {
if (showConfiguration == Boolean.TRUE) {
dumpConfiguration();
}
checkSettings();
setUserConfig();
if (flushCache) {
flushCache();
}
//Factory config is set up, now we can create the user agent
foUserAgent = factory.newFOUserAgent();
foUserAgent.getRendererOptions().putAll(renderingOptions);
if (targetResolution != 0) {
foUserAgent.setTargetResolution(targetResolution);
}
addXSLTParameter("fop-output-format", getOutputFormat());
addXSLTParameter("fop-version", Version.getVersion());
foUserAgent.setConserveMemoryPolicy(conserveMemoryPolicy);
if (!useComplexScriptFeatures) {
foUserAgent.setComplexScriptFeaturesEnabled(false);
}
} else {
return false;
}
} catch (FOPException e) {
printUsage(System.err);
throw e;
} catch (java.io.FileNotFoundException e) {
printUsage(System.err);
throw e;
}
inputHandler = createInputHandler();
if (MimeConstants.MIME_FOP_AWT_PREVIEW.equals(outputmode)) {
//set the system look&feel for the preview dialog
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.err.println("Couldn't set system look & feel!");
}
AWTRenderer renderer = new AWTRenderer(foUserAgent, inputHandler, true, true);
foUserAgent.setRendererOverride(renderer);
} else if (MimeConstants.MIME_FOP_AREA_TREE.equals(outputmode)
&& mimicRenderer != null) {
// render from FO to Intermediate Format
Renderer targetRenderer = foUserAgent.getRendererFactory().createRenderer(
foUserAgent, mimicRenderer);
XMLRenderer xmlRenderer = new XMLRenderer(foUserAgent);
//Tell the XMLRenderer to mimic the target renderer
xmlRenderer.mimicRenderer(targetRenderer);
//Make sure the prepared XMLRenderer is used
foUserAgent.setRendererOverride(xmlRenderer);
} else if (MimeConstants.MIME_FOP_IF.equals(outputmode)
&& mimicRenderer != null) {
// render from FO to Intermediate Format
IFSerializer serializer = new IFSerializer();
serializer.setContext(new IFContext(foUserAgent));
IFDocumentHandler targetHandler
= foUserAgent.getRendererFactory().createDocumentHandler(
foUserAgent, mimicRenderer);
serializer.mimicDocumentHandler(targetHandler);
//Make sure the prepared serializer is used
foUserAgent.setDocumentHandlerOverride(serializer);
}
return true;
}
// in src/java/org/apache/fop/cli/CommandLineOptions.java
private void setUserConfig() throws FOPException, IOException {
if (userConfigFile == null) {
return;
}
try {
factory.setUserConfig(userConfigFile);
} catch (SAXException e) {
throw new FOPException(e);
}
}
// in src/codegen/unicode/java/org/apache/fop/hyphenation/UnicodeClasses.java
public static void writeGenerated(Writer w) throws IOException {
w.write("<!-- !!! THIS IS A GENERATED FILE !!! -->\n");
w.write("<!-- If updates are needed, then: -->\n");
w.write("<!-- * run 'ant codegen-hyphenation-classes', -->\n");
w.write("<!-- which will generate a new file classes.xml -->\n");
w.write("<!-- in 'src/java/org/apache/fop/hyphenation' -->\n");
w.write("<!-- * commit the changed file -->\n");
}
// in src/codegen/unicode/java/org/apache/fop/hyphenation/UnicodeClasses.java
public static void fromJava(boolean hexcode, String outfilePath) throws IOException {
File f = new File(outfilePath);
if (f.exists()) {
f.delete();
}
f.createNewFile();
FileOutputStream fw = new FileOutputStream(f);
OutputStreamWriter ow = new OutputStreamWriter(fw, "utf-8");
int maxChar;
maxChar = Character.MAX_VALUE;
ow.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
License.writeXMLLicenseId(ow);
ow.write("\n");
writeGenerated(ow);
ow.write("\n");
ow.write("<classes>\n");
// loop over the first Unicode plane
for (int code = Character.MIN_VALUE; code <= maxChar; ++code) {
// skip surrogate area
if (code == Character.MIN_SURROGATE) {
code = Character.MAX_SURROGATE;
continue;
}
// we are only interested in LC, UC and TC letters which are their own LC,
// and in 'other letters'
if (!(((Character.isLowerCase(code) || Character.isUpperCase(code)
|| Character.isTitleCase(code))
&& code == Character.toLowerCase(code))
|| Character.getType(code) == Character.OTHER_LETTER)) {
continue;
}
// skip a number of blocks
Character.UnicodeBlock ubi = Character.UnicodeBlock.of(code);
if (ubi.equals(Character.UnicodeBlock.SUPERSCRIPTS_AND_SUBSCRIPTS)
|| ubi.equals(Character.UnicodeBlock.LETTERLIKE_SYMBOLS)
|| ubi.equals(Character.UnicodeBlock.ALPHABETIC_PRESENTATION_FORMS)
|| ubi.equals(Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS)
|| ubi.equals(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS)
|| ubi.equals(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A)
|| ubi.equals(Character.UnicodeBlock.HANGUL_SYLLABLES)) {
continue;
}
int uppercode = Character.toUpperCase(code);
int titlecode = Character.toTitleCase(code);
StringBuilder s = new StringBuilder();
if (hexcode) {
s.append("0x" + Integer.toHexString(code) + " ");
}
s.append(Character.toChars(code));
if (uppercode != code) {
s.append(Character.toChars(uppercode));
}
if (titlecode != code && titlecode != uppercode) {
s.append(Character.toChars(titlecode));
}
ow.write(s.toString() + "\n");
}
ow.write("</classes>\n");
ow.flush();
ow.close();
}
// in src/codegen/unicode/java/org/apache/fop/hyphenation/UnicodeClasses.java
public static void fromUCD(boolean hexcode, String unidataPath, String outfilePath)
throws IOException, URISyntaxException {
URI unidata;
if (unidataPath.endsWith("/")) {
unidata = new URI(unidataPath);
} else {
unidata = new URI(unidataPath + "/");
}
String scheme = unidata.getScheme();
if (scheme == null || !(scheme.equals("file") || scheme.equals("http"))) {
throw new FileNotFoundException
("URI with file or http scheme required for UNIDATA input directory");
}
File f = new File(outfilePath);
if (f.exists()) {
f.delete();
}
f.createNewFile();
FileOutputStream fw = new FileOutputStream(f);
OutputStreamWriter ow = new OutputStreamWriter(fw, "utf-8");
URI inuri = unidata.resolve("Blocks.txt");
InputStream inis = null;
if (scheme.equals("file")) {
File in = new File(inuri);
inis = new FileInputStream(in);
} else if (scheme.equals("http")) {
inis = inuri.toURL().openStream();
}
InputStreamReader insr = new InputStreamReader(inis, "utf-8");
BufferedReader inbr = new BufferedReader(insr);
Map blocks = new HashMap();
for (String line = inbr.readLine(); line != null; line = inbr.readLine()) {
if (line.startsWith("#") || line.matches("^\\s*$")) {
continue;
}
String[] parts = line.split(";");
String block = parts[1].trim();
String[] indices = parts[0].split("\\.\\.");
int[] ind = {Integer.parseInt(indices[0], 16), Integer.parseInt(indices[1], 16)};
blocks.put(block, ind);
}
inbr.close();
inuri = unidata.resolve("UnicodeData.txt");
if (scheme.equals("file")) {
File in = new File(inuri);
inis = new FileInputStream(in);
} else if (scheme.equals("http")) {
inis = inuri.toURL().openStream();
}
insr = new InputStreamReader(inis, "utf-8");
inbr = new BufferedReader(insr);
int maxChar;
maxChar = Character.MAX_VALUE;
ow.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
License.writeXMLLicenseId(ow);
ow.write("\n");
writeGenerated(ow);
ow.write("\n");
ow.write("<classes>\n");
for (String line = inbr.readLine(); line != null; line = inbr.readLine()) {
String[] fields = line.split(";", NUM_FIELDS);
int code = Integer.parseInt(fields[UNICODE], 16);
if (code > maxChar) {
break;
}
if (((fields[GENERAL_CATEGORY].equals("Ll") || fields[GENERAL_CATEGORY].equals("Lu")
|| fields[GENERAL_CATEGORY].equals("Lt"))
&& ("".equals(fields[SIMPLE_LOWERCASE_MAPPING])
|| fields[UNICODE].equals(fields[SIMPLE_LOWERCASE_MAPPING])))
|| fields[GENERAL_CATEGORY].equals("Lo")) {
String[] blockNames = {"Superscripts and Subscripts",
"Letterlike Symbols",
"Alphabetic Presentation Forms",
"Halfwidth and Fullwidth Forms",
"CJK Unified Ideographs",
"CJK Unified Ideographs Extension A",
"Hangul Syllables"};
int j;
for (j = 0; j < blockNames.length; ++j) {
int[] ind = (int[]) blocks.get(blockNames[j]);
if (code >= ind[0] && code <= ind[1]) {
break;
}
}
if (j < blockNames.length) {
continue;
}
int uppercode = -1;
int titlecode = -1;
if (!"".equals(fields[SIMPLE_UPPERCASE_MAPPING])) {
uppercode = Integer.parseInt(fields[SIMPLE_UPPERCASE_MAPPING], 16);
}
if (!"".equals(fields[SIMPLE_TITLECASE_MAPPING])) {
titlecode = Integer.parseInt(fields[SIMPLE_TITLECASE_MAPPING], 16);
}
StringBuilder s = new StringBuilder();
if (hexcode) {
s.append("0x" + fields[UNICODE].replaceFirst("^0+", "").toLowerCase() + " ");
}
s.append(Character.toChars(code));
if (uppercode != -1 && uppercode != code) {
s.append(Character.toChars(uppercode));
}
if (titlecode != -1 && titlecode != code && titlecode != uppercode) {
s.append(Character.toChars(titlecode));
}
ow.write(s.toString() + "\n");
}
}
ow.write("</classes>\n");
ow.flush();
ow.close();
inbr.close();
}
// in src/codegen/unicode/java/org/apache/fop/hyphenation/UnicodeClasses.java
public static void fromTeX(boolean hexcode, String lettersPath, String outfilePath)
throws IOException {
File in = new File(lettersPath);
File f = new File(outfilePath);
if (f.exists()) {
f.delete();
}
f.createNewFile();
FileOutputStream fw = new FileOutputStream(f);
OutputStreamWriter ow = new OutputStreamWriter(fw, "utf-8");
FileInputStream inis = new FileInputStream(in);
InputStreamReader insr = new InputStreamReader(inis, "utf-8");
BufferedReader inbr = new BufferedReader(insr);
ow.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
License.writeXMLLicenseId(ow);
ow.write("\n");
writeGenerated(ow);
ow.write("\n");
ow.write("<classes>\n");
for (String line = inbr.readLine(); line != null; line = inbr.readLine()) {
String[] codes = line.split("\\s+");
if (!(codes[0].equals("\\L") || codes[0].equals("\\l"))) {
continue;
}
if (codes.length == 3) {
ow.write("\"" + line + "\" has two codes");
continue;
}
if (codes[0].equals("\\l") && codes.length != 2) {
ow.write("\"" + line + "\" should have one code");
continue;
} else if (codes[0].equals("\\L") && codes.length != 4) {
ow.write("\"" + line + "\" should have three codes");
continue;
}
if (codes[0].equals("\\l") || (codes[0].equals("\\L") && codes[1].equals(codes[3]))) {
StringBuilder s = new StringBuilder();
if (hexcode) {
s.append("0x" + codes[1].replaceFirst("^0+", "").toLowerCase() + " ");
}
s.append(Character.toChars(Integer.parseInt(codes[1], 16)));
if (codes[0].equals("\\L")) {
s.append(Character.toChars(Integer.parseInt(codes[2], 16)));
}
ow.write(s.toString() + "\n");
}
}
ow.write("</classes>\n");
ow.flush();
ow.close();
inbr.close();
}
// in src/codegen/unicode/java/org/apache/fop/hyphenation/UnicodeClasses.java
public static void main(String[] args) throws IOException, URISyntaxException {
String type = "ucd";
String prefix = "--";
String infile = null;
String outfile = null;
boolean hexcode = false;
int i;
for (i = 0; i < args.length && args[i].startsWith(prefix); ++i) {
String option = args[i].substring(prefix.length());
if (option.equals("java") || option.equals("ucd") || option.equals("tex")) {
type = option;
} else if (option.equals("hexcode")) {
hexcode = true;
} else {
System.err.println("Unknown option: " + option);
System.exit(1);
}
}
if (i < args.length) {
outfile = args[i];
} else {
System.err.println("Output file is required; aborting");
System.exit(1);
}
if (++i < args.length) {
infile = args[i];
}
if (type.equals("java") && infile != null) {
System.err.println("Type java does not allow an infile");
System.exit(1);
} else if (type.equals("ucd") && infile == null) {
infile = UNICODE_DIR;
} else if (type.equals("tex") && infile == null) {
System.err.println("Type tex requires an input file");
System.exit(1);
}
if (type.equals("java")) {
fromJava(hexcode, outfile);
} else if (type.equals("ucd")) {
fromUCD(hexcode, infile, outfile);
} else if (type.equals("tex")) {
fromTeX(hexcode, infile, outfile);
} else {
System.err.println("Unknown type: " + type + ", nothing done");
System.exit(1);
}
}
// in src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java
private static int readType ( String line, BufferedReader b, List lines ) throws IOException {
lines.add ( line );
return 0;
}
// in src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java
private static int readLevels ( String line, BufferedReader b, List lines ) throws IOException {
boolean done = false;
int n = 0;
lines.add ( line );
while ( ! done ) {
switch ( testPrefix ( b, PFX_LEVELS ) ) {
case 0: // within current levels
if ( ( line = b.readLine() ) != null ) {
n++;
if ( ( line.length() > 0 ) && ! line.startsWith("#") ) {
lines.add ( line );
}
} else {
done = true;
}
break;
case 1: // end of current levels
case -1: // eof
default:
done = true;
break;
}
}
return n;
}
// in src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java
private static int testPrefix ( BufferedReader b, String pfx ) throws IOException {
int rv = 0;
int pfxLen = pfx.length();
b.mark ( pfxLen );
for ( int i = 0, n = pfxLen; i < n; i++ ) {
int c = b.read();
if ( c < 0 ) {
rv = -1;
break;
} else if ( c != pfx.charAt ( i ) ) {
rv = 0;
break;
} else {
rv = 1;
}
}
b.reset();
return rv;
}
// in src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java
private static void dumpData ( PrintWriter out, String outFileName ) throws IOException {
File f = new File ( outFileName );
File p = f.getParentFile();
if ( td != null ) {
String pfxTD = "TD";
dumpResourcesDescriptor ( out, pfxTD, td.length );
dumpResourcesData ( p, f.getName(), pfxTD, td );
}
if ( ld != null ) {
String pfxTD = "LD";
dumpResourcesDescriptor ( out, pfxTD, ld.length );
dumpResourcesData ( p, f.getName(), pfxTD, ld );
}
}
// in src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java
private static void dumpResourcesData ( File btcDir, String btcName, String prefix, int[][] data ) throws IOException {
String btdName = extractDataFileName ( btcName );
for ( int i = 0, n = data.length; i < n; i++ ) {
File f = new File ( btcDir, btdName + "$" + prefix + i + ".ser" );
ObjectOutputStream os = new ObjectOutputStream ( new FileOutputStream ( f ) );
os.writeObject ( data[i] );
os.close();
}
}
// in src/codegen/unicode/java/org/apache/fop/util/License.java
public static void writeJavaLicenseId(Writer w) throws IOException {
w.write("/*\n");
for (int i = 0; i < LICENSE.length; ++i) {
if (LICENSE[i].equals("")) {
w.write(" *\n");
} else {
w.write(" * " + LICENSE[i] + "\n");
}
}
w.write(" */\n");
w.write("\n");
w.write("/* " + ID + " */\n");
}
// in src/codegen/unicode/java/org/apache/fop/util/License.java
public static void writeXMLLicenseId(Writer w) throws IOException {
for (int i = 0; i < LICENSE.length; ++i) {
w.write(String.format("<!-- %-" + maxLength + "s -->\n", new Object[] {LICENSE[i]}));
}
w.write("\n");
w.write("<!-- " + ID + " -->\n");
}
// in src/codegen/unicode/java/org/apache/fop/util/License.java
public static void main(String[] args) throws IOException {
StringWriter w = new StringWriter();
if (args.length == 0 || args[0].equals("--java")) {
writeJavaLicenseId(w);
} else if (args[0].equals("--xml")) {
writeXMLLicenseId(w);
}
System.out.println(w.toString());
}
// in src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java
protected void updateTranslationFile(File modelFile) throws IOException {
try {
boolean resultExists = getTranslationFile().exists();
SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
//Generate fresh generated translation file as template
Source src = new StreamSource(modelFile.toURI().toURL().toExternalForm());
StreamSource xslt1 = new StreamSource(
getClass().getResourceAsStream(MODEL2TRANSLATION));
if (xslt1.getInputStream() == null) {
throw new FileNotFoundException(MODEL2TRANSLATION + " not found");
}
DOMResult domres = new DOMResult();
Transformer transformer = tFactory.newTransformer(xslt1);
transformer.transform(src, domres);
final Node generated = domres.getNode();
Node sourceDocument;
if (resultExists) {
//Load existing translation file into memory (because we overwrite it later)
src = new StreamSource(getTranslationFile().toURI().toURL().toExternalForm());
domres = new DOMResult();
transformer = tFactory.newTransformer();
transformer.transform(src, domres);
sourceDocument = domres.getNode();
} else {
//Simply use generated as source document
sourceDocument = generated;
}
//Generate translation file (with potentially new translations)
src = new DOMSource(sourceDocument);
//The following triggers a bug in older Xalan versions
//Result res = new StreamResult(getTranslationFile());
OutputStream out = new java.io.FileOutputStream(getTranslationFile());
out = new java.io.BufferedOutputStream(out);
Result res = new StreamResult(out);
try {
StreamSource xslt2 = new StreamSource(
getClass().getResourceAsStream(MERGETRANSLATION));
if (xslt2.getInputStream() == null) {
throw new FileNotFoundException(MERGETRANSLATION + " not found");
}
transformer = tFactory.newTransformer(xslt2);
transformer.setURIResolver(new URIResolver() {
public Source resolve(String href, String base) throws TransformerException {
if ("my:dom".equals(href)) {
return new DOMSource(generated);
}
return null;
}
});
if (resultExists) {
transformer.setParameter("generated-url", "my:dom");
}
transformer.transform(src, res);
if (resultExists) {
log("Translation file updated: " + getTranslationFile());
} else {
log("Translation file generated: " + getTranslationFile());
}
} finally {
IOUtils.closeQuietly(out);
}
} catch (TransformerException te) {
throw new IOException(te.getMessage());
}
}
// in src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java
protected long processFileSets(EventProducerCollector collector)
throws IOException, EventConventionException, ClassNotFoundException {
long lastModified = 0;
Iterator<FileSet> iter = filesets.iterator();
while (iter.hasNext()) {
FileSet fs = (FileSet)iter.next();
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
String[] srcFiles = ds.getIncludedFiles();
File directory = fs.getDir(getProject());
for (int i = 0, c = srcFiles.length; i < c; i++) {
String filename = srcFiles[i];
File src = new File(directory, filename);
boolean eventProducerFound = collector.scanFile(src);
if (eventProducerFound) {
lastModified = Math.max(lastModified, src.lastModified());
}
}
}
return lastModified;
}
// in src/codegen/java/org/apache/fop/tools/EventProducerCollector.java
public boolean scanFile(File src)
throws IOException, EventConventionException, ClassNotFoundException {
JavaDocBuilder builder = new JavaDocBuilder(this.tagFactory);
builder.addSource(src);
JavaClass[] classes = builder.getClasses();
boolean eventProducerFound = false;
for (int i = 0, c = classes.length; i < c; i++) {
JavaClass clazz = classes[i];
if (clazz.isInterface() && implementsInterface(clazz, CLASSNAME_EVENT_PRODUCER)) {
processEventProducerInterface(clazz);
eventProducerFound = true;
}
}
return eventProducerFound;
}