Browse Source

Merged revisions 607034-611115 via svnmerge from

https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk

........
  r607036 | jeremias | 2007-12-27 11:51:11 +0100 (Do, 27 Dez 2007) | 1 line
  
  Don't just exit with no error message if the document contains no content. Pretty irritating if it does so.
........
  r608812 | acumiskey | 2008-01-04 13:14:33 +0100 (Fr, 04 Jan 2008) | 3 lines
  
  The fonts variable would have always had an empty Configuration node (non-null value) even if a <fonts/> wasn't present
  in the fop configuration.
........
  r609567 | jeremias | 2008-01-07 11:52:09 +0100 (Mo, 07 Jan 2008) | 4 lines
  
  Reenabled documentation for fox:destination.
  Enabled intermediate format functionality for fox:destination.
  Added a test case to check fox:destination.
  Deprecated FOP's XMLizable in favor of the XML Graphics Commons variant (and extend that variant).
........
  r609627 | jeremias | 2008-01-07 16:06:24 +0100 (Mo, 07 Jan 2008) | 5 lines
  
  Bugzilla #44176:
  Support for custom fonts in Java2DRenderer and derived renderers.
  Submitted by: Patrick Jaromin <patrick.at.jgsullivan.dot.com>
  
  Patch modified slightly by jeremias.
........
  r610020 | acumiskey | 2008-01-08 16:27:02 +0100 (Di, 08 Jan 2008) | 2 lines
  
  cleaned up
........
  r610021 | acumiskey | 2008-01-08 16:28:56 +0100 (Di, 08 Jan 2008) | 2 lines
  
  Appears to be unused/referenced and superceeded by PageGroup
........
  r610022 | acumiskey | 2008-01-08 16:34:07 +0100 (Di, 08 Jan 2008) | 2 lines
  
  cleaned up
........
  r610023 | acumiskey | 2008-01-08 16:35:18 +0100 (Di, 08 Jan 2008) | 2 lines
  
  fixed javadoc
........
  r610337 | vhennebert | 2008-01-09 12:02:08 +0100 (Mi, 09 Jan 2008) | 2 lines
  
  Fixed checkstyle issues: tabs and trailing spaces
........
  r610355 | vhennebert | 2008-01-09 13:01:21 +0100 (Mi, 09 Jan 2008) | 2 lines
  
  keep-together is an inherited property
........
  r610420 | acumiskey | 2008-01-09 16:40:25 +0100 (Mi, 09 Jan 2008) | 2 lines
  
  cleanup
........
  r610704 | jeremias | 2008-01-10 08:38:47 +0100 (Do, 10 Jan 2008) | 1 line
  
  Added basic support for PDF page labels.
........
  r610739 | jeremias | 2008-01-10 11:13:21 +0100 (Do, 10 Jan 2008) | 1 line
  
  PostScript output now generates the bounding box DSC comments for the whole document.
........
  r610821 | vhennebert | 2008-01-10 16:53:20 +0100 (Do, 10 Jan 2008) | 4 lines
  
  - renamed variables for clarity
  - moved the computation of a cell's content length in PrimaryGridUnit
  - better javadoc for getHeight method in EffRow
........
  r610848 | vhennebert | 2008-01-10 18:41:52 +0100 (Do, 10 Jan 2008) | 2 lines
  
  No need to check if the end of the cell is reached when creating the areas for a row
........
  r610853 | vhennebert | 2008-01-10 18:54:16 +0100 (Do, 10 Jan 2008) | 2 lines
  
  Simplified addAreasAndFlushRow
........
  r610886 | vhennebert | 2008-01-10 20:23:56 +0100 (Do, 10 Jan 2008) | 2 lines
  
  Removed endPart() method and moved its content into addAreasAndFlushRow()
........
  r610891 | vhennebert | 2008-01-10 20:34:13 +0100 (Do, 10 Jan 2008) | 2 lines
  
  Removed accumulatedBPD which is redundant with yoffset
........
  r610893 | vhennebert | 2008-01-10 20:35:24 +0100 (Do, 10 Jan 2008) | 2 lines
  
  The return value of addAreasAndFlushRow is never used, changed it to void
........
  r610905 | vhennebert | 2008-01-10 20:57:29 +0100 (Do, 10 Jan 2008) | 2 lines
  
  Renamed lastRow into currentRow and yoffset into currentRowOffset
........
  r611114 | jeremias | 2008-01-11 10:04:28 +0100 (Fr, 11 Jan 2008) | 2 lines
  
  Bugfix: Some string objects were not encrypted (for example in named destinations)
  I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year.
........


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImagePackageRedesign@611120 13f79535-47bb-0310-9956-ffa450edef68
Temp_ImagePackageRedesign
Jeremias Maerki 16 years ago
parent
commit
f8e731bb87
58 changed files with 1480 additions and 730 deletions
  1. 3
    4
      src/documentation/content/xdocs/trunk/extensions.xml
  2. 21
    0
      src/java/org/apache/fop/area/AreaTreeParser.java
  3. 11
    6
      src/java/org/apache/fop/area/DestinationData.java
  4. 1
    1
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  5. 7
    0
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  6. 9
    2
      src/java/org/apache/fop/fo/flow/table/EffRow.java
  7. 4
    5
      src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java
  8. 26
    33
      src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java
  9. 33
    55
      src/java/org/apache/fop/layoutmgr/table/RowPainter.java
  10. 0
    1
      src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
  11. 15
    26
      src/java/org/apache/fop/pdf/AbstractPDFStream.java
  12. 0
    9
      src/java/org/apache/fop/pdf/BitmapImage.java
  13. 46
    26
      src/java/org/apache/fop/pdf/PDFArray.java
  14. 19
    21
      src/java/org/apache/fop/pdf/PDFDestination.java
  15. 1
    1
      src/java/org/apache/fop/pdf/PDFDests.java
  16. 48
    20
      src/java/org/apache/fop/pdf/PDFDictionary.java
  17. 18
    1
      src/java/org/apache/fop/pdf/PDFDocument.java
  18. 15
    12
      src/java/org/apache/fop/pdf/PDFEncryptionJCE.java
  19. 16
    4
      src/java/org/apache/fop/pdf/PDFFactory.java
  20. 2
    2
      src/java/org/apache/fop/pdf/PDFFilterList.java
  21. 3
    3
      src/java/org/apache/fop/pdf/PDFFormXObject.java
  22. 1
    4
      src/java/org/apache/fop/pdf/PDFImage.java
  23. 4
    3
      src/java/org/apache/fop/pdf/PDFImageXObject.java
  24. 8
    5
      src/java/org/apache/fop/pdf/PDFName.java
  25. 1
    1
      src/java/org/apache/fop/pdf/PDFNameTreeNode.java
  26. 7
    3
      src/java/org/apache/fop/pdf/PDFNull.java
  27. 121
    0
      src/java/org/apache/fop/pdf/PDFNumberTreeNode.java
  28. 104
    0
      src/java/org/apache/fop/pdf/PDFNumsArray.java
  29. 67
    24
      src/java/org/apache/fop/pdf/PDFObject.java
  30. 48
    0
      src/java/org/apache/fop/pdf/PDFPageLabels.java
  31. 6
    3
      src/java/org/apache/fop/pdf/PDFReference.java
  32. 98
    91
      src/java/org/apache/fop/pdf/PDFRoot.java
  33. 11
    5
      src/java/org/apache/fop/pdf/PDFWritable.java
  34. 1
    1
      src/java/org/apache/fop/render/PrintRendererConfigurator.java
  35. 4
    2
      src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java
  36. 0
    79
      src/java/org/apache/fop/render/afp/modca/EndPageGroup.java
  37. 2
    2
      src/java/org/apache/fop/render/afp/modca/ImageSizeParameter.java
  38. 15
    24
      src/java/org/apache/fop/render/afp/modca/IncludePageOverlay.java
  39. 13
    18
      src/java/org/apache/fop/render/afp/modca/IncludePageSegment.java
  40. 1
    8
      src/java/org/apache/fop/render/afp/modca/MapPageOverlay.java
  41. 1
    0
      src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java
  42. 205
    0
      src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java
  43. 7
    167
      src/java/org/apache/fop/render/java2d/FontMetricsMapper.java
  44. 106
    33
      src/java/org/apache/fop/render/java2d/FontSetup.java
  45. 1
    1
      src/java/org/apache/fop/render/java2d/Java2DRenderer.java
  46. 1
    0
      src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java
  47. 194
    0
      src/java/org/apache/fop/render/java2d/SystemFontMetricsMapper.java
  48. 1
    1
      src/java/org/apache/fop/render/pcl/PCLRenderer.java
  49. 2
    0
      src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java
  50. 21
    2
      src/java/org/apache/fop/render/pdf/PDFRenderer.java
  51. 16
    1
      src/java/org/apache/fop/render/ps/PSRenderer.java
  52. 11
    1
      src/java/org/apache/fop/render/ps/ResourceHandler.java
  53. 4
    2
      src/java/org/apache/fop/render/ps/extensions/PSExtensionAttachment.java
  54. 1
    1
      src/java/org/apache/fop/render/ps/extensions/PSSetPageDevice.java
  55. 24
    5
      src/java/org/apache/fop/render/xml/XMLRenderer.java
  56. 2
    11
      src/java/org/apache/fop/util/XMLizable.java
  57. 12
    0
      status.xml
  58. 61
    0
      test/layoutengine/standard-testcases/fox_destination_1.xml

+ 3
- 4
src/documentation/content/xdocs/trunk/extensions.xml View File

@@ -63,8 +63,7 @@
</section>
<section id="named-destinations">
<title>Anchors or Named Destinations</title>
<p>This extension element hasn't been reimplemented for the redesigned code, yet.</p>
<!--p>Use the fox:destination element to define "named destinations" inside a PDF document.
<p>Use the fox:destination element to define "named destinations" inside a PDF document.
These are useful as fragment identifiers, e.g. "http://server/document.pdf#anchor-name".
fox:destination elements can be placed almost anywhere in the fo document, including a child of
root, a block-level element, or an inline-level element.
@@ -77,7 +76,7 @@ PDF document. The fox:destination simply gives that view an independent name.
<fo:block id="table-of-contents">Table of Contents</fo:block>]]></source>
<warning>It is possible that in some future release of FOP, <em>all </em>elements with
"id" attributes will generate named-destinations, which will eliminate the need for
fox:destination.</warning-->
fox:destination.</warning>
</section>
<section id="table-continue-label">
<title>Table Continuation Label</title>
@@ -136,7 +135,7 @@ to following pages. Here is an example of FO code creating such a table-header:<
</p>
<p>
<code>
(layout-master-set, declarations?, bookmark-tree?, (page-sequence|page-sequence-wrapper|fox:external-document)+)
(layout-master-set, declarations?, bookmark-tree?, (page-sequence|page-sequence-wrapper|fox:external-document|fox:destination)+)
</code>
</p>
<section>

+ 21
- 0
src/java/org/apache/fop/area/AreaTreeParser.java View File

@@ -184,6 +184,7 @@ public class AreaTreeParser {
makers.put("foreignObject", new ForeignObjectMaker());
makers.put("bookmarkTree", new BookmarkTreeMaker());
makers.put("bookmark", new BookmarkMaker());
makers.put("destination", new DestinationMaker());
}

private static Rectangle2D parseRect(String rect) {
@@ -927,6 +928,26 @@ public class AreaTreeParser {
}
}

private class DestinationMaker extends AbstractMaker {

public void startElement(Attributes attributes) {
String[] linkdata
= InternalLink.parseXMLAttribute(lastAttributes.getValue("internal-link"));
PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]);
DestinationData dest = new DestinationData(linkdata[1]);
List pages = new java.util.ArrayList();
pages.add(pv);
dest.resolveIDRef(linkdata[1], pages);
areaStack.push(dest);
}

public void endElement() {
Object tos = areaStack.pop();
assertObjectOfClass(tos, DestinationData.class);
treeModel.handleOffDocumentItem((DestinationData) tos);
}
}

// ====================================================================



+ 11
- 6
src/java/org/apache/fop/area/DestinationData.java View File

@@ -22,7 +22,6 @@ package org.apache.fop.area;
import java.util.List;

import org.apache.fop.fo.extensions.destination.Destination;
import org.apache.fop.area.PageViewport;
/**
* An instance of this class is named destination from fox:destination
*/
@@ -46,10 +45,18 @@ public class DestinationData extends AbstractOffDocumentItem implements Resolvab
* @param destination the fo:bookmark object
*/
public DestinationData(Destination destination) {
idRef = destination.getInternalDestination();
idRefs = new String[] {idRef};
this(destination.getInternalDestination());
}

