Browse Source

Merged changes from Trunk


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ChangingIPDHack@808127 13f79535-47bb-0310-9956-ffa450edef68
Temp_ChangingIPDHack
Vincent Hennebert 14 years ago
parent
commit
45055a8f6f
68 changed files with 10207 additions and 1222 deletions
  1. 2
    1
      build.properties
  2. 42
    10
      build.xml
  3. 12
    12
      src/documentation/content/xdocs/compliance.ihtml
  4. 21
    15
      src/documentation/content/xdocs/trunk/extensions.xml
  5. 4
    4
      src/documentation/content/xdocs/trunk/output.xml
  6. 3
    0
      src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java
  7. 24
    8
      src/java/org/apache/fop/afp/AFPGraphics2D.java
  8. 10
    9
      src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrderContainer.java
  9. 126
    0
      src/java/org/apache/fop/afp/util/CubicBezierApproximator.java
  10. 3
    0
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  11. 12
    0
      src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
  12. 15
    21
      src/java/org/apache/fop/fo/flow/table/EffRow.java
  13. 11
    12
      src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java
  14. 60
    12
      src/java/org/apache/fop/hyphenation/PatternParser.java
  15. 132
    0
      src/java/org/apache/fop/hyphenation/SerializeHyphPattern.java
  16. 354
    0
      src/java/org/apache/fop/hyphenation/UnicodeClasses.java
  17. 7628
    0
      src/java/org/apache/fop/hyphenation/classes.xml
  18. 15
    20
      src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
  19. 6
    9
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  20. 22
    8
      src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java
  21. 71
    25
      src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
  22. 29
    20
      src/java/org/apache/fop/layoutmgr/BreakElement.java
  23. 16
    5
      src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
  24. 6
    6
      src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
  25. 6
    6
      src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java
  26. 152
    0
      src/java/org/apache/fop/layoutmgr/Keep.java
  27. 0
    109
      src/java/org/apache/fop/layoutmgr/KeepUtil.java
  28. 42
    48
      src/java/org/apache/fop/layoutmgr/KnuthPenalty.java
  29. 16
    17
      src/java/org/apache/fop/layoutmgr/LayoutContext.java
  30. 26
    21
      src/java/org/apache/fop/layoutmgr/PageBreaker.java
  31. 148
    0
      src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
  32. 43
    0
      src/java/org/apache/fop/layoutmgr/PageProvider.java
  33. 6
    6
      src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
  34. 38
    22
      src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
  35. 7
    10
      src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
  36. 8
    9
      src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
  37. 19
    23
      src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
  38. 11
    7
      src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
  39. 2
    2
      src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java
  40. 6
    16
      src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java
  41. 5
    17
      src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java
  42. 22
    21
      src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
  43. 10
    11
      src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
  44. 9
    11
      src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
  45. 12
    16
      src/java/org/apache/fop/layoutmgr/table/TableStepper.java
  46. 11
    4
      src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
  47. 58
    21
      src/java/org/apache/fop/render/afp/AFPRenderer.java
  48. 5
    3
      src/java/org/apache/fop/render/afp/extensions/AFPInvokeMediumMapElement.java
  49. 3
    3
      src/java/org/apache/fop/render/awt/AWTRenderer.java
  50. 235
    0
      src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java
  51. 0
    186
      src/java/org/apache/fop/render/extensions/prepress/PageBoundariesAttributes.java
  52. 33
    23
      src/java/org/apache/fop/render/extensions/prepress/PageScale.java
  53. 9
    19
      src/java/org/apache/fop/render/java2d/Java2DRenderer.java
  54. 21
    35
      src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
  55. 0
    178
      src/java/org/apache/fop/tools/anttasks/SerializeHyphPattern.java
  56. 39
    42
      src/sandbox/org/apache/fop/render/svg/SVGDocumentHandler.java
  57. 17
    0
      status.xml
  58. 4
    2
      test/java/org/apache/fop/StandardTestSuite.java
  59. 0
    129
      test/java/org/apache/fop/render/extensions/PrepressTest.java
  60. 176
    0
      test/java/org/apache/fop/render/extensions/prepress/PageBoundariesTest.java
  61. 79
    0
      test/java/org/apache/fop/render/extensions/prepress/PageScaleTest.java
  62. 6
    0
      test/layoutengine/disabled-testcases.xml
  63. 3
    4
      test/layoutengine/standard-testcases/inline_block_nested_6.xml
  64. 155
    0
      test/layoutengine/standard-testcases/keep_within-column_basic.xml
  65. 58
    0
      test/layoutengine/standard-testcases/keep_within-page_multi-column_overflow.xml
  66. 77
    0
      test/layoutengine/standard-testcases/marker_white-space_npe.xml
  67. 3
    3
      test/layoutengine/standard-testcases/table-row_keep-together.xml
  68. 3
    1
      test/layoutengine/standard-testcases/table_keep-together.xml

+ 2
- 1
build.properties View File

@@ -50,5 +50,6 @@
# layoutengine.disabled = test/layoutengine/disabled-testcases.txt

## Specify an alternate directory to scan for user supplied
## hyphenation pattern files.
## hyphenation pattern files and Unicode data files.
# user.hyph.dir = /home/bart/offo
# unidata.dir = /usr/share/doc/Unicode/UNIDATA

+ 42
- 10
build.xml View File

@@ -157,6 +157,8 @@ list of possible build targets.
<property name="fo.examples.force" value="false"/>
<property name="lib.dir" value="${basedir}/lib"/>
<property name="user.hyph.dir" value="${basedir}/hyph"/>
<property name="unidata.dir" value="${basedir}/UNIDATA"/>
<property name="hyph.stacksize" value="512k"/>
<property name="build.dir" value="${basedir}/build"/>
<property name="build.gensrc.dir" value="${build.dir}/gensrc"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
@@ -425,21 +427,51 @@ list of possible build targets.
</copy>
</target>
<target name="compile" depends="compile-java, compile-copy-resources" description="Compiles the source code"/>
<!-- =================================================================== -->
<!-- compiles hyphenation patterns -->
<!-- =================================================================== -->
<target name="compile-hyphenation" depends="compile">
<!-- =================================================================== -->
<!-- Helper task to generate source files that have already been checked -->
<!-- into the repository. This task uses Unicode Character Database -->
<!-- files. This task need only be run when the latter files have been -->
<!-- updated. This target should never be part of the normal build -->
<!-- process. Output is UnicodeClasses.CLASSES_XML -->
<!-- (src/java/org/apache/fop/hyphenation/classes.xml). -->
<!-- =================================================================== -->
<target name="codegen-hyphenation-classes">
<java classname="org.apache.fop.hyphenation.UnicodeClasses" resultproperty="classes.result" classpath="${build.classes.dir}">
<arg value="${unidata.dir}"/>
</java>
<condition property="classes.result.message" value="Generation of classes successful">
<not>
<isfailure code="${classes.result}"/>
</not>
</condition>
<condition property="classes.result.message" value="Generation of classes failed">
<isfailure code="${classes.result}"/>
</condition>
<echo message="${classes.result.message}"/>
</target>
<!-- =================================================================== -->
<!-- compiles hyphenation patterns -->
<!-- =================================================================== -->
<target name="compile-hyphenation" depends="compile" description="Compiles the hyphenation pattern files">
<path id="hyph-classpath">
<path refid="libs-build-classpath"/>
<pathelement location="${build.classes.dir}"/>
</path>
<taskdef name="serHyph" classname="org.apache.fop.tools.anttasks.SerializeHyphPattern" classpathref="hyph-classpath"/>
<mkdir dir="${build.classes.dir}/hyph"/>
<serHyph targetDir="${build.classes.dir}/hyph">
<fileset dir="${user.hyph.dir}">
<include name="*.xml"/>
</fileset>
</serHyph>
<java classname="org.apache.fop.hyphenation.SerializeHyphPattern" fork="true" resultproperty="hyph.result" classpathref="hyph-classpath">
<arg value="${user.hyph.dir}"/>
<arg value="${build.classes.dir}/hyph"/>
<jvmarg value="-Xss${hyph.stacksize}"/>
</java>
<condition property="hyph.result.message" value="Hyphenation successful">
<not>
<isfailure code="${hyph.result}"/>
</not>
</condition>
<condition property="hyph.result.message" value="Hyphenation failed">
<isfailure code="${hyph.result}"/>
</condition>
<echo message="${hyph.result.message}"/>
</target>
<target name="uptodate-jar-hyphenation" depends="compile-hyphenation">
<uptodate property="jar.hyphenation.uptodate" targetfile="${build.dir}/fop-hyph.jar">

+ 12
- 12
src/documentation/content/xdocs/compliance.ihtml View File

@@ -533,11 +533,11 @@

<td class="no">no</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td align="center">&nbsp;</td>
</tr>
@@ -552,11 +552,11 @@

<td class="no">no</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td align="center">&nbsp;</td>
</tr>
@@ -870,11 +870,11 @@

<td class="no">no</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td class="no">no</td>
<td class="yes">yes</td>

<td align="center">&nbsp;</td>
</tr>
@@ -1714,11 +1714,11 @@

<td class="partial">partial</td>

<td class="partial">partial</td>
<td class="yes">yes</td>

<td align="left">
<ul>
<li>[0.94 and later] Only works as expected with inline-level content.</li>
<li>[0.95] Only works as expected with inline-level content.</li>
</ul>
</td>
</tr>
@@ -4827,7 +4827,7 @@
<li>[0.95] works on all implemented FOs, except list- and inline-level
FOs.</li>
<li>[Trunk] does not work on inline-level FOs.</li>
<li>[0.95 and earlier] &lt;integer&gt; values are not supported.</li>
<li>[Trunk] minimal support for &lt;integer&gt; value.</li>
</ul>

+ 21
- 15
src/documentation/content/xdocs/trunk/extensions.xml View File

@@ -240,19 +240,20 @@ to following pages. Here is an example of FO code creating such a table-header:<
registration marks, color bars and page information are placed.
For details, please read on below.
</p>
<note>
Those extensions have been implemented in the PDF and Java2D renderers only.
</note>
<section id="scale">
<title>fox:scale</title>
<p>Default: 1</p>
<p>Value: &lt;number&gt;{1,2}</p>
<p>Initial: 1</p>
<p>Applies to: fo:simple-page-master</p>
<p>
<code>fox:scale="sx [sy]"</code> attribute is used in <code>fo:simple-page-master</code> element and specifies
the a scale operation by sx and sy. If sy is not provided, it is assumed to be equal to sx.
sx and sy should be a positive number. A scale factor smaller than 1 shrinks the page.
A scale factor greater than 1 enlarges the page.
This property specifies a scale factor along resp. the x and y axes. If only one number
is provided it is used for both the x and y scales. A scale factor smaller than 1
shrinks the page. A scale factor greater than 1 enlarges the page.
</p>
<note>
It is implemented for PDF and Java2D renderers.
</note>
</section>
<section id="bleed">
<title>fox:bleed</title>
@@ -260,15 +261,17 @@ to following pages. Here is an example of FO code creating such a table-header:<
Value: &lt;length&gt;{1,4}
</p>
<p>
Default: 0pt
Initial: 0pt
</p>
<p>Applies to: fo:simple-page-master</p>
<p>
If there is only one value, it applies to all sides. If there are two values, the top and bottom
bleed widths are set to the first value and the right and left bleed widths are set to the second.
If there are three values, the top is set to the first value, the left and right are set to the second,
and the bottom is set to the third. If there are four values, they apply to the top, right, bottom, and
left, respectively.
(Corresponds to <a href="http://www.w3.org/TR/xsl11/#padding">http://www.w3.org/TR/xsl11/#padding</a>).
(Corresponds to <a href="http://www.w3.org/TR/xsl11/#padding">the definition of
padding</a>).
</p>
<p>
This extension indirectly defines the BleedBox and is calculated by expanding the TrimBox by
@@ -281,10 +284,12 @@ to following pages. Here is an example of FO code creating such a table-header:<
Value: &lt;length&gt;{1,4}
</p>
<p>
Default: 0pt
Initial: bleed (see below)
</p>
<p>Applies to: fo:simple-page-master</p>
<p>
Same behaviour as with fox:bleed.
Same behaviour as with fox:bleed. The initial value is set to the same values as the
fox:bleed property.
</p>
<p>
This extension indirectly defines the MediaBox and is calculated by expanding
@@ -294,11 +299,12 @@ to following pages. Here is an example of FO code creating such a table-header:<
<section id="cropBox">
<title>fox:crop-box</title>
<p>
Value: (trim-box|bleed-box|media-box)
Value: [trim-box | bleed-box | media-box]
</p>
<p>
Default: media-box
Initial: media-box
</p>
<p>Applies to: fo:simple-page-master</p>
<p>
The crop box controls how Acrobat displays the page (CropBox in PDF) or how the Java2DRenderer sizes
the output media. The PDF specification defines that the CropBox defaults to the MediaBox. This extension
@@ -307,7 +313,7 @@ to following pages. Here is an example of FO code creating such a table-header:<
</p>
<p>
If requested in the future, we could offer to specify the CropBox in absolute coordinates rather
than just be referencing another box.
than just by referencing another box.
</p>
</section>
</section>

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

@@ -857,10 +857,10 @@ out = proc.getOutputStream();]]></source>
]]></source>
<p>
The invoke-medium-map element is allowed as child of fo:page-sequence (page group
level). It is NOT supported on document level (fo:root), yet. FOP also doesn't support
specifying medium maps inside XML (using BMM/EMM). It can only reference an existing
medium map by name. The medium map has to be constructed through different means and
available on the target platform.
level) or fo:simple-page-master. It is NOT supported on document level (fo:root), yet.
FOP also doesn't support specifying medium maps inside XML (using BMM/EMM). It can
only reference an existing medium map by name. The medium map has to be constructed
through different means and available on the target platform.
</p>
</section>
<section id="afp-form-maps">

+ 3
- 0
src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java View File

@@ -55,6 +55,9 @@ public class AFPDitheredRectanglePainter extends AbstractAFPPainter {
/** {@inheritDoc} */
public void paint(PaintingInfo paintInfo) throws IOException {
RectanglePaintingInfo rectanglePaintInfo = (RectanglePaintingInfo)paintInfo;
if (rectanglePaintInfo.getWidth() <= 0 || rectanglePaintInfo.getHeight() <= 0) {
return;
}

int ditherMatrix = DitherUtil.DITHER_MATRIX_8X8;
Dimension ditherSize = new Dimension(ditherMatrix, ditherMatrix);

+ 24
- 8
src/java/org/apache/fop/afp/AFPGraphics2D.java View File

@@ -62,6 +62,7 @@ import org.apache.xmlgraphics.util.UnitConv;
import org.apache.fop.afp.goca.GraphicsSetLineType;
import org.apache.fop.afp.modca.GraphicsObject;
import org.apache.fop.afp.svg.AFPGraphicsConfiguration;
import org.apache.fop.afp.util.CubicBezierApproximator;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.svg.NativeImageHandler;

@@ -437,6 +438,7 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand
*/
private void processPathIterator(PathIterator iter) {
double[] dstPts = new double[6];
double[] currentPosition = new double[2];
for (int[] openingCoords = new int[2]; !iter.isDone(); iter.next()) {
switch (iter.currentSegment(dstPts)) {
case PathIterator.SEG_LINETO:
@@ -444,6 +446,7 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand
(int)Math.round(dstPts[X]),
(int)Math.round(dstPts[Y])
}, true);
currentPosition = new double[]{dstPts[X], dstPts[Y]};
break;
case PathIterator.SEG_QUADTO:
graphicsObj.addFillet(new int[] {
@@ -452,26 +455,39 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand
(int)Math.round(dstPts[X2]),
(int)Math.round(dstPts[Y2])
}, true);
currentPosition = new double[]{dstPts[X2], dstPts[Y2]};
break;
case PathIterator.SEG_CUBICTO:
graphicsObj.addFillet(new int[] {
(int)Math.round(dstPts[X1]),
(int)Math.round(dstPts[Y1]),
(int)Math.round(dstPts[X2]),
(int)Math.round(dstPts[Y2]),
(int)Math.round(dstPts[X3]),
(int)Math.round(dstPts[Y3])
}, true);
double[] cubicCoords = new double[] {currentPosition[0], currentPosition[1],
dstPts[X1], dstPts[Y1], dstPts[X2], dstPts[Y2], dstPts[X3], dstPts[Y3]};
double[][] quadParts = CubicBezierApproximator.fixedMidPointApproximation(
cubicCoords);
if (quadParts.length >= 4) {
for (int segIndex = 0; segIndex < quadParts.length; segIndex++) {
double[] quadPts = quadParts[segIndex];
if (quadPts != null && quadPts.length == 4) {
graphicsObj.addFillet(new int[]{
(int) Math.round(quadPts[X1]),
(int) Math.round(quadPts[Y1]),
(int) Math.round(quadPts[X2]),
(int) Math.round(quadPts[Y2])
}, true);
currentPosition = new double[]{quadPts[X2], quadPts[Y2]};
}
}
}
break;
case PathIterator.SEG_MOVETO:
openingCoords = new int[] {
(int)Math.round(dstPts[X]),
(int)Math.round(dstPts[Y])
};
currentPosition = new double[]{dstPts[X], dstPts[Y]};
graphicsObj.setCurrentPosition(openingCoords);
break;
case PathIterator.SEG_CLOSE:
graphicsObj.addLine(openingCoords, true);
currentPosition = new double[]{openingCoords[0], openingCoords[1]};
break;
default:
log.debug("Unrecognised path iterator type");

+ 10
- 9
src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrderContainer.java View File

@@ -46,6 +46,8 @@ implements StructuredData, Completable, Startable {
/** object has started */
private boolean started = false;

private int dataLength = 0;

/**
* Default constructor
*/
@@ -78,6 +80,7 @@ implements StructuredData, Completable, Startable {
*/
public void addObject(StructuredData object) {
objects.add(object);
dataLength += object.getDataLength();
}

/**
@@ -88,6 +91,7 @@ implements StructuredData, Completable, Startable {
public void addAll(AbstractGraphicsDrawingOrderContainer graphicsContainer) {
Collection/*<StructuredDataObject>*/ objects = graphicsContainer.getObjects();
objects.addAll(objects);
dataLength += graphicsContainer.getDataLength();
}

/**
@@ -107,9 +111,11 @@ implements StructuredData, Completable, Startable {
public StructuredData removeLast() {
int lastIndex = objects.size() - 1;
StructuredData object = null;
if (lastIndex > -1) {
object = (StructuredData)objects.get(lastIndex);
objects.remove(lastIndex);
if (lastIndex >= 0) {
object = (StructuredData)objects.remove(lastIndex);
}
if (object != null) {
dataLength -= object.getDataLength();
}
return object;
}
@@ -121,12 +127,7 @@ implements StructuredData, Completable, Startable {
* all enclosed objects (and their containers)
*/
public int getDataLength() {
int dataLen = 0;
Iterator it = objects.iterator();
while (it.hasNext()) {
dataLen += ((StructuredData)it.next()).getDataLength();
}
return dataLen;
return this.dataLength;
}

/** {@inheritDoc} */

+ 126
- 0
src/java/org/apache/fop/afp/util/CubicBezierApproximator.java View File

@@ -0,0 +1,126 @@
/*
* 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.afp.util;

import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;

/**
* This class can be used to convert a cubic bezier curve within
* a path into multiple quadratic bezier curves which will approximate
* the original cubic curve.
* The various techniques are described here:
* http://www.timotheegroleau.com/Flash/articles/cubic_bezier_in_flash.htm
*/
public class CubicBezierApproximator {

/**
* This method will take in an array containing the x and y coordinates of the four control
* points that describe the cubic bezier curve to be approximated using the fixed mid point
* approximation. The curve will be approximated using four quadratic bezier curves the points
* for which will be returned in a two dimensional array, with each array within that containing
* the points for a single quadratic curve. The returned data will not include the start point
* for any of the curves; the first point passed in to this method should already have been
* set as the current position and will be the assumed start of the first curve.
*
* @param cubicControlPointCoords an array containing the x and y coordinates of the
* four control points.
* @return an array of arrays containing the x and y coordinates of the quadratic curves
* that approximate the original supplied cubic bezier curve.
*/
public static double[][] fixedMidPointApproximation(double[] cubicControlPointCoords) {
if (cubicControlPointCoords.length < 8) {
throw new IllegalArgumentException("Must have at least 8 coordinates");
}

//extract point objects from source array
Point2D p0 = new Point2D.Double(cubicControlPointCoords[0], cubicControlPointCoords[1]);
Point2D p1 = new Point2D.Double(cubicControlPointCoords[2], cubicControlPointCoords[3]);
Point2D p2 = new Point2D.Double(cubicControlPointCoords[4], cubicControlPointCoords[5]);
Point2D p3 = new Point2D.Double(cubicControlPointCoords[6], cubicControlPointCoords[7]);

//calculates the useful base points
Point2D pa = getPointOnSegment(p0, p1, 3.0 / 4.0);
Point2D pb = getPointOnSegment(p3, p2, 3.0 / 4.0);

//get 1/16 of the [P3, P0] segment
double dx = (p3.getX() - p0.getX()) / 16.0;
double dy = (p3.getY() - p0.getY()) / 16.0;

//calculates control point 1
Point2D pc1 = getPointOnSegment(p0, p1, 3.0 / 8.0);

//calculates control point 2
Point2D pc2 = getPointOnSegment(pa, pb, 3.0 / 8.0);
pc2 = movePoint(pc2, -dx, -dy);

//calculates control point 3
Point2D pc3 = getPointOnSegment(pb, pa, 3.0 / 8.0);
pc3 = movePoint(pc3, dx, dy);

//calculates control point 4
Point2D pc4 = getPointOnSegment(p3, p2, 3.0 / 8.0);

//calculates the 3 anchor points
Point2D pa1 = getMidPoint(pc1, pc2);
Point2D pa2 = getMidPoint(pa, pb);
Point2D pa3 = getMidPoint(pc3, pc4);

//return the points for the four quadratic curves
return new double[][] {
{pc1.getX(), pc1.getY(), pa1.getX(), pa1.getY()},
{pc2.getX(), pc2.getY(), pa2.getX(), pa2.getY()},
{pc3.getX(), pc3.getY(), pa3.getX(), pa3.getY()},
{pc4.getX(), pc4.getY(), p3.getX(), p3.getY()}};
}

private static Double movePoint(Point2D point, double dx, double dy) {
return new Point2D.Double(point.getX() + dx, point.getY() + dy);
}

/**
* This method will calculate the coordinates of a point half way along a segment [P0, P1]
*
* @param p0 - The point describing the start of the segment.
* @param p1 - The point describing the end of the segment.
* @return a Point object describing the coordinates of the calculated point on the segment.
*/
private static Point2D getMidPoint(Point2D p0, Point2D p1) {
return getPointOnSegment(p0, p1, 0.5);
}

/**
* This method will calculate the coordinates of a point on a segment [P0, P1]
* whose distance along the segment [P0, P1] from P0, is the given ratio
* of the length the [P0, P1] segment.
*
* @param p0 The point describing the start of the segment.
* @param p1 The point describing the end of the segment.
* @param ratio The distance of the point being calculated from P0 as a ratio of
* the segment length.
* @return a Point object describing the coordinates of the calculated point on the segment.
*/
private static Point2D getPointOnSegment(Point2D p0, Point2D p1, double ratio) {
double x = p0.getX() + ((p1.getX() - p0.getX()) * ratio);
double y = p0.getY() + ((p1.getY() - p0.getY()) * ratio);
return new Point2D.Double(x, y);
}

}

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

@@ -288,6 +288,9 @@ public class FOTreeBuilder extends DefaultHandler {
builderContext.switchMarkerContext(true);
}
}
if (foNode.getNameId() == Constants.FO_PAGE_SEQUENCE) {
builderContext.getXMLWhiteSpaceHandler().reset();
}
} catch (IllegalArgumentException e) {
throw new SAXException(e);
}

+ 12
- 0
src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java View File

@@ -233,6 +233,18 @@ public class XMLWhiteSpaceHandler {
}
}

/**
* Reset the handler, release all references
*/
protected final void reset() {
if (pendingInlines != null) {
pendingInlines.clear();
}
nestedBlockStack.clear();
charIter = null;
firstWhiteSpaceInSeq = null;
}

/**
* Handle white-space for the fo that is passed in, starting at
* firstTextNode (when a nested FO is encountered)

+ 15
- 21
src/java/org/apache/fop/fo/flow/table/EffRow.java View File

@@ -23,8 +23,7 @@ import java.util.Iterator;
import java.util.List;

import org.apache.fop.fo.Constants;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.table.TableRowIterator;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.util.BreakUtil;
@@ -170,20 +169,19 @@ public class EffRow {
*
* @return the strength of the keep-with-previous constraint
*/
public int getKeepWithPreviousStrength() {
int strength = BlockLevelLayoutManager.KEEP_AUTO;
public Keep getKeepWithPrevious() {
Keep keep = Keep.KEEP_AUTO;
TableRow row = getTableRow();
if (row != null) {
strength = Math.max(strength,
KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithPrevious()));
keep = Keep.getKeep(row.getKeepWithPrevious());
}
for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next();
if (gu.isPrimary()) {
strength = Math.max(strength, gu.getPrimary().getKeepWithPreviousStrength());
keep = keep.compare(gu.getPrimary().getKeepWithPrevious());
}
}
return strength;
return keep;
}

