git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ChangingIPDHack@808127 13f79535-47bb-0310-9956-ffa450edef68Temp_ChangingIPDHack
@@ -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 |
@@ -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"> |
@@ -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"> </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"> </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"> </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] <integer> values are not supported.</li> | |||
<li>[Trunk] minimal support for <integer> value.</li> | |||
</ul> |
@@ -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: <number>{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: <length>{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: <length>{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> |
@@ -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"> |
@@ -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); |
@@ -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"); |
@@ -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} */ |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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) |
@@ -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; | |||
} | |||
/** |
@@ -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; | |||
} | |||
/** |
@@ -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(); | |||
} | |||
} | |||
} | |||
} |
@@ -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])); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
/** |
@@ -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} */ |
@@ -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(); | |||
} |
@@ -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(); | |||
} | |||
/** |
@@ -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); |
@@ -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); | |||
} |
@@ -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} */ |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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" : "") + "]"; | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
@@ -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; |
@@ -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. |
@@ -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; | |||
} | |||
} |
@@ -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 |
@@ -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} */ |
@@ -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; | |||
} | |||
} |
@@ -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} */ |
@@ -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() { |
@@ -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(); |
@@ -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()); | |||
*/ | |||
} | |||
} | |||
} |
@@ -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()); |
@@ -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 --------- // |
@@ -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(); | |||
} |
@@ -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 --------- // |
@@ -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)); | |||
} |
@@ -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; |
@@ -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); | |||
} | |||
} | |||
} | |||
} |
@@ -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"); | |||
} |
@@ -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(); |
@@ -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})); | |||
} | |||
} | |||
} |
@@ -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})); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); |
@@ -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); |
@@ -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(); | |||
* } | |||
*/ | |||
} |
@@ -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()); | |||
} |
@@ -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. |
@@ -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; | |||
} |
@@ -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! | |||
} | |||
} | |||
} |
@@ -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! | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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> |
@@ -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> |
@@ -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> | |||
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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"/> |