/**
* Create a new named destination.
* @param idRef the id reference of the destination
*/
public DestinationData(String idRef) {
this.idRef = idRef;
this.idRefs = new String[] {idRef};
}
/**
* Get the idref for this destination
*
@@ -99,9 +106,7 @@ public class DestinationData extends AbstractOffDocumentItem implements Resolvab
// TODO get rect area of id on page
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public String getName() {
return "Destination";
}

+ 1
- 1
src/java/org/apache/fop/fo/FOPropertyMapping.java View File

@@ -1802,7 +1802,7 @@ public final class FOPropertyMapping implements Constants {
// keep-together
m = new KeepProperty.Maker(PR_KEEP_TOGETHER);
m.useGeneric(genericKeep);
m.setInherited(false);
m.setInherited(true);
m.setDefault("auto");
m.addShorthand(s_generics[PR_PAGE_BREAK_INSIDE]);
addPropertyMaker("keep-together", m);

+ 7
- 0
src/java/org/apache/fop/fo/FOTreeBuilder.java View File

@@ -81,6 +81,7 @@ public class FOTreeBuilder extends DefaultHandler {
private FOUserAgent userAgent;
private boolean used = false;
private boolean empty = true;
private int depth;
@@ -147,6 +148,7 @@ public class FOTreeBuilder extends DefaultHandler {
+ " Please instantiate a new instance.");
}
used = true;
empty = true;
rootFObj = null; // allows FOTreeBuilder to be reused
if (log.isDebugEnabled()) {
log.debug("Building formatting object tree");
@@ -162,6 +164,10 @@ public class FOTreeBuilder extends DefaultHandler {
*/
public void endDocument() throws SAXException {
this.delegate.endDocument();
if (this.rootFObj == null && empty) {
throw new ValidationException(
"Document is empty (something might be wrong with your XSLT stylesheet).");
}
rootFObj = null;
if (log.isDebugEnabled()) {
log.debug("Parsing of document complete");
@@ -280,6 +286,7 @@ public class FOTreeBuilder extends DefaultHandler {

// Check to ensure first node encountered is an fo:root
if (rootFObj == null) {
empty = false;
if (!namespaceURI.equals(FOElementMapping.URI)
|| !localName.equals("root")) {
throw new ValidationException(

+ 9
- 2
src/java/org/apache/fop/fo/flow/table/EffRow.java View File

@@ -80,13 +80,20 @@ public class EffRow {
return getGridUnit(0).getRow();
}
/** @return the calculated height for this EffRow. */
/**
* Returns the calculated height for this EffRow, including the cells'
* bpds/paddings/borders, and the table's border-separation.
*
* @return the row's height
*/
public MinOptMax getHeight() {
return this.height;
}
/**
* Sets the calculated height for this EffRow.
* Sets the calculated height for this EffRow, including everything (cells' bpds,
* paddings, borders, and border-separation).
*
* @param mom the calculated height
*/
public void setHeight(MinOptMax mom) {

+ 4
- 5
src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java View File

@@ -24,6 +24,7 @@ import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.table.TableCellLayoutManager;

/**
@@ -142,13 +143,11 @@ public class PrimaryGridUnit extends GridUnit {
return getHalfMaxBeforeBorderWidth() + getHalfMaxAfterBorderWidth();
}

/** @param value The length of the cell content to remember. */
public void setContentLength(int value) {
this.contentLength = value;
}

/** @return the length of the cell content. */
public int getContentLength() {
if (contentLength < 0) {
contentLength = ElementListUtils.calcContentLength(elements);
}
return contentLength;
}


+ 26
- 33
src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java View File

@@ -148,9 +148,9 @@ class RowGroupLayoutManager {
TableRow tableRow = null;
// The row's minimum content height; 0 if the row's height is auto, otherwise
// the .minimum component of the explicitly specified value
int minContentHeight = 0;
int maxCellHeight = 0;
int effRowContentHeight = 0;
int minRowBPD = 0;
// The BPD of the biggest cell in the row
int maxCellBPD = 0;
for (int j = 0; j < row.getGridUnits().size(); j++) {
assert maxColumnCount == 0 || maxColumnCount == row.getGridUnits().size();
maxColumnCount = Math.max(maxColumnCount, row.getGridUnits().size());
@@ -168,14 +168,12 @@ class RowGroupLayoutManager {
tableRow = primary.getRow();
//Check for bpd on row, see CSS21, 17.5.3 Table height algorithms
LengthRangeProperty bpd = tableRow.getBlockProgressionDimension();
if (!bpd.getMinimum(tableLM).isAuto()) {
minContentHeight = Math.max(
minContentHeight,
bpd.getMinimum(
tableLM).getLength().getValue(tableLM));
LengthRangeProperty rowBPD = tableRow.getBlockProgressionDimension();
if (!rowBPD.getMinimum(tableLM).isAuto()) {
minRowBPD = Math.max(minRowBPD,
rowBPD.getMinimum(tableLM).getLength().getValue(tableLM));
}
MinOptMaxUtil.restrict(explicitRowHeights[rgi], bpd, tableLM);
MinOptMaxUtil.restrict(explicitRowHeights[rgi], rowBPD, tableLM);
}

@@ -218,31 +216,27 @@ class RowGroupLayoutManager {
}
}

//Calculate height of cell contents
primary.setContentLength(ElementListUtils.calcContentLength(
primary.getElements()));
maxCellHeight = Math.max(maxCellHeight, primary.getContentLength());

//Calculate height of row, see CSS21, 17.5.3 Table height algorithms
if (gu.isLastGridUnitRowSpan()) {
int effCellContentHeight = minContentHeight;
LengthRangeProperty bpd = primary.getCell().getBlockProgressionDimension();
if (!bpd.getMinimum(tableLM).isAuto()) {
effCellContentHeight = Math.max(
effCellContentHeight,
bpd.getMinimum(tableLM).getLength().getValue(tableLM));
// The effective cell's bpd, after taking into account bpd
// (possibly explicitly) set on the row or on the cell, and the
// cell's content length
int effectiveCellBPD = minRowBPD;
LengthRangeProperty cellBPD = primary.getCell()
.getBlockProgressionDimension();
if (!cellBPD.getMinimum(tableLM).isAuto()) {
effectiveCellBPD = Math.max(effectiveCellBPD,
cellBPD.getMinimum(tableLM).getLength().getValue(tableLM));
}
if (!bpd.getOptimum(tableLM).isAuto()) {
effCellContentHeight = Math.max(
effCellContentHeight,
bpd.getOptimum(tableLM).getLength().getValue(tableLM));
if (!cellBPD.getOptimum(tableLM).isAuto()) {
effectiveCellBPD = Math.max(effectiveCellBPD,
cellBPD.getOptimum(tableLM).getLength().getValue(tableLM));
}
if (gu.getRowSpanIndex() == 0) {
//TODO ATM only non-row-spanned cells are taken for this
MinOptMaxUtil.restrict(explicitRowHeights[rgi], bpd, tableLM);
MinOptMaxUtil.restrict(explicitRowHeights[rgi], cellBPD, tableLM);
}
effCellContentHeight = Math.max(effCellContentHeight,
effectiveCellBPD = Math.max(effectiveCellBPD,
primary.getContentLength());
int borderWidths;
@@ -253,13 +247,12 @@ class RowGroupLayoutManager {
borderWidths = primary.getHalfMaxBorderWidth();
}
int padding = 0;
effRowContentHeight = Math.max(effRowContentHeight,
effCellContentHeight);
maxCellBPD = Math.max(maxCellBPD, effectiveCellBPD);
CommonBorderPaddingBackground cbpb
= primary.getCell().getCommonBorderPaddingBackground();
padding += cbpb.getPaddingBefore(false, primary.getCellLM());
padding += cbpb.getPaddingAfter(false, primary.getCellLM());
int effRowHeight = effCellContentHeight
int effRowHeight = effectiveCellBPD
+ padding + borderWidths
+ 2 * tableLM.getHalfBorderSeparationBPD();
for (int previous = 0; previous < gu.getRowSpanIndex(); previous++) {
@@ -279,13 +272,13 @@ class RowGroupLayoutManager {

row.setHeight(rowHeights[rgi]);
row.setExplicitHeight(explicitRowHeights[rgi]);
if (effRowContentHeight > row.getExplicitHeight().max) {
if (maxCellBPD > row.getExplicitHeight().max) {
log.warn(FONode.decorateWithContextInfo(
"The contents of row " + (row.getIndex() + 1)
+ " are taller than they should be (there is a"
+ " block-progression-dimension or height constraint on the indicated row)."
+ " Due to its contents the row grows"
+ " to " + effRowContentHeight + " millipoints, but the row shouldn't get"
+ " to " + maxCellBPD + " millipoints, but the row shouldn't get"
+ " any taller than " + row.getExplicitHeight() + " millipoints.",
row.getTableRow()));
}

+ 33
- 55
src/java/org/apache/fop/layoutmgr/table/RowPainter.java View File

@@ -42,10 +42,9 @@ class RowPainter {
/** The fo:table-row containing the currently handled grid rows. */
private TableRow rowFO = null;
private int colCount;
private int yoffset = 0;
private int accumulatedBPD = 0;
private int currentRowOffset = 0;
/** Currently handled row (= last encountered row). */
private EffRow lastRow = null;
private EffRow currentRow = null;
private LayoutContext layoutContext;
/**
* Index of the first row of the current part present on the current page.
@@ -91,7 +90,7 @@ class RowPainter {
}

int getAccumulatedBPD() {
return this.accumulatedBPD;
return currentRowOffset;
}

/**
@@ -101,16 +100,16 @@ class RowPainter {
* @param tcpos a position representing the row fragment
*/
void handleTableContentPosition(TableContentPosition tcpos) {
if (lastRow != tcpos.row && lastRow != null) {
if (tcpos.row != currentRow && currentRow != null) {
addAreasAndFlushRow(false);
}
if (log.isDebugEnabled()) {
log.debug("===handleTableContentPosition(" + tcpos);
}
rowFO = tcpos.row.getTableRow();
lastRow = tcpos.row;
currentRow = tcpos.row;
if (firstRowIndex < 0) {
firstRowIndex = lastRow.getIndex();
firstRowIndex = currentRow.getIndex();
}
Iterator partIter = tcpos.cellParts.iterator();
//Iterate over all grid units in the current step
@@ -146,15 +145,15 @@ class RowPainter {
* @param forcedFlush true if the elements must be drawn even if the row isn't
* finished yet (last row on the page), or if the row is the last of the current table
* part
* @return the height of the (grid) row
*/
int addAreasAndFlushRow(boolean forcedFlush) {
void addAreasAndFlushRow(boolean forcedFlush) {
int actualRowHeight = 0;

if (log.isDebugEnabled()) {
log.debug("Remembering yoffset for row " + lastRow.getIndex() + ": " + yoffset);
log.debug("Remembering yoffset for row " + currentRow.getIndex() + ": "
+ currentRowOffset);
}
recordRowOffset(lastRow.getIndex(), yoffset);
recordRowOffset(currentRow.getIndex(), currentRowOffset);

for (int i = 0; i < primaryGridUnits.length; i++) {
if ((primaryGridUnits[i] != null)
@@ -166,55 +165,38 @@ class RowPainter {
actualRowHeight += 2 * tclm.getTableLM().getHalfBorderSeparationBPD();

//Add areas for row
tclm.addRowBackgroundArea(rowFO, actualRowHeight, layoutContext.getRefIPD(), yoffset);
tclm.addRowBackgroundArea(rowFO, actualRowHeight, layoutContext.getRefIPD(),
currentRowOffset);
for (int i = 0; i < primaryGridUnits.length; i++) {
GridUnit currentGU = lastRow.getGridUnit(i);
if (primaryGridUnits[i] != null) {
if (forcedFlush || ((end[i] == primaryGridUnits[i].getElements().size() - 1)
&& currentGU.isLastGridUnitRowSpan())) {
//the last line in the "if" above is to avoid a premature end of a
//row-spanned cell because no CellParts are generated after a cell is
//finished with its content.
//See table-cell_number-rows-spanned_bug38397.xml
addAreasForCell(primaryGridUnits[i], start[i], end[i], lastRow, partBPD[i],
actualRowHeight);
primaryGridUnits[i] = null;
start[i] = 0;
end[i] = -1;
partBPD[i] = 0;
}
} else if (!currentGU.isEmpty()
&& currentGU.getColSpanIndex() == 0
GridUnit currentGU = currentRow.getGridUnit(i);
if (!currentGU.isEmpty() && currentGU.getColSpanIndex() == 0
&& (forcedFlush || currentGU.isLastGridUnitRowSpan())) {
//A row-spanned cell has finished contributing content on the previous page
//and now still has to cause grid units to be painted.
//See table-cell_page-break_span.xml
addAreasForCell(currentGU.getPrimary(), start[i], end[i], lastRow, partBPD[i],
addAreasForCell(currentGU.getPrimary(), start[i], end[i], currentRow, partBPD[i],
actualRowHeight);
primaryGridUnits[i] = null;
start[i] = 0;
end[i] = -1;
partBPD[i] = 0;
}
}
yoffset += actualRowHeight;
accumulatedBPD += actualRowHeight;
currentRowOffset += actualRowHeight;
if (forcedFlush) {
// Either the end of the page is reached, then this was the last call of this
// method and we no longer care about lastRow; or the end of a table-part
// method and we no longer care about currentRow; or the end of a table-part
// (header, footer, body) has been reached, and the next row will anyway be
// different from the current one, and this is unnecessary to recall this
// method in the first lines of handleTableContentPosition, so we may reset
// lastRow
lastRow = null;
// the following variables
currentRow = null;
firstRowIndex = -1;
rowOffsets.clear();
}
return actualRowHeight;
}

/**
* Computes the total height of the part of the given cell spanning on the current
* active row, including borders and paddings. The bpd is also stored in partBPD, and
* it is ensured that the cell's or row's explicit height is respected. yoffset is
* updated accordingly.
* it is ensured that the cell's or row's explicit height is respected.
*
* @param pgu primary grid unit corresponding to the cell
* @param start index of the first element of the cell occuring on the current page
@@ -290,7 +272,7 @@ class RowPainter {
len += pgu.getHalfMaxAfterBorderWidth();
}
int cellOffset = getRowOffset(Math.max(pgu.getStartRow(), firstRowIndex));
len -= yoffset - cellOffset;
len -= currentRowOffset - cellOffset;
return len;
}

@@ -298,7 +280,7 @@ class RowPainter {
EffRow row, int contentHeight, int rowHeight) {
//Determine the first row in this sequence
int startRowIndex = Math.max(pgu.getStartRow(), firstRowIndex);
int lastRowIndex = lastRow.getIndex();
int currentRowIndex = currentRow.getIndex();

// In collapsing-border model, if the cell spans over several columns/rows then
// dedicated areas will be created for each grid unit to hold the corresponding
@@ -306,23 +288,24 @@ class RowPainter {
// grid row spanned over by the cell
int[] spannedGridRowHeights = null;
if (!tclm.getTableLM().getTable().isSeparateBorderModel() && pgu.hasSpanning()) {
spannedGridRowHeights = new int[lastRowIndex - startRowIndex + 1];
spannedGridRowHeights = new int[currentRowIndex - startRowIndex + 1];
int prevOffset = getRowOffset(startRowIndex);
for (int i = 0; i < lastRowIndex - startRowIndex; i++) {
for (int i = 0; i < currentRowIndex - startRowIndex; i++) {
int newOffset = getRowOffset(startRowIndex + i + 1);
spannedGridRowHeights[i] = newOffset - prevOffset;
prevOffset = newOffset;
}
spannedGridRowHeights[lastRowIndex - startRowIndex] = rowHeight;
spannedGridRowHeights[currentRowIndex - startRowIndex] = rowHeight;
}

int cellOffset = getRowOffset(startRowIndex);
int effCellHeight = rowHeight;
effCellHeight += yoffset - cellOffset;
effCellHeight += currentRowOffset - cellOffset;
if (log.isDebugEnabled()) {
log.debug("Creating area for cell:");
log.debug(" current row: " + row.getIndex());
log.debug(" start row: " + pgu.getStartRow() + " " + yoffset + " " + cellOffset);
log.debug(" start row: " + pgu.getStartRow() + " " + currentRowOffset + " "
+ cellOffset);
log.debug(" contentHeight: " + contentHeight + " rowHeight=" + rowHeight
+ " effCellHeight=" + effCellHeight);
}
@@ -339,7 +322,7 @@ class RowPainter {
}
cellLM.addAreas(new KnuthPossPosIter(pgu.getElements(), startPos, endPos + 1),
layoutContext, spannedGridRowHeights, startRowIndex - pgu.getStartRow(),
lastRowIndex - pgu.getStartRow() + 1);
currentRowIndex - pgu.getStartRow() + 1);
}

/**
@@ -357,7 +340,7 @@ class RowPainter {
* TableContentPosition will be created for this row. Thus its index will never be
* recorded by the #handleTableContentPosition method.
*
* The yoffset for such a row is the same as the next non-empty row. It's needed
* The offset of such a row is the same as the next non-empty row. It's needed
* to correctly offset blocks for cells starting on this row. Hence the loop
* below.
*/
@@ -375,9 +358,4 @@ class RowPainter {
private int getRowOffset(int rowIndex) {
return ((Integer) rowOffsets.get(rowIndex - firstRowIndex)).intValue();
}

void endPart() {
firstRowIndex = -1;
rowOffsets.clear();
}
}

+ 0
- 1
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java View File

@@ -418,7 +418,6 @@ public class TableContentLayoutManager implements PercentBaseContext {
handleMarkersAndPositions(lst, body, firstPos, false, painter);
}
painter.addAreasAndFlushRow(true);
painter.endPart();
}

private void handleMarkersAndPositions(List positions, TableBody body, boolean firstPos,

+ 15
- 26
src/java/org/apache/fop/pdf/AbstractPDFStream.java View File

@@ -21,8 +21,10 @@ package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

import org.apache.commons.io.output.CountingOutputStream;

import org.apache.fop.util.CloseBlockerOutputStream;

/**
@@ -169,8 +171,12 @@ public abstract class AbstractPDFStream extends PDFDictionary {
* {@inheritDoc}
*/
protected int output(OutputStream stream) throws IOException {
int length = 0;
setupFilterList();

CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
writer.write(getObjectID());
//int length = 0;
StreamCache encodedStream = null;
PDFNumber refLength = null;
@@ -184,38 +190,21 @@ public abstract class AbstractPDFStream extends PDFDictionary {
lengthEntry = new Integer(encodedStream.getSize() + 1);
}
byte[] p = encode(buildStreamDict(lengthEntry));
stream.write(p);
length += p.length;
populateStreamDict(lengthEntry);
writeDictionary(cout, writer);
//Send encoded stream to target OutputStream
writer.flush();
if (encodedStream == null) {
int bytesWritten = encodeAndWriteStream(stream, refLength);
length += bytesWritten;
encodeAndWriteStream(cout, refLength);
} else {
length += outputStreamData(encodedStream, stream);
outputStreamData(encodedStream, cout);
encodedStream.clear(); //Encoded stream can now be discarded
}
p = encode("\nendobj\n");
stream.write(p);
length += p.length;
return length;
}

/**
* Constructs the dictionary for the stream. Override this method if you
* need additional entries.
* @param lengthEntry value for the /Length entry
* @return the newly constructed dictionary
*/
protected String buildStreamDict(Object lengthEntry) {
StringBuffer sb = new StringBuffer();
sb.append(getObjectID());
populateStreamDict(lengthEntry);
writeDictionary(sb);
return sb.toString();
writer.write("\nendobj\n");
writer.flush();
return cout.getCount();
}

/**

+ 0
- 9
src/java/org/apache/fop/pdf/BitmapImage.java View File

@@ -159,15 +159,6 @@ public class BitmapImage implements PDFImage {
return null;
}

/**
* Get the soft mask reference for this image.
*
* @return the soft mask reference if any
*/
public String getSoftMask() {
return maskRef.toInlinePDFString();
}
/** {@inheritDoc} */
public PDFReference getSoftMaskReference() {
return maskRef;

+ 46
- 26
src/java/org/apache/fop/pdf/PDFArray.java View File

@@ -19,9 +19,14 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Collection;
import java.util.List;

import org.apache.commons.io.output.CountingOutputStream;

/**
* Class representing an array object.
*/
@@ -33,20 +38,21 @@ public class PDFArray extends PDFObject {

/**
* Create a new, empty array object
* @param parent the array's parent if any
*/
public PDFArray() {
public PDFArray(PDFObject parent) {
/* generic creation of PDF object */
super();
super(parent);
}

/**
* Create the array object
*
* Create an array object.
* @param parent the array's parent if any
* @param values the actual array wrapped by this object
*/
public PDFArray(int[] values) {
public PDFArray(PDFObject parent, int[] values) {
/* generic creation of PDF object */
super();
super(parent);

for (int i = 0, c = values.length; i < c; i++) {
this.values.add(new Integer(values[i]));
@@ -54,25 +60,25 @@ public class PDFArray extends PDFObject {
}

/**
* Create the array object
*
* Create an array object.
* @param parent the array's parent if any
* @param values the actual values wrapped by this object
*/
public PDFArray(Collection values) {
public PDFArray(PDFObject parent, Collection values) {
/* generic creation of PDF object */
super();
super(parent);
this.values.addAll(values);
}
/**
* Create the array object
*
* @param parent the array's parent if any
* @param values the actual array wrapped by this object
*/
public PDFArray(Object[] values) {
public PDFArray(PDFObject parent, Object[] values) {
/* generic creation of PDF object */
super();
super(parent);
for (int i = 0, c = values.length; i < c; i++) {
this.values.add(values[i]);
@@ -114,6 +120,17 @@ public class PDFArray extends PDFObject {
return this.values.get(index);
}
/**
* Adds a new value to the array.
* @param obj the value
*/
public void add(PDFObject obj) {
if (obj != null) {
obj.setParent(this);
}
this.values.add(obj);
}
/**
* Adds a new value to the array.
* @param obj the value
@@ -130,27 +147,30 @@ public class PDFArray extends PDFObject {
this.values.add(new Double(value));
}
/**
* {@inheritDoc}
*/
public String toPDFString() {
StringBuffer p = new StringBuffer(64);
/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
p.append(getObjectID());
writer.write(getObjectID());
}
p.append("[");
writer.write('[');
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
p.append(" ");
writer.write(' ');
}
Object obj = this.values.get(i);
formatObject(obj, p);
formatObject(obj, cout, writer);
}
p.append("]");
writer.write(']');
if (hasObjectNumber()) {
p.append("\nendobj\n");
writer.write("\nendobj\n");
}
return p.toString();
writer.flush();
return cout.getCount();
}

}

+ 19
- 21
src/java/org/apache/fop/pdf/PDFDestination.java View File

@@ -19,6 +19,12 @@

package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

import org.apache.commons.io.output.CountingOutputStream;

/**
* class representing a named destination
*/
@@ -40,30 +46,24 @@ public class PDFDestination extends PDFObject {
* @param goToRef Object reference to the GoTo Action
*/
public PDFDestination(String idRef, Object goToRef) {
super();
this.goToReference = goToRef;
this.idRef = idRef;
}

/**
* Creates the key/value pair for this destination entry for the name tree.
* @return the formatted key/value pair
*/
public String toKeyValuePair() {
StringBuffer sb = new StringBuffer();
sb.append("(").append(getIDRef()).append(") ");
if (goToReference instanceof PDFWritable) {
sb.append(((PDFWritable)goToReference).toInlinePDFString());
} else {
sb.append(goToReference);
}
return sb.toString();
}
/** {@inheritDoc} */
protected String toPDFString() {
return toKeyValuePair();
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
formatObject(getIDRef(), cout, writer);
writer.write(' ');
formatObject(goToReference, cout, writer);
writer.flush();
return cout.getCount();
}

/**
* Sets the GoToReference in the associated DestinationData object.
*
@@ -124,9 +124,7 @@ public class PDFDestination extends PDFObject {
return false;
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public int hashCode() {
return getIDRef().hashCode();
}

+ 1
- 1
src/java/org/apache/fop/pdf/PDFDests.java View File

@@ -40,7 +40,7 @@ public class PDFDests extends PDFNameTreeNode {
*/
public PDFDests(List destinationList) {
this();
setNames(new PDFArray(destinationList));
setNames(new PDFArray(this, destinationList));
}

}

+ 48
- 20
src/java/org/apache/fop/pdf/PDFDictionary.java View File

@@ -19,10 +19,15 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.output.CountingOutputStream;

/**
* Class representing a PDF dictionary object
*/
@@ -40,13 +45,20 @@ public class PDFDictionary extends PDFObject {
protected List order = new java.util.ArrayList();
/**
* Create the dictionary object
* Create a new dictionary object.
*/
public PDFDictionary() {
/* generic creation of PDF object */
super();
}

/**
* Create a new dictionary object.
* @param parent the object's parent if any
*/
public PDFDictionary(PDFObject parent) {
super(parent);
}

/**
* Puts a new name/value pair.
* @param name the name
@@ -80,37 +92,53 @@ public class PDFDictionary extends PDFObject {
return this.entries.get(name);
}
/**
* {@inheritDoc}
*/
public String toPDFString() {
StringBuffer p = new StringBuffer(64);
/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
p.append(getObjectID());
writer.write(getObjectID());
}
writeDictionary(p);
writeDictionary(cout, writer);

if (hasObjectNumber()) {
p.append("endobj\n");
writer.write("\nendobj\n");
}
return p.toString();
writer.flush();
return cout.getCount();
}

/**
* Writes the contents of the dictionary to a StringBuffer.
* @param sb the target StringBuffer
* @param out the OutputStream (for binary content)
* @param writer the Writer (for text content, wraps the above OutputStream)
* @throws IOException if an I/O error occurs
*/
protected void writeDictionary(StringBuffer sb) {
sb.append("<<");
protected void writeDictionary(OutputStream out, Writer writer) throws IOException {
writer.write("<<");
boolean compact = (this.order.size() <= 2);
Iterator iter = this.order.iterator();
while (iter.hasNext()) {
String key = (String)iter.next();
sb.append("\n /");
sb.append(key);
sb.append(" ");
if (compact) {
writer.write(' ');
} else {
writer.write("\n ");
}
writer.write('/');
writer.write(key);
writer.write(' ');
Object obj = this.entries.get(key);
formatObject(obj, sb);
formatObject(obj, out, writer);
}
if (compact) {
writer.write(' ');
} else {
writer.write('\n');
}
sb.append("\n>>\n");
writer.write(">>\n");
}

}

+ 18
- 1
src/java/org/apache/fop/pdf/PDFDocument.java View File

@@ -24,15 +24,16 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -316,6 +317,22 @@ public class PDFDocument {
}
}

/**
* Creates and returns a Writer object wrapping the given OutputStream. The Writer is
* buffered to reduce the number of calls to the encoding converter so don't forget
* to <code>flush()</code> the Writer after use or before writing directly to the
* underlying OutputStream.
* @param out the OutputStream to write to
* @return the requested Writer
*/
public static Writer getWriterFor(OutputStream out) {
try {
return new java.io.BufferedWriter(new java.io.OutputStreamWriter(out, ENCODING));
} catch (UnsupportedEncodingException uee) {
throw new Error("JVM doesn't support " + ENCODING + " encoding!");
}
}
/**
* set the producer of the document
*

+ 15
- 12
src/java/org/apache/fop/pdf/PDFEncryptionJCE.java View File

@@ -20,20 +20,20 @@
package org.apache.fop.pdf;

// Java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;

import java.util.Random;
import javax.crypto.spec.SecretKeySpec;

/**
* class representing a /Filter /Standard object.
@@ -358,17 +358,20 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
if (this.encryptionKey == null) {
throw new IllegalStateException("PDF Encryption has not been initialized");
}
log.debug("encrypting with for " + number + " " + generation);

byte[] hash = calcHash(number, generation);
return encryptWithHash(data, hash, hash.length);
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public byte[] encrypt(byte[] data, PDFObject refObj) {
return encryptData(data, refObj.getObjectNumber(), refObj.getGeneration());
PDFObject o = refObj;
while (o != null && !o.hasObjectNumber()) {
o = o.getParent();
}
if (o == null) {
throw new IllegalStateException("No object number could be obtained for a PDF object");
}
return encryptData(data, o.getObjectNumber(), o.getGeneration());
}

private byte[] calcHash(int number, int generation) {

+ 16
- 4
src/java/org/apache/fop/pdf/PDFFactory.java View File

@@ -849,6 +849,17 @@ public class PDFFactory {
return names;
}

/**
* Make a names dictionary (the /PageLabels object).
* @return the new PDFPageLabels object
*/
public PDFPageLabels makePageLabels() {
PDFPageLabels pageLabels = new PDFPageLabels();
getDocument().assignObjectNumber(pageLabels);
getDocument().addTrailerObject(pageLabels);
return pageLabels;
}

/**
* Make a the head object of the name dictionary (the /Dests object).
*
@@ -862,7 +873,7 @@ public class PDFFactory {
//true for a "deep" structure (one node per entry), true for a "flat" structure
if (deep) {
dests = new PDFDests();
PDFArray kids = new PDFArray();
PDFArray kids = new PDFArray(dests);
Iterator iter = destinationList.iterator();
while (iter.hasNext()) {
PDFDestination dest = (PDFDestination)iter.next();
@@ -870,8 +881,9 @@ public class PDFFactory {
getDocument().registerObject(node);
node.setLowerLimit(dest.getIDRef());
node.setUpperLimit(dest.getIDRef());
node.setNames(new PDFArray());
node.getNames().add(dest);
node.setNames(new PDFArray(node));
PDFArray names = node.getNames();
names.add(dest);
kids.add(node);
}
dests.setLowerLimit(((PDFNameTreeNode)kids.get(0)).getLowerLimit());
@@ -1514,7 +1526,7 @@ public class PDFFactory {
* @return the PDF Array with the int values
*/
public PDFArray makeArray(int[] values) {
PDFArray array = new PDFArray(values);
PDFArray array = new PDFArray(null, values);

getDocument().registerObject(array);
return array;

+ 2
- 2
src/java/org/apache/fop/pdf/PDFFilterList.java View File

@@ -282,7 +282,7 @@ public class PDFFilterList {
}

private void putFilterEntries(PDFDictionary dict, List names) {
PDFArray array = new PDFArray();
PDFArray array = new PDFArray(dict);
for (int i = 0, c = names.size(); i < c; i++) {
final String name = (String)names.get(i);
if (name.length() > 0) {
@@ -328,7 +328,7 @@ public class PDFFilterList {

private void putDecodeParams(PDFDictionary dict, List parms) {
boolean needParmsEntry = false;
PDFArray array = new PDFArray();
PDFArray array = new PDFArray(dict);
for (int i = 0, c = parms.size(); i < c; i++) {
Object obj = parms.get(i);
if (obj != null) {

+ 3
- 3
src/java/org/apache/fop/pdf/PDFFormXObject.java View File

@@ -63,7 +63,7 @@ public class PDFFormXObject extends PDFXObject {
public void setBBox(Rectangle2D bbox) {
PDFArray array = (PDFArray)get("BBox");
if (array == null) {
array = new PDFArray();
array = new PDFArray(this);
array.add(bbox.getX());
array.add(bbox.getY());
array.add(bbox.getWidth());
@@ -105,7 +105,7 @@ public class PDFFormXObject extends PDFXObject {
double[] m = new double[6];
at.getMatrix(m);
if (array == null) {
array = new PDFArray();
array = new PDFArray(this);
array.add(m[0]);
array.add(m[1]);
array.add(m[2]);
@@ -170,7 +170,7 @@ public class PDFFormXObject extends PDFXObject {
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
if (get("Matrix") == null) {
put("Matrix", new PDFArray(new int[] {1, 0, 0, 1, 0, 0}));
put("Matrix", new PDFArray(this, new int[] {1, 0, 0, 1, 0, 0}));
}
put("Resources", resRef);
super.populateStreamDict(lengthEntry);

+ 1
- 4
src/java/org/apache/fop/pdf/PDFImage.java View File

@@ -105,11 +105,8 @@ public interface PDFImage {

/**
* Get the PDF reference for a soft mask.
*
* @return the PDF reference for a soft mask image
* @return the PDF reference for a soft mask image (or null if there's no soft mask)
*/
String getSoftMask();
PDFReference getSoftMaskReference();

/** @return true for CMYK images generated by Adobe Photoshop */

+ 4
- 3
src/java/org/apache/fop/pdf/PDFImageXObject.java View File

@@ -94,7 +94,8 @@ public class PDFImageXObject extends PDFXObject {

PDFICCStream pdfICCStream = pdfimage.getICCStream();
if (pdfICCStream != null) {
put("ColorSpace", new PDFArray(new Object[] {new PDFName("ICCBased"), pdfICCStream}));
put("ColorSpace", new PDFArray(this,
new Object[] {new PDFName("ICCBased"), pdfICCStream}));
} else {
PDFDeviceColorSpace cs = pdfimage.getColorSpace();
put("ColorSpace", new PDFName(cs.getName()));
@@ -107,7 +108,7 @@ public class PDFImageXObject extends PDFXObject {
*/
final Float zero = new Float(0.0f);
final Float one = new Float(1.0f);
PDFArray decode = new PDFArray();
PDFArray decode = new PDFArray(this);
for (int i = 0, c = pdfimage.getColorSpace().getNumComponents(); i < c; i++) {
decode.add(one);
decode.add(zero);
@@ -117,7 +118,7 @@ public class PDFImageXObject extends PDFXObject {

if (pdfimage.isTransparent()) {
PDFColor transp = pdfimage.getTransparentColor();
PDFArray mask = new PDFArray();
PDFArray mask = new PDFArray(this);
if (pdfimage.getColorSpace().isGrayColorSpace()) {
mask.add(new Integer(transp.red255()));
mask.add(new Integer(transp.red255()));

+ 8
- 5
src/java/org/apache/fop/pdf/PDFName.java View File

@@ -19,6 +19,10 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

/**
* Class representing a PDF name object.
*/
@@ -65,15 +69,14 @@ public class PDFName implements PDFWritable {
sb.append(DIGITS[ch & 0x0F]);
}
/** {@inheritDoc} */
public String toInlinePDFString() {
public String toString() {
return this.name;
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
public void outputInline(OutputStream out, Writer writer) throws IOException {
writer.write(toString());
}
}

+ 1
- 1
src/java/org/apache/fop/pdf/PDFNameTreeNode.java View File

@@ -108,7 +108,7 @@ public class PDFNameTreeNode extends PDFDictionary {
private PDFArray prepareLimitsArray() {
PDFArray limits = (PDFArray)get(LIMITS);
if (limits == null) {
limits = new PDFArray(new Object[2]);
limits = new PDFArray(this, new Object[2]);
put(LIMITS, limits);
}
if (limits.length() != 2) {

+ 7
- 3
src/java/org/apache/fop/pdf/PDFNull.java View File

@@ -19,6 +19,10 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

/**
* Class representing a PDF name object.
*/
@@ -35,13 +39,13 @@ public final class PDFNull implements PDFWritable {
}

/** {@inheritDoc} */
public String toInlinePDFString() {
public String toString() {
return "null";
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
public void outputInline(OutputStream out, Writer writer) throws IOException {
writer.write(toString());
}
}

+ 121
- 0
src/java/org/apache/fop/pdf/PDFNumberTreeNode.java View File

@@ -0,0 +1,121 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.pdf;

/**
* Class representing a PDF number tree node.
*/
public class PDFNumberTreeNode extends PDFDictionary {

private static final String KIDS = "Kids";
private static final String NUMS = "Nums";
private static final String LIMITS = "Limits";

/**
* create a named destination
*/
public PDFNumberTreeNode() {
/* generic creation of PDF object */
super();
}

/**
* Sets the Kids array.
* @param kids the Kids array
*/
public void setKids(PDFArray kids) {
put(KIDS, kids);
}
/**
* Returns the Kids array.
* @return the Kids array
*/
public PDFArray getKids() {
return (PDFArray)get(KIDS);
}
/**
* Sets the Nums array.
* @param nums the Nums array
*/
public void setNums(PDFNumsArray nums) {
put(NUMS, nums);
}
/**
* Returns the Nums array.
* @return the Nums array
*/
public PDFNumsArray getNums() {
return (PDFNumsArray)get(NUMS);
}
/**
* Sets the lower limit value of the Limits array.
* @param key the lower limit value
*/
public void setLowerLimit(Integer key) {
PDFArray limits = prepareLimitsArray();
limits.set(0, key);
}

/**
* Returns the lower limit value of the Limits array.
* @return the lower limit value
*/
public Integer getLowerLimit() {
PDFArray limits = prepareLimitsArray();
return (Integer)limits.get(0);
}

/**
* Sets the upper limit value of the Limits array.
* @param key the upper limit value
*/
public void setUpperLimit(Integer key) {
PDFArray limits = prepareLimitsArray();
limits.set(1, key);
}

/**
* Returns the upper limit value of the Limits array.
* @return the upper limit value
*/
public Integer getUpperLimit() {
PDFArray limits = prepareLimitsArray();
return (Integer)limits.get(1);
}


private PDFArray prepareLimitsArray() {
PDFArray limits = (PDFArray)get(LIMITS);
if (limits == null) {
limits = new PDFArray(this, new Object[2]);
put(LIMITS, limits);
}
if (limits.length() != 2) {
throw new IllegalStateException("Limits array must have 2 entries");
}
return limits;
}
}


+ 104
- 0
src/java/org/apache/fop/pdf/PDFNumsArray.java View File

@@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;

import org.apache.commons.io.output.CountingOutputStream;

/**
* Class representing an "Nums" array object (for Number Trees).
*/
public class PDFNumsArray extends PDFObject {
/** Sorted Map holding the values of this array. */
protected SortedMap map = new java.util.TreeMap();

/**
* Create a new, empty array object.
* @param parent the object's parent if any
*/
public PDFNumsArray(PDFObject parent) {
super(parent);
}

/**
* Returns the length of the array
* @return the length of the array
*/
public int length() {
return this.map.size();
}
/**
* Sets an entry.
* @param key the key of the value to set
* @param obj the new value
*/
public void put(int key, Object obj) {
this.map.put(new Integer(key), obj);
}
/**
* Gets an entry.
* @param key the key of requested value
* @return the requested value
*/
public Object get(int key) {
return this.map.get(new Integer(key));
}
/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
writer.write(getObjectID());
}
writer.write('[');
boolean first = true;
Iterator iter = this.map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
if (!first) {
writer.write(" ");
}
first = false;
formatObject(entry.getKey(), cout, writer);
writer.write(" ");
formatObject(entry.getValue(), cout, writer);
}
writer.write(']');
if (hasObjectNumber()) {
writer.write("\nendobj\n");
}
writer.flush();
return cout.getCount();
}
}

+ 67
- 24
src/java/org/apache/fop/pdf/PDFObject.java View File

@@ -22,6 +22,7 @@ package org.apache.fop.pdf;
// Java
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
@@ -57,6 +58,9 @@ public abstract class PDFObject implements PDFWritable {
*/
private PDFDocument document;

/** the parent PDFObject (may be null and may not always be set, needed for encryption) */
private PDFObject parent;
/**
* Returns the object's number.
* @return the PDF Object number
@@ -68,6 +72,21 @@ public abstract class PDFObject implements PDFWritable {
return this.objnum;
}
/**
* Default constructor.
*/
public PDFObject() {
//nop
}
/**
* Constructor for direct objects.
* @param parent the containing PDFObject instance
*/
public PDFObject(PDFObject parent) {
setParent(parent);
}
/**
* Indicates whether this PDFObject has already been assigned an
* object number.
@@ -102,7 +121,13 @@ public abstract class PDFObject implements PDFWritable {
* has not been assigned)
*/
public final PDFDocument getDocument() {
return this.document;
if (this.document != null) {
return this.document;
} else if (getParent() != null) {
return getParent().getDocument();
} else {
return null;
}
}

/**
@@ -127,6 +152,22 @@ public abstract class PDFObject implements PDFWritable {
this.document = doc;
}

/**
* Returns this objects's parent. The parent is null if it is a "direct object".
* @return the parent or null if there's no parent (or it hasn't been set)
*/
public PDFObject getParent() {
return this.parent;
}
/**
* Sets the direct parent object.
* @param parent the direct parent
*/
public void setParent(PDFObject parent) {
this.parent = parent;
}

/**
* Returns the PDF representation of the Object ID.
* @return the Object ID
@@ -169,6 +210,16 @@ public abstract class PDFObject implements PDFWritable {
return pdf.length;
}

/** {@inheritDoc} */
public void outputInline(OutputStream out, Writer writer) throws IOException {
if (hasObjectNumber()) {
writer.write(referencePDF());
} else {
writer.flush();
output(out);
}
}
/**
* Encodes the object as a byte array for output to a PDF file.
*
@@ -184,7 +235,9 @@ public abstract class PDFObject implements PDFWritable {
* is normally converted/encoded to a byte array by toPDF(). Only use
* this method to implement the serialization if the object can be fully
* represented as text. If the PDF representation of the object contains
* binary content use toPDF() or output(OutputStream) instead.
* binary content use toPDF() or output(OutputStream) instead. This applies
* to any object potentially containing a string object because string object
* are encrypted and therefore need to be binary.
* @return String the String representation
*/
protected String toPDFString() {
@@ -192,20 +245,6 @@ public abstract class PDFObject implements PDFWritable {
+ "Use output(OutputStream) instead.");
}
/**
* Returns a representation of this object for in-object placement, i.e. if the object
* has an object number its reference is returned. Otherwise, its PDF representation is
* returned.
* @return the String representation
*/
public String toInlinePDFString() {
if (hasObjectNumber()) {
return referencePDF();
} else {
return toPDFString();
}
}
/**
* Converts text to a byte array for writing to a PDF file.
* @param text text to convert/encode
@@ -250,23 +289,27 @@ public abstract class PDFObject implements PDFWritable {
/**
* Formats an object for serialization to PDF.
* @param obj the object
* @param sb the StringBuffer to write to
* @param out the OutputStream to write to
* @param writer a Writer for text content (will always be a wrapper around the above
* OutputStream. Make sure <code>flush</code> is called when mixing calls)
* @throws IOException If an I/O error occurs
*/
protected void formatObject(Object obj, StringBuffer sb) {
protected void formatObject(Object obj, OutputStream out, Writer writer) throws IOException {
if (obj == null) {
sb.append("null");
writer.write("null");
} else if (obj instanceof PDFWritable) {
sb.append(((PDFWritable)obj).toInlinePDFString());
((PDFWritable)obj).outputInline(out, writer);
} else if (obj instanceof Number) {
if (obj instanceof Double || obj instanceof Float) {
sb.append(PDFNumber.doubleOut(((Number)obj).doubleValue()));
writer.write(PDFNumber.doubleOut(((Number)obj).doubleValue()));
} else {
sb.append(obj);
writer.write(obj.toString());
}
} else if (obj instanceof Boolean) {
sb.append(obj);
writer.write(obj.toString());
} else {
sb.append("(").append(obj).append(")");
writer.flush();
out.write(encodeText(obj.toString()));
}
}

+ 48
- 0
src/java/org/apache/fop/pdf/PDFPageLabels.java View File

@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.pdf;

/**
* Class representing a PDF /PageLabels dictionary.
*/
public class PDFPageLabels extends PDFNumberTreeNode {
/**
* Create the /PageLabels dictionary
*/
public PDFPageLabels() {
super();
}

/**
* Returns the Nums object
* @return the Nums object (an empty PDFNumsArray for the "/Nums" entry is created
* if it doesn't exist)
*/
public PDFNumsArray getNums() {
PDFNumsArray nums = super.getNums();
if (nums == null) {
nums = new PDFNumsArray(this);
setNums(nums);
}
return nums;
}
}

+ 6
- 3
src/java/org/apache/fop/pdf/PDFReference.java View File

@@ -19,6 +19,9 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;

@@ -68,13 +71,13 @@ public class PDFReference implements PDFWritable {
}
/** {@inheritDoc} */
public String toInlinePDFString() {
public String toString() {
return this.indirectReference;
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
public void outputInline(OutputStream out, Writer writer) throws IOException {
writer.write(toString());
}
}

+ 98
- 91
src/java/org/apache/fop/pdf/PDFRoot.java View File

@@ -19,12 +19,10 @@
package org.apache.fop.pdf;

import java.util.List;

/**
* class representing a Root (/Catalog) object
* Class representing a Root (/Catalog) object.
*/
public class PDFRoot extends PDFObject {
public class PDFRoot extends PDFDictionary {

/**
* Use no page mode setting, default
@@ -46,27 +44,13 @@ public class PDFRoot extends PDFObject {
*/
public static final int PAGEMODE_FULLSCREEN = 3;

/**
* the /Pages object that is root of the Pages hierarchy
*/
protected PDFPages rootPages;

/**
* Root outline object
*/
private PDFOutline outline;

/** Optional Metadata object */
private PDFMetadata metadata;
private static final PDFName[] PAGEMODE_NAMES = new PDFName[] {
new PDFName("UseNone"),
new PDFName("UseOutlines"),
new PDFName("UseThumbs"),
new PDFName("FullScreen"),
};
/** The array of OutputIntents */
private List outputIntents;
/** the /Dests object, if this PDF has a Names Dictionary */
private PDFNames names;

private int pageMode = PAGEMODE_USENONE;

/**
* create a Root (/Catalog) object. NOTE: The PDFRoot
* object must be created before the PDF document is
@@ -80,25 +64,45 @@ public class PDFRoot extends PDFObject {
public PDFRoot(int objnum, PDFPages pages) {
super();
setObjectNumber(objnum);
put("Type", new PDFName("Catalog"));
setRootPages(pages);
}

/**
* Set the page mode for the PDF document.
*
* @param mode the page mode
* @param mode the page mode (one of PAGEMODE_*)
*/
public void setPageMode(int mode) {
pageMode = mode;
put("PageMode", PAGEMODE_NAMES[mode]);
}

/**
* Returns the currently active /PageMode.
* @return the /PageMode (one of PAGEMODE_*)
*/
public int getPageMode() {
PDFName mode = (PDFName)get("PageMode");
if (mode != null) {
for (int i = 0; i < PAGEMODE_NAMES.length; i++) {
if (PAGEMODE_NAMES[i].equals(mode)) {
return i;
}
}
throw new IllegalStateException("Unknown /PageMode encountered: " + mode);
} else {
return PAGEMODE_USENONE;
}
}
/**
* add a /Page object to the root /Pages object
*
* @param page the /Page object to add
*/
public void addPage(PDFPage page) {
this.rootPages.addPage(page);
PDFPages pages = getRootPages();
pages.addPage(page);
}

/**
@@ -107,16 +111,50 @@ public class PDFRoot extends PDFObject {
* @param pages the /Pages object to set as root
*/
public void setRootPages(PDFPages pages) {
this.rootPages = pages;
put("Pages", pages.makeReference());
}

/**
* Returns the /PageLabels object.
* @return the /PageLabels object if set, null otherwise.
* @since PDF 1.3
*/
public PDFPages getRootPages() {
PDFReference ref = (PDFReference)get("Pages");
return (ref != null ? (PDFPages)ref.getObject() : null);
}
/**
* Sets the /PageLabels object.
* @param pageLabels the /PageLabels object
*/
public void setPageLabels(PDFPageLabels pageLabels) {
put("PageLabels", pageLabels.makeReference());
}
/**
* Returns the /PageLabels object.
* @return the /PageLabels object if set, null otherwise.
* @since PDF 1.3
*/
public PDFPageLabels getPageLabels() {
PDFReference ref = (PDFReference)get("PageLabels");
return (ref != null ? (PDFPageLabels)ref.getObject() : null);
}
/**
* Set the root outline for the PDF document.
*
* @param out the root PDF Outline
*/
public void setRootOutline(PDFOutline out) {
outline = out;
put("Outlines", out.makeReference());
//Set /PageMode to /UseOutlines by default if no other mode has been set
PDFName mode = (PDFName)get("PageMode");
if (mode == null) {
setPageMode(PAGEMODE_USEOUTLINES);
}
}

/**
@@ -125,24 +163,27 @@ public class PDFRoot extends PDFObject {
* @return the root PDF Outline
*/
public PDFOutline getRootOutline() {
return outline;
PDFReference ref = (PDFReference)get("Outlines");
return (ref != null ? (PDFOutline)ref.getObject() : null);
}
/**
* Set the Names object.
* Set the /Names object.
* @param names the Names object
* @since PDF 1.2
*/
public void setNames(PDFNames names) {
this.names = names;
put("Names", names.makeReference());
}
/**
* Returns the /Names object.
* @return the Names object if set, null otherwise.
* @since PDF 1.2
*/
public PDFNames getNames() {
return this.names;
PDFReference ref = (PDFReference)get("Names");
return (ref != null ? (PDFNames)ref.getObject() : null);
}
/**
@@ -151,78 +192,44 @@ public class PDFRoot extends PDFObject {
* @since PDF 1.4
*/
public void setMetadata(PDFMetadata meta) {
this.metadata = meta;
if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
put("Metadata", meta.makeReference());
}
}
/**
* @return the Metadata object if set, null otherwise.
* Returns the /Metadata object
* @return the /Metadata object if set, null otherwise.
* @since PDF 1.4
*/
public PDFMetadata getMetadata() {
return this.metadata;
PDFReference ref = (PDFReference)get("Metadata");
return (ref != null ? (PDFMetadata)ref.getObject() : null);
}

/**
* Adds an OutputIntent to the PDF
* @param outputIntent the OutputIntent dictionary
* Returns the /OutputIntents array.
* @return the /OutputIntents array or null if it doesn't exist
* @since PDF 1.4
*/
public void addOutputIntent(PDFOutputIntent outputIntent) {
if (this.outputIntents == null) {
this.outputIntents = new java.util.ArrayList();
}
this.outputIntents.add(outputIntent);
public PDFArray getOutputIntents() {
return (PDFArray)get("OutputIntents");
}
/**
* {@inheritDoc}
*/
public String toPDFString() {
StringBuffer p = new StringBuffer(128);
p.append(getObjectID());
p.append("<< /Type /Catalog\n /Pages "
+ this.rootPages.referencePDF()
+ "\n");
if (outline != null) {
p.append(" /Outlines " + outline.referencePDF() + "\n");
p.append(" /PageMode /UseOutlines\n");
} else {
switch (pageMode) {
case PAGEMODE_USEOUTLINES:
p.append(" /PageMode /UseOutlines\n");
break;
case PAGEMODE_USETHUMBS:
p.append(" /PageMode /UseThumbs\n");
break;
case PAGEMODE_FULLSCREEN:
p.append(" /PageMode /FullScreen\n");
break;
case PAGEMODE_USENONE:
default:
break;
}
}
if (getDocumentSafely().hasDestinations() && getNames() != null) {
p.append(" /Names " + getNames().referencePDF() + "\n");
}
if (getMetadata() != null
&& getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
p.append(" /Metadata " + getMetadata().referencePDF() + "\n");
}
if (this.outputIntents != null
&& this.outputIntents.size() > 0
&& getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
p.append(" /OutputIntents [");
for (int i = 0, c = this.outputIntents.size(); i < c; i++) {
PDFOutputIntent outputIntent = (PDFOutputIntent)this.outputIntents.get(i);
if (i > 0) {
p.append(" ");
}
p.append(outputIntent.referencePDF());
* Adds an OutputIntent to the PDF
* @param outputIntent the OutputIntent dictionary
* @since PDF 1.4
*/
public void addOutputIntent(PDFOutputIntent outputIntent) {
if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
PDFArray outputIntents = getOutputIntents();
if (outputIntents == null) {
outputIntents = new PDFArray(this);
put("OutputIntents", outputIntents);
}
p.append("]\n");
outputIntents.add(outputIntent);
}
p.append(">>\nendobj\n");
return p.toString();
}
}

+ 11
- 5
src/java/org/apache/fop/pdf/PDFWritable.java View File

@@ -19,6 +19,10 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

/**
* This interface is implemented by classes that can be serialized to a PDF file either by
* serializing the object or by writing a indirect reference to the actual object.
@@ -26,11 +30,13 @@ package org.apache.fop.pdf;
public interface PDFWritable {
/**
* Returns a representation of this object for in-object placement, i.e. if the object
* has an object number its reference is returned. Otherwise, its PDF representation is
* returned.
* @return the String representation
* Writes a "direct object" (inline object) representation to the stream. A Writer is given
* for optimized encoding of text content. Since the Writer is buffered, make sure
* <code>flush()</code> is called before any direct calls to <code>out</code> are made.
* @param out the OutputStream (for binary content)
* @param writer the Writer (for text content, wraps the above OutputStream)
* @throws IOException if an I/O error occurs
*/
String toInlinePDFString();
void outputInline(OutputStream out, Writer writer) throws IOException;
}

+ 1
- 1
src/java/org/apache/fop/render/PrintRendererConfigurator.java View File

@@ -118,7 +118,7 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
boolean strict, FontCache fontCache) throws FOPException {
List fontInfoList = new java.util.ArrayList();

Configuration fonts = cfg.getChild("fonts");
Configuration fonts = cfg.getChild("fonts", false);
if (fonts != null) {
long start = 0;
if (log.isDebugEnabled()) {

+ 4
- 2
src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java View File

@@ -21,12 +21,14 @@ package org.apache.fop.render.afp.extensions;

import java.io.Serializable;

import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.util.XMLizable;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.xmlgraphics.util.XMLizable;

import org.apache.fop.fo.extensions.ExtensionAttachment;

/**
* This is the pass-through value object for the PostScript extension.
*/

+ 0
- 79
src/java/org/apache/fop/render/afp/modca/EndPageGroup.java View File

@@ -1,79 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.render.afp.modca;

import java.io.IOException;
import java.io.OutputStream;

/**
* The End Named Page Group (ENG) structured field terminates a page group that was
* initiated by a Begin Named Page Group structured field.
*
* Note :This object will be used to represent an ENG
* structured field. It is necessary as you can't end
* a PageGroup because you don't know where the group
* will end (as this is controlled by the tags in the FO).
* <p>
*
*/
public class EndPageGroup extends AbstractNamedAFPObject {

/**
* Main constructor
* @param groupId the group id
*/
public EndPageGroup(String groupId) {

super(groupId);

if (log.isDebugEnabled()) {
log.debug("A ENG is being created for group: " + groupId);
}
}

/**
* Accessor method to write the AFP datastream for the End Page Group.
* @param os The stream to write to
* @throws java.io.IOException thrown if an I/O exception of some sort has occurred
*/
public void writeDataStream(OutputStream os)
throws IOException {
byte[] data = new byte[17];

data[0] = 0x5A; // Structured field identifier
data[1] = 0x00; // Length byte 1
data[2] = 0x10; // Length byte 2
data[3] = (byte) 0xD3; // Structured field id byte 1
data[4] = (byte) 0xA9; // Structured field id byte 2
data[5] = (byte) 0xAD; // Structured field id byte 3
data[6] = 0x00; // Flags
data[7] = 0x00; // Reserved
data[8] = 0x00; // Reserved

for (int i = 0; i < nameBytes.length; i++) {

data[9 + i] = nameBytes[i];

}

os.write(data);
}

}

+ 2
- 2
src/java/org/apache/fop/render/afp/modca/ImageSizeParameter.java View File

@@ -38,8 +38,8 @@ public class ImageSizeParameter extends AbstractAFPObject {
* resolution, hsize and vsize.
* @param hresol The horizontal resolution of the image.
* @param vresol The vertical resolution of the image.
* @param hsize The hsize of the image.
* @param vsize The vsize of the vsize.
* @param hsize The horizontal size of the image.
* @param vsize The vertical size of the image.
*/
public ImageSizeParameter(int hresol, int vresol, int hsize, int vsize) {
this.hRes = hresol;

+ 15
- 24
src/java/org/apache/fop/render/afp/modca/IncludePageOverlay.java View File

@@ -42,12 +42,12 @@ public class IncludePageOverlay extends AbstractNamedAFPObject {
/**
* The x coordinate
*/
private int xCoor = 0;
private int x = 0;

/**
* The y coordinate
*/
private int yCoor = 0;
private int y = 0;

/**
* The orientation
@@ -62,11 +62,9 @@ public class IncludePageOverlay extends AbstractNamedAFPObject {
* @param orientation The orientation
*/
public IncludePageOverlay(String overlayName, int x, int y, int orientation) {

super(overlayName);

xCoor = x;
yCoor = y;
this.x = x;
this.y = y;
setOrientation(orientation);
}

@@ -77,7 +75,6 @@ public class IncludePageOverlay extends AbstractNamedAFPObject {
* The orientation (0,90, 180, 270)
*/
public void setOrientation(int orientation) {

if (orientation == 0 || orientation == 90 || orientation == 180
|| orientation == 270) {
this.orientation = orientation;
@@ -85,7 +82,6 @@ public class IncludePageOverlay extends AbstractNamedAFPObject {
throw new IllegalArgumentException(
"The orientation must be one of the values 0, 90, 180, 270");
}

}

/**
@@ -101,9 +97,9 @@ public class IncludePageOverlay extends AbstractNamedAFPObject {
data[0] = 0x5A;

// Set the total record length
byte[] rl1 = BinaryUtils.convert(24, 2); //Ignore first byte
data[1] = rl1[0];
data[2] = rl1[1];
byte[] len = BinaryUtils.convert(24, 2); //Ignore first byte
data[1] = len[0];
data[2] = len[1];

// Structured field ID for a IPO
data[3] = (byte) 0xD3;
@@ -115,20 +111,18 @@ public class IncludePageOverlay extends AbstractNamedAFPObject {
data[8] = 0x00; // Reserved

for (int i = 0; i < nameBytes.length; i++) {

data[9 + i] = nameBytes[i];

}

byte[] r2 = BinaryUtils.convert(xCoor, 3);
data[17] = r2[0]; // x coordinate
data[18] = r2[1];
data[19] = r2[2];
byte[] xcoord = BinaryUtils.convert(x, 3);
data[17] = xcoord[0]; // x coordinate
data[18] = xcoord[1];
data[19] = xcoord[2];

byte[] r3 = BinaryUtils.convert(yCoor, 3);
data[20] = r3[0]; // y coordinate
data[21] = r3[1];
data[22] = r3[2];
byte[] ycoord = BinaryUtils.convert(y, 3);
data[20] = ycoord[0]; // y coordinate
data[21] = ycoord[1];
data[22] = ycoord[2];

switch (orientation) {
case 90:
@@ -148,9 +142,6 @@ public class IncludePageOverlay extends AbstractNamedAFPObject {
data[24] = 0x00;
break;
}

os.write(data);

}

}

+ 13
- 18
src/java/org/apache/fop/render/afp/modca/IncludePageSegment.java View File

@@ -45,24 +45,24 @@ public class IncludePageSegment extends AbstractNamedAFPObject {
/**
* The x position where we need to put this object on the page
*/
private byte[] xCoor;
private byte[] x;

/**
* The y position where we need to put this object on the page
*/
private byte[] yCoor;
private byte[] y;

/**
* Constructor for the Include Page Segment
* @param name Name of the page segment
* @param xVal The x position
* @param yVal The y position
* @param x The x position
* @param y The y position
*/
public IncludePageSegment(String name, int xVal, int yVal) {
public IncludePageSegment(String name, int x, int y) {

super(name);
this.xCoor = BinaryUtils.convert(xVal, 3);
this.yCoor = BinaryUtils.convert(yVal, 3);
this.x = BinaryUtils.convert(x, 3);
this.y = BinaryUtils.convert(y, 3);

}

@@ -93,22 +93,17 @@ public class IncludePageSegment extends AbstractNamedAFPObject {
data[8] = 0x00; // Reserved

for (int i = 0; i < nameBytes.length; i++) {

data[9 + i] = nameBytes[i];

}

data[17] = xCoor[0]; // x coordinate
data[18] = xCoor[1];
data[19] = xCoor[2];
data[17] = x[0]; // x coordinate
data[18] = x[1];
data[19] = x[2];

data[20] = yCoor[0]; // y coordinate
data[21] = yCoor[1];
data[22] = yCoor[2];
data[20] = y[0]; // y coordinate
data[21] = y[1];
data[22] = y[2];

os.write(data);

}


}

+ 1
- 8
src/java/org/apache/fop/render/afp/modca/MapPageOverlay.java View File

@@ -30,7 +30,6 @@ import org.apache.fop.render.afp.tools.BinaryUtils;
* The Map Page Overlay structured field maps a Resource Local ID to the name of
* a Begin Overlay structured field. A Map Page Overlay structured field may
* contain from one to 254 repeating groups.
*
*/
public class MapPageOverlay extends AbstractAFPObject {

@@ -68,15 +67,10 @@ public class MapPageOverlay extends AbstractAFPObject {
log.debug("addOverlay():: adding overlay " + name);
}

byte[] data;

try {

data = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
byte[] data = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
overLays.add(data);

} catch (UnsupportedEncodingException usee) {

log.error("addOverlay():: UnsupportedEncodingException translating the name "
+ name);
}
@@ -117,7 +111,6 @@ public class MapPageOverlay extends AbstractAFPObject {
byte olayref = 0x00;

for (int i = 0; i < oLayCount; i++) {

olayref = (byte) (olayref + 1);

data[++pos] = 0x00;

+ 1
- 0
src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java View File

@@ -68,5 +68,6 @@ public class TIFFRendererConfigurator extends PrintRendererConfigurator {
log.info("TIFF compression set to " + name);
}
}
super.configure(renderer);
}
}

+ 205
- 0
src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java View File

@@ -0,0 +1,205 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.render.java2d;

import java.awt.Font;
import java.awt.FontFormatException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.LazyFont;
import org.apache.fop.fonts.Typeface;

/**
* FontMetricsMapper that delegates most methods to an underlying
* <tt>FontMetrics</tt> instance. This class was designed to allow
* the underlying <tt>java.awt.Font</tt> to be loaded from a
* user-configured file not registered in the current graphics environment.
*/
public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapper {

/**
* Font metrics for the font this class models.
*/
private Typeface typeface;

/**
* The font required by the Java2D renderer.
*/
private java.awt.Font font;

/**
* Maintains the most recently requested size.
*/
private float size = 1;

/**
* Construction of this class results in the immediate construction.
* of the underlying <tt>java.awt.Font</tt>
* @param fontMetrics
* @throws FontFormatException
* @throws IOException
*/
public CustomFontMetricsMapper(final CustomFont fontMetrics)
throws FontFormatException, IOException {
this.typeface = fontMetrics;
initialize(fontMetrics.getEmbedFileSource());
}

/**
* Construction of this class results in the immediate construction
* of the underlying <tt>java.awt.Font</tt>
* @param fontMetrics
* @throws FontFormatException
* @throws IOException
*/
public CustomFontMetricsMapper(final LazyFont fontMetrics, final Source fontSource)
throws FontFormatException, IOException {
this.typeface = fontMetrics;
initialize(fontSource);
}

private static final int TYPE1_FONT = 1; //Defined in Java 1.5

/**
* Loads the java.awt.Font
* @param source
* @throws FontFormatException
* @throws IOException
*/
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();

}

/** {@inheritDoc} */
public final String getEncoding() {
return null; //Not applicable to Java2D rendering
}

/** {@inheritDoc} */
public final boolean hasChar(final char c) {
return font.canDisplay(c);
}

/** {@inheritDoc} */
public final char mapChar(final char c) {
return typeface.mapChar(c);
}

/** {@inheritDoc} */
public final Font getFont(final int size) {
if (this.size == size) {
return font;
}

this.size = size / 1000f;
font = font.deriveFont(this.size);
return font;
}

/** {@inheritDoc} */
public final int getAscender(final int size) {
return typeface.getAscender(size);
}

/** {@inheritDoc} */
public final int getCapHeight(final int size) {
return typeface.getCapHeight(size);
}

/** {@inheritDoc} */
public final int getDescender(final int size) {
return typeface.getDescender(size);
}

/** {@inheritDoc} */
public final String getEmbedFontName() {
return typeface.getEmbedFontName();
}

/** {@inheritDoc} */
public final Set getFamilyNames() {
return typeface.getFamilyNames();
}

/** {@inheritDoc} */
public final String getFontName() {
return typeface.getFontName();
}

/** {@inheritDoc} */
public final FontType getFontType() {
return typeface.getFontType();
}

/** {@inheritDoc} */
public final String getFullName() {
return typeface.getFullName();
}

/** {@inheritDoc} */
public final Map getKerningInfo() {
return typeface.getKerningInfo();
}

/** {@inheritDoc} */
public final int getWidth(final int i, final int size) {
return typeface.getWidth(i, size);
}

/** {@inheritDoc} */
public final int[] getWidths() {
return typeface.getWidths();
}

/** {@inheritDoc} */
public final int getXHeight(final int size) {
return typeface.getXHeight(size);
}

/** {@inheritDoc} */
public final boolean hasKerningInfo() {
return typeface.hasKerningInfo();
}

}

+ 7
- 167
src/java/org/apache/fop/render/java2d/FontMetricsMapper.java View File

@@ -16,183 +16,23 @@
*/

/* $Id$ */
package org.apache.fop.render.java2d;

// Java
import java.awt.Graphics2D;
import java.util.Map;
import java.util.Set;
package org.apache.fop.render.java2d;

import org.apache.fop.fonts.FontMetrics;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.Typeface;


/**
* This class implements org.apache.fop.layout.FontMetrics and
* is added to the hash table in FontInfo. It deferes the
* actual calculation of the metrics to
* Java2DFontMetrics. It only keeps the java name and
* style as member varibles
* Adds method to retrieve the actual <tt>java.awt.Font</tt>
* for use by <tt>Java2DRenderer</tt>s.
*/

public class FontMetricsMapper extends Typeface implements FontMetrics {

/**
* This is a Java2DFontMetrics that does the real calculation.
* It is only one class that dynamically determines the font-size.
*/
private static Java2DFontMetrics metric = null;

/**
* The java name of the font.
* # Make the family name immutable.
*/
private final String family;

/**
* The java style of the font.
* # Make the style immutable.
*/
private final int style;

/**
* Constructs a new Font-metrics.
* @param family the family name of the font (java value)
* @param style the java type style value of the font
* @param graphics a Graphics2D object - this is needed so
* that we can get an instance of java.awt.FontMetrics
*/
public FontMetricsMapper(String family, int style, Graphics2D graphics) {
this.family = family;
this.style = style;
if (metric == null) {
metric = new Java2DFontMetrics(graphics);
}
}

/** {@inheritDoc} */
public String getFontName() {
return family;
}

/** {@inheritDoc} */
public String getEmbedFontName() {
return getFontName();
}

/** {@inheritDoc} */
public String getFullName() {
return getFontName();
}

/** {@inheritDoc} */
public Set getFamilyNames() {
Set s = new java.util.HashSet();
s.add(this.family);
return s;
}

/**
* {@inheritDoc}
*/
public FontType getFontType() {
return FontType.OTHER;
}
/**
* {@inheritDoc}
*/
public int getMaxAscent(int size) {
return metric.getMaxAscent(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getAscender(int size) {
return metric.getAscender(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getCapHeight(int size) {
return metric.getCapHeight(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getDescender(int size) {
return metric.getDescender(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getXHeight(int size) {
return metric.getXHeight(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getWidth(int i, int size) {
return metric.width(i, family, style, size);
}


/**
* {@inheritDoc}
*/
public int[] getWidths() {
return metric.getWidths(family, style, Java2DFontMetrics.FONT_SIZE);
}
public interface FontMetricsMapper extends FontMetrics {

/**
* Gets a Font instance of the Font that this
* FontMetrics describes in the desired size.
* @param size font size
* @return font with the desired characeristics.
*/
public java.awt.Font getFont(int size) {
return metric.getFont(family, style, size);
}

/**
* {@inheritDoc}
*/
public Map getKerningInfo() {
return java.util.Collections.EMPTY_MAP;
}

/**
* {@inheritDoc}
* @return font with the desired characteristics.
*/
public boolean hasKerningInfo() {
return false;
}

/** {@inheritDoc} */
public String getEncoding() {
return null; //Not applicable to Java2D rendering
}

/** {@inheritDoc} */
public char mapChar(char c) {
return c;
}

/** {@inheritDoc} */
public boolean hasChar(char c) {
return metric.hasChar(family, style, Java2DFontMetrics.FONT_SIZE, c);
}

java.awt.Font getFont(int size);
}






+ 106
- 33
src/java/org/apache/fop/render/java2d/FontSetup.java View File

@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,14 +22,23 @@ package org.apache.fop.render.java2d;
// FOP
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.util.List;
import java.util.Set;

import javax.xml.transform.Source;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.FontUtil;
import org.apache.fop.fonts.LazyFont;

/**
* Sets up the Java2D/AWT fonts. It is similar to
@@ -41,18 +50,18 @@ public class FontSetup {

/** logging instance */
protected static Log log = LogFactory.getLog(FontSetup.class);
private static final int LAST_PREDEFINED_FONT_NUMBER = 14;

private static final Set HARDCODED_FONT_NAMES;
static {
HARDCODED_FONT_NAMES = new java.util.HashSet();
HARDCODED_FONT_NAMES.add("any");
HARDCODED_FONT_NAMES.add("sans-serif");
HARDCODED_FONT_NAMES.add("serif");
HARDCODED_FONT_NAMES.add("monospace");
HARDCODED_FONT_NAMES.add("Helvetica");
HARDCODED_FONT_NAMES.add("Times");
HARDCODED_FONT_NAMES.add("Courier");
@@ -62,7 +71,7 @@ public class FontSetup {
HARDCODED_FONT_NAMES.add("Times-Roman");
HARDCODED_FONT_NAMES.add("Computer-Modern-Typewriter");
}
/**
* Sets up the font info object.
*
@@ -70,9 +79,12 @@ public class FontSetup {
* triplets for lookup.
*
* @param fontInfo the font info object to set up
* @param graphics needed for acces to font metrics
* @param configuredFontList of fop config fonts
* @param resolver for resolving the font file URI
* @param graphics needed for access to font metrics
*/
public static void setup(FontInfo fontInfo, Graphics2D graphics) {
public static void setup(FontInfo fontInfo, List configuredFontList,
FontResolver resolver, Graphics2D graphics) {
FontMetricsMapper metric;
int normal, bold, bolditalic, italic;

@@ -87,47 +99,47 @@ public class FontSetup {
italic = java.awt.Font.ITALIC;
bolditalic = java.awt.Font.BOLD + java.awt.Font.ITALIC;

metric = new FontMetricsMapper("SansSerif", normal, graphics);
metric = new SystemFontMetricsMapper("SansSerif", normal, graphics);
// --> goes to F1
fontInfo.addMetrics("F1", metric);
metric = new FontMetricsMapper("SansSerif", italic, graphics);
metric = new SystemFontMetricsMapper("SansSerif", italic, graphics);
// --> goes to F2
fontInfo.addMetrics("F2", metric);
metric = new FontMetricsMapper("SansSerif", bold, graphics);
metric = new SystemFontMetricsMapper("SansSerif", bold, graphics);
// --> goes to F3
fontInfo.addMetrics("F3", metric);
metric = new FontMetricsMapper("SansSerif", bolditalic, graphics);
metric = new SystemFontMetricsMapper("SansSerif", bolditalic, graphics);
// --> goes to F4
fontInfo.addMetrics("F4", metric);


metric = new FontMetricsMapper("Serif", normal, graphics);
metric = new SystemFontMetricsMapper("Serif", normal, graphics);
// --> goes to F5
fontInfo.addMetrics("F5", metric);
metric = new FontMetricsMapper("Serif", italic, graphics);
metric = new SystemFontMetricsMapper("Serif", italic, graphics);
// --> goes to F6
fontInfo.addMetrics("F6", metric);
metric = new FontMetricsMapper("Serif", bold, graphics);
metric = new SystemFontMetricsMapper("Serif", bold, graphics);
// --> goes to F7
fontInfo.addMetrics("F7", metric);
metric = new FontMetricsMapper("Serif", bolditalic, graphics);
metric = new SystemFontMetricsMapper("Serif", bolditalic, graphics);
// --> goes to F8
fontInfo.addMetrics("F8", metric);

metric = new FontMetricsMapper("MonoSpaced", normal, graphics);
metric = new SystemFontMetricsMapper("MonoSpaced", normal, graphics);
// --> goes to F9
fontInfo.addMetrics("F9", metric);
metric = new FontMetricsMapper("MonoSpaced", italic, graphics);
metric = new SystemFontMetricsMapper("MonoSpaced", italic, graphics);
// --> goes to F10
fontInfo.addMetrics("F10", metric);
metric = new FontMetricsMapper("MonoSpaced", bold, graphics);
metric = new SystemFontMetricsMapper("MonoSpaced", bold, graphics);
// --> goes to F11
fontInfo.addMetrics("F11", metric);
metric = new FontMetricsMapper("MonoSpaced", bolditalic, graphics);
metric = new SystemFontMetricsMapper("MonoSpaced", bolditalic, graphics);
// --> goes to F12
fontInfo.addMetrics("F12", metric);

metric = new FontMetricsMapper("Serif", normal, graphics);
metric = new SystemFontMetricsMapper("Serif", normal, graphics);
//"Symbol" doesn't seem to work here, but "Serif" does the job just fine. *shrug*
// --> goes to F13 and F14
fontInfo.addMetrics("F13", metric);
@@ -206,31 +218,32 @@ public class FontSetup {
fontInfo.addFontProperties("F8", "Times Roman", "italic", Font.WEIGHT_BOLD);
fontInfo.addFontProperties("F9", "Computer-Modern-Typewriter",
"normal", Font.WEIGHT_NORMAL);
configureInstalledAWTFonts(fontInfo, graphics, LAST_PREDEFINED_FONT_NUMBER + 1);

int lastNum = configureInstalledAWTFonts(fontInfo, graphics, LAST_PREDEFINED_FONT_NUMBER + 1);
addConfiguredFonts(fontInfo, configuredFontList, resolver, lastNum++);
}

private static void configureInstalledAWTFonts(FontInfo fontInfo, Graphics2D graphics,
private static int configureInstalledAWTFonts(FontInfo fontInfo, Graphics2D graphics,
int startNumber) {
int num = startNumber;
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
java.awt.Font[] fonts = env.getAllFonts();
for (int i = 0; i < fonts.length; i++) {
java.awt.Font f = fonts[i];
if (HARDCODED_FONT_NAMES.contains(f.getName())) {
continue; //skip
}
if (log.isTraceEnabled()) {
log.trace("AWT Font: " + f.getFontName()
+ ", family: " + f.getFamily()
+ ", PS: " + f.getPSName()
log.trace("AWT Font: " + f.getFontName()
+ ", family: " + f.getFamily()
+ ", PS: " + f.getPSName()
+ ", Name: " + f.getName()
+ ", Angle: " + f.getItalicAngle()
+ ", Style: " + f.getStyle());
}
String searchName = FontUtil.stripWhiteSpace(f.getName()).toLowerCase();
String guessedStyle = FontUtil.guessStyle(searchName);
int guessedWeight = FontUtil.guessWeight(searchName);
@@ -239,7 +252,7 @@ public class FontSetup {
String fontKey = "F" + num;
int style = convertToAWTFontStyle(guessedStyle, guessedWeight);
addFontMetricsMapper(fontInfo, f.getName(), fontKey, graphics, style);
//Register appropriate font triplets matching the font. Two different strategies:
//Example: "Arial Bold", normal, normal
addFontTriplet(fontInfo, f.getName(),
@@ -250,9 +263,69 @@ public class FontSetup {
guessedStyle, guessedWeight, fontKey);
}
}
return num;

}

/**
* Add fonts from configuration file starting with internal name F<num>.
*
* @param fontInfo the font info object to set up
* @param fontList a list of EmbedFontInfo objects
* @param num starting index for internal font numbering
* @param resolver the font resolver
*/
private static void addConfiguredFonts(FontInfo fontInfo, List fontList, FontResolver resolver, int num) {

if (fontList == null || fontList.size() < 1) {
log.debug("No user configured fonts found.");
return;
}
if (resolver == null) {
// Ensure that we have minimal font resolution capabilities
resolver = org.apache.fop.fonts.FontSetup
.createMinimalFontResolver();
}
String internalName = null;

for (int i = 0; i < fontList.size(); i++) {

EmbedFontInfo configFontInfo = (EmbedFontInfo) fontList.get(i);
String fontFile = configFontInfo.getEmbedFile();
internalName = "F" + num;
num++;
try {
FontMetricsMapper font = null;
String metricsUrl = configFontInfo.getMetricsFile();
// If the user specified an XML-based metrics file, we'll use it
// Otherwise, calculate metrics directly from the font file.
if (metricsUrl != null) {
LazyFont fontMetrics = new LazyFont(configFontInfo, resolver);
Source fontSource = resolver.resolve(configFontInfo.getEmbedFile());
font = new CustomFontMetricsMapper(fontMetrics, fontSource);
} else {
CustomFont fontMetrics = FontLoader.loadFont(fontFile, resolver);
font = new CustomFontMetricsMapper(fontMetrics);
}

fontInfo.addMetrics(internalName, font);

List triplets = configFontInfo.getFontTriplets();
for (int c = 0; c < triplets.size(); c++) {
FontTriplet triplet = (FontTriplet) triplets.get(c);

if (log.isDebugEnabled()) {
log.debug("Registering: " + triplet + " under " + internalName);
}
fontInfo.addFontProperties(internalName, triplet);
}
} catch (Exception e) {
log.warn("Unable to load custom font from file '" + fontFile + "'", e);
}
}
}


private static void addFontTriplet(FontInfo fontInfo, String fontName, String fontStyle,
int fontWeight, String fontKey) {
FontTriplet triplet = FontInfo.createFontKey(fontName, fontStyle, fontWeight);
@@ -261,7 +334,7 @@ public class FontSetup {

private static void addFontMetricsMapper(FontInfo fontInfo, String family, String fontKey,
Graphics2D graphics, int style) {
FontMetricsMapper metric = new FontMetricsMapper(family, style, graphics);
FontMetricsMapper metric = new SystemFontMetricsMapper(family, style, graphics);
fontInfo.addMetrics(fontKey, metric);
}

@@ -275,6 +348,6 @@ public class FontSetup {
}
return style;
}
}


+ 1
- 1
src/java/org/apache/fop/render/java2d/Java2DRenderer.java View File

@@ -176,7 +176,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
//The next line is important to get accurate font metrics!
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
FontSetup.setup(fontInfo, g);
FontSetup.setup(fontInfo, fontList, fontResolver, g);
}

/** {@inheritDoc} */

+ 1
- 0
src/java/org/apache/fop/render/java2d/Java2DRendererConfigurator.java View File

@@ -53,5 +53,6 @@ public class Java2DRendererConfigurator extends PrintRendererConfigurator {
java2dRenderer.setTransparentPageBackground("true".equalsIgnoreCase(value));
}
}
super.configure(renderer);
}
}

+ 194
- 0
src/java/org/apache/fop/render/java2d/SystemFontMetricsMapper.java View File

@@ -0,0 +1,194 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.render.java2d;

// Java
import java.awt.Graphics2D;
import java.util.Map;
import java.util.Set;

import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.Typeface;


/**
* This class implements org.apache.fop.layout.FontMetrics and
* is added to the hash table in FontInfo. It deferes the
* actual calculation of the metrics to
* Java2DFontMetrics. It only keeps the java name and
* style as member varibles
*/

public class SystemFontMetricsMapper extends Typeface implements FontMetricsMapper {

/**
* This is a Java2DFontMetrics that does the real calculation.
* It is only one class that dynamically determines the font-size.
*/
private static Java2DFontMetrics metric = null;

/**
* The java name of the font.
* # Make the family name immutable.
*/
private final String family;

/**
* The java style of the font.
* # Make the style immutable.
*/
private final int style;

/**
* Constructs a new Font-metrics.
* @param family the family name of the font (java value)
* @param style the java type style value of the font
* @param graphics a Graphics2D object - this is needed so
* that we can get an instance of java.awt.FontMetrics
*/
public SystemFontMetricsMapper(String family, int style, Graphics2D graphics) {
this.family = family;
this.style = style;
if (metric == null) {
metric = new Java2DFontMetrics(graphics);
}
}

/** {@inheritDoc} */
public String getFontName() {
return family;
}

/** {@inheritDoc} */
public String getEmbedFontName() {
return getFontName();
}

/** {@inheritDoc} */
public String getFullName() {
return getFontName();
}

/** {@inheritDoc} */
public Set getFamilyNames() {
Set s = new java.util.HashSet();
s.add(this.family);
return s;
}

/**
* {@inheritDoc}
*/
public FontType getFontType() {
return FontType.OTHER;
}

/**
* {@inheritDoc}
*/
public int getMaxAscent(int size) {
return metric.getMaxAscent(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getAscender(int size) {
return metric.getAscender(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getCapHeight(int size) {
return metric.getCapHeight(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getDescender(int size) {
return metric.getDescender(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getXHeight(int size) {
return metric.getXHeight(family, style, size);
}

/**
* {@inheritDoc}
*/
public int getWidth(int i, int size) {
return metric.width(i, family, style, size);
}


/**
* {@inheritDoc}
*/
public int[] getWidths() {
return metric.getWidths(family, style, Java2DFontMetrics.FONT_SIZE);
}

/**
* {@inheritDoc}
*/
public java.awt.Font getFont(int size) {
return metric.getFont(family, style, size);
}

/**
* {@inheritDoc}
*/
public Map getKerningInfo() {
return java.util.Collections.EMPTY_MAP;
}

/**
* {@inheritDoc}
*/
public boolean hasKerningInfo() {
return false;
}

/** {@inheritDoc} */
public String getEncoding() {
return null; //Not applicable to Java2D rendering
}

/** {@inheritDoc} */
public char mapChar(char c) {
return c;
}

/** {@inheritDoc} */
public boolean hasChar(char c) {
return metric.hasChar(family, style, Java2DFontMetrics.FONT_SIZE, c);
}

}






+ 1
- 1
src/java/org/apache/fop/render/pcl/PCLRenderer.java View File

@@ -192,7 +192,7 @@ public class PCLRenderer extends PrintRenderer {
//The next line is important to get accurate font metrics!
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
FontSetup.setup(fontInfo, g);
FontSetup.setup(fontInfo, fontList, fontResolver, g);
}

/**

+ 2
- 0
src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java View File

@@ -20,6 +20,7 @@
package org.apache.fop.render.pcl;

import org.apache.avalon.framework.configuration.Configuration;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.render.PrintRendererConfigurator;
@@ -73,5 +74,6 @@ public class PCLRendererConfigurator extends PrintRendererConfigurator {
pclRenderer.setPJLDisabled(cfg.getChild("disable-pjl").getValueAsBoolean(false));
}
super.configure(renderer);
}
}

+ 21
- 2
src/java/org/apache/fop/render/pdf/PDFRenderer.java View File

@@ -39,9 +39,11 @@ import java.util.Map;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.CountingOutputStream;

import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
@@ -83,6 +85,7 @@ import org.apache.fop.pdf.PDFAction;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
@@ -95,9 +98,11 @@ import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutline;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFState;
@@ -361,7 +366,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
this.pdfDoc.getInfo().setTitle(userAgent.getTitle());
this.pdfDoc.getInfo().setKeywords(userAgent.getKeywords());
this.pdfDoc.setFilterMap(filterMap);
this.pdfDoc.outputHeader(stream);
this.pdfDoc.outputHeader(ostream);

//Setup encryption if necessary
PDFEncryptionManager.setupPDFEncryption(encryptionParams, this.pdfDoc);
@@ -721,6 +726,20 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
page.getPageIndex());
pageReferences.put(page.getKey(), currentPage.referencePDF());
pvReferences.put(page.getKey(), page);
//Produce page labels
PDFPageLabels pageLabels = this.pdfDoc.getRoot().getPageLabels();
if (pageLabels == null) {
//Set up PageLabels
pageLabels = this.pdfDoc.getFactory().makePageLabels();
this.pdfDoc.getRoot().setPageLabels(pageLabels);
}
PDFNumsArray nums = pageLabels.getNums();
PDFDictionary dict = new PDFDictionary(nums);
dict.put("P", page.getPageNumberString());
//TODO If the sequence of generated page numbers were inspected, this could be
//expressed in a more space-efficient way
nums.put(page.getPageIndex(), dict);
}
/**

+ 16
- 1
src/java/org/apache/fop/render/ps/PSRenderer.java View File

@@ -36,6 +36,8 @@ import java.util.Map;

import javax.xml.transform.Source;

import org.w3c.dom.Document;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -168,6 +170,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer
/** Whether or not Dublin Core Standard (dsc) compliant output is enforced */
private boolean dscCompliant = true;

/** Is used to determine the document's bounding box */
private Rectangle2D documentBoundingBox;
/** This is a collection holding all document header comments */
private Collection headerComments;

@@ -913,6 +918,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer
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);
this.documentBoundingBox = new Rectangle2D.Double();
gen.writeDSCComment(DSCConstants.DOCUMENT_SUPPLIED_RESOURCES,
new Object[] {DSCConstants.ATEND});
if (headerComments != null) {
@@ -970,6 +978,8 @@ public class PSRenderer extends AbstractPathOrientedRenderer
footerComments.clear();
}
gen.writeDSCComment(DSCConstants.PAGES, new Integer(this.currentPageNumber));
new DSCCommentBoundingBox(this.documentBoundingBox).generate(gen);
new DSCCommentHiResBoundingBox(this.documentBoundingBox).generate(gen);
gen.getResourceTracker().writeResources(false, gen);
gen.writeDSCComment(DSCConstants.EOF);
gen.flush();
@@ -1000,7 +1010,8 @@ public class PSRenderer extends AbstractPathOrientedRenderer
try {
try {
ResourceHandler.process(this.userAgent, in, this.outputStream,
this.fontInfo, resTracker, this.formResources, this.currentPageNumber);
this.fontInfo, resTracker, this.formResources,
this.currentPageNumber, this.documentBoundingBox);
this.outputStream.flush();
} catch (DSCException e) {
throw new RuntimeException(e.getMessage());
@@ -1168,7 +1179,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer
log.error(e.getMessage());
}
final Integer zero = new Integer(0);
Rectangle2D pageBoundingBox = new Rectangle2D.Double();
if (rotate) {
pageBoundingBox.setRect(0, 0, pageHeight, pageWidth);
gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] {
zero, zero, new Long(Math.round(pageHeight)),
new Long(Math.round(pageWidth)) });
@@ -1177,6 +1190,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer
new Double(pageWidth) });
gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Landscape");
} else {
pageBoundingBox.setRect(0, 0, pageWidth, pageHeight);
gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] {
zero, zero, new Long(Math.round(pageWidth)),
new Long(Math.round(pageHeight)) });
@@ -1188,6 +1202,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer
"Portrait");
}
}
this.documentBoundingBox.add(pageBoundingBox);
gen.writeDSCComment(DSCConstants.PAGE_RESOURCES,
new Object[] {DSCConstants.ATEND});


+ 11
- 1
src/java/org/apache/fop/render/ps/ResourceHandler.java View File

@@ -21,6 +21,7 @@ package org.apache.fop.render.ps;

import java.awt.geom.Dimension2D;
import java.awt.image.RenderedImage;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -54,8 +55,10 @@ import org.apache.xmlgraphics.ps.dsc.DSCParserConstants;
import org.apache.xmlgraphics.ps.dsc.DefaultNestedDocumentHandler;
import org.apache.xmlgraphics.ps.dsc.ResourceTracker;
import org.apache.xmlgraphics.ps.dsc.events.DSCComment;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentNeededResources;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentSuppliedResources;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentLanguageLevel;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPage;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPages;
@@ -85,11 +88,14 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
* @param resTracker the resource tracker to use
* @param formResources Contains all forms used by this document (maintained by PSRenderer)
* @param pageCount the number of pages (given here because PSRenderer writes an "(atend)")
* @param documentBoundingBox the document's bounding box
* (given here because PSRenderer writes an "(atend)")
* @throws DSCException If there's an error in the DSC structure of the PS file
* @throws IOException In case of an I/O error
*/
public static void process(FOUserAgent userAgent, InputStream in, OutputStream out,
FontInfo fontInfo, ResourceTracker resTracker, Map formResources, int pageCount)
FontInfo fontInfo, ResourceTracker resTracker, Map formResources,
int pageCount, Rectangle2D documentBoundingBox)
throws DSCException, IOException {
DSCParser parser = new DSCParser(in);
PSGenerator gen = new PSGenerator(out);
@@ -104,6 +110,8 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
{
//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);
}
@@ -127,6 +135,8 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
//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, formResources);

+ 4
- 2
src/java/org/apache/fop/render/ps/extensions/PSExtensionAttachment.java View File

@@ -19,12 +19,14 @@
package org.apache.fop.render.ps.extensions;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.util.XMLizable;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.apache.xmlgraphics.util.XMLizable;
import org.apache.fop.fo.extensions.ExtensionAttachment;
/**
* This is the pass-through value object for the PostScript extension.
*/

+ 1
- 1
src/java/org/apache/fop/render/ps/extensions/PSSetPageDevice.java View File

@@ -96,7 +96,7 @@ public class PSSetPageDevice extends PSExtensionAttachment {
* Generates SAX events representing the object's state.
* @param handler ContentHandler instance to send the SAX events to
* @throws SAXException if there's a problem generating the SAX events
* @see org.apache.fop.util.XMLizable#toSAX(org.xml.sax.ContentHandler)
* @see org.apache.xmlgraphics.util.XMLizable#toSAX(org.xml.sax.ContentHandler)
*/
public void toSAX(ContentHandler handler) throws SAXException {
AttributesImpl atts = new AttributesImpl();

+ 24
- 5
src/java/org/apache/fop/render/xml/XMLRenderer.java View File

@@ -41,7 +41,8 @@ import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.fop.util.QName;
import org.apache.xmlgraphics.util.XMLizable;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
@@ -51,21 +52,22 @@ import org.apache.fop.area.BeforeFloat;
import org.apache.fop.area.Block;
import org.apache.fop.area.BlockViewport;
import org.apache.fop.area.BodyRegion;
import org.apache.fop.area.BookmarkData;
import org.apache.fop.area.CTM;
import org.apache.fop.area.DestinationData;
import org.apache.fop.area.Footnote;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.MainReference;
import org.apache.fop.area.NormalFlow;
import org.apache.fop.area.OffDocumentExtensionAttachment;
import org.apache.fop.area.OffDocumentItem;
import org.apache.fop.area.BookmarkData;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.RegionReference;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Span;
import org.apache.fop.area.Trait;
import org.apache.fop.area.Trait.InternalLink;
import org.apache.fop.area.Trait.Background;
import org.apache.fop.area.Trait.InternalLink;
import org.apache.fop.area.inline.Container;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
@@ -87,7 +89,7 @@ import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.XMLHandler;
import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.XMLizable;
import org.apache.fop.util.QName;

/**
* Renderer that renders areas to XML for debugging purposes.
@@ -419,6 +421,8 @@ public class XMLRenderer extends PrintRenderer {
public void processOffDocumentItem(OffDocumentItem oDI) {
if (oDI instanceof BookmarkData) {
renderBookmarkTree((BookmarkData) oDI);
} else if (oDI instanceof DestinationData) {
renderDestination((DestinationData) oDI);
} else if (oDI instanceof OffDocumentExtensionAttachment) {
ExtensionAttachment attachment = ((OffDocumentExtensionAttachment)oDI).getAttachment();
if (extensionAttachments == null) {
@@ -466,8 +470,23 @@ public class XMLRenderer extends PrintRenderer {
}

/**
* {@inheritDoc}
* Renders a DestinationData object (named destination)
* @param destination the destination object
*/
protected void renderDestination(DestinationData destination) {
if (destination.getWhenToProcess() == OffDocumentItem.END_OF_DOC) {
endPageSequence();
}
atts.clear();
PageViewport pv = destination.getPageViewport();
String pvKey = pv == null ? null : pv.getKey();
addAttribute("internal-link",
InternalLink.makeXMLAttribute(pvKey, destination.getIDRef()));
startElement("destination", atts);
endElement("destination");
}

/** {@inheritDoc} */
public void startRenderer(OutputStream outputStream)
throws IOException {
log.debug("Rendering areas to Area Tree XML");

+ 2
- 11
src/java/org/apache/fop/util/XMLizable.java View File

@@ -25,20 +25,11 @@ package org.apache.fop.util;
* src/java/org/apache/excalibur/xml/sax/XMLizable.java
*/

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/**
* This interface can be implemented by classes willing to provide an XML representation
* of their current state as SAX events.
* @deprecated Use the interface in Apache XML Graphics Commons instead.
*/
public interface XMLizable {
/**
* Generates SAX events representing the object's state.
* @param handler ContentHandler instance to send the SAX events to
* @throws SAXException if there's a problem generating the SAX events
*/
void toSAX(ContentHandler handler) throws SAXException;
public interface XMLizable extends org.apache.xmlgraphics.util.XMLizable {
}

+ 12
- 0
status.xml View File

@@ -28,6 +28,18 @@

<changes>
<release version="FOP Trunk">
<action context="Code" dev="JM" type="fix">
Fixed generation of named destinations so it works when the PDF document is encrypted.
</action>
<action context="Code" dev="JM" type="add">
PostScript output now generates the bounding box DSC comments for the whole document.
</action>
<action context="Code" dev="JM" type="add">
Added support for PDF page labels.
</action>
<action context="Code" dev="JM" type="add" fixes-bug="44176" due-to="Patrick Jaromin">
Added support for custom fonts in Java2DRenderer and derived renderers.
</action>
<action context="Code" dev="JM" type="add">
Added new extension element: fox:external-document. It allows to add whole documents
such as multi-page TIFF images to be inserted as peers to a page-sequence. Each image

+ 61
- 0
test/layoutengine/standard-testcases/fox_destination_1.xml View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks the basics of fox:destination.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fox:destination internal-destination="chapter1"/>
<fox:destination internal-destination="chapter2"/>
<fox:destination internal-destination="chapter2-sec1"/>
<fo:page-sequence id="page-sequence" master-reference="normal">
<fo:flow flow-name="xsl-region-body">
<fo:block id="chapter1" font-weight="bold" font-size="larger">Chapter 1</fo:block>
<fo:block>Blah blah bla.</fo:block>
<fo:block id="chapter2" font-weight="bold" font-size="larger" break-before="page">Chapter 2</fo:block>
<fo:block>Blah blah bla.</fo:block>
<fo:block id="chapter2-sec1" font-weight="bold">Section 1</fo:block>
<fo:block>Blah blah bla.</fo:block>
<fo:block id="chapter2-sec2" font-weight="bold"><fox:destination internal-destination="chapter2-sec2"/>Section 2</fo:block>
<fo:block>Blah blah bla.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="1" xpath="count(/areaTree/pageSequence)"/>
<eval expected="2" xpath="count(//pageViewport)"/>

<eval expected="4" xpath="count(//destination)"/>
<eval expected="(P1,chapter1)" xpath="//destination[1]/@internal-link"/>
<eval expected="(P2,chapter2)" xpath="//destination[2]/@internal-link"/>
<eval expected="(P2,chapter2-sec1)" xpath="//destination[3]/@internal-link"/>
<eval expected="(P2,chapter2-sec2)" xpath="//destination[4]/@internal-link"/>
</checks>
</testcase>

Loading…
Cancel
Save