/**
@@ -192,20 +190,19 @@ public class EffRow {
*
* @return the strength of the keep-with-next constraint
*/
public int getKeepWithNextStrength() {
int strength = BlockLevelLayoutManager.KEEP_AUTO;
public Keep getKeepWithNext() {
Keep keep = Keep.KEEP_AUTO;
TableRow row = getTableRow();
if (row != null) {
strength = Math.max(strength,
KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithNext()));
keep = Keep.getKeep(row.getKeepWithNext());
}
for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next();
if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) {
strength = Math.max(strength, gu.getPrimary().getKeepWithNextStrength());
keep = keep.compare(gu.getPrimary().getKeepWithNext());
}
}
return strength;
return keep;
}

/**
@@ -213,16 +210,13 @@ public class EffRow {
* not take the parent table's keeps into account!
* @return the keep-together strength
*/
public int getKeepTogetherStrength() {
public Keep getKeepTogether() {
TableRow row = getTableRow();
int strength = BlockLevelLayoutManager.KEEP_AUTO;
Keep keep = Keep.KEEP_AUTO;
if (row != null) {
strength = Math.max(strength, KeepUtil.getKeepStrength(
row.getKeepTogether().getWithinPage()));
strength = Math.max(strength, KeepUtil.getKeepStrength(
row.getKeepTogether().getWithinColumn()));
keep = Keep.getKeep(row.getKeepTogether());
}
return strength;
return keep;
}

/**

+ 11
- 12
src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java View File

@@ -19,14 +19,13 @@

package org.apache.fop.fo.flow.table;

import java.util.LinkedList;
import java.util.List;

import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.table.TableCellLayoutManager;

/**
@@ -54,8 +53,8 @@ public class PrimaryGridUnit extends GridUnit {
private boolean isSeparateBorderModel;
private int halfBorderSeparationBPD;

private int keepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
private int keepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
private Keep keepWithPrevious = Keep.KEEP_AUTO;
private Keep keepWithNext = Keep.KEEP_AUTO;
private int breakBefore = Constants.EN_AUTO;
private int breakAfter = Constants.EN_AUTO;

@@ -334,16 +333,16 @@ public class PrimaryGridUnit extends GridUnit {
*
* @return the keep-with-previous strength
*/
public int getKeepWithPreviousStrength() {
public Keep getKeepWithPrevious() {
return keepWithPrevious;
}

/**
* Don't use, reserved for TableCellLM. TODO
* @param strength the keep strength
* @param keep the keep strength
*/
public void setKeepWithPreviousStrength(int strength) {
this.keepWithPrevious = strength;
public void setKeepWithPrevious(Keep keep) {
this.keepWithPrevious = keep;
}

/**
@@ -352,16 +351,16 @@ public class PrimaryGridUnit extends GridUnit {
*
* @return the keep-with-next strength
*/
public int getKeepWithNextStrength() {
public Keep getKeepWithNext() {
return keepWithNext;
}

/**
* Don't use, reserved for TableCellLM. TODO
* @param strength the keep strength
* @param keep the keep strength
*/
public void setKeepWithNextStrength(int strength) {
this.keepWithNext = strength;
public void setKeepWithNext(Keep keep) {
this.keepWithNext = keep;
}

/**

+ 60
- 12
src/java/org/apache/fop/hyphenation/PatternParser.java View File

@@ -30,7 +30,10 @@ import org.xml.sax.Attributes;
// Java
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.util.ArrayList;

@@ -51,6 +54,7 @@ public class PatternParser extends DefaultHandler implements PatternConsumer {
ArrayList exception;
char hyphenChar;
String errMsg;
boolean hasClasses = false;

static final int ELEM_CLASSES = 1;
static final int ELEM_EXCEPTIONS = 2;
@@ -58,24 +62,19 @@ public class PatternParser extends DefaultHandler implements PatternConsumer {
static final int ELEM_HYPHEN = 4;

public PatternParser() throws HyphenationException {
this.consumer = this;
token = new StringBuffer();
parser = createParser();
parser.setContentHandler(this);
parser.setErrorHandler(this);
hyphenChar = '-'; // default

}

public PatternParser(PatternConsumer consumer)
throws HyphenationException {
public PatternParser(PatternConsumer consumer) throws HyphenationException {
this();
this.consumer = consumer;
}

public void setConsumer(PatternConsumer consumer) {
this.consumer = consumer;
}

/**
* Parses a hyphenation pattern file.
* @param filename the filename
@@ -249,15 +248,32 @@ public class PatternParser extends DefaultHandler implements PatternConsumer {
return il.toString();
}

protected void getExternalClasses() throws SAXException {
XMLReader mainParser = parser;
parser = createParser();
parser.setContentHandler(this);
parser.setErrorHandler(this);
InputStream stream = this.getClass().getResourceAsStream("classes.xml");
InputSource source = new InputSource(stream);
try {
parser.parse(source);
} catch (IOException ioe) {
throw new SAXException(ioe.getMessage());
} finally {
parser = mainParser;
}
}
//
// ContentHandler methods
//

/**
* {@inheritDoc}
* @throws SAXException
*/
public void startElement(String uri, String local, String raw,
Attributes attrs) {
Attributes attrs) throws SAXException {
if (local.equals("hyphen-char")) {
String h = attrs.getValue("value");
if (h != null && h.length() == 1) {
@@ -266,8 +282,14 @@ public class PatternParser extends DefaultHandler implements PatternConsumer {
} else if (local.equals("classes")) {
currElement = ELEM_CLASSES;
} else if (local.equals("patterns")) {
if (!hasClasses) {
getExternalClasses();
}
currElement = ELEM_PATTERNS;
} else if (local.equals("exceptions")) {
if (!hasClasses) {
getExternalClasses();
}
currElement = ELEM_EXCEPTIONS;
exception = new ArrayList();
} else if (local.equals("hyphen")) {
@@ -311,6 +333,9 @@ public class PatternParser extends DefaultHandler implements PatternConsumer {
token.setLength(0);
}
}
if (currElement == ELEM_CLASSES) {
hasClasses = true;
}
if (currElement == ELEM_HYPHEN) {
currElement = ELEM_EXCEPTIONS;
} else {
@@ -403,23 +428,46 @@ public class PatternParser extends DefaultHandler implements PatternConsumer {

// PatternConsumer implementation for testing purposes
public void addClass(String c) {
System.out.println("class: " + c);
testOut.println("class: " + c);
}

public void addException(String w, ArrayList e) {
System.out.println("exception: " + w + " : " + e.toString());
testOut.println("exception: " + w + " : " + e.toString());
}

public void addPattern(String p, String v) {
System.out.println("pattern: " + p + " : " + v);
testOut.println("pattern: " + p + " : " + v);
}
private PrintStream testOut = System.out;
/**
* @param testOut the testOut to set
*/
public void setTestOut(PrintStream testOut) {
this.testOut = testOut;
}
public void closeTestOut() {
testOut.flush();
testOut.close();
}

public static void main(String[] args) throws Exception {
if (args.length > 0) {
PatternParser pp = new PatternParser();
pp.setConsumer(pp);
PrintStream p = null;
if (args.length > 1) {
FileOutputStream f = new FileOutputStream(args[1]);
p = new PrintStream(f, false, "utf-8");
pp.setTestOut(p);
}
pp.parse(args[0]);
if (pp != null) {
pp.closeTestOut();
}
}
}

}

+ 132
- 0
src/java/org/apache/fop/hyphenation/SerializeHyphPattern.java View File

@@ -0,0 +1,132 @@
/*
* 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.hyphenation;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
* Serialize hyphenation patterns
* For all xml files in the source directory a pattern file is built in the target directory
* This class may be called from the ant build file in a java task
*/
public class SerializeHyphPattern {
private boolean errorDump = false;

/**
* Controls the amount of error information dumped.
* @param errorDump True if more error info should be provided
*/
public void setErrorDump(boolean errorDump) {
this.errorDump = errorDump;
}

/**
* {@inheritDoc}
*/
public void serializeDir(File sourceDir, File targetDir) {
final String extension = ".xml";
String[] sourceFiles = sourceDir.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
return(name.endsWith(extension));
}
});
for (int j = 0; j < sourceFiles.length; j++) {
File infile = new File(sourceDir, sourceFiles[j]);
String outfilename =
sourceFiles[j].substring(0, sourceFiles[j].length() - extension.length()) + ".hyp";
File outfile = new File(targetDir, outfilename);
serializeFile(infile, outfile);
}
}

/*
* checks whether input or output files exists or the latter is older than input file
* and start build if necessary
*/
private void serializeFile(File infile, File outfile) {
boolean startProcess;
startProcess = rebuild(infile, outfile);
if (startProcess) {
HyphenationTree hTree = buildPatternFile(infile);
// serialize class
try {
ObjectOutputStream out = new ObjectOutputStream(
new java.io.BufferedOutputStream(
new java.io.FileOutputStream(outfile)));
out.writeObject(hTree);
out.close();
} catch (IOException ioe) {
System.err.println("Can't write compiled pattern file: "
+ outfile);
System.err.println(ioe);
}
}
}

/*
* serializes pattern files
*/
private HyphenationTree buildPatternFile(File infile) {
System.out.println("Processing " + infile);
HyphenationTree hTree = new HyphenationTree();
try {
hTree.loadPatterns(infile.toString());
if (errorDump) {
System.out.println("Stats: ");
hTree.printStats();
}
} catch (HyphenationException ex) {
System.err.println("Can't load patterns from xml file " + infile
+ " - Maybe hyphenation.dtd is missing?");
if (errorDump) {
System.err.println(ex.toString());
}
}
return hTree;
}

/**
* Checks for existence of output file and compares
* dates with input and stylesheet file
*/
private boolean rebuild(File infile, File outfile) {
if (outfile.exists()) {
// checks whether output file is older than input file
if (outfile.lastModified() < infile.lastModified()) {
return true;
}
} else {
// if output file does not exist, start process
return true;
}
return false;
} // end rebuild


public static void main (String args[]) {
SerializeHyphPattern ser = new SerializeHyphPattern();
ser.serializeDir(new File(args[0]), new File(args[1]));
}

}

+ 354
- 0
src/java/org/apache/fop/hyphenation/UnicodeClasses.java View File

@@ -0,0 +1,354 @@
/*
* 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.hyphenation;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;

/**
* Create the default classes file classes.xml,
* for use in building hyphenation patterns
* from pattern files which do not contain their own classes.
* The class contains three methods to do that.
* The method fromJava gets its infirmation from Java's compiled-in Unicode Character Database,
* the method fromUCD gets its information from the UCD files,
* the method fromTeX gets its information from the file unicode-letters-XeTeX.tex,
* which is the basis of XeTeX's unicode support.
* In the build file only the method from UCD is used;
* the other two methods are there for demonstration.
* The methods fromJava and fromTeX are commented out because they are not Java 1.4 compliant.
*/
public final class UnicodeClasses {
/**
* default path relative to the FOP base directory
*/
public static final String CLASSES_XML = "src/java/org/apache/fop/hyphenation/classes.xml";
/**
* Disallow constructor for this utility class
*/
private UnicodeClasses() { }

/**
* Generate classes.xml from Java's compiled-in Unicode Character Database
* @param hexcode whether to prefix each class with the hexcode (only for debugging purposes)
* @param outfilePath output file
* @throws IOException
*/
/* public static void fromJava(boolean hexcode, String outfilePath) throws IOException {
File f = new File(outfilePath);
if (f.exists()) {
f.delete();
}
f.createNewFile();
FileOutputStream fw = new FileOutputStream(f);
OutputStreamWriter ow = new OutputStreamWriter(fw, "utf-8");
int maxChar;
maxChar = Character.MAX_VALUE;

ow.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<classes>\n");
// loop over the first Unicode plane
for (int code = Character.MIN_VALUE; code <= maxChar; ++code) {
// skip surrogate area
if (code == Character.MIN_SURROGATE) {
code = Character.MAX_SURROGATE;
continue;
}

// we are only interested in LC, UC and TC letters which are their own LC,
// and in 'other letters'
if (!(((Character.isLowerCase(code) || Character.isUpperCase(code)
|| Character.isTitleCase(code))
&& code == Character.toLowerCase(code))
|| Character.getType(code) == Character.OTHER_LETTER)) {
continue;
}
// skip a number of blocks
Character.UnicodeBlock ubi = Character.UnicodeBlock.of(code);
if (ubi.equals(Character.UnicodeBlock.SUPERSCRIPTS_AND_SUBSCRIPTS)
|| ubi.equals(Character.UnicodeBlock.LETTERLIKE_SYMBOLS)
|| ubi.equals(Character.UnicodeBlock.ALPHABETIC_PRESENTATION_FORMS)
|| ubi.equals(Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS)
|| ubi.equals(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS)
|| ubi.equals(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A)
|| ubi.equals(Character.UnicodeBlock.HANGUL_SYLLABLES)) {
continue;
}

int uppercode = Character.toUpperCase(code);
int titlecode = Character.toTitleCase(code);
StringBuilder s = new StringBuilder();
if (hexcode) {
s.append("0x" + Integer.toHexString(code) + " ");
}
s.append(Character.toChars(code));
if (uppercode != code) {
s.append(Character.toChars(uppercode));
}
if (titlecode != code && titlecode != uppercode) {
s.append(Character.toChars(titlecode));
}
ow.write(s.toString() + "\n");
}
ow.write("</classes>\n");
ow.flush();
ow.close();
}
*/
/**
* The column numbers in the UCD file
*/
public static final int UNICODE = 0, GENERAL_CATEGORY = 2, SIMPLE_UPPERCASE_MAPPING = 12,
SIMPLE_LOWERCASE_MAPPING = 13, SIMPLE_TITLECASE_MAPPING = 14, NUM_FIELDS = 15;
/**
* Generate classes.xml from Unicode Character Database files
* @param hexcode whether to prefix each class with the hexcode (only for debugging purposes)
* @param unidataPath path to the directory with UCD files
* @param outfilePath output file
* @throws IOException if the input files are not found
*/
public static void fromUCD(boolean hexcode, String unidataPath, String outfilePath)
throws IOException {
File unidata = new File(unidataPath);
File f = new File(outfilePath);
if (f.exists()) {
f.delete();
}
f.createNewFile();
FileOutputStream fw = new FileOutputStream(f);
OutputStreamWriter ow = new OutputStreamWriter(fw, "utf-8");
File in = new File(unidata, "Blocks.txt");
FileInputStream inis = new FileInputStream(in);
InputStreamReader insr = new InputStreamReader(inis, "utf-8");
BufferedReader inbr = new BufferedReader(insr);
Map blocks = new HashMap();
for (String line = inbr.readLine(); line != null; line = inbr.readLine()) {
if (line.startsWith("#") || line.matches("^\\s*$")) {
continue;
}
String[] parts = line.split(";");
String block = parts[1].trim();
String[] indices = parts[0].split("\\.\\.");
int[] ind = {Integer.parseInt(indices[0], 16), Integer.parseInt(indices[1], 16)};
blocks.put(block, ind);
}
inbr.close();

in = new File(unidata, "UnicodeData.txt");
inis = new FileInputStream(in);
insr = new InputStreamReader(inis, "utf-8");
inbr = new BufferedReader(insr);
int maxChar;
maxChar = Character.MAX_VALUE;

ow.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<classes>\n");
for (String line = inbr.readLine(); line != null; line = inbr.readLine()) {
String[] fields = line.split(";", NUM_FIELDS);
int code = Integer.parseInt(fields[UNICODE], 16);
if (code > maxChar) {
break;
}
if (((fields[GENERAL_CATEGORY].equals("Ll") || fields[GENERAL_CATEGORY].equals("Lu")
|| fields[GENERAL_CATEGORY].equals("Lt"))
&& ("".equals(fields[SIMPLE_LOWERCASE_MAPPING])
|| fields[UNICODE].equals(fields[SIMPLE_LOWERCASE_MAPPING])))
|| fields[GENERAL_CATEGORY].equals("Lo")) {
String[] blockNames = {"Superscripts and Subscripts",
"Letterlike Symbols",
"Alphabetic Presentation Forms",
"Halfwidth and Fullwidth Forms",
"CJK Unified Ideographs",
"CJK Unified Ideographs Extension A",
"Hangul Syllables"};
int j;
for (j = 0; j < blockNames.length; ++j) {
int[] ind = (int[]) blocks.get(blockNames[j]);
if (code >= ind[0] && code <= ind[1]) {
break;
}
}
if (j < blockNames.length) {
continue;
}
int uppercode = -1, titlecode = -1;
if (!"".equals(fields[SIMPLE_UPPERCASE_MAPPING])) {
uppercode = Integer.parseInt(fields[SIMPLE_UPPERCASE_MAPPING], 16);
}
if (!"".equals(fields[SIMPLE_TITLECASE_MAPPING])) {
titlecode = Integer.parseInt(fields[SIMPLE_TITLECASE_MAPPING], 16);
}
StringBuilder s = new StringBuilder();
if (hexcode) {
s.append("0x" + fields[UNICODE].replaceFirst("^0+", "").toLowerCase() + " ");
}
// s.append(Character.toChars(code));
/* This cast only works correctly when we do not exceed Character.MAX_VALUE */
s.append((char) code);
if (uppercode != -1 && uppercode != code) {
// s.append(Character.toChars(uppercode));
s.append((char) uppercode);
}
if (titlecode != -1 && titlecode != code && titlecode != uppercode) {
// s.append(Character.toChars(titlecode));
s.append((char) titlecode);
}
ow.write(s.toString() + "\n");
}
}
ow.write("</classes>\n");
ow.flush();
ow.close();
inbr.close();
}

/**
* Generate classes.xml from XeTeX's Unicode letters file
* @param hexcode whether to prefix each class with the hexcode (only for debugging purposes)
* @param lettersPath path to XeTeX's Unicode letters file unicode-letters-XeTeX.tex
* @param outfilePath output file
* @throws IOException
*/
/* public static void fromTeX(boolean hexcode, String lettersPath, String outfilePath)
throws IOException {
File in = new File(lettersPath);

File f = new File(outfilePath);
if (f.exists()) {
f.delete();
}
f.createNewFile();
FileOutputStream fw = new FileOutputStream(f);
OutputStreamWriter ow = new OutputStreamWriter(fw, "utf-8");

FileInputStream inis = new FileInputStream(in);
InputStreamReader insr = new InputStreamReader(inis, "utf-8");
BufferedReader inbr = new BufferedReader(insr);

ow.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<classes>\n");
for (String line = inbr.readLine(); line != null; line = inbr.readLine()) {
String[] codes = line.split("\\s+");
if (!(codes[0].equals("\\L") || codes[0].equals("\\l"))) {
continue;
}
if (codes.length == 3) {
ow.write("\"" + line + "\" has two codes");
continue;
}
if (codes[0].equals("\\l") && codes.length != 2) {
ow.write("\"" + line + "\" should have one code");
continue;
}
else if (codes[0].equals("\\L") && codes.length != 4) {
ow.write("\"" + line + "\" should have three codes");
continue;
}
if (codes[0].equals("\\l") || (codes[0].equals("\\L") && codes[1].equals(codes[3]))) {
StringBuilder s = new StringBuilder();
if (hexcode) {
s.append("0x" + codes[1].replaceFirst("^0+", "").toLowerCase() + " ");
}
s.append((char) Integer.parseInt(codes[1], 16));
if (codes[0].equals("\\L")) {
s.append((char) Integer.parseInt(codes[2], 16));
}
ow.write(s.toString() + "\n");
}
}
ow.write("</classes>\n");
ow.flush();
ow.close();
inbr.close();
}
*/
/**
* @param args [--hexcode] [--java|--ucd|--tex] [--out outfile] infile
* @throws IOException if the input file cannot be found
*/
public static void main(String[] args) throws IOException {
String type = "ucd", prefix = "--", infile = null, outfile = CLASSES_XML;
boolean hexcode = false;
for (int i = 0; i < args.length; ++i) {
if (args[i].startsWith(prefix)) {
String option = args[i].substring(prefix.length());
if (option.equals("java") || option.equals("ucd") || option.equals("tex")) {
type = option;
} else if (option.equals("hexcode")) {
hexcode = true;
} else if (option.equals("out")) {
outfile = args[++i];
} else {
System.err.println("Unknown option: " + option);
System.exit(1);
}
} else {
if (infile != null) {
System.err.println("Only one non-option argument can be given, for infile");
System.exit(1);
}
infile = args[i];
}
}
if (type.equals("java")) {
if (infile != null) {
System.err.println("Type java does not allow an infile");
System.exit(1);
}
} else {
if (infile == null) {
System.err.println("Types ucd and tex require an infile");
System.exit(1);
}
}
/* if (type.equals("java")) {
fromJava(hexcode, outfile);
} else
*/
if (type.equals("ucd")) {
fromUCD(hexcode, infile, outfile);
/* } else if (type.equals("tex")) {
fromTeX(hexcode, infile, outfile);
*/
} else {
System.err.println("Unknown type: " + type + ", nothing done");
System.exit(1);
}
}

}

+ 7628
- 0
src/java/org/apache/fop/hyphenation/classes.xml
File diff suppressed because it is too large
View File


+ 15
- 20
src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java View File

@@ -38,6 +38,7 @@ import org.apache.fop.datatypes.FODimension;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.properties.CommonAbsolutePosition;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
import org.apache.fop.util.ListUtil;
@@ -262,7 +263,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager

if (!firstVisibleMarkServed) {
addKnuthElementsForSpaceBefore(returnList, alignment);
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
}

addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
@@ -272,9 +273,9 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
//Spaces, border and padding to be repeated at each break
addPendingMarks(context);

BlockLevelLayoutManager curLM; // currently active LM
BlockLevelLayoutManager prevLM = null; // previously active LM
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
LayoutManager curLM; // currently active LM
LayoutManager prevLM = null; // previously active LM
while ((curLM = getChildLM()) != null) {
LayoutContext childLC = new LayoutContext(0);
childLC.copyPendingMarksFrom(context);
// curLM is a ?
@@ -324,8 +325,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
//Avoid NoSuchElementException below (happens with empty blocks)
continue;
}
if (((ListElement) ListUtil.getLast(returnedList))
.isForcedBreak()) {
if (ElementListUtils.endsWithForcedBreak(returnedList)) {
// a descendant of this block has break-after
if (curLM.isFinished()) {
// there is no other content in this block;
@@ -392,7 +392,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
context.clearPendingMarks();
addKnuthElementsForBreakAfter(returnList, context);

context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithNextPending(getKeepWithNext());

setFinished(true);
return returnList;
@@ -471,7 +471,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager

if (!firstVisibleMarkServed) {
addKnuthElementsForSpaceBefore(returnList, alignment);
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
}

addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
@@ -692,7 +692,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
context.clearPendingMarks();
addKnuthElementsForBreakAfter(returnList, context);

context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithNextPending(getKeepWithNext());

setFinished(true);
return returnList;
@@ -1317,23 +1317,18 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
getBlockContainerFO().getKeepTogether());
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
public KeepProperty getKeepTogetherProperty() {
return getBlockContainerFO().getKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(
getBlockContainerFO().getKeepWithNext());
public KeepProperty getKeepWithPreviousProperty() {
return getBlockContainerFO().getKeepWithPrevious();
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(
getBlockContainerFO().getKeepWithPrevious());
public KeepProperty getKeepWithNextProperty() {
return getBlockContainerFO().getKeepWithNext();
}

/**

+ 6
- 9
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java View File

@@ -219,21 +219,18 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
KeepProperty keep = getBlockFO().getKeepTogether();
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(keep);
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
public KeepProperty getKeepTogetherProperty() {
return getBlockFO().getKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getBlockFO().getKeepWithNext());
public KeepProperty getKeepWithPreviousProperty() {
return getBlockFO().getKeepWithPrevious();
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getBlockFO().getKeepWithPrevious());
public KeepProperty getKeepWithNextProperty() {
return getBlockFO().getKeepWithNext();
}

/** {@inheritDoc} */

+ 22
- 8
src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java View File

@@ -19,6 +19,8 @@

package org.apache.fop.layoutmgr;

import org.apache.fop.fo.properties.KeepProperty;

/**
* The interface for LayoutManagers which generate block areas
*/
@@ -35,11 +37,6 @@ public interface BlockLevelLayoutManager extends LayoutManager {
/** Adjustment class: adjustment for line height */
int LINE_HEIGHT_ADJUSTMENT = 3;

/** The integer value for "auto" keep strength */
int KEEP_AUTO = Integer.MIN_VALUE;
/** The integer value for "always" keep strength */
int KEEP_ALWAYS = Integer.MAX_VALUE;

int negotiateBPDAdjustment(int adj, KnuthElement lastElement);

void discardSpace(KnuthGlue spaceGlue);
@@ -48,7 +45,7 @@ public interface BlockLevelLayoutManager extends LayoutManager {
* Returns the keep-together strength for this element.
* @return the keep-together strength
*/
int getKeepTogetherStrength();
Keep getKeepTogether();

/**
* @return true if this element must be kept together
@@ -59,7 +56,7 @@ public interface BlockLevelLayoutManager extends LayoutManager {
* Returns the keep-with-previous strength for this element.
* @return the keep-with-previous strength
*/
int getKeepWithPreviousStrength();
Keep getKeepWithPrevious();

/**
* @return true if this element must be kept with the previous element.
@@ -70,11 +67,28 @@ public interface BlockLevelLayoutManager extends LayoutManager {
* Returns the keep-with-next strength for this element.
* @return the keep-with-next strength
*/
int getKeepWithNextStrength();
Keep getKeepWithNext();

/**
* @return true if this element must be kept with the next element.
*/
boolean mustKeepWithNext();

/**
* Returns the keep-together property specified on the FObj.
* @return the keep-together property
*/
KeepProperty getKeepTogetherProperty();

/**
* Returns the keep-with-previous property specified on the FObj.
* @return the keep-together property
*/
KeepProperty getKeepWithPreviousProperty();

/**
* Returns the keep-with-next property specified on the FObj.
* @return the keep-together property
*/
KeepProperty getKeepWithNextProperty();
}

+ 71
- 25
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -31,9 +31,11 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.BlockParent;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.properties.BreakPropertySet;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
import org.apache.fop.layoutmgr.inline.LineLayoutManager;
@@ -259,7 +261,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

if (!firstVisibleMarkServed) {
addKnuthElementsForSpaceBefore(elements, alignment);
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
}

addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
@@ -350,7 +352,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
elements.add(forcedBreakAfterLast);
}

context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithNextPending(getKeepWithNext());

setFinished(true);

@@ -377,7 +379,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

if (!firstVisibleMarkServed) {
addKnuthElementsForSpaceBefore(elements, alignment);
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
}

addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
@@ -538,7 +540,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
elements.add(forcedBreakAfterLast);
}

context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithNextPending(getKeepWithNext());

setFinished(true);

@@ -580,31 +582,31 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

/**
* Adds a break element to the content list between individual child elements.
* @param contentList the content list to populate
* @param context the current layout context
* @param contentList
* @param parentLC
* @param childLC the currently active child layout context
*/
protected void addInBetweenBreak(List contentList, LayoutContext context,
LayoutContext childLC) {
protected void addInBetweenBreak(List contentList, LayoutContext parentLC,
LayoutContext childLC) {

if (mustKeepTogether()
|| context.isKeepWithNextPending()
|| parentLC.isKeepWithNextPending()
|| childLC.isKeepWithPreviousPending()) {

int strength = getKeepTogetherStrength();
Keep keep = getKeepTogether();

//Handle pending keep-with-next
strength = Math.max(strength, context.getKeepWithNextPending());
context.clearKeepWithNextPending();
keep = keep.compare(parentLC.getKeepWithNextPending());
parentLC.clearKeepWithNextPending();

//Handle pending keep-with-previous from child LM
strength = Math.max(strength, childLC.getKeepWithPreviousPending());
keep = keep.compare(childLC.getKeepWithPreviousPending());
childLC.clearKeepWithPreviousPending();

int penalty = KeepUtil.getPenaltyForKeep(strength);

// add a penalty to forbid or discourage a break between blocks
contentList.add(new BreakElement(
new Position(this), penalty, context));
new Position(this), keep.getPenalty(),
keep.getContext(), parentLC));
return;
}

@@ -635,7 +637,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

// add a null penalty to allow a break between blocks
contentList.add(new BreakElement(
new Position(this), 0, context));
new Position(this), 0, Constants.EN_AUTO, parentLC));
}
}

@@ -971,33 +973,77 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
* Retrieves and returns the keep-together strength from the parent element.
* @return the keep-together strength
*/
protected int getParentKeepTogetherStrength() {
int strength = KEEP_AUTO;
protected Keep getParentKeepTogether() {
Keep keep = Keep.KEEP_AUTO;
if (getParent() instanceof BlockLevelLayoutManager) {
strength = ((BlockLevelLayoutManager)getParent()).getKeepTogetherStrength();
keep = ((BlockLevelLayoutManager)getParent()).getKeepTogether();
} else if (getParent() instanceof InlineLayoutManager) {
if (((InlineLayoutManager) getParent()).mustKeepTogether()) {
strength = KEEP_ALWAYS;
keep = Keep.KEEP_ALWAYS;
}
//TODO Fix me
//strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength();
}
return strength;
return keep;
}

/** {@inheritDoc} */
public boolean mustKeepTogether() {
return getKeepTogetherStrength() > KEEP_AUTO;
return !getKeepTogether().isAuto();
}

/** {@inheritDoc} */
public boolean mustKeepWithPrevious() {
return getKeepWithPreviousStrength() > KEEP_AUTO;
return !getKeepWithPrevious().isAuto();
}

/** {@inheritDoc} */
public boolean mustKeepWithNext() {
return getKeepWithNextStrength() > KEEP_AUTO;
return !getKeepWithNext().isAuto();
}

/** {@inheritDoc} */
public Keep getKeepTogether() {
Keep keep = Keep.getKeep(getKeepTogetherProperty());
keep = keep.compare(getParentKeepTogether());
return keep;
}

/** {@inheritDoc} */
public Keep getKeepWithPrevious() {
return Keep.getKeep(getKeepWithPreviousProperty());
}

/** {@inheritDoc} */
public Keep getKeepWithNext() {
return Keep.getKeep(getKeepWithNextProperty());
}

/**
* {@inheritDoc}
* Default implementation throws {@code IllegalStateException}
* Must be implemented by the subclass, if applicable.
*/
public KeepProperty getKeepTogetherProperty() {
throw new IllegalStateException();
}

/**
* {@inheritDoc}
* Default implementation throws {@code IllegalStateException}
* Must be implemented by the subclass, if applicable.
*/
public KeepProperty getKeepWithPreviousProperty() {
throw new IllegalStateException();
}

/**
* {@inheritDoc}
* Default implementation throws {@code IllegalStateException}
* Must be implemented by the subclass, if applicable.
*/
public KeepProperty getKeepWithNextProperty() {
throw new IllegalStateException();
}

/**

+ 29
- 20
src/java/org/apache/fop/layoutmgr/BreakElement.java View File

@@ -41,7 +41,22 @@ public class BreakElement extends UnresolvedListElement {
* @param context the layout context which contains the pending conditional elements
*/
public BreakElement(Position position, int penaltyValue, LayoutContext context) {
this(position, 0, penaltyValue, -1, context);
this(position, penaltyValue, -1, context);
}

/**
* Create a new BreakElement for the given {@code position}, {@code penaltyValue}
* and {@code breakClass}. (Used principally to generate break-possibilities in
* ranges of content that must be kept together within the context corresponding
* to the {@code breakClass}; expected to be one of {@link Constants#EN_AUTO},
* {@link Constants#EN_LINE}, {@link Constants#EN_COLUMN} or {@link Constants#EN_PAGE})
* @param position the corresponding {@link Position}
* @param penaltyValue the penalty value
* @param breakClass the break class
* @param context the {@link LayoutContext}
*/
public BreakElement(Position position, int penaltyValue, int breakClass, LayoutContext context) {
this(position, 0, penaltyValue, breakClass, context);
}

/**
@@ -65,6 +80,10 @@ public class BreakElement extends UnresolvedListElement {
this.pendingAfterMarks = context.getPendingAfterMarks();
}

private static String getBreakClassName(int breakClass) {
return AbstractBreaker.getBreakClassName(breakClass);
}

/** {@inheritDoc} */
public boolean isConditional() {
return false; //Does not really apply here
@@ -143,27 +162,17 @@ public class BreakElement extends UnresolvedListElement {

/** {@inheritDoc} */
public String toString() {
StringBuffer sb = new StringBuffer();
StringBuffer sb = new StringBuffer(64);
sb.append("BreakPossibility[p:");
sb.append(this.penaltyValue);
sb.append(KnuthPenalty.valueOf(this.penaltyValue));
if (isForcedBreak()) {
sb.append(" (forced break");
switch (getBreakClass()) {
case Constants.EN_PAGE:
sb.append(", page");
break;
case Constants.EN_COLUMN:
sb.append(", column");
break;
case Constants.EN_EVEN_PAGE:
sb.append(", even page");
break;
case Constants.EN_ODD_PAGE:
sb.append(", odd page");
break;
default:
}
sb.append(")");
sb.append(" (forced break, ")
.append(getBreakClassName(this.breakClass))
.append(")");
} else if (this.penaltyValue >= 0 && this.breakClass != -1) {
sb.append(" (keep constraint, ")
.append(getBreakClassName(this.breakClass))
.append(")");
}
sb.append("; w:");
sb.append(penaltyWidth);

+ 16
- 5
src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java View File

@@ -621,6 +621,14 @@ public abstract class BreakingAlgorithm {
best.getNode(fitness));
}

/**
* Return the last node that yielded a too short line.
* @return the node corresponding to the last too short line
*/
protected final KnuthNode getLastTooShort() {
return this.lastTooShort;
}

/**
* Generic handler for a {@link KnuthElement} at the given {@code position},
* taking into account whether the preceding element was a box, and which
@@ -658,7 +666,7 @@ public abstract class BreakingAlgorithm {

/**
* Handle a {@link KnuthBox}.
* <em>Note: default implementation just adds the box's width
* <br/><em>Note: default implementation just adds the box's width
* to the total content width. Subclasses that do not keep track
* of this themselves, but override this method, should remember
* to call {@code super.handleBox(box)} to avoid unwanted side-effects.</em>
@@ -819,14 +827,16 @@ public abstract class BreakingAlgorithm {
lastDeactivated = null;
lastTooLong = null;
for (int line = startLine; line < endLine; line++) {
if (!elementCanEndLine(element, line)) {
continue;
}
for (KnuthNode node = getNode(line); node != null; node = node.next) {
if (node.position == elementIdx) {
continue;
}
int difference = computeDifference(node, element, elementIdx);
if (!elementCanEndLine(element, endLine, difference)) {
log.trace("Skipping legal break");
break;
}

double r = computeAdjustmentRatio(node, difference);
int availableShrink = totalShrink - node.totalShrink;
int availableStretch = totalStretch - node.totalStretch;
@@ -865,9 +875,10 @@ public abstract class BreakingAlgorithm {
* number.
* @param element the element
* @param line the line number
* @param difference
* @return {@code true} if the element can end the line
*/
protected boolean elementCanEndLine(KnuthElement element, int line) {
protected boolean elementCanEndLine(KnuthElement element, int line, int difference) {
return (!element.isPenalty()
|| element.getP() < KnuthElement.INFINITE);
}

+ 6
- 6
src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java View File

@@ -246,18 +246,18 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
return KEEP_AUTO;
public Keep getKeepTogether() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */

+ 6
- 6
src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java View File

@@ -92,18 +92,18 @@ public class FootnoteBodyLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
return getParentKeepTogetherStrength();
public Keep getKeepTogether() {
return getParentKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
}

}

+ 152
- 0
src/java/org/apache/fop/layoutmgr/Keep.java View File

@@ -0,0 +1,152 @@
/*
* 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.layoutmgr;

import org.apache.fop.fo.Constants;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.Property;

/**
* Object representing a keep constraint, corresponding
* to the XSL-FO <a href="http://www.w3.org/TR/xsl/#d0e26492">keep properties</a>.
*/
public class Keep {

/** The integer value for "auto" keep strength. */
private static final int STRENGTH_AUTO = Integer.MIN_VALUE;

/** The integer value for "always" keep strength. */
private static final int STRENGTH_ALWAYS = Integer.MAX_VALUE;

public static final Keep KEEP_AUTO = new Keep(STRENGTH_AUTO, Constants.EN_AUTO);

public static final Keep KEEP_ALWAYS = new Keep(STRENGTH_ALWAYS, Constants.EN_LINE);

private int strength;

private int context;

private Keep(int strength, int context) {
this.strength = strength;
this.context = context;
}

private static int getKeepStrength(Property keep) {
if (keep.isAuto()) {
return STRENGTH_AUTO;
} else if (keep.getEnum() == Constants.EN_ALWAYS) {
return STRENGTH_ALWAYS;
} else {
return keep.getNumber().intValue();
}
}

/**
* Obtain a Keep instance corresponding to the given {@link KeepProperty}
*
* @param keepProperty the {@link KeepProperty}
* @return a new instance corresponding to the given property
*/
public static Keep getKeep(KeepProperty keepProperty) {
Keep keep = new Keep(STRENGTH_AUTO, Constants.EN_AUTO);
keep.update(keepProperty.getWithinPage(), Constants.EN_PAGE);
keep.update(keepProperty.getWithinColumn(), Constants.EN_COLUMN);
keep.update(keepProperty.getWithinLine(), Constants.EN_LINE);
return keep;
}

private void update(Property keep, int context) {
if (!keep.isAuto()) {
this.strength = getKeepStrength(keep);
this.context = context;
}
}

/** @return {@code true} if the keep property was specified as "auto" */
public boolean isAuto() {
return strength == STRENGTH_AUTO;
}

/**
* Returns the context of this keep.
*
* @return one of {@link Constants#EN_LINE}, {@link Constants#EN_COLUMN} or
* {@link Constants#EN_PAGE}
*/
public int getContext() {
return context;
}

/** @return the penalty value corresponding to the strength of this Keep */
public int getPenalty() {
if (strength == STRENGTH_AUTO) {
return 0;
} else if (strength == STRENGTH_ALWAYS) {
return KnuthElement.INFINITE;
} else {
return KnuthElement.INFINITE - 1;
}
}

private static int getKeepContextPriority(int context) {
switch (context) {
case Constants.EN_LINE: return 0;
case Constants.EN_COLUMN: return 1;
case Constants.EN_PAGE: return 2;
case Constants.EN_AUTO: return 3;
default: throw new IllegalArgumentException();
}
}

/**
* Compare this Keep instance to another one, and return the
* stronger one if the context is the same
*
* @param other the instance to compare to
* @return the winning Keep instance
*/
public Keep compare(Keep other) {

/* check strength "always" first, regardless of priority */
if (this.strength == STRENGTH_ALWAYS
&& this.strength > other.strength) {
return this;
} else if (other.strength == STRENGTH_ALWAYS
&& other.strength > this.strength) {
return other;
}

int pThis = getKeepContextPriority(this.context);
int pOther = getKeepContextPriority(other.context);

/* equal priority: strongest wins */
if (pThis == pOther) {
return (strength >= other.strength) ? this : other;
}

/* different priority: lowest priority wins */
return (pThis < pOther) ? this : other;
}

/** {@inheritDoc} */
public String toString() {
return (strength == STRENGTH_AUTO) ? "auto"
: (strength == STRENGTH_ALWAYS) ? "always"
: Integer.toString(strength);
}
}

+ 0
- 109
src/java/org/apache/fop/layoutmgr/KeepUtil.java View File

@@ -1,109 +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.layoutmgr;

import org.apache.fop.fo.Constants;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.Property;

/**
* Utility class for working with keeps.
*/
public class KeepUtil {

/**
* Converts a keep property into an integer value.
* <p>
* Note: The conversion restricts the effectively available integer range by two values.
* Integer.MIN_VALUE is used to represent the value "auto" and
* Integer.MAX_VALUE is used to represebt the value "always".
* @param keep the keep property
* @return the keep value as an integer
*/
public static int getKeepStrength(Property keep) {
if (keep.isAuto()) {
return BlockLevelLayoutManager.KEEP_AUTO;
} else if (keep.getEnum() == Constants.EN_ALWAYS) {
return BlockLevelLayoutManager.KEEP_ALWAYS;
} else {
return keep.getNumber().intValue();
}
}

/**
* Returns the combined block-level keep strength from a keep property.
* <p>
* Note: This is a temporary method to be used until it is possible to differentiate between
* page and column keeps!
* @param keep the keep property
* @return the combined keep strength
*/
public static int getCombinedBlockLevelKeepStrength(KeepProperty keep) {
return Math.max(
getKeepStrength(keep.getWithinPage()),
getKeepStrength(keep.getWithinColumn()));
}

/**
* Indicates whether a keep strength indicates a keep constraint.
* @param strength the keep strength
* @return true if the keep is not "auto"
*/
public static boolean hasKeep(int strength) {
return strength > BlockLevelLayoutManager.KEEP_AUTO;
}

/**
* Returns the penalty value to be used for a certain keep strength.
* <ul>
* <li>"auto": returns 0</li>
* <li>"always": returns KnuthElement.INFINITE</li>
* <li>otherwise: returns KnuthElement.INFINITE - 1</li>
* </ul>
* @param keepStrength the keep strength
* @return the penalty value
*/
public static int getPenaltyForKeep(int keepStrength) {
if (keepStrength == BlockLevelLayoutManager.KEEP_AUTO) {
return 0;
}
int penalty = KnuthElement.INFINITE;
if (keepStrength < BlockLevelLayoutManager.KEEP_ALWAYS) {
penalty--;
}
return penalty;
}

/**
* Returns a string representation of a keep strength value.
* @param keepStrength the keep strength
* @return the string representation
*/
public static String keepStrengthToString(int keepStrength) {
if (keepStrength == BlockLevelLayoutManager.KEEP_AUTO) {
return "auto";
} else if (keepStrength == BlockLevelLayoutManager.KEEP_ALWAYS) {
return "always";
} else {
return Integer.toString(keepStrength);
}
}

}

+ 42
- 48
src/java/org/apache/fop/layoutmgr/KnuthPenalty.java View File

@@ -45,7 +45,7 @@ public class KnuthPenalty extends KnuthElement {
public static final int FLAGGED_PENALTY = 50;

private int penalty;
private boolean bFlagged;
private boolean isFlagged;
private int breakClass = -1;

/**
@@ -55,12 +55,12 @@ public class KnuthPenalty extends KnuthElement {
* @param p the penalty value of this penalty
* @param f is this penalty flagged?
* @param pos the Position stored in this penalty
* @param bAux is this penalty auxiliary?
* @param isAuxiliary is this penalty auxiliary?
*/
public KnuthPenalty(int w, int p, boolean f, Position pos, boolean bAux) {
super(w, pos, bAux);
public KnuthPenalty(int w, int p, boolean f, Position pos, boolean isAuxiliary) {
super(w, pos, isAuxiliary);
penalty = p;
bFlagged = f;
isFlagged = f;
}

/**
@@ -69,18 +69,37 @@ public class KnuthPenalty extends KnuthElement {
* @param w the width of this penalty
* @param p the penalty value of this penalty
* @param f is this penalty flagged?
* @param iBreakClass the break class of this penalty (one of
* @param breakClass the break class of this penalty (one of
* {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
* {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE})
* @param pos the Position stored in this penalty
* @param bAux is this penalty auxiliary?
* @param isAuxiliary is this penalty auxiliary?
*/
public KnuthPenalty(int w, int p, boolean f,
int iBreakClass, Position pos, boolean bAux) {
super(w, pos, bAux);
penalty = p;
bFlagged = f;
breakClass = iBreakClass;
int breakClass, Position pos, boolean isAuxiliary) {
this(w, p, f, pos, isAuxiliary);
this.breakClass = breakClass;
}

private static String getBreakClassName(int breakClass) {
return AbstractBreaker.getBreakClassName(breakClass);
}

/**
* Get the penalty's value as a {@code java.lang.String}.
* (Mainly used in {@code toString()} methods, to improve readability
* of the trace logs.)
*
* @param penaltyValue the penalty value
* @return the penalty value as a {@code java.lang.String}
*/
protected static String valueOf(int penaltyValue) {
String result = (penaltyValue < 0) ? "-" : "";
int tmpValue = Math.abs(penaltyValue);
result += (tmpValue == KnuthElement.INFINITE)
? "INFINITE"
: String.valueOf(tmpValue);
return result;
}

/** {@inheritDoc} */
@@ -105,7 +124,7 @@ public class KnuthPenalty extends KnuthElement {

/** @return true is this penalty is a flagged one. */
public boolean isFlagged() {
return bFlagged;
return isFlagged;
}

/** {@inheritDoc} */
@@ -121,14 +140,6 @@ public class KnuthPenalty extends KnuthElement {
return breakClass;
}

/**
* Sets the break class for this penalty.
* @param cl the break class (EN_AUTO, EN_COLUMN, EN_PAGE, EN_EVEN_PAGE, EN_ODD_PAGE)
*/
public void setBreakClass(int cl) {
this.breakClass = cl;
}

/** {@inheritDoc} */
public String toString() {
StringBuffer sb = new StringBuffer(64);
@@ -137,39 +148,22 @@ public class KnuthPenalty extends KnuthElement {
}
sb.append("penalty");
sb.append(" p=");
if (getP() < 0) {
sb.append("-");
}
if (Math.abs(getP()) == INFINITE) {
sb.append("INFINITE");
} else {
sb.append(getP());
}
if (isFlagged()) {
sb.append(valueOf(this.penalty));
if (this.isFlagged) {
sb.append(" [flagged]");
}
sb.append(" w=");
sb.append(getW());
if (isForcedBreak()) {
sb.append(" (forced break");
switch (getBreakClass()) {
case Constants.EN_PAGE:
sb.append(", page");
break;
case Constants.EN_COLUMN:
sb.append(", column");
break;
case Constants.EN_EVEN_PAGE:
sb.append(", even page");
break;
case Constants.EN_ODD_PAGE:
sb.append(", odd page");
break;
default:
}
sb.append(")");
sb.append(" (forced break, ")
.append(getBreakClassName(this.breakClass))
.append(")");
} else if (this.penalty >= 0 && this.breakClass != -1) {
//penalty corresponding to a keep constraint
sb.append(" (keep constraint, ")
.append(getBreakClassName(this.breakClass))
.append(")");
}
return sb.toString();
}

}

+ 16
- 17
src/java/org/apache/fop/layoutmgr/LayoutContext.java View File

@@ -136,8 +136,8 @@ public class LayoutContext {
private int breakBefore;
private int breakAfter;

private int pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
private int pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
private Keep pendingKeepWithNext = Keep.KEEP_AUTO;
private Keep pendingKeepWithPrevious = Keep.KEEP_AUTO;

private int disableColumnBalancing;

@@ -227,7 +227,7 @@ public class LayoutContext {
* Returns the strength of a keep-with-next currently pending.
* @return the keep-with-next strength
*/
public int getKeepWithNextPending() {
public Keep getKeepWithNextPending() {
return this.pendingKeepWithNext;
}

@@ -235,7 +235,7 @@ public class LayoutContext {
* Returns the strength of a keep-with-previous currently pending.
* @return the keep-with-previous strength
*/
public int getKeepWithPreviousPending() {
public Keep getKeepWithPreviousPending() {
return this.pendingKeepWithPrevious;
}

@@ -243,14 +243,14 @@ public class LayoutContext {
* Clears any pending keep-with-next strength.
*/
public void clearKeepWithNextPending() {
this.pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
this.pendingKeepWithNext = Keep.KEEP_AUTO;
}

/**
* Clears any pending keep-with-previous strength.
*/
public void clearKeepWithPreviousPending() {
this.pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
this.pendingKeepWithPrevious = Keep.KEEP_AUTO;
}

/**
@@ -263,18 +263,18 @@ public class LayoutContext {

/**
* Updates the currently pending keep-with-next strength.
* @param strength the new strength to consider
* @param keep the new strength to consider
*/
public void updateKeepWithNextPending(int strength) {
this.pendingKeepWithNext = Math.max(this.pendingKeepWithNext, strength);
public void updateKeepWithNextPending(Keep keep) {
this.pendingKeepWithNext = this.pendingKeepWithNext.compare(keep);
}

/**
* Updates the currently pending keep-with-previous strength.
* @param strength the new strength to consider
* @param keep the new strength to consider
*/
public void updateKeepWithPreviousPending(int strength) {
this.pendingKeepWithPrevious = Math.max(this.pendingKeepWithPrevious, strength);
public void updateKeepWithPreviousPending(Keep keep) {
this.pendingKeepWithPrevious = this.pendingKeepWithPrevious.compare(keep);
}

/**
@@ -282,7 +282,7 @@ public class LayoutContext {
* @return true if a keep-with-next constraint is pending
*/
public boolean isKeepWithNextPending() {
return getKeepWithNextPending() != BlockLevelLayoutManager.KEEP_AUTO;
return !getKeepWithNextPending().isAuto();
}

/**
@@ -290,7 +290,7 @@ public class LayoutContext {
* @return true if a keep-with-previous constraint is pending
*/
public boolean isKeepWithPreviousPending() {
return getKeepWithPreviousPending() != BlockLevelLayoutManager.KEEP_AUTO;
return !getKeepWithPreviousPending().isAuto();
}

public void setLeadingSpace(SpaceSpecifier space) {
@@ -640,9 +640,8 @@ public class LayoutContext {
+ "\nStarts New Area: \t" + startsNewArea()
+ "\nIs Last Area: \t" + isLastArea()
+ "\nTry Hyphenate: \t" + tryHyphenate()
+ "\nKeeps: \t[keep-with-next=" + KeepUtil.keepStrengthToString(getKeepWithNextPending())
+ "][keep-with-previous="
+ KeepUtil.keepStrengthToString(getKeepWithPreviousPending()) + "] pending"
+ "\nKeeps: \t[keep-with-next=" + getKeepWithNextPending()
+ "][keep-with-previous=" + getKeepWithPreviousPending() + "] pending"
+ "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "]["
+ (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]";
}

+ 26
- 21
src/java/org/apache/fop/layoutmgr/PageBreaker.java View File

@@ -476,9 +476,7 @@ public class PageBreaker extends AbstractBreaker {
pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished();
}

/**
* @return the current child flow layout manager
*/
/** @return the current child flow layout manager */
protected LayoutManager getCurrentChildLM() {
return childFLM;
}
@@ -497,44 +495,51 @@ public class PageBreaker extends AbstractBreaker {
*/
private void handleBreakTrait(int breakVal) {
Page curPage = pslm.getCurrentPage();
if (breakVal == Constants.EN_ALL) {
switch (breakVal) {
case Constants.EN_ALL:
//break due to span change in multi-column layout
curPage.getPageViewport().createSpan(true);
return;
} else if (breakVal == Constants.EN_NONE) {
case Constants.EN_NONE:
curPage.getPageViewport().createSpan(false);
return;
} else if (breakVal == Constants.EN_COLUMN
|| breakVal <= 0
|| breakVal == Constants.EN_AUTO) {
case Constants.EN_COLUMN:
case Constants.EN_AUTO:
case Constants.EN_PAGE:
case -1:
PageViewport pv = curPage.getPageViewport();

//Check if previous page was spanned
boolean forceNewPageWithSpan = false;
RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion(
Constants.FO_REGION_BODY);
if (rb.getColumnCount() > 1
&& pv.getCurrentSpan().getColumnCount() == 1) {
forceNewPageWithSpan = true;
}
forceNewPageWithSpan
= (rb.getColumnCount() > 1
&& pv.getCurrentSpan().getColumnCount() == 1);

if (forceNewPageWithSpan) {
log.trace("Forcing new page with span");
curPage = pslm.makeNewPage(false, false);
curPage.getPageViewport().createSpan(true);
} else if (pv.getCurrentSpan().hasMoreFlows()) {
log.trace("Moving to next flow");
pv.getCurrentSpan().moveToNextFlow();
} else {
curPage = pslm.makeNewPage(false, false);
log.trace("Making new page");
/*curPage = */pslm.makeNewPage(false, false);
}
return;
}
log.debug("handling break-before after page " + pslm.getCurrentPageNum()
+ " breakVal=" + getBreakClassName(breakVal));
if (needBlankPageBeforeNew(breakVal)) {
curPage = pslm.makeNewPage(true, false);
}
if (needNewPage(breakVal)) {
curPage = pslm.makeNewPage(false, false);
default:
log.debug("handling break-before after page " + pslm.getCurrentPageNum()
+ " breakVal=" + getBreakClassName(breakVal));
if (needBlankPageBeforeNew(breakVal)) {
log.trace("Inserting blank page");
/*curPage = */pslm.makeNewPage(true, false);
}
if (needNewPage(breakVal)) {
log.trace("Making new page");
/*curPage = */pslm.makeNewPage(false, false);
}
}
}


+ 148
- 0
src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java View File

@@ -99,6 +99,11 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
private boolean ipdChange;
private KnuthNode bestNodeForIPDChange;

//Used to keep track of switches in keep-context
private int currentKeepContext = Constants.EN_AUTO;
private KnuthNode lastBeforeKeepContextSwitch;


public PageBreakingAlgorithm(LayoutManager topLevelLM,
PageProvider pageProvider,
PageBreakingLayoutListener layoutListener,
@@ -193,6 +198,72 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
footnoteElementIndex = -1;
}

/**
* {@inheritDoc}
* Overridden to defer a part to the next page, if it
* must be kept within one page, but is too large to fit in
* the last column.
*/
protected KnuthNode recoverFromTooLong(KnuthNode lastTooLong) {

if (log.isDebugEnabled()) {
log.debug("Recovering from too long: " + lastTooLong);
log.debug("\tlastTooShort = " + getLastTooShort());
log.debug("\tlastBeforeKeepContextSwitch = " + lastBeforeKeepContextSwitch);
log.debug("\tcurrentKeepContext = " + AbstractBreaker.getBreakClassName(currentKeepContext));
}

if (lastBeforeKeepContextSwitch == null
|| currentKeepContext == Constants.EN_AUTO) {
return super.recoverFromTooLong(lastTooLong);
}

KnuthNode node = lastBeforeKeepContextSwitch;
lastBeforeKeepContextSwitch = null;
// content would overflow, insert empty page/column(s) and try again
while (!pageProvider.endPage(node.line - 1)) {
log.trace("Adding node for empty column");
node = createNode(
node.position,
node.line + 1, 1,
0, 0, 0,
0, 0, 0,
0, 0, node);
}
return node;
}

/**
* Compare two KnuthNodes and return the node with the least demerit.
*
* @param node1 The first knuth node.
* @param node2 The other knuth node.
* @return the node with the least demerit.
*/
protected KnuthNode compareNodes(KnuthNode node1, KnuthNode node2) {

/* if either node is null, return the other one */
if (node1 == null || node2 == null) {
return (node1 == null) ? node2 : node1;
}

/* if either one of the nodes corresponds to a mere column-break,
* and the other one corresponds to a page-break, return the page-break node
*/
if (pageProvider != null) {
if (pageProvider.endPage(node1.line - 1)
&& !pageProvider.endPage(node2.line - 1)) {
return node1;
} else if (pageProvider.endPage(node2.line - 1)
&& !pageProvider.endPage(node1.line - 1)) {
return node2;
}
}

/* all other cases: use superclass implementation */
return super.compareNodes(node1, node2);
}

/** {@inheritDoc} */
protected KnuthNode createNode(int position, int line, int fitness,
int totalWidth, int totalStretch, int totalShrink,
@@ -236,6 +307,28 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
}
}

/**
* {@inheritDoc}
* Overridden to consider penalties with value {@link KnuthElement#INFINITE}
* as legal break-points, if the current keep-context allows this
* (a keep-*.within-page="always" constraint still permits column-breaks)
*/
protected void handlePenaltyAt(KnuthPenalty penalty, int position,
int allowedBreaks) {
super.handlePenaltyAt(penalty, position, allowedBreaks);
/* if the penalty had value INFINITE, default implementation
* will not have considered it a legal break, but it could still
* be one.
*/
if (penalty.getP() == KnuthPenalty.INFINITE) {
int breakClass = penalty.getBreakClass();
if (breakClass == Constants.EN_PAGE
|| breakClass == Constants.EN_COLUMN) {
considerLegalBreak(penalty, position);
}
}
}

/**
* Handles the footnotes cited inside a block-level box. Updates footnotesList and the
* value of totalFootnotesLength with the lengths of the given footnotes.
@@ -320,10 +413,65 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {

/** {@inheritDoc} */
protected void considerLegalBreak(KnuthElement element, int elementIdx) {
if (element.isPenalty()) {
int breakClass = ((KnuthPenalty) element).getBreakClass();
switch (breakClass) {
case Constants.EN_PAGE:
if (this.currentKeepContext != breakClass) {
this.lastBeforeKeepContextSwitch = getLastTooShort();
}
this.currentKeepContext = breakClass;
break;
case Constants.EN_COLUMN:
if (this.currentKeepContext != breakClass) {
this.lastBeforeKeepContextSwitch = getLastTooShort();
}
this.currentKeepContext = breakClass;
break;
case Constants.EN_AUTO:
this.currentKeepContext = breakClass;
break;
default:
//nop
}
}
super.considerLegalBreak(element, elementIdx);
newFootnotes = false;
}

/** {@inheritDoc} */
protected boolean elementCanEndLine(KnuthElement element, int line, int difference) {
if (!(element.isPenalty()) || pageProvider == null) {
return true;
} else {
KnuthPenalty p = (KnuthPenalty) element;
if (p.getP() <= 0) {
return true;
} else {
int context = p.getBreakClass();
switch (context) {
case Constants.EN_LINE:
case Constants.EN_COLUMN:
return p.getP() < KnuthPenalty.INFINITE;
case Constants.EN_PAGE:
return p.getP() < KnuthPenalty.INFINITE
|| !pageProvider.endPage(line - 1);
case Constants.EN_AUTO:
log.debug("keep is not auto but context is");
return true;
default:
if (p.getP() < KnuthPenalty.INFINITE) {
log.debug("Non recognized keep context:" + context);
return true;
} else {
return false;
}
}
}
}
}

/** {@inheritDoc} */
protected int computeDifference(KnuthNode activeNode, KnuthElement element,
int elementIndex) {
KnuthPageNode pageNode = (KnuthPageNode) activeNode;

+ 43
- 0
src/java/org/apache/fop/layoutmgr/PageProvider.java View File

@@ -146,6 +146,20 @@ public class PageProvider implements Constants {
return this.lastReportedBPD;
}

// Wish there were a more elegant way to do this in Java
private int[] getColIndexAndColCount(int index) {
int columnCount = 0;
int colIndex = startColumnOfCurrentElementList + index;
int pageIndex = -1;
do {
colIndex -= columnCount;
pageIndex++;
Page page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
columnCount = page.getPageViewport().getCurrentSpan().getColumnCount();
} while (colIndex >= columnCount);
return new int[] {colIndex, columnCount};
}

/**
* Returns true if the part following the given one has a different IPD.
*
@@ -173,6 +187,35 @@ public class PageProvider implements Constants {
}
}

/**
* Checks if a break at the passed index would start a new page
* @param index the index of the element before the break
* @return {@code true} if the break starts a new page
*/
boolean startPage(int index) {
return getColIndexAndColCount(index)[0] == 0;
}

/**
* Checks if a break at the passed index would end a page
* @param index the index of the element before the break
* @return {@code true} if the break ends a page
*/
boolean endPage(int index) {
int[] colIndexAndColCount = getColIndexAndColCount(index);
return colIndexAndColCount[0] == colIndexAndColCount[1] - 1;
}

/**
* Obtain the applicable column-count for the element at the
* passed index
* @param index the index of the element
* @return the number of columns
*/
int getColumnCount(int index) {
return getColIndexAndColCount(index)[1];
}

/**
* Returns the part index (0<x<partCount) which denotes the first part on the last page
* generated by the current element list.

+ 6
- 6
src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java View File

@@ -314,18 +314,18 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
return KEEP_AUTO;
public Keep getKeepTogether() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
}

}

+ 38
- 22
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java View File

@@ -37,6 +37,7 @@ import org.apache.fop.datatypes.Numeric;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.properties.CommonHyphenation;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
@@ -47,7 +48,7 @@ import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.BreakingAlgorithm;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.InlineKnuthSequence;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
@@ -901,12 +902,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
for (int p = 0; p < knuthParagraphs.size(); p++) {
// penalty between paragraphs
if (p > 0) {
int strength = getKeepTogetherStrength();
int penalty = KeepUtil.getPenaltyForKeep(strength);
if (penalty < KnuthElement.INFINITE) {
returnList.add(new BreakElement(
new Position(this), penalty, context));
}
Keep keep = getKeepTogether();
returnList.add(new BreakElement(
new Position(this),
keep.getPenalty(),
keep.getContext(),
context));
}

LineLayoutPossibilities llPoss;
@@ -935,7 +936,6 @@ public class LineLayoutManager extends InlineStackingLayoutManager
} else {
/* "normal" vertical alignment: create a sequence whose boxes
represent effective lines, and contain LineBreakPositions */
Position returnPosition = new LeafPosition(this, p);
int startIndex = 0;
for (int i = 0;
i < llPoss.getChosenLineCount();
@@ -945,12 +945,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
&& i >= fobj.getOrphans()
&& i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
// penalty allowing a page break between lines
int strength = getKeepTogetherStrength();
int penalty = KeepUtil.getPenaltyForKeep(strength);
if (penalty < KnuthElement.INFINITE) {
returnList.add(new BreakElement(
new LeafPosition(this, p, endIndex), penalty, context));
}
Keep keep = getKeepTogether();
returnList.add(new BreakElement(
new LeafPosition(this, p, endIndex),
keep.getPenalty(),
keep.getContext(),
context));
}
endIndex = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos();
// create a list of the FootnoteBodyLM handling footnotes
@@ -1128,28 +1128,43 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
return ((BlockLevelLayoutManager) getParent()).getKeepTogetherStrength();
public KeepProperty getKeepTogetherProperty() {
return ((BlockLevelLayoutManager) getParent()).getKeepTogetherProperty();
}

/** {@inheritDoc} */
public KeepProperty getKeepWithPreviousProperty() {
return ((BlockLevelLayoutManager) getParent()).getKeepWithPreviousProperty();
}

/** {@inheritDoc} */
public KeepProperty getKeepWithNextProperty() {
return ((BlockLevelLayoutManager) getParent()).getKeepWithNextProperty();
}

/** {@inheritDoc} */
public Keep getKeepTogether() {
return ((BlockLevelLayoutManager) getParent()).getKeepTogether();
}

/** {@inheritDoc} */
public boolean mustKeepWithPrevious() {
return getKeepWithPreviousStrength() > KEEP_AUTO;
return !getKeepWithPrevious().isAuto();
}

/** {@inheritDoc} */
public boolean mustKeepWithNext() {
return getKeepWithNextStrength() > KEEP_AUTO;
return !getKeepWithNext().isAuto();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
@@ -1254,6 +1269,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
break;
}
//TODO Something's not right here. See block_hyphenation_linefeed_preserve.xml
//for more info: see also https://issues.apache.org/bugzilla/show_bug.cgi?id=38264

// collect word fragments, ignoring auxiliary elements;
// each word fragment was created by a different TextLM

+ 7
- 10
src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java View File

@@ -29,10 +29,10 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
@@ -279,21 +279,18 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
getListBlockFO().getKeepTogether());
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
public KeepProperty getKeepTogetherProperty() {
return getListBlockFO().getKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getListBlockFO().getKeepWithNext());
public KeepProperty getKeepWithPreviousProperty() {
return getListBlockFO().getKeepWithPrevious();
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getListBlockFO().getKeepWithPrevious());
public KeepProperty getKeepWithNextProperty() {
return getListBlockFO().getKeepWithNext();
}

/** {@inheritDoc} */

+ 8
- 9
src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java View File

@@ -28,8 +28,9 @@ import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.AbstractListItemPart;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
@@ -221,20 +222,18 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(getPartFO().getKeepTogether());
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
public KeepProperty getKeepTogetherProperty() {
return getPartFO().getKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
}

}

+ 19
- 23
src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java View File

@@ -32,13 +32,13 @@ import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
@@ -83,8 +83,8 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
private MinOptMax effSpaceBefore;
private MinOptMax effSpaceAfter;

private int keepWithNextPendingOnLabel;
private int keepWithNextPendingOnBody;
private Keep keepWithNextPendingOnLabel;
private Keep keepWithNextPendingOnBody;

private int listItemHeight;

@@ -254,8 +254,8 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager

context.updateKeepWithNextPending(this.keepWithNextPendingOnLabel);
context.updateKeepWithNextPending(this.keepWithNextPendingOnBody);
context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithNextPending(getKeepWithNext());
context.updateKeepWithPreviousPending(getKeepWithPrevious());

setFinished(true);
resetSpaces();
@@ -276,16 +276,16 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
int step;
int addedBoxHeight = 0;
int keepWithNextActive = BlockLevelLayoutManager.KEEP_AUTO;
Keep keepWithNextActive = Keep.KEEP_AUTO;

LinkedList returnList = new LinkedList();
while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) {

if (end[0] + 1 == elementLists[0].size()) {
keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnLabel);
keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnLabel);
}
if (end[1] + 1 == elementLists[1].size()) {
keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnBody);
keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnBody);
}

// compute penalty height and box height
@@ -339,14 +339,13 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
}

if (addedBoxHeight < totalHeight) {
int strength = BlockLevelLayoutManager.KEEP_AUTO;
strength = Math.max(strength, keepWithNextActive);
strength = Math.max(strength, getKeepTogetherStrength());
Keep keep = keepWithNextActive.compare(getKeepTogether());
int p = stepPenalty;
if (p > -KnuthElement.INFINITE) {
p = Math.max(p, KeepUtil.getPenaltyForKeep(strength));
p = Math.max(p, keep.getPenalty());
}
returnList.add(new BreakElement(stepPosition, penaltyHeight, p, -1, context));
returnList.add(new BreakElement(stepPosition, penaltyHeight, p, keep.getContext(),
context));
}
}

@@ -644,21 +643,18 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
getListItemFO().getKeepTogether());
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
public KeepProperty getKeepTogetherProperty() {
return getListItemFO().getKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getListItemFO().getKeepWithNext());
public KeepProperty getKeepWithPreviousProperty() {
return getListItemFO().getKeepWithPrevious();
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getListItemFO().getKeepWithPrevious());
public KeepProperty getKeepWithNextProperty() {
return getListItemFO().getKeepWithNext();
}

/** {@inheritDoc} */

+ 11
- 7
src/java/org/apache/fop/layoutmgr/table/ActiveCell.java View File

@@ -32,8 +32,8 @@ import org.apache.fop.fo.flow.table.ConditionalBorder;
import org.apache.fop.fo.flow.table.EffRow;
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
@@ -75,7 +75,7 @@ class ActiveCell {
/** True if the next CellPart that will be created will be the last one for this cell. */
private boolean lastCellPart;

private int keepWithNextStrength;
private Keep keepWithNext;

private int spanIndex = 0;

@@ -218,7 +218,7 @@ class ActiveCell {
includedLength = -1; // Avoid troubles with cells having content of zero length
totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList);
endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1;
keepWithNextStrength = BlockLevelLayoutManager.KEEP_AUTO;
keepWithNext = Keep.KEEP_AUTO;
remainingLength = totalLength - previousRowsLength;

afterNextStep = new Step(previousRowsLength);
@@ -314,7 +314,11 @@ class ActiveCell {
KnuthElement el = (KnuthElement) knuthIter.next();
if (el.isPenalty()) {
prevIsBox = false;
if (el.getP() < KnuthElement.INFINITE) {
if (el.getP() < KnuthElement.INFINITE
|| ((KnuthPenalty) el).getBreakClass() == Constants.EN_PAGE) {
// TODO too much is being done in that test, only to handle
// keep.within-column properly.

// First legal break point
breakFound = true;
KnuthPenalty p = (KnuthPenalty) el;
@@ -533,7 +537,7 @@ class ActiveCell {
*/
CellPart createCellPart() {
if (nextStep.end + 1 == elementList.size()) {
keepWithNextStrength = pgu.getKeepWithNextStrength();
keepWithNext = pgu.getKeepWithNext();
// TODO if keep-with-next is set on the row, must every cell of the row
// contribute some content from children blocks?
// see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/
@@ -576,8 +580,8 @@ class ActiveCell {
}
}

int getKeepWithNextStrength() {
return keepWithNextStrength;
Keep getKeepWithNext() {
return keepWithNext;
}

int getPenaltyValue() {

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

@@ -60,8 +60,8 @@ class RowGroupLayoutManager {
LinkedList returnList = new LinkedList();
createElementsForRowGroup(context, alignment, bodyType, returnList);

context.updateKeepWithPreviousPending(rowGroup[0].getKeepWithPreviousStrength());
context.updateKeepWithNextPending(rowGroup[rowGroup.length - 1].getKeepWithNextStrength());
context.updateKeepWithPreviousPending(rowGroup[0].getKeepWithPrevious());
context.updateKeepWithNextPending(rowGroup[rowGroup.length - 1].getKeepWithNext());

int breakBefore = Constants.EN_AUTO;
TableRow firstRow = rowGroup[0].getTableRow();

+ 6
- 16
src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java View File

@@ -23,6 +23,7 @@ import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.table.TableAndCaption;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator;

@@ -201,19 +202,8 @@ public class TableAndCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KEEP_AUTO;
/* TODO Complete me!
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
getTableAndCaptionFO().getKeepTogether());
*/
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableAndCaptionFO().getKeepWithNext());
@@ -221,12 +211,12 @@ public class TableAndCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableAndCaptionFO().getKeepWithPrevious());
*/
}

}
}

+ 5
- 17
src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java View File

@@ -23,6 +23,7 @@ import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.table.TableCaption;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator;

@@ -197,21 +198,8 @@ public class TableCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KEEP_AUTO;
/* TODO Complete me!
strength = Math.max(strength, KeepUtil.getKeepStrength(
getTableCaptionFO().getKeepTogether().getWithinPage()));
strength = Math.max(strength, KeepUtil.getKeepStrength(
getTableCaptionFO().getKeepTogether().getWithinColumn()));
*/
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableCaptionFO().getKeepWithNext());
@@ -219,8 +207,8 @@ public class TableCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableCaptionFO().getKeepWithPrevious());

+ 22
- 21
src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.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.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.Trait;
@@ -31,21 +32,23 @@ import org.apache.fop.fo.flow.table.ConditionalBorder;
import org.apache.fop.fo.flow.table.GridUnit;
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
import org.apache.fop.layoutmgr.AreaAdditionUtil;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceResolver;
@@ -138,9 +141,9 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
List contentList = new LinkedList();
List returnList = new LinkedList();

BlockLevelLayoutManager curLM; // currently active LM
BlockLevelLayoutManager prevLM = null; // previously active LM
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
LayoutManager curLM; // currently active LM
LayoutManager prevLM = null; // previously active LM
while ((curLM = getChildLM()) != null) {
LayoutContext childLC = new LayoutContext(0);
// curLM is a ?
childLC.setStackLimitBP(MinOptMax.subtract(context
@@ -153,11 +156,12 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
log.debug("child LM signals pending keep with next");
}
if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
primaryGridUnit.setKeepWithPreviousStrength(childLC.getKeepWithPreviousPending());
primaryGridUnit.setKeepWithPrevious(childLC.getKeepWithPreviousPending());
childLC.clearKeepWithPreviousPending();
}

if (prevLM != null) {
if (prevLM != null
&& !ElementListUtils.endsWithForcedBreak(contentList)) {
// there is a block handled by prevLM
// before the one handled by curLM
addInBetweenBreak(contentList, context, childLC);
@@ -174,7 +178,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
prevLM = curLM;
}
primaryGridUnit.setKeepWithNextStrength(context.getKeepWithNextPending());
primaryGridUnit.setKeepWithNext(context.getKeepWithNextPending());

returnedList = new LinkedList();
if (!contentList.isEmpty()) {
@@ -195,7 +199,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
final KnuthElement lastItem = (KnuthElement) ListUtil
.getLast(returnList);
if (((KnuthElement) lastItem).isForcedBreak()) {
if (lastItem.isForcedBreak()) {
KnuthPenalty p = (KnuthPenalty) lastItem;
primaryGridUnit.setBreakAfter(p.getBreakClass());
p.setP(0);
@@ -556,26 +560,23 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KEEP_AUTO;
public Keep getKeepTogether() {
Keep keep = Keep.KEEP_AUTO;
if (primaryGridUnit.getRow() != null) {
strength = Math.max(strength, KeepUtil.getKeepStrength(
primaryGridUnit.getRow().getKeepTogether().getWithinPage()));
strength = Math.max(strength, KeepUtil.getKeepStrength(
primaryGridUnit.getRow().getKeepTogether().getWithinColumn()));
keep = Keep.getKeep(primaryGridUnit.getRow().getKeepTogether());
}
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
keep = keep.compare(getParentKeepTogether());
return keep;
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-next!)
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-next!)
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-previous!)
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-previous!)
}

// --------- Property Resolution related functions --------- //

+ 10
- 11
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java View File

@@ -35,10 +35,9 @@ import org.apache.fop.fo.flow.table.EffRow;
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
@@ -213,13 +212,13 @@ public class TableContentLayoutManager implements PercentBaseContext {
context.clearKeepsPending();
context.setBreakBefore(Constants.EN_AUTO);
context.setBreakAfter(Constants.EN_AUTO);
int keepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
Keep keepWithPrevious = Keep.KEEP_AUTO;
int breakBefore = Constants.EN_AUTO;
if (rowGroup != null) {
RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup,
stepper);
List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType);
keepWithPrevious = Math.max(keepWithPrevious, context.getKeepWithPreviousPending());
keepWithPrevious = keepWithPrevious.compare(context.getKeepWithPreviousPending());
breakBefore = context.getBreakBefore();
int breakBetween = context.getBreakAfter();
returnList.addAll(nextRowGroupElems);
@@ -228,7 +227,7 @@ public class TableContentLayoutManager implements PercentBaseContext {

//Note previous pending keep-with-next and clear the strength
//(as the layout context is reused)
int keepWithNextPending = context.getKeepWithNextPending();
Keep keepWithNextPending = context.getKeepWithNextPending();
context.clearKeepWithNextPending();

//Get elements for next row group
@@ -246,17 +245,17 @@ public class TableContentLayoutManager implements PercentBaseContext {
*/

//Determine keep constraints
int penaltyStrength = BlockLevelLayoutManager.KEEP_AUTO;
penaltyStrength = Math.max(penaltyStrength, keepWithNextPending);
penaltyStrength = Math.max(penaltyStrength, context.getKeepWithPreviousPending());
Keep keep = keepWithNextPending.compare(context.getKeepWithPreviousPending());
context.clearKeepWithPreviousPending();
penaltyStrength = Math.max(penaltyStrength, getTableLM().getKeepTogetherStrength());
int penaltyValue = KeepUtil.getPenaltyForKeep(penaltyStrength);
keep = keep.compare(getTableLM().getKeepTogether());
int penaltyValue = keep.getPenalty();
int breakClass = keep.getContext();

breakBetween = BreakUtil.compareBreakClasses(breakBetween,
context.getBreakBefore());
if (breakBetween != Constants.EN_AUTO) {
penaltyValue = -KnuthElement.INFINITE;
breakClass = breakBetween;
}
BreakElement breakElement;
ListIterator elemIter = returnList.listIterator(returnList.size());
@@ -267,7 +266,7 @@ public class TableContentLayoutManager implements PercentBaseContext {
breakElement = (BreakElement) elem;
}
breakElement.setPenaltyValue(penaltyValue);
breakElement.setBreakClass(breakBetween);
breakElement.setBreakClass(breakClass);
returnList.addAll(nextRowGroupElems);
breakBetween = context.getBreakAfter();
}

+ 9
- 11
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java View File

@@ -35,11 +35,11 @@ import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.BlockLevelEventProducer;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.LayoutContext;
@@ -256,10 +256,10 @@ public class TableLayoutManager extends BlockStackingLayoutManager
log.debug(contentKnuthElements);
wrapPositionElements(contentKnuthElements, returnList);

context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());

context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithNextPending(getKeepWithNext());
context.updateKeepWithNextPending(childLC.getKeepWithNextPending());

if (getTable().isSeparateBorderModel()) {
@@ -448,20 +448,18 @@ public class TableLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepTogether());
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
public KeepProperty getKeepTogetherProperty() {
return getTable().getKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepWithNext());
public KeepProperty getKeepWithPreviousProperty() {
return getTable().getKeepWithPrevious();
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepWithPrevious());
public KeepProperty getKeepWithNextProperty() {
return getTable().getKeepWithNext();
}

// --------- Property Resolution related functions --------- //

+ 12
- 16
src/java/org/apache/fop/layoutmgr/table/TableStepper.java View File

@@ -30,12 +30,10 @@ import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.table.EffRow;
import org.apache.fop.fo.flow.table.GridUnit;
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.LayoutContext;
@@ -241,40 +239,38 @@ public class TableStepper {
}
}

int strength = BlockLevelLayoutManager.KEEP_AUTO;
Keep keep = Keep.KEEP_AUTO;
int stepPenalty = 0;
for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
ActiveCell activeCell = (ActiveCell) iter.next();
strength = Math.max(strength, activeCell.getKeepWithNextStrength());
keep = keep.compare(activeCell.getKeepWithNext());
stepPenalty = Math.max(stepPenalty, activeCell.getPenaltyValue());
}
if (!rowFinished) {
strength = Math.max(strength, rowGroup[activeRowIndex].getKeepTogetherStrength());
keep = keep.compare(rowGroup[activeRowIndex].getKeepTogether());
//The above call doesn't take the penalty from the table into account, so...
strength = Math.max(strength, getTableLM().getKeepTogetherStrength());
keep = keep.compare(getTableLM().getKeepTogether());
} else if (activeRowIndex < rowGroup.length - 1) {
strength = Math.max(strength,
rowGroup[activeRowIndex].getKeepWithNextStrength());
strength = Math.max(strength,
rowGroup[activeRowIndex + 1].getKeepWithPreviousStrength());
keep = keep.compare(rowGroup[activeRowIndex].getKeepWithNext());
keep = keep.compare(rowGroup[activeRowIndex + 1].getKeepWithPrevious());
nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
rowGroup[activeRowIndex].getBreakAfter());
nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
rowGroup[activeRowIndex + 1].getBreakBefore());
}
int p = KeepUtil.getPenaltyForKeep(strength);
int p = keep.getPenalty();
if (rowHeightSmallerThanFirstStep) {
rowHeightSmallerThanFirstStep = false;
p = KnuthPenalty.INFINITE;
}
if (p > -KnuthElement.INFINITE) {
p = Math.max(p, stepPenalty);
}
p = Math.max(p, stepPenalty);
int breakClass = keep.getContext();
if (nextBreakClass != Constants.EN_AUTO) {
log.trace("Forced break encountered");
p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0)
breakClass = nextBreakClass;
}
returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, nextBreakClass, context));
returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, breakClass, context));
if (penaltyOrGlueLen < 0) {
returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true));
}

+ 11
- 4
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java View File

@@ -77,6 +77,9 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
private Map/*<String,String>*/pageSegmentMap
= new java.util.HashMap/*<String,String>*/();

/** Medium Map referenced on previous page **/
private String lastMediumMap;

private static final int LOC_ELSEWHERE = 0;
private static final int LOC_FOLLOWING_PAGE_SEQUENCE = 1;
private static final int LOC_IN_PAGE_HEADER = 2;
@@ -299,15 +302,19 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
}
}
} else if (extension instanceof AFPInvokeMediumMap) {
if (this.location != LOC_FOLLOWING_PAGE_SEQUENCE) {
if (this.location != LOC_FOLLOWING_PAGE_SEQUENCE
&& this.location != LOC_IN_PAGE_HEADER) {

throw new IFException(
"AFP IMM extension must be between page-sequence and the first page: "
+ extension, null);
"AFP IMM extension must be between page-sequence"
+ " and the first page or child of page-header: "
+ extension, null);
}
AFPInvokeMediumMap imm = (AFPInvokeMediumMap)extension;
String mediumMap = imm.getName();
if (mediumMap != null) {
if (mediumMap != null && !mediumMap.equals(lastMediumMap)) {
dataStream.createInvokeMediumMap(mediumMap);
lastMediumMap = mediumMap;
}
} else if (extension instanceof AFPIncludeFormMap) {
AFPIncludeFormMap formMap = (AFPIncludeFormMap)extension;

+ 58
- 21
src/java/org/apache/fop/render/afp/AFPRenderer.java View File

@@ -181,6 +181,9 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust
/** the shading mode for filled rectangles */
private AFPShadingMode shadingMode = AFPShadingMode.COLOR;

/** medium map referenced used on previous page **/
private String lastMediumMap;

/**
* Constructor for AFPRenderer.
*/
@@ -380,6 +383,9 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust

int resolution = paintingState.getResolution();

// IMM should occur before BPG
renderInvokeMediumMap(pageViewport);

dataStream.startPage(pageWidth, pageHeight, pageRotation,
resolution, resolution);

@@ -703,6 +709,35 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust
return MimeConstants.MIME_AFP;
}

/**
* checks for IMM Extension and renders if found and different
* from previous page
*
* @param pageViewport the page object
*/
private void renderInvokeMediumMap(PageViewport pageViewport) {
if (pageViewport.getExtensionAttachments() != null
&& pageViewport.getExtensionAttachments().size() > 0) {
Iterator it = pageViewport.getExtensionAttachments().iterator();
while (it.hasNext()) {
ExtensionAttachment attachment = (ExtensionAttachment) it.next();
if (AFPExtensionAttachment.CATEGORY.equals(attachment.getCategory())) {
AFPExtensionAttachment aea = (AFPExtensionAttachment)attachment;
if (AFPElementMapping.INVOKE_MEDIUM_MAP.equals(aea.getElementName())) {
AFPInvokeMediumMap imm = (AFPInvokeMediumMap)attachment;
String mediumMap = imm.getName();
if (mediumMap != null) {
if (!mediumMap.equals(lastMediumMap)) {
dataStream.createInvokeMediumMap(mediumMap);
lastMediumMap = mediumMap;
}
}
}
}
}
}
}

/**
* Method to render the page extension.
* <p>
@@ -720,27 +755,29 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust
while (it.hasNext()) {
ExtensionAttachment attachment = (ExtensionAttachment) it.next();
if (AFPPageSetup.CATEGORY.equals(attachment.getCategory())) {
AFPPageSetup aps = (AFPPageSetup) attachment;
String element = aps.getElementName();
if (AFPElementMapping.INCLUDE_PAGE_OVERLAY.equals(element)) {
String overlay = aps.getName();
if (overlay != null) {
dataStream.createIncludePageOverlay(overlay);
}
} else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT
.equals(element)) {
String name = aps.getName();
String source = aps.getValue();
pageSegmentMap.put(source, name);
} else if (AFPElementMapping.TAG_LOGICAL_ELEMENT
.equals(element)) {
String name = aps.getName();
String value = aps.getValue();
dataStream.createTagLogicalElement(name, value);
} else if (AFPElementMapping.NO_OPERATION.equals(element)) {
String content = aps.getContent();
if (content != null) {
dataStream.createNoOperation(content);
if (attachment instanceof AFPPageSetup) {
AFPPageSetup aps = (AFPPageSetup) attachment;
String element = aps.getElementName();
if (AFPElementMapping.INCLUDE_PAGE_OVERLAY.equals(element)) {
String overlay = aps.getName();
if (overlay != null) {
dataStream.createIncludePageOverlay(overlay);
}
} else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT
.equals(element)) {
String name = aps.getName();
String source = aps.getValue();
pageSegmentMap.put(source, name);
} else if (AFPElementMapping.TAG_LOGICAL_ELEMENT
.equals(element)) {
String name = aps.getName();
String value = aps.getValue();
dataStream.createTagLogicalElement(name, value);
} else if (AFPElementMapping.NO_OPERATION.equals(element)) {
String content = aps.getContent();
if (content != null) {
dataStream.createNoOperation(content);
}
}
}
}

+ 5
- 3
src/java/org/apache/fop/render/afp/extensions/AFPInvokeMediumMapElement.java View File

@@ -26,8 +26,8 @@ import org.apache.fop.fo.extensions.ExtensionAttachment;

/**
* This class represents an AFP-specific extension element to embed Invoke Medium Map (IMM)
* fields at the beginning of a page group. The element is optional and expected as a direct child
* of an fo:page-sequence.
* fields at the beginning of a page group or just prior to a Page. The element is optional
* and expected as a direct child of an fo:page-sequence or fo:simple-page-master
*/
public class AFPInvokeMediumMapElement extends AbstractAFPExtensionObject {

@@ -42,7 +42,9 @@ public class AFPInvokeMediumMapElement extends AbstractAFPExtensionObject {
/** {@inheritDoc} */
protected void startOfNode() throws FOPException {
super.startOfNode();
if (parent.getNameId() != Constants.FO_PAGE_SEQUENCE) {
if (parent.getNameId() != Constants.FO_PAGE_SEQUENCE
&& parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) {
invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(),
"rule.childOfPageSequence");
}

+ 3
- 3
src/java/org/apache/fop/render/awt/AWTRenderer.java View File

@@ -47,7 +47,7 @@ import org.apache.fop.render.awt.viewer.PreviewDialog;
import org.apache.fop.render.awt.viewer.Renderable;
import org.apache.fop.render.awt.viewer.StatusListener;
import org.apache.fop.render.java2d.Java2DRenderer;
import org.apache.fop.render.extensions.prepress.PageScaleAttributes;
import org.apache.fop.render.extensions.prepress.PageScale;

/**
* The AWTRender outputs the pages generated by the layout engine to a Swing
@@ -159,8 +159,8 @@ public class AWTRenderer extends Java2DRenderer implements Pageable {
/ userAgent.getTargetPixelUnitToMillimeter();
if (getPageViewport(pageNum).getForeignAttributes() != null) {
String scale = (String) getPageViewport(pageNum).getForeignAttributes().get(
PageScaleAttributes.EXT_PAGE_SCALE);
Point2D scales = PageScaleAttributes.getScaleAttributes(scale);
PageScale.EXT_PAGE_SCALE);
Point2D scales = PageScale.getScale(scale);
if (scales != null) {
scaleX *= scales.getX();
scaleY *= scales.getY();

+ 235
- 0
src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java View File

@@ -0,0 +1,235 @@
/*
* 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.extensions.prepress;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.text.MessageFormat;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.properties.FixedLength;

/**
* This class is used to calculate the effective boundaries of a page including special-purpose
* boxes used in prepress. These are specified using extension attributes:
* bleedBox, trimBox and cropBox. The semantics are further described on the website.
*/
public class PageBoundaries {

/**
* The extension attribute for calculating the PDF BleedBox area - specifies the bleed width.
*/
public static final QName EXT_BLEED
= new QName(ExtensionElementMapping.URI, null, "bleed");

/**
* The extension attribute for the PDF CropBox area.
*/
public static final QName EXT_CROP_OFFSET
= new QName(ExtensionElementMapping.URI, null, "crop-offset");

/**
* The extension attribute for the PDF CropBox area.
*/
public static final QName EXT_CROP_BOX
= new QName(ExtensionElementMapping.URI, null, "crop-box");


private static final Pattern SIZE_UNIT_PATTERN
= Pattern.compile("^(-?\\d*\\.?\\d*)(px|in|cm|mm|pt|pc|mpt)$");

private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+");

private Rectangle trimBox;
private Rectangle bleedBox;
private Rectangle mediaBox;
private Rectangle cropBox;

/**
* Creates a new instance.
* @param pageSize the page size (in mpt) defined by the simple-page-master.
* @param bleed the bleed value (raw value as given in the property value)
* @param cropOffset the crop-offset value (raw value as given in the property value)
* @param cropBoxSelector the crop-box, valid values: (trim-box|bleed-box|media-box)
*/
public PageBoundaries(Dimension pageSize, String bleed, String cropOffset,
String cropBoxSelector) {
calculate(pageSize, bleed, cropOffset, cropBoxSelector);
}

/**
* Creates a new instance.
* @param pageSize the page size (in mpt) defined by the simple-page-master.
* @param foreignAttributes the foreign attributes for the page
* (used to extract the extension attribute values)
*/
public PageBoundaries(Dimension pageSize, Map foreignAttributes) {
String bleed = (String)foreignAttributes.get(EXT_BLEED);
String cropOffset = (String)foreignAttributes.get(EXT_CROP_OFFSET);
String cropBoxSelector = (String)foreignAttributes.get(EXT_CROP_BOX);
calculate(pageSize, bleed, cropOffset, cropBoxSelector);
}

private void calculate(Dimension pageSize, String bleed, String cropOffset,
String cropBoxSelector) {
this.trimBox = new Rectangle(pageSize);
this.bleedBox = getBleedBoxRectangle(this.trimBox, bleed);
Rectangle cropMarksBox = getCropMarksAreaRectangle(trimBox, cropOffset);

//MediaBox includes all of the following three rectangles
this.mediaBox = new Rectangle();
this.mediaBox.add(this.trimBox);
this.mediaBox.add(this.bleedBox);
this.mediaBox.add(cropMarksBox);

if ("trim-box".equals(cropBoxSelector)) {
this.cropBox = this.trimBox;
} else if ("bleed-box".equals(cropBoxSelector)) {
this.cropBox = this.bleedBox;
} else if ("media-box".equals(cropBoxSelector)
|| cropBoxSelector == null
|| "".equals(cropBoxSelector)) {
this.cropBox = this.mediaBox;
} else {
final String err = "The crop-box has invalid value: {0}, "
+ "possible values of crop-box: (trim-box|bleed-box|media-box)";
throw new IllegalArgumentException(MessageFormat.format(err,
new Object[]{cropBoxSelector}));
}
}

/**
* Returns the trim box for the page. This is equal to the page size given in XSL-FO.
* After production the printed media is trimmed to this rectangle.
* @return the trim box
*/
public Rectangle getTrimBox() {
return this.trimBox;
}

/**
* Returns the bleed box for the page.
* @return the bleed box
*/
public Rectangle getBleedBox() {
return this.bleedBox;
}

/**
* Returns the media box for the page.
* @return the media box
*/
public Rectangle getMediaBox() {
return this.mediaBox;
}

/**
* Returns the crop box for the page. The crop box is used by Adobe Acrobat to select which
* parts of the document shall be displayed and it also defines the rectangle to which a
* RIP will clip the document. For bitmap output, this defines the size of the bitmap.
* @return the crop box
*/
public Rectangle getCropBox() {
return this.cropBox;
}

/**
* The BleedBox is calculated by expanding the TrimBox by the bleed widths.
*
* @param trimBox the TrimBox rectangle
* @param bleed the given bleed widths
* @return the calculated BleedBox rectangle
*/
private static Rectangle getBleedBoxRectangle(Rectangle trimBox, String bleed) {
return getRectangleUsingOffset(trimBox, bleed);
}

/**
* The MediaBox is calculated by expanding the TrimBox by the crop offsets.
*
* @param trimBox the TrimBox rectangle
* @param cropOffsets the given crop offsets
* @return the calculated MediaBox rectangle
*/
private static Rectangle getCropMarksAreaRectangle(Rectangle trimBox, String cropOffsets) {
return getRectangleUsingOffset(trimBox, cropOffsets);
}

private static Rectangle getRectangleUsingOffset(Rectangle originalRect, String offset) {
if (offset == null || "".equals(offset) || originalRect == null) {
return originalRect;
}

String[] offsets = WHITESPACE_PATTERN.split(offset);
int[] coords = new int[4]; // top, right, bottom, left
switch (offsets.length) {
case 1:
coords[0] = getLengthIntValue(offsets[0]);
coords[1] = coords[0];
coords[2] = coords[0];
coords[3] = coords[0];
break;
case 2:
coords[0] = getLengthIntValue(offsets[0]);
coords[1] = getLengthIntValue(offsets[1]);
coords[2] = coords[0];
coords[3] = coords[1];
break;
case 3:
coords[0] = getLengthIntValue(offsets[0]);
coords[1] = getLengthIntValue(offsets[1]);
coords[2] = getLengthIntValue(offsets[2]);
coords[3] = coords[1];
break;
case 4:
coords[0] = getLengthIntValue(offsets[0]);
coords[1] = getLengthIntValue(offsets[1]);
coords[2] = getLengthIntValue(offsets[2]);
coords[3] = getLengthIntValue(offsets[3]);
break;
default:
// TODO throw appropriate exception that can be caught by the event
// notification mechanism
throw new IllegalArgumentException("Too many arguments");
}
return new Rectangle(originalRect.x - coords[3],
originalRect.y - coords[0],
originalRect.width + coords[3] + coords[1],
originalRect.height + coords[0] + coords[2]);
}

private static int getLengthIntValue(final String length) {
final String err = "Incorrect length value: {0}";
Matcher m = SIZE_UNIT_PATTERN.matcher(length);

if (m.find()) {
return FixedLength.getInstance(Double.parseDouble(m.group(1)),
m.group(2)).getLength().getValue();
} else {
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{length}));
}
}

}

+ 0
- 186
src/java/org/apache/fop/render/extensions/prepress/PageBoundariesAttributes.java View File

@@ -1,186 +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.extensions.prepress;

import java.awt.Rectangle;
import java.text.MessageFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.properties.FixedLength;


/**
* This class contains definition of page boundaries FOF's extension attributes for XSL-FO.
* That is: bleedBox, trimBox and cropBox.
* Also this class provides method to parse the possible values of these attributes
* and to generate original size of bounded area.
*/
public final class PageBoundariesAttributes {

/**
* The extension attribute for calculating the PDF BleedBox area - specifies the bleed width
*/
public static final QName EXT_BLEED
= new QName(ExtensionElementMapping.URI, null, "bleed");

/**
* The extension attribute for the PDF CropBox area
*/
public static final QName EXT_CROP_OFFSET
= new QName(ExtensionElementMapping.URI, null, "crop-offset");

/**
* The extension attribute for the PDF CropBox area
*/
public static final QName EXT_CROP_BOX
= new QName(ExtensionElementMapping.URI, null, "crop-box");


private static final Pattern SIZE_UNIT_PATTERN
= Pattern.compile("^(-?\\d*\\.?\\d*)(px|in|cm|mm|pt|pc|mpt)$");

/**
* Utility classes should not have a public or default constructor.
*/
private PageBoundariesAttributes() {
}

/**
* The BleedBox is calculated by expanding the TrimBox by the bleed widths.
*
* @param trimBox the TrimBox rectangle
* @param bleed the given bleed widths
* @return the calculated BleedBox rectangle
*/
public static Rectangle getBleedBoxRectangle(Rectangle trimBox, String bleed) {
return getRectagleUsingOffset(trimBox, bleed);
}

/**
* The MediaBox is calculated by expanding the TrimBox by the crop offsets.
*
* @param trimBox the TrimBox rectangle
* @param cropOffsets the given crop offsets
* @return the calculated MediaBox rectangle
*/
public static Rectangle getMediaBoxRectangle(Rectangle trimBox, String cropOffsets) {
return getRectagleUsingOffset(trimBox, cropOffsets);
}

/**
* The crop box controls how Acrobat display the page or how the Java2DRenderer
* sizes the output media. The PDF spec defines that the CropBox defaults to the MediaBox.
* <p/>
* The possible values of crop-box: (trim-box|bleed-box|media-box)
* Default value: media-box
*
* @param trimBox the TrimBox rectangle
* @param bleedBox the BleedBox rectangle
* @param mediaBox the MediaBox rectangle
* @param value the crop-box value
* @return the calculated CropBox rectangle
*/
public static Rectangle getCropBoxRectangle(final Rectangle trimBox, final Rectangle bleedBox,
final Rectangle mediaBox, final String value) {
final String err = "The crop-box has invalid value: {0}, "
+ "possible values of crop-box: (trim-box|bleed-box|media-box)";

if ("trim-box".equals(value)) {
return trimBox;
} else if ("bleed-box".equals(value)) {
return bleedBox;
} else if ("media-box".equals(value) || value == null || "".equals(value)) {
return mediaBox;
} else {
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{value}));
}
}

/**
* The crop box controls how Acrobat display the page or how the Java2DRenderer
* sizes the output media. The PDF spec defines that the CropBox defaults to the MediaBox
* <p/>
* The possible values of crop-box: (trim-box|bleed-box|media-box)
* Default value: media-box
*
* @param trimBox the TrimBox rectangle
* @param bleed the given bleed widths
* @param cropOffset the given crop offsets
* @param value the crop-box value
* @return the calculated CropBox rectangle
*/
public static Rectangle getCropBoxRectangle(final Rectangle trimBox, final String bleed,
final String cropOffset, final String value) {
Rectangle bleedBox = getBleedBoxRectangle(trimBox, bleed);
Rectangle mediaBox = getMediaBoxRectangle(trimBox, cropOffset);

return getCropBoxRectangle(trimBox, bleedBox, mediaBox, value);
}

private static Rectangle getRectagleUsingOffset(Rectangle originalRect, String offset) {
if (offset == null || "".equals(offset) || originalRect == null) {
return originalRect;
}

String[] bleeds = offset.split(" ");
int[] coords = new int[4]; // top, rigth, bottom, left
if (bleeds.length == 1) {
coords[0] = getLengthIntValue(bleeds[0]);
coords[1] = coords[0];
coords[2] = coords[0];
coords[3] = coords[0];
} else if (bleeds.length == 2) {
coords[0] = getLengthIntValue(bleeds[0]);
coords[2] = coords[0];
coords[1] = getLengthIntValue(bleeds[1]);
coords[3] = coords[1];
} else if (bleeds.length == 3) {
coords[0] = getLengthIntValue(bleeds[0]);
coords[1] = getLengthIntValue(bleeds[1]);
coords[3] = coords[1];
coords[2] = getLengthIntValue(bleeds[2]);
} else if (bleeds.length == 4) {
coords[0] = getLengthIntValue(bleeds[0]);
coords[1] = getLengthIntValue(bleeds[1]);
coords[2] = getLengthIntValue(bleeds[2]);
coords[3] = getLengthIntValue(bleeds[3]);
}
return new Rectangle((int) (originalRect.getX() - coords[3]),
(int) (originalRect.getY() - coords[0]),
(int) (originalRect.getWidth() + coords[3] + coords[1]),
(int) (originalRect.getHeight() + coords[0] + coords[2]));
}

private static int getLengthIntValue(final String length) {
final String err = "Incorrect length value: {0}";
Matcher m = SIZE_UNIT_PATTERN.matcher(length);

if (m.find()) {
return FixedLength.getInstance(Double.parseDouble(m.group(1)),
m.group(2)).getLength().getValue();
} else {
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{length}));
}
}
}

src/java/org/apache/fop/render/extensions/prepress/PageScaleAttributes.java → src/java/org/apache/fop/render/extensions/prepress/PageScale.java View File

@@ -21,62 +21,72 @@ package org.apache.fop.render.extensions.prepress;

import java.awt.geom.Point2D;
import java.text.MessageFormat;
import java.util.regex.Pattern;

import org.apache.xmlgraphics.util.QName;

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


/**
* This class contains definition of 'scale' FOF's extension attribute for XSL-FO, and provides
* utility method to parse the possible values of this attibute
* This class provides utility methods to parse the 'fox:scale' extension attribute.
*/
public final class PageScaleAttributes {
public final class PageScale {

/**
* The extension 'scale' attribute for simple-page-master element
* The extension 'scale' attribute for the simple-page-master element.
*/
public static final QName EXT_PAGE_SCALE
= new QName(ExtensionElementMapping.URI, null, "scale");

private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+");

/**
* Utility classes should not have a public or default constructor
*/
private PageScaleAttributes() {
private PageScale() {
}

/**
* Compute scale parameters from given fox:scale attribute which has format: scaleX [scaleY]
* If scaleY is not defined, it equals scaleX
* Compute scale parameters from given fox:scale attribute which has the format: scaleX [scaleY]
* If scaleY is not defined, it equals scaleX.
* @param scale scale attribute, input format: scaleX [scaleY]
* @return the pair of (sx, sy) values
*/
public static Point2D.Double getScaleAttributes(String scale) {
public static Point2D getScale(String scale) {
// TODO throw appropriate exceptions that can be caught by the event
// notification mechanism
final String err = "Extension 'scale' attribute has incorrect value(s): {0}";

if (scale == null) {
if (scale == null || scale.equals("")) {
return null;
}

Point2D.Double result = null;
String[] scales = WHITESPACE_PATTERN.split(scale);
double scaleX;
try {
String[] scales = scale.split(" ");
if (scales.length > 0) {
result = new Point2D.Double(Double.parseDouble(scales[0]),
Double.parseDouble(scales[0]));
}
if (scales.length > 1) {
result.y = Double.parseDouble(scales[1]);
}
if (result.x <= 0 || result.y <= 0) {
scaleX = Double.parseDouble(scales[0]);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{scale}));
}
double scaleY;
switch (scales.length) {
case 1:
scaleY = scaleX;
break;
case 2:
try {
scaleY = Double.parseDouble(scales[1]);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{scale}));
}
} catch (NumberFormatException nfe) {
break;
default:
throw new IllegalArgumentException("Too many arguments");
}
if (scaleX <= 0 || scaleY <= 0) {
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{scale}));
}

return result;
return new Point2D.Double(scaleX, scaleY);
}
}

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

@@ -24,6 +24,7 @@ import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
@@ -75,8 +76,8 @@ import org.apache.fop.fonts.Typeface;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.extensions.prepress.PageBoundariesAttributes;
import org.apache.fop.render.extensions.prepress.PageScaleAttributes;
import org.apache.fop.render.extensions.prepress.PageBoundaries;
import org.apache.fop.render.extensions.prepress.PageScale;
import org.apache.fop.render.pdf.CTMHelper;
import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.ColorUtil;
@@ -292,20 +293,10 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem

this.currentPageViewport = pageViewport;
try {
String bleed = (String) currentPageViewport.getForeignAttributes().get(
PageBoundariesAttributes.EXT_BLEED);
String cropOffset = (String) currentPageViewport.getForeignAttributes().get(
PageBoundariesAttributes.EXT_CROP_OFFSET);
String cropBoxValue = (String) currentPageViewport.getForeignAttributes().get(
PageBoundariesAttributes.EXT_CROP_BOX);
Rectangle2D bounds = PageBoundariesAttributes.getCropBoxRectangle(
pageViewport.getViewArea(),
bleed,
cropOffset,
cropBoxValue
);
Rectangle2D bleedBox = PageBoundariesAttributes.getBleedBoxRectangle(
pageViewport.getViewArea(), bleed);
PageBoundaries boundaries = new PageBoundaries(
pageViewport.getViewArea().getSize(), pageViewport.getForeignAttributes());
Rectangle bounds = boundaries.getCropBox();
Rectangle bleedBox = boundaries.getBleedBox();
this.pageWidth = (int) Math.round(bounds.getWidth() / 1000f);
this.pageHeight = (int) Math.round(bounds.getHeight() / 1000f);

@@ -318,14 +309,13 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
double scaleX = scaleFactor;
double scaleY = scaleFactor;
String scale = (String) currentPageViewport.getForeignAttributes().get(
PageScaleAttributes.EXT_PAGE_SCALE);
Point2D scales = PageScaleAttributes.getScaleAttributes(scale);
PageScale.EXT_PAGE_SCALE);
Point2D scales = PageScale.getScale(scale);
if (scales != null) {
scaleX *= scales.getX();
scaleY *= scales.getY();
}


scaleX = scaleX
* (25.4f / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION)
/ userAgent.getTargetPixelUnitToMillimeter();

+ 21
- 35
src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java View File

@@ -24,6 +24,7 @@ import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Double;
import java.io.IOException;
import java.util.Map;

@@ -40,8 +41,8 @@ import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFReference;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
import org.apache.fop.render.extensions.prepress.PageBoundariesAttributes;
import org.apache.fop.render.extensions.prepress.PageScaleAttributes;
import org.apache.fop.render.extensions.prepress.PageBoundaries;
import org.apache.fop.render.extensions.prepress.PageScale;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
@@ -171,29 +172,19 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
throws IFException {
this.pdfResources = this.pdfDoc.getResources();

String bleedWidth = (String) getContext().getForeignAttribute(
PageBoundariesAttributes.EXT_BLEED);
String cropOffset = (String) getContext().getForeignAttribute(
PageBoundariesAttributes.EXT_CROP_OFFSET);
String cropBoxValue = (String) getContext().getForeignAttribute(
PageBoundariesAttributes.EXT_CROP_BOX);
PageBoundaries boundaries = new PageBoundaries(size, getContext().getForeignAttributes());

Rectangle trimBox = new Rectangle(0, 0,
(int) size.getWidth(), (int) size.getHeight());
Rectangle bleedBox
= PageBoundariesAttributes.getBleedBoxRectangle(trimBox, bleedWidth);
Rectangle mediaBox
= PageBoundariesAttributes.getMediaBoxRectangle(trimBox, cropOffset);

Rectangle cropBox = PageBoundariesAttributes.getCropBoxRectangle(
trimBox, bleedBox, mediaBox, cropBoxValue);
Rectangle trimBox = boundaries.getTrimBox();
Rectangle bleedBox = boundaries.getBleedBox();
Rectangle mediaBox = boundaries.getMediaBox();
Rectangle cropBox = boundaries.getCropBox();

// set scale attributes
double scaleX = 1;
double scaleY = 1;
String scale = (String) getContext().getForeignAttribute(
PageScaleAttributes.EXT_PAGE_SCALE);
Point2D scales = PageScaleAttributes.getScaleAttributes(scale);
PageScale.EXT_PAGE_SCALE);
Point2D scales = PageScale.getScale(scale);
if (scales != null) {
scaleX = scales.getX();
scaleY = scales.getY();
@@ -202,22 +193,10 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
this.currentPage = this.pdfDoc.getFactory().makePage(
this.pdfResources,
index,
new Rectangle2D.Double(mediaBox.getX() * scaleX / 1000,
mediaBox.getY() * scaleY / 1000,
mediaBox.getWidth() * scaleX / 1000,
mediaBox.getHeight() * scaleY / 1000),
new Rectangle2D.Double(cropBox.getX() * scaleX / 1000,
cropBox.getY() * scaleY / 1000,
cropBox.getWidth() * scaleX / 1000,
cropBox.getHeight() * scaleY / 1000),
new Rectangle2D.Double(bleedBox.getX() * scaleX / 1000,
bleedBox.getY() * scaleY / 1000,
bleedBox.getWidth() * scaleX / 1000,
bleedBox.getHeight() * scaleY / 1000),
new Rectangle2D.Double(trimBox.getX() * scaleX / 1000,
trimBox.getY() * scaleY / 1000,
trimBox.getWidth() * scaleX / 1000,
trimBox.getHeight() * scaleY / 1000));
toPointAndScale(mediaBox, scaleX, scaleY),
toPointAndScale(cropBox, scaleX, scaleY),
toPointAndScale(bleedBox, scaleX, scaleY),
toPointAndScale(trimBox, scaleX, scaleY));

pdfUtil.generatePageLabel(index, name);

@@ -232,6 +211,13 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
generator.concatenate(basicPageTransform);
}

private Double toPointAndScale(Rectangle box, double scaleX, double scaleY) {
return new Rectangle2D.Double(box.getX() * scaleX / 1000,
box.getY() * scaleY / 1000,
box.getWidth() * scaleX / 1000,
box.getHeight() * scaleY / 1000);
}

/** {@inheritDoc} */
public IFPainter startPageContent() throws IFException {
return new PDFPainter(this);

+ 0
- 178
src/java/org/apache/fop/tools/anttasks/SerializeHyphPattern.java View File

@@ -1,178 +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.tools.anttasks;

// Java
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.List;

// Ant
import org.apache.tools.ant.Task;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.types.FileSet;

// FOP
import org.apache.fop.hyphenation.HyphenationTree;
import org.apache.fop.hyphenation.HyphenationException;

/**
* SerializeHyphPattern
*/


public class SerializeHyphPattern extends Task {
private List filesets = new java.util.ArrayList();
private File targetDir;
private boolean errorDump = false;

/**
* {@inheritDoc}
*/
public void execute() throws org.apache.tools.ant.BuildException {
// deal with the filesets
for (int i = 0; i < getFilesets().size(); i++) {
FileSet fs = (FileSet) getFilesets().get(i);
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
File basedir = ds.getBasedir();
String[] files = ds.getIncludedFiles();
for (int j = 0; j < files.length; j++) {
processFile(basedir, files[j].substring(0, files[j].length() - 4));
}
}
} // end execute


/**
* Adds a set of pattern files (nested fileset attribute).
* @param set a fileset
*/
public void addFileset(FileSet set) {
filesets.add(set);
}

/**
* Returns the current list of filesets.
* @return the filesets
*/
public List getFilesets() {
return this.filesets;
}

/**
* Sets the target directory
* @param targetDir target directory
*/
public void setTargetDir(String targetDir) {
File dir = new File(targetDir);
this.targetDir = dir;
}

/**
* Controls the amount of error information dumped.
* @param errorDump True if more error info should be provided
*/
public void setErrorDump(boolean errorDump) {
this.errorDump = errorDump;
}


/*
* checks whether input or output files exists or the latter is older than input file
* and start build if necessary
*/
private void processFile(File basedir, String filename) {
File infile = new File(basedir, filename + ".xml");
File outfile = new File(targetDir, filename + ".hyp");
//long outfileLastModified = outfile.lastModified();
boolean startProcess = true;

startProcess = rebuild(infile, outfile);
if (startProcess) {
buildPatternFile(infile, outfile);
}
}

/*
* serializes pattern files
*/
private void buildPatternFile(File infile, File outfile) {
System.out.println("Processing " + infile);
HyphenationTree hTree = new HyphenationTree();
try {
hTree.loadPatterns(infile.toString());
if (errorDump) {
System.out.println("Stats: ");
hTree.printStats();
}
} catch (HyphenationException ex) {
System.err.println("Can't load patterns from xml file " + infile
+ " - Maybe hyphenation.dtd is missing?");
if (errorDump) {
System.err.println(ex.toString());
}
}
// serialize class
try {
ObjectOutputStream out = new ObjectOutputStream(
new java.io.BufferedOutputStream(
new java.io.FileOutputStream(outfile)));
out.writeObject(hTree);
out.close();
} catch (IOException ioe) {
System.err.println("Can't write compiled pattern file: "
+ outfile);
System.err.println(ioe);
}
}

/**
* Checks for existence of output file and compares
* dates with input and stylesheet file
*/
private boolean rebuild(File infile, File outfile) {
if (outfile.exists()) {
// checks whether output file is older than input file
if (outfile.lastModified() < infile.lastModified()) {
return true;
}
} else {
// if output file does not exist, start process
return true;
}
return false;
} // end rebuild

/*
* //quick access for debugging
* public static void main (String args[]) {
* SerializeHyphPattern ser = new SerializeHyphPattern();
* FileSet set = new FileSet();
* set.setDir(new File("src/hyph"));
* set.setIncludes("*.xml");
* ser.addFileset(set);
* ser.setTargetDir("build/hyph");
* ser.execute();
* }
*/


}

+ 39
- 42
src/sandbox/org/apache/fop/render/svg/SVGDocumentHandler.java View File

@@ -22,9 +22,6 @@ package org.apache.fop.render.svg;
import java.awt.Dimension;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -66,6 +63,9 @@ public class SVGDocumentHandler extends AbstractSVGDocumentHandler {
private StreamResult firstStream;
private StreamResult currentStream;

/** Used for single-page documents rendered to a DOM or SAX. */
private Result simpleResult;

private Document reusedParts;

/**
@@ -92,7 +92,7 @@ public class SVGDocumentHandler extends AbstractSVGDocumentHandler {
getUserAgent().getOutputFile());
this.firstStream = (StreamResult)result;
} else {
throw new UnsupportedOperationException("Result is not supported: " + result);
this.simpleResult = result;
}
}

@@ -152,46 +152,19 @@ public class SVGDocumentHandler extends AbstractSVGDocumentHandler {
/** {@inheritDoc} */
public void startPage(int index, String name, String pageMasterName, Dimension size)
throws IFException {
OutputStream out;
try {
if (index == 0) {
out = null;
} else {
out = this.multiFileUtil.createOutputStream(index);
if (out == null) {
//TODO Convert to event
throw new IFException(
"No filename information available. Stopping after first page.", null);
}
}
} catch (IOException ioe) {
throw new IFException("I/O exception while setting up output file", ioe);
}
if (out == null) {
this.handler = decorate(createContentHandler(this.firstStream));
if (this.multiFileUtil != null) {
prepareHandlerWithOutputStream(index);
} else {
this.currentStream = new StreamResult(out);
this.handler = decorate(createContentHandler(this.currentStream));
}
if (false) {
final ContentHandler originalHandler = this.handler;
this.handler = decorate((ContentHandler)Proxy.newProxyInstance(
ContentHandler.class.getClassLoader(),
new Class[] {ContentHandler.class},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
System.out.println(methodName + ":");
if (args != null) {
for (int i = 0; i < args.length; i++) {
System.out.println(" " + args[i]);
}
}
return method.invoke(originalHandler, args);
}
}));
if (this.simpleResult == null) {
//Only one page is supported with this approach at the moment
throw new IFException(
"Only one page is supported for output with the given Result instance!",
null);
}
super.setResult(this.simpleResult);
this.simpleResult = null;
}

try {
handler.startDocument();
handler.startPrefixMapping("", NAMESPACE);
@@ -227,6 +200,30 @@ public class SVGDocumentHandler extends AbstractSVGDocumentHandler {
}
}

private void prepareHandlerWithOutputStream(int index) throws IFException {
OutputStream out;
try {
if (index == 0) {
out = null;
} else {
out = this.multiFileUtil.createOutputStream(index);
if (out == null) {
//TODO Convert to event
throw new IFException(
"No filename information available. Stopping after first page.", null);
}
}
} catch (IOException ioe) {
throw new IFException("I/O exception while setting up output file", ioe);
}
if (out == null) {
this.handler = decorate(createContentHandler(this.firstStream));
} else {
this.currentStream = new StreamResult(out);
this.handler = decorate(createContentHandler(this.currentStream));
}
}

private GenerationHelperContentHandler decorate(ContentHandler contentHandler) {
return new GenerationHelperContentHandler(contentHandler, getMainNamespace());
}

+ 17
- 0
status.xml View File

@@ -58,6 +58,23 @@
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
<action context="Renderers" dev="AD" type="add" fixes-bug="46905">
Added basic implementation for column-keeps.
</action>
<action context="Renderers" dev="AD" type="fix" fixes-bug="46883">
Hotspot in AbstractGraphicsDrawingOrderContainer. Reduced time spent in the method
by introducing a member variable to hold the data-length.
</action>
<action context="Code" dev="AD" type="fix" fixes-bug="47710">
White-space handling in markers with inline-content throws a NullPointerException
in some cases.
</action>
<action context="Renderers" dev="CB" type="fix" fixes-bug="47694">
Dithered Background Shading can produce illegal AFP if objects are very small
</action>
<action context="Renderers" dev="CB" type="add">
AFP Output: Added support for IMM Extension on fo:simple-page-master.
</action>
<action context="Renderers" dev="JM" type="add" fixes-bug="47311" due-to="Peter Coppens">
Added an initial set of extensions for prepress support (fox:bleed, fox:crop-offset,
fox:crop-box and fox:scale). This is currently supported only by PDF and Java2D renderers.

+ 4
- 2
test/java/org/apache/fop/StandardTestSuite.java View File

@@ -26,12 +26,13 @@ import org.apache.fop.fonts.TrueTypeAnsiTestCase;
import org.apache.fop.image.loader.batik.ImageLoaderTestCase;
import org.apache.fop.image.loader.batik.ImagePreloaderTestCase;
import org.apache.fop.intermediate.IFMimickingTestCase;
import org.apache.fop.render.extensions.prepress.PageBoundariesTest;
import org.apache.fop.render.extensions.prepress.PageScaleTest;
import org.apache.fop.render.pdf.PDFAConformanceTestCase;
import org.apache.fop.render.pdf.PDFCMapTestCase;
import org.apache.fop.render.pdf.PDFEncodingTestCase;
import org.apache.fop.render.pdf.PDFsRGBSettingsTestCase;
import org.apache.fop.render.rtf.RichTextFormatTestSuite;
import org.apache.fop.render.extensions.PrepressTest;

/**
* Test suite for basic functionality of FOP.
@@ -57,7 +58,8 @@ public class StandardTestSuite {
suite.addTest(new TestSuite(ImageLoaderTestCase.class));
suite.addTest(new TestSuite(ImagePreloaderTestCase.class));
suite.addTest(new TestSuite(IFMimickingTestCase.class));
suite.addTest(new TestSuite(PrepressTest.class));
suite.addTest(new TestSuite(PageBoundariesTest.class));
suite.addTest(new TestSuite(PageScaleTest.class));
//$JUnit-END$
return suite;
}

+ 0
- 129
test/java/org/apache/fop/render/extensions/PrepressTest.java View File

@@ -1,129 +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.extensions;

import java.awt.Rectangle;
import java.awt.geom.Point2D;

import junit.framework.TestCase;

import org.apache.fop.render.extensions.prepress.PageBoundariesAttributes;
import org.apache.fop.render.extensions.prepress.PageScaleAttributes;

/**
* Base class for automated tests for
* {@link org.apache.fop.render.extensions.prepress.PageBoundariesAttributes}
* and
* {@link org.apache.fop.render.extensions.prepress.PageScaleAttributes}
*/
public class PrepressTest extends TestCase {

private static final int W = 20000;
private static final int H = 15000;
private static final Rectangle TEST_AREA = new Rectangle(0, 0, W, H);
private static final String BLEED1 = "5pt";
private static final String CROP_OFFSET1 = "8pt";

/**
* Main constructor
* @param name the name of the test case
*/
public PrepressTest(String name) {
super(name);
}

/**
* Tests for 'scale' extension attribute
*/
public void testScaleOk() throws Exception {
Point2D res = PageScaleAttributes.getScaleAttributes("0.5");
assertEquals("Points should be equal", res.getX(), res.getY(), 0);
}

public void testScaleFailIllArgExc() throws Exception {
try {
Point2D res = PageScaleAttributes.getScaleAttributes("0.5mm 0.5cm");
fail("Expected IllegalArgumentException. Scale shouldn't contain units");
} catch (IllegalArgumentException iae) {
// Good!
}
}

public void testScaleNotEqual() throws Exception {
Point2D res = PageScaleAttributes.getScaleAttributes("0.5 0.6");
assertFalse("Points shouldn't be equal", res.getX() == res.getY());
}

public void testScaleNull() throws Exception {
Point2D res = PageScaleAttributes.getScaleAttributes(null);
assertNull("Result shouldn't be null", res);
}

/**
* Tests for page boundaries
*/
public void testBoxOk1() throws Exception {
Rectangle res = PageBoundariesAttributes.getBleedBoxRectangle(TEST_AREA, null);
assertSame("Result should be the same as TEST_AREA object", res, TEST_AREA);

res = PageBoundariesAttributes.getBleedBoxRectangle(null, BLEED1);
assertNull(res);
}

public void testBoxOk2() throws Exception {
Rectangle res1 = PageBoundariesAttributes.getBleedBoxRectangle(TEST_AREA, BLEED1);
assertNotNull("Expected not null object", res1);
assertEquals(-5000, res1.getX(), 1);
assertEquals(-5000, res1.getY(), 1);
assertEquals(30000, res1.getWidth(), 1);
assertEquals(25000, res1.getHeight(), 1);

Rectangle res2 = PageBoundariesAttributes.getMediaBoxRectangle(TEST_AREA, CROP_OFFSET1);
assertNotNull("Expected not null object", res2);
assertEquals(-8000, res2.getX(), 1);
assertEquals(-8000, res2.getY(), 1);
assertEquals(36000, res2.getWidth(), 1);
assertEquals(31000, res2.getHeight(), 1);

Rectangle res3 = PageBoundariesAttributes.getCropBoxRectangle(
TEST_AREA, res1, res2, "media-box");
assertNotNull("Expected not null object", res3);
assertEquals(res3, res2);

res3 = PageBoundariesAttributes.getCropBoxRectangle(
TEST_AREA, res1, res2, "bleed-box");
assertNotNull("Expected not null object", res3);
assertEquals(res3, res1);

res3 = PageBoundariesAttributes.getCropBoxRectangle(
TEST_AREA, res1, res2, "trim-box");
assertNotNull("Expected not null object", res3);
assertEquals(res3, TEST_AREA);
}

public void testBoxIllArgExc() throws Exception {
try {
Rectangle res = PageBoundariesAttributes.getBleedBoxRectangle(TEST_AREA, "0");
fail("Expected IllegalArgumentException. Box should have units");
} catch (IllegalArgumentException iae) {
// Good!
}
}
}

+ 176
- 0
test/java/org/apache/fop/render/extensions/prepress/PageBoundariesTest.java View File

@@ -0,0 +1,176 @@
/*
* 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.extensions.prepress;

import java.awt.Dimension;
import java.awt.Rectangle;

import junit.framework.TestCase;

/**
* Tests for the fox:bleed, fox:crop-offset, fox:crop-box extension properties.
*/
public class PageBoundariesTest extends TestCase {

private static final Dimension TEST_AREA_SIZE = new Dimension(20000, 15000);

private static final Rectangle TEST_AREA = new Rectangle(TEST_AREA_SIZE);

private static final String BLEED = "5pt";

private static final String CROP_OFFSET = "8pt";

/**
* Default constructor.
*/
public PageBoundariesTest() {
}

/**
* Creates a test case with the given name.
*
* @param name name for the test case
*/
public PageBoundariesTest(String name) {
super(name);
}

/** Test for page boundaries. */
public void testBoundaries1() {
PageBoundaries boundaries = new PageBoundaries(TEST_AREA_SIZE, BLEED, CROP_OFFSET, null);
assertEquals(TEST_AREA, boundaries.getTrimBox());

Rectangle bleedBox = boundaries.getBleedBox();
assertNotNull("Expected not null object", bleedBox);
assertEquals(-5000, bleedBox.x);
assertEquals(-5000, bleedBox.y);
assertEquals(30000, bleedBox.width);
assertEquals(25000, bleedBox.height);

Rectangle mediaBox = boundaries.getMediaBox();
assertNotNull("Expected not null object", mediaBox);
assertEquals(-8000, mediaBox.x);
assertEquals(-8000, mediaBox.y);
assertEquals(36000, mediaBox.width);
assertEquals(31000, mediaBox.height);
}

/** Test for page boundaries. */
public void testBoundaries2() {
PageBoundaries boundaries = new PageBoundaries(
TEST_AREA_SIZE, BLEED, null, null);
Rectangle bleedBox = boundaries.getBleedBox();
assertNotNull("Expected not null object", bleedBox);
assertEquals(-5000, bleedBox.x);
assertEquals(-5000, bleedBox.y);
assertEquals(30000, bleedBox.width);
assertEquals(25000, bleedBox.height);
assertEquals(bleedBox, boundaries.getMediaBox());
}

/** Two values for the properties. */
public void testBoundaries2Values() {
PageBoundaries boundaries = new PageBoundaries(
TEST_AREA_SIZE, "5pt 10pt", "6pt \t 12pt", null);
Rectangle bleedBox = boundaries.getBleedBox();
assertEquals(-10000, bleedBox.x);
assertEquals(-5000, bleedBox.y);
assertEquals(40000, bleedBox.width);
assertEquals(25000, bleedBox.height);

Rectangle mediaBox = boundaries.getMediaBox();
assertEquals(-12000, mediaBox.x);
assertEquals(-6000, mediaBox.y);
assertEquals(44000, mediaBox.width);
assertEquals(27000, mediaBox.height);
}

/** Three values for the properties. */
public void testBoundaries3Values() {
PageBoundaries boundaries = new PageBoundaries(
TEST_AREA_SIZE, "5pt 10pt 7pt", "6pt \t 12pt 14pt", null);
Rectangle bleedBox = boundaries.getBleedBox();
assertEquals(-10000, bleedBox.x);
assertEquals(-5000, bleedBox.y);
assertEquals(40000, bleedBox.width);
assertEquals(27000, bleedBox.height);

Rectangle mediaBox = boundaries.getMediaBox();
assertEquals(-12000, mediaBox.x);
assertEquals(-6000, mediaBox.y);
assertEquals(44000, mediaBox.width);
assertEquals(35000, mediaBox.height);
}

/** Four values for the properties. */
public void testBoundaries4Values() {
PageBoundaries boundaries = new PageBoundaries(
TEST_AREA_SIZE, "5pt 6pt 7pt 8pt", "9pt 10pt 11pt 12pt", null);
Rectangle bleedBox = boundaries.getBleedBox();
assertEquals(-8000, bleedBox.x);
assertEquals(-5000, bleedBox.y);
assertEquals(34000, bleedBox.width);
assertEquals(27000, bleedBox.height);

Rectangle mediaBox = boundaries.getMediaBox();
assertEquals(-12000, mediaBox.x);
assertEquals(-9000, mediaBox.y);
assertEquals(42000, mediaBox.width);
assertEquals(35000, mediaBox.height);
}

/** Test for the different values of crop-box. */
public void testCropBox() {
PageBoundaries boundaries = new PageBoundaries(TEST_AREA_SIZE, BLEED, CROP_OFFSET, null);
assertEquals(boundaries.getMediaBox(), boundaries.getCropBox());

boundaries = new PageBoundaries(TEST_AREA_SIZE, BLEED, CROP_OFFSET, "");
assertEquals(boundaries.getMediaBox(), boundaries.getCropBox());

boundaries = new PageBoundaries(TEST_AREA_SIZE, BLEED, CROP_OFFSET, "trim-box");
assertEquals(TEST_AREA, boundaries.getCropBox());

boundaries = new PageBoundaries(TEST_AREA_SIZE, BLEED, CROP_OFFSET, "bleed-box");
assertEquals(boundaries.getBleedBox(), boundaries.getCropBox());

boundaries = new PageBoundaries(TEST_AREA_SIZE, BLEED, CROP_OFFSET, "media-box");
assertEquals(boundaries.getMediaBox(), boundaries.getCropBox());
}

/** Test for default values returned when properties are null. */
public void testBoundariesNull() {
PageBoundaries b = new PageBoundaries(TEST_AREA_SIZE, null, null, null);

assertEquals("Result should be the same as TEST_AREA object", b.getTrimBox(), TEST_AREA);
assertEquals("Result should be the same as TEST_AREA object", b.getBleedBox(), TEST_AREA);
assertEquals("Result should be the same as TEST_AREA object", b.getMediaBox(), TEST_AREA);
assertEquals("Result should be the same as TEST_AREA object", b.getCropBox(), TEST_AREA);
}

/** Units must be specified. */
public void testBoundariesFail() {
try {
new PageBoundaries(TEST_AREA_SIZE, "0", null, null);
fail("Expected IllegalArgumentException. Box should have units");
} catch (IllegalArgumentException iae) {
// Good!
}
}
}

+ 79
- 0
test/java/org/apache/fop/render/extensions/prepress/PageScaleTest.java View File

@@ -0,0 +1,79 @@
/*
* 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.extensions.prepress;

import java.awt.geom.Point2D;

import junit.framework.TestCase;

/**
* Tests for the fox:scale extension property.
*/
public class PageScaleTest extends TestCase {

/**
* Default constructor.
*/
public PageScaleTest() {
super();
}

/**
* Creates a test case with the given name.
*
* @param name name for the test case
*/
public PageScaleTest(String name) {
super(name);
}

/** 1 value is used for both x and y. */
public void testScale1() {
Point2D res = PageScale.getScale(".5");
assertEquals(0.5, res.getX(), 0.0);
assertEquals(0.5, res.getY(), 0.0);
}

/** Two values, used resp. for x and y. */
public void testScale2() {
Point2D res = PageScale.getScale("1. \t \n 1.2");
assertEquals(1.0, res.getX(), 0.0);
assertEquals(1.2, res.getY(), 0.0);
}

/** Scale must not contain units. */
public void testScaleFail() {
try {
PageScale.getScale("0.5mm 0.5cm");
fail("Expected IllegalArgumentException. Scale shouldn't contain units");
} catch (IllegalArgumentException iae) {
// Good!
}
}

/** @{code null} is returned when scale is unspecified. */
public void testScaleNull() {
Point2D res = PageScale.getScale(null);
assertNull("Result should be null", res);
res = PageScale.getScale("");
assertNull("Result should be null", res);
}

}

+ 6
- 0
test/layoutengine/disabled-testcases.xml View File

@@ -216,4 +216,10 @@
<description>A soft hyphen should be a preferred as break compared to a
normal hyphenation point but is not.</description>
</testcase>
<testcase>
<name>Page-keep not respected in multi-column layout</name>
<file>keep_within-page_multi-column_overflow.xml</file>
<description>The block should cause overflow in the
last column on the page, rather than be broken.</description>
</testcase>
</disabled-testcases>

+ 3
- 4
test/layoutengine/standard-testcases/inline_block_nested_6.xml View File

@@ -52,16 +52,15 @@
<skip>5</skip>
<!-- penalty between blocks b11 and b12, set by InlineLM in b1 -->
<penalty w="0" p="0"/>
<skip>6</skip>
<skip>5</skip>
<!-- penalty between blocks b21 and b22, set by InlineLM in b2 -->
<!-- keep-together.within-page="always" -->
<penalty w="0" p="1000"/>
<skip>6</skip>
<skip>3</skip>
<!-- penalty between blocks b31 and b32, set by InlineLM in b3 -->
<!-- keep-with-next.within-page="always" -->
<penalty w="0" p="1000"/>
<skip>5</skip>
<skip>3</skip>
<skip>14</skip>
</element-list>
</checks>
</testcase>

+ 155
- 0
test/layoutengine/standard-testcases/keep_within-column_basic.xml View File

@@ -0,0 +1,155 @@
<?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 whether keeps within-column are respected.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page" page-width="400pt" page-height="70pt">
<fo:region-body column-count="5" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" font-size="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block break-before="page">
<!-- simple test: keep the second block together within
one column, breaking the preceding block early
if necessary -->
<fo:block id="block-1">
[BOB-1] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-1]
</fo:block>
<fo:block id="block-2" keep-together.within-column="always">
[BOB-2] foo bar foo bar foo bar foo bar foo [EOB-2]
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- same as the first, but now a nested block
with a higher integer value, and some content
following -->
<fo:block id="block-3" keep-together.within-column="5">
[BOB-3] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
<fo:block font-weight="bold" id="block-3a" keep-together.within-column="always">
[BOB-3a] foo bar foo bar foo bar foo bar foo [EOB-3a]
</fo:block>
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-3]
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- nested block must be kept together within the same
page, while the outer block may be broken, if necessary -->
<fo:block font-style="italic" id="block-4" keep-together.within-column="5">
[BOB-4] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
<fo:block id="block-4a" keep-together.within-page="always">
[BOB-4a] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-4a]
</fo:block>
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-4]
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- test keep-with-next in conjunction with keep-together
respecting the default value for widows/orphans -->
<fo:block id="block-5">
<fo:block id="block-5a">
[BOB-5a] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-5a]
</fo:block>
<fo:block id="block-5b" keep-with-next.within-column="always">
[BOB-5b] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-5b]
</fo:block>
<fo:block id="block-5c" keep-together.within-column="always">
[BOB-5c] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-5c]
</fo:block>
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- test keep-together in conjunction with keep-with-previous -->
<fo:block id="block-6">
<fo:block id="block-6a">
[BOB-6a] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-6a]
</fo:block>
<fo:block id="block-6b" keep-together.within-column="always">
[BOB-6b] foo bar foo bar foo bar foo bar foo bar [EOB-6b]
</fo:block>
<fo:block id="block-6c" keep-with-previous.within-column="always">
[BOB-6c] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-6c]
</fo:block>
</fo:block>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<!-- check total page-count -->
<eval expected="10" xpath="count(//page)" />
<!-- block-2 should end up in its own column, column 4 -->
<eval expected="1" xpath="count(//block[@prod-id='block-2']/ancestor::flow)" />
<eval expected="3" xpath="count(//block[@prod-id='block-2']/ancestor::flow/preceding-sibling::flow)" />
<!-- block-3a should end up in its own column, column 5 -->
<eval expected="1" xpath="count(//block[@prod-id='block-3a']/ancestor::flow)" />
<eval expected="4" xpath="count(//block[@prod-id='block-3a']/ancestor::flow/preceding-sibling::flow)" />
<!-- block-4a should end up in its own page -->
<eval expected="1" xpath="count(//block[@prod-id='block-4a']/ancestor::page)" />
<!-- block 5c should end up in its own column, with two preceding lines from block 5b -->
<eval expected="1" xpath="count(//block[@prod-id='block-5c']/ancestor::flow)" />
<eval expected="2" xpath="count(//block[@prod-id='block-5c']/preceding-sibling::block/lineArea)" />
<!-- block 6b should end up in its own column, with two following lines from block 6c -->
<eval expected="1" xpath="count(//block[@prod-id='block-6b']/ancestor::flow)" />
<eval expected="2" xpath="count(//block[@prod-id='block-6b']/following-sibling::block/lineArea)" />
</checks>
</testcase>


+ 58
- 0
test/layoutengine/standard-testcases/keep_within-page_multi-column_overflow.xml View File

@@ -0,0 +1,58 @@
<?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 for a remaining issue after adding support
for keep-*.within column (see Bugzilla 46905).
keep-together.within-page does not work as expected in multi-column
layout. If the part does not fit into one page, it will ultimately
still be broken.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page" page-width="400pt" page-height="70pt">
<fo:region-body column-count="5" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" font-size="10pt">
<fo:flow flow-name="xsl-region-body">
<!-- block must be kept together within the same page -->
<fo:block id="block-4a" keep-together.within-page="always">
[BOB-4a] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-4a]
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="1" xpath="count(//pageViewport)" />
</checks>
</testcase>

+ 77
- 0
test/layoutengine/standard-testcases/marker_white-space_npe.xml View File

@@ -0,0 +1,77 @@
<?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 for a potential NPE after white-space handling
for retrieved markers with only inline content.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master margin-right="6mm" margin-left="7mm" margin-bottom="4mm" margin-top="5mm" page-width="210mm" page-height="297mm" master-name="letterPageFront">
<fo:region-body margin-right="59mm" margin-left="8mm" margin-top="53mm" margin-bottom="57mm" region-name="letterPageBody"/>
<fo:region-after precedence="false" extent="52mm" region-name="letterPageFooter"/>
<fo:region-end precedence="true" extent="49mm" region-name="letterPageSidebar"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence initial-page-number="1" page-break-before="right" master-reference="letterPageFront">
<fo:flow flow-name="letterPageBody">
<fo:block>page 1</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="letterPageFront">
<fo:static-content flow-name="letterPageFooter">
<fo:block text-align="right" margin-right="1cm" margin-left="8mm">
<fo:retrieve-marker retrieve-position="last-ending-within-page" retrieve-boundary="page-sequence" retrieve-class-name="statementFooterMarker"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="letterPageBody">
<fo:block>
<fo:block font="bold 16pt Arial">
<fo:block>
<fo:marker marker-class-name="statementFooterMarker">
<fo:inline font-family="HelveticaNeue-LightCond" font-size="11pt" line-height="13pt" text-align="right">Test Marker</fo:inline>
</fo:marker>
</fo:block>
</fo:block>
<fo:block break-before="page">
<fo:block>
<fo:marker marker-class-name="statementFooterMarker"/>
</fo:block>
</fo:block>
</fo:block>
<fo:block id="TH_LastPage"/>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="letterPageFront">
<fo:static-content flow-name="letterPageSidebar">
<fo:block-container height="284mm">
<fo:block> </fo:block>
</fo:block-container>
</fo:static-content>
<fo:flow break-before="odd-page" flow-name="letterPageBody">
<fo:block>last page</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks /><!-- none except the default; simply check for non-occurrence of NPE -->
</testcase>

+ 3
- 3
test/layoutengine/standard-testcases/table-row_keep-together.xml View File

@@ -64,10 +64,10 @@
<element-list category="breaker" index="0">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="28800"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<skip>3</skip>
<penalty w="0" p="INF"/>
<box w="14400"/>
<skip>5</skip>
</element-list>
</checks>
</testcase>

+ 3
- 1
test/layoutengine/standard-testcases/table_keep-together.xml View File

@@ -101,7 +101,9 @@
<element-list category="breaker" index="0">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="28800"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="0"/>

Loading…
Cancel
Save