1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873 |
- <?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 Bug 39414 - Index overflow on long texts
- </p>
- </info>
- <fo>
- <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
- <fo:layout-master-set>
- <fo:simple-page-master master-name="normal" page-width="10in" page-height="5in">
- <fo:region-body/>
- </fo:simple-page-master>
- </fo:layout-master-set>
- <fo:page-sequence master-reference="normal" white-space-collapse="true">
- <fo:flow flow-name="xsl-region-body">
- <fo:block font-family="monospace" font-size="8pt" white-space="pre"><![CDATA[
- /*
- * Copyright 1999-2006 The Apache Software Foundation.
- *
- * Licensed 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.inline;
-
- import org.apache.fop.datatypes.Length;
- import org.apache.fop.datatypes.Numeric;
- import org.apache.fop.fo.Constants;
- import org.apache.fop.fo.FONode;
- import org.apache.fop.fo.flow.Block;
- import org.apache.fop.fo.properties.CommonHyphenation;
- import org.apache.fop.hyphenation.Hyphenation;
- import org.apache.fop.hyphenation.Hyphenator;
- import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
- 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.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.KnuthPossPosIter;
- import org.apache.fop.layoutmgr.KnuthSequence;
- import org.apache.fop.layoutmgr.LayoutContext;
- import org.apache.fop.layoutmgr.LayoutManager;
- import org.apache.fop.layoutmgr.LeafPosition;
- import org.apache.fop.layoutmgr.ListElement;
- import org.apache.fop.layoutmgr.NonLeafPosition;
- import org.apache.fop.layoutmgr.Position;
- import org.apache.fop.layoutmgr.PositionIterator;
- import org.apache.fop.layoutmgr.SpaceSpecifier;
- import org.apache.fop.area.Area;
- import org.apache.fop.area.LineArea;
- import org.apache.fop.area.inline.InlineArea;
-
- import java.util.ListIterator;
- import java.util.List;
- import java.util.ArrayList;
- import java.util.LinkedList;
- import org.apache.fop.area.Trait;
- import org.apache.fop.fonts.Font;
-
- import org.apache.fop.traits.MinOptMax;
-
- /**
- * LayoutManager for lines. It builds one or more lines containing
- * inline areas generated by its sub layout managers.
- * A break is found for each line which may contain one of more
- * breaks from the child layout managers.
- * Once a break is found then it is return for the parent layout
- * manager to handle.
- * When the areas are being added to the page this manager
- * creates a line area to contain the inline areas added by the
- * child layout managers.
- */
- public class LineLayoutManager extends InlineStackingLayoutManager
- implements BlockLevelLayoutManager {
-
- private Block fobj;
- private boolean isFirstInBlock;
-
- /** @see org.apache.fop.layoutmgr.LayoutManager#initialize() */
- public void initialize() {
- textAlignment = fobj.getTextAlign();
- textAlignmentLast = fobj.getTextAlignLast();
- textIndent = fobj.getTextIndent();
- lastLineEndIndent = fobj.getLastLineEndIndent();
- hyphenationProperties = fobj.getCommonHyphenation();
- hyphenationLadderCount = fobj.getHyphenationLadderCount();
- wrapOption = fobj.getWrapOption();
- whiteSpaceTreament = fobj.getWhitespaceTreatment();
- //
- effectiveAlignment = getEffectiveAlignment(textAlignment, textAlignmentLast);
- isFirstInBlock = (this == getParent().getChildLMs().get(0));
- }
-
- private int getEffectiveAlignment(int alignment, int alignmentLast) {
- if (textAlignment != EN_JUSTIFY && textAlignmentLast == EN_JUSTIFY) {
- return 0;
- } else {
- return textAlignment;
- }
- }
-
- /**
- * Private class to store information about inline breaks.
- * Each value holds the start and end indexes into a List of
- * inline break positions.
- */
- private static class LineBreakPosition extends LeafPosition {
- private int iParIndex; // index of the Paragraph this Position refers to
- private int iStartIndex; //index of the first element this Position refers to
- private int availableShrink;
- private int availableStretch;
- private int difference;
- private double dAdjust; // Percentage to adjust (stretch or shrink)
- private double ipdAdjust; // Percentage to adjust (stretch or shrink)
- private int startIndent;
- private int lineHeight;
- private int lineWidth;
- private int spaceBefore;
- private int spaceAfter;
- private int baseline;
-
- LineBreakPosition(LayoutManager lm, int index, int iStartIndex, int iBreakIndex,
- int shrink, int stretch, int diff,
- double ipdA, double adjust, int ind,
- int lh, int lw, int sb, int sa, int bl) {
- super(lm, iBreakIndex);
- availableShrink = shrink;
- availableStretch = stretch;
- difference = diff;
- iParIndex = index;
- this.iStartIndex = iStartIndex;
- ipdAdjust = ipdA;
- dAdjust = adjust;
- startIndent = ind;
- lineHeight = lh;
- lineWidth = lw;
- spaceBefore = sb;
- spaceAfter = sa;
- baseline = bl;
- }
-
- }
-
-
- private int textAlignment = EN_JUSTIFY;
- private int textAlignmentLast;
- private int effectiveAlignment;
- private Length textIndent;
- private Length lastLineEndIndent;
- private CommonHyphenation hyphenationProperties;
- private Numeric hyphenationLadderCount;
- private int wrapOption = EN_WRAP;
- private int whiteSpaceTreament;
- //private LayoutProps layoutProps;
-
- private Length lineHeight;
- private int lead;
- private int follow;
- private AlignmentContext alignmentContext = null;
-
- private List knuthParagraphs = null;
- private int iReturnedLBP = 0;
-
- // parameters of Knuth's algorithm:
- // penalty value for flagged penalties
- private int flaggedPenalty = 50;
-
- private LineLayoutPossibilities lineLayouts;
- private List lineLayoutsList;
- private int iLineWidth = 0;
-
- /**
- * this constant is used to create elements when text-align is center:
- * every TextLM descendant of LineLM must use the same value,
- * otherwise the line breaking algorithm does not find the right
- * break point
- */
- public static final int DEFAULT_SPACE_WIDTH = 3336;
-
-
- /**
- * This class is used to remember
- * which was the first element in the paragraph
- * returned by each LM.
- */
- private class Update {
- private InlineLevelLayoutManager inlineLM;
- private int iFirstIndex;
-
- public Update(InlineLevelLayoutManager lm, int index) {
- inlineLM = lm;
- iFirstIndex = index;
- }
- }
-
- // this class represents a paragraph
- private class Paragraph extends InlineKnuthSequence {
- /** Number of elements to ignore at the beginning of the list. */
- private int ignoreAtStart = 0;
- /** Number of elements to ignore at the end of the list. */
- private int ignoreAtEnd = 0;
-
- // space at the end of the last line (in millipoints)
- private MinOptMax lineFiller;
- private int textAlignment;
- private int textAlignmentLast;
- private int textIndent;
- private int lastLineEndIndent;
- private int lineWidth;
- // the LM which created the paragraph
- private LineLayoutManager layoutManager;
-
- public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
- int indent, int endIndent) {
- super();
- layoutManager = llm;
- textAlignment = alignment;
- textAlignmentLast = alignmentLast;
- textIndent = indent;
- lastLineEndIndent = endIndent;
- }
-
- public void startParagraph(int lw) {
- lineWidth = lw;
- startSequence();
- }
-
- public void startSequence() {
- // set the minimum amount of empty space at the end of the
- // last line
- if (textAlignment == EN_CENTER) {
- lineFiller = new MinOptMax(lastLineEndIndent);
- } else {
- lineFiller = new MinOptMax(lastLineEndIndent, lastLineEndIndent, lineWidth);
- }
-
- // add auxiliary elements at the beginning of the paragraph
- if (textAlignment == EN_CENTER && textAlignmentLast != EN_JUSTIFY) {
- this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
- null, false));
- ignoreAtStart++;
- }
-
- // add the element representing text indentation
- // at the beginning of the first paragraph
- if (isFirstInBlock && knuthParagraphs.size() == 0
- && textIndent != 0) {
- this.add(new KnuthInlineBox(textIndent, null,
- null, false));
- ignoreAtStart++;
- }
- }
-
- public void endParagraph() {
- KnuthSequence finishedPar = this.endSequence();
- if (finishedPar != null) {
- knuthParagraphs.add(finishedPar);
- }
- }
-
- public KnuthSequence endSequence() {
- if (this.size() > ignoreAtStart) {
- if (textAlignment == EN_CENTER
- && textAlignmentLast != EN_JUSTIFY) {
- this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
- null, false));
- this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE,
- false, null, false));
- ignoreAtEnd = 2;
- } else if (textAlignmentLast != EN_JUSTIFY) {
- // add the elements representing the space
- // at the end of the last line
- // and the forced break
- this.add(new KnuthPenalty(0, KnuthElement.INFINITE,
- false, null, false));
- this.add(new KnuthGlue(0,
- lineFiller.max - lineFiller.opt,
- lineFiller.opt - lineFiller.min, null, false));
- this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE,
- false, null, false));
- ignoreAtEnd = 3;
- } else {
- // add only the element representing the forced break
- this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE,
- false, null, false));
- ignoreAtEnd = 1;
- }
- return this;
- } else {
- this.clear();
- return null;
- }
- }
-
- /**
- * @return true if the sequence contains a box
- */
- public boolean containsBox() {
- for (int i = 0; i < this.size(); i++) {
- KnuthElement el = (KnuthElement)this.get(i);
- if (el.isBox()) {
- return true;
- }
- }
- return false;
- }
- }
-
- private class LineBreakingAlgorithm extends BreakingAlgorithm {
- private LineLayoutManager thisLLM;
- private int pageAlignment;
- private int activePossibility;
- private int addedPositions;
- private int textIndent;
- private int fillerMinWidth;
- private int lineHeight;
- private int lead;
- private int follow;
- private int maxDiff;
- private static final double MAX_DEMERITS = 10e6;
-
- public LineBreakingAlgorithm (int pageAlign,
- int textAlign, int textAlignLast,
- int indent, int fillerWidth,
- int lh, int ld, int fl, boolean first,
- int maxFlagCount, LineLayoutManager llm) {
- super(textAlign, textAlignLast, first, false, maxFlagCount);
- pageAlignment = pageAlign;
- textIndent = indent;
- fillerMinWidth = fillerWidth;
- lineHeight = lh;
- lead = ld;
- follow = fl;
- thisLLM = llm;
- activePossibility = -1;
- maxDiff = fobj.getWidows() >= fobj.getOrphans()
- ? fobj.getWidows()
- : fobj.getOrphans();
- }
-
- public void updateData1(int lineCount, double demerits) {
- lineLayouts.addPossibility(lineCount, demerits);
- log.trace("Layout possibility in " + lineCount + " lines; break at position:");
- }
-
- public void updateData2(KnuthNode bestActiveNode,
- KnuthSequence par,
- int total) {
- // compute indent and adjustment ratio, according to
- // the value of text-align and text-align-last
- int indent = 0;
- int difference = bestActiveNode.difference;
- int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
- indent += (textAlign == Constants.EN_CENTER)
- ? difference / 2 : (textAlign == Constants.EN_END) ? difference : 0;
- indent += (bestActiveNode.line == 1 && bFirst && isFirstInBlock) ? textIndent : 0;
- double ratio = (textAlign == Constants.EN_JUSTIFY
- || difference < 0 && -difference <= bestActiveNode.availableShrink)
- ? bestActiveNode.adjustRatio : 0;
-
- // add nodes at the beginning of the list, as they are found
- // backwards, from the last one to the first one
-
- // the first time this method is called, initialize activePossibility
- if (activePossibility == -1) {
- activePossibility = 0;
- addedPositions = 0;
- }
-
- if (addedPositions == lineLayouts.getLineCount(activePossibility)) {
- activePossibility++;
- addedPositions = 0;
- }
-
- if (difference + bestActiveNode.availableShrink < 0) {
- if (log.isWarnEnabled()) {
- log.warn(FONode.decorateWithContextInfo(
- "Line " + (addedPositions + 1)
- + " of a paragraph overflows the available area.", getFObj()));
- }
- }
-
- //log.debug("LLM> (" + (lineLayouts.getLineNumber(activePossibility) - addedPositions)
- // + ") difference = " + difference + " ratio = " + ratio);
- lineLayouts.addBreakPosition(makeLineBreakPosition(par,
- (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1 : 0),
- bestActiveNode.position,
- bestActiveNode.availableShrink - (addedPositions > 0
- ? 0 : ((Paragraph)par).lineFiller.opt - ((Paragraph)par).lineFiller.min),
- bestActiveNode.availableStretch,
- difference, ratio, indent), activePossibility);
- addedPositions++;
- }
-
- /* reset activePossibility, as if breakpoints have not yet been computed
- */
- public void resetAlgorithm() {
- activePossibility = -1;
- }
-
- private LineBreakPosition makeLineBreakPosition(KnuthSequence par,
- int firstElementIndex,
- int lastElementIndex,
- int availableShrink,
- int availableStretch,
- int difference,
- double ratio,
- int indent) {
- // line height calculation - spaceBefore may differ from spaceAfter
- // by 1mpt due to rounding
- int spaceBefore = (lineHeight - lead - follow) / 2;
- int spaceAfter = lineHeight - lead - follow - spaceBefore;
- // height before the main baseline
- int lineLead = lead;
- // maximum follow
- int lineFollow = follow;
- // true if this line contains only zero-height, auxiliary boxes
- // and the actual line width is 0; in this case, the line "collapses"
- // i.e. the line area will have bpd = 0
- boolean bZeroHeightLine = (difference == iLineWidth);
-
- // if line-stacking-strategy is "font-height", the line height
- // is not affected by its content
- if (fobj.getLineStackingStrategy() != EN_FONT_HEIGHT) {
- ListIterator inlineIterator
- = par.listIterator(firstElementIndex);
- AlignmentContext lastAC = null;
- int maxIgnoredHeight = 0; // See spec 7.13
- for (int j = firstElementIndex;
- j <= lastElementIndex;
- j++) {
- KnuthElement element = (KnuthElement) inlineIterator.next();
- if (element instanceof KnuthInlineBox ) {
- AlignmentContext ac = ((KnuthInlineBox) element).getAlignmentContext();
- if (ac != null && lastAC != ac) {
- if (!ac.usesInitialBaselineTable()
- || ac.getAlignmentBaselineIdentifier() != EN_BEFORE_EDGE
- && ac.getAlignmentBaselineIdentifier() != EN_AFTER_EDGE) {
- int alignmentOffset = ac.getTotalAlignmentBaselineOffset();
- if (alignmentOffset + ac.getAltitude() > lineLead) {
- lineLead = alignmentOffset + ac.getAltitude();
- }
- if (ac.getDepth() - alignmentOffset > lineFollow) {
- lineFollow = ac.getDepth() - alignmentOffset;
- }
- } else {
- if (ac.getHeight() > maxIgnoredHeight) {
- maxIgnoredHeight = ac.getHeight();
- }
- }
- lastAC = ac;
- }
- if (bZeroHeightLine
- && (!element.isAuxiliary() || ac != null && ac.getHeight() > 0)) {
- bZeroHeightLine = false;
- }
- }
- }
-
- if (lineFollow < maxIgnoredHeight - lineLead) {
- lineFollow = maxIgnoredHeight - lineLead;
- }
- }
-
- constantLineHeight = lineLead + lineFollow;
-
- if (bZeroHeightLine) {
- return new LineBreakPosition(thisLLM,
- knuthParagraphs.indexOf(par),
- firstElementIndex, lastElementIndex,
- availableShrink, availableStretch,
- difference, ratio, 0, indent,
- 0, iLineWidth, 0, 0, 0);
- } else {
- return new LineBreakPosition(thisLLM,
- knuthParagraphs.indexOf(par),
- firstElementIndex, lastElementIndex,
- availableShrink, availableStretch,
- difference, ratio, 0, indent,
- lineLead + lineFollow,
- iLineWidth, spaceBefore, spaceAfter,
- lineLead);
- }
- }
-
- public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
- double threshold, boolean force,
- int allowedBreaks) {
- return super.findBreakingPoints(par, /*lineWidth,*/
- threshold, force, allowedBreaks);
- }
-
- protected int filterActiveNodes() {
- KnuthNode bestActiveNode = null;
-
- if (pageAlignment == EN_JUSTIFY) {
- // leave all active nodes and find the optimum line number
- //log.debug("LBA.filterActiveNodes> " + activeNodeCount + " layouts");
- for (int i = startLine; i < endLine; i++) {
- for (KnuthNode node = getNode(i); node != null; node = node.next) {
- //log.debug(" + lines = " + node.line + " demerits = " + node.totalDemerits);
- bestActiveNode = compareNodes(bestActiveNode, node);
- }
- }
-
- // scan the node set once again and remove some nodes
- //log.debug("LBA.filterActiveList> layout selection");
- for (int i = startLine; i < endLine; i++) {
- for (KnuthNode node = getNode(i); node != null; node = node.next) {
- //if (Math.abs(node.line - bestActiveNode.line) > maxDiff) {
- //if (false) {
- if (node.line != bestActiveNode.line
- && node.totalDemerits > MAX_DEMERITS) {
- //log.debug(" XXX lines = " + node.line + " demerits = " + node.totalDemerits);
- removeNode(i, node);
- } else {
- //log.debug(" ok lines = " + node.line + " demerits = " + node.totalDemerits);
- }
- }
- }
- } else {
- // leave only the active node with fewest total demerits
- for (int i = startLine; i < endLine; i++) {
- for (KnuthNode node = getNode(i); node != null; node = node.next) {
- bestActiveNode = compareNodes(bestActiveNode, node);
- if (node != bestActiveNode) {
- removeNode(i, node);
- }
- }
- }
- }
- return bestActiveNode.line;
- }
- }
-
-
- private int constantLineHeight = 12000;
-
-
- /**
- * Create a new Line Layout Manager.
- * This is used by the block layout manager to create
- * line managers for handling inline areas flowing into line areas.
- * @param block the block formatting object
- * @param lh the default line height
- * @param l the default lead, from top to baseline
- * @param f the default follow, from baseline to bottom
- */
- public LineLayoutManager(Block block, Length lh, int l, int f) {
- super(block);
- fobj = block;
- // the child FObj are owned by the parent BlockLM
- // this LM has all its childLMs preloaded
- fobjIter = null;
- lineHeight = lh;
- lead = l;
- follow = f;
- }
-
- /** @see org.apache.fop.layoutmgr.LayoutManager */
- public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
- Font fs = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo(), this);
- alignmentContext
- = new AlignmentContext(fs, lineHeight.getValue(this), context.getWritingMode());
- context.setAlignmentContext(alignmentContext);
- // Get a break from currently active child LM
- // Set up constraints for inline level managers
-
- // IPD remaining in line
- MinOptMax availIPD = context.getStackLimit();
-
- clearPrevIPD();
-
- //PHASE 1: Create Knuth elements
- if (knuthParagraphs == null) {
- // it's the first time this method is called
- knuthParagraphs = new ArrayList();
-
- // here starts Knuth's algorithm
- //TODO availIPD should not really be used here, so we can later support custom line
- //widths for for each line (side-floats, differing available IPD after page break)
- collectInlineKnuthElements(context, availIPD);
- } else {
- // this method has been called before
- // all line breaks are already calculated
- }
-
- // return finished when there's no content
- if (knuthParagraphs.size() == 0) {
- setFinished(true);
- return null;
- }
-
- //PHASE 2: Create line breaks
- return createLineBreaks(context.getBPAlignment(), context);
- /*
- LineBreakPosition lbp = null;
- if (breakpoints == null) {
- // find the optimal line breaking points for each paragraph
- breakpoints = new ArrayList();
- ListIterator paragraphsIterator
- = knuthParagraphs.listIterator(knuthParagraphs.size());
- Paragraph currPar = null;
- while (paragraphsIterator.hasPrevious()) {
- currPar = (Paragraph) paragraphsIterator.previous();
- findBreakingPoints(currPar, context.getStackLimit().opt);
- }
- }*/
-
- //PHASE 3: Return lines
-
- /*
- // get a break point from the list
- lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++);
- if (iReturnedLBP == breakpoints.size()) {
- setFinished(true);
- }
-
- BreakPoss curLineBP = new BreakPoss(lbp);
- curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
- curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight));
- return curLineBP;
- */
- }
-
- /**
- * Phase 1 of Knuth algorithm: Collect all inline Knuth elements before determining line breaks.
- * @param context the LayoutContext
- * @param availIPD available IPD for line (should be removed!)
- */
- private void collectInlineKnuthElements(LayoutContext context, MinOptMax availIPD) {
- LayoutContext inlineLC = new LayoutContext(context);
-
- InlineLevelLayoutManager curLM;
- LinkedList returnedList = null;
- iLineWidth = context.getStackLimit().opt;
-
- // convert all the text in a sequence of paragraphs made
- // of KnuthBox, KnuthGlue and KnuthPenalty objects
- boolean bPrevWasKnuthBox = false;
-
- StringBuffer trace = new StringBuffer("LineLM:");
-
- Paragraph lastPar = null;
-
- while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
- returnedList = curLM.getNextKnuthElements(inlineLC, effectiveAlignment);
- if (returnedList == null) {
- // curLM returned null; this can happen
- // if it has nothing more to layout,
- // so just iterate once more to see
- // if there are other children
- continue;
- }
- if (returnedList.size() == 0) {
- continue;
- }
-
- if (lastPar != null) {
- KnuthSequence firstSeq = (KnuthSequence) returnedList.getFirst();
-
- // finish last paragraph before a new block sequence
- if (!firstSeq.isInlineSequence()) {
- lastPar.endParagraph();
- ElementListObserver.observe(lastPar, "line", null);
- lastPar = null;
- if (log.isTraceEnabled()) {
- trace.append(" ]");
- }
- bPrevWasKnuthBox = false;
- }
-
- // does the first element of the first paragraph add to an existing word?
- if (lastPar != null) {
- KnuthElement thisElement;
- thisElement = (KnuthElement) firstSeq.get(0);
- if (thisElement.isBox() && !thisElement.isAuxiliary()
- && bPrevWasKnuthBox) {
- lastPar.addALetterSpace();
- }
- }
- }
-
- // loop over the KnuthSequences (and single KnuthElements) in returnedList
- ListIterator iter = returnedList.listIterator();
- while (iter.hasNext()) {
- KnuthSequence sequence = (KnuthSequence) iter.next();
- // the sequence contains inline Knuth elements
- if (sequence.isInlineSequence()) {
- // look at the last element
- ListElement lastElement;
- lastElement = sequence.getLast();
- if (lastElement == null) {
- throw new NullPointerException(
- "Sequence was empty! lastElement is null");
- }
- bPrevWasKnuthBox = lastElement.isBox() && ((KnuthElement) lastElement).getW() != 0;
-
- // if last paragraph is open, add the new elements to the paragraph
- // else this is the last paragraph
- if (lastPar == null) {
- lastPar = new Paragraph(this,
- textAlignment, textAlignmentLast,
- textIndent.getValue(this),
- lastLineEndIndent.getValue(this));
- lastPar.startParagraph(availIPD.opt);
- if (log.isTraceEnabled()) {
- trace.append(" [");
- }
- } else {
- if (log.isTraceEnabled()) {
- trace.append(" +");
- }
- }
- lastPar.addAll(sequence);
- if (log.isTraceEnabled()) {
- trace.append(" I");
- }
-
- // finish last paragraph if it was closed with a linefeed
- if (lastElement.isPenalty()
- && ((KnuthPenalty) lastElement).getP()
- == -KnuthPenalty.INFINITE) {
- // a penalty item whose value is -inf
- // represents a preserved linefeed,
- // which forces a line break
- lastPar.removeLast();
- if (!lastPar.containsBox()) {
- //only a forced linefeed on this line
- //-> compensate with a zero width box
- lastPar.add(new KnuthInlineBox(0, null, null, false));
- }
- lastPar.endParagraph();
- ElementListObserver.observe(lastPar, "line", null);
- lastPar = null;
- if (log.isTraceEnabled()) {
- trace.append(" ]");
- }
- bPrevWasKnuthBox = false;
- }
- } else { // the sequence is a block sequence
- // the positions will be wrapped with this LM in postProcessLineBreaks
- knuthParagraphs.add(sequence);
- if (log.isTraceEnabled()) {
- trace.append(" B");
- }
- }
- } // end of loop over returnedList
- }
- if (lastPar != null) {
- lastPar.endParagraph();
- ElementListObserver.observe(lastPar, "line", fobj.getId());
- if (log.isTraceEnabled()) {
- trace.append(" ]");
- }
- }
- log.trace(trace);
- }
-
- /**
- * Find a set of breaking points.
- * This method is called only once by getNextBreakPoss, and it
- * subsequently calls the other findBreakingPoints() method with
- * different parameters, until a set of breaking points is found.
- *
- * @param par the list of elements that must be parted
- * into lines
- * @param lineWidth the desired length ot the lines
- */
- /*
- private void findBreakingPoints(Paragraph par, int lineWidth) {
- // maximum adjustment ratio permitted
- float maxAdjustment = 1;
-
- // first try
- if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
- // the first try failed, now try something different
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
- if (hyphenationProperties.hyphenate == Constants.EN_TRUE) {
- // consider every hyphenation point as a legal break
- findHyphenationPoints(par);
- } else {
- // try with a higher threshold
- maxAdjustment = 5;
- }
-
- if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
- // the second try failed too, try with a huge threshold;
- // if this fails too, use a different algorithm
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
- + (hyphenationProperties.hyphenate == Constants.EN_TRUE ? " and hyphenation" : ""));
- maxAdjustment = 20;
- if (!findBreakingPoints(par, lineWidth, maxAdjustment, true)) {
- log.debug("No set of breaking points found, using first-fit algorithm");
- }
- }
- }
- }
-
- private boolean findBreakingPoints(Paragraph par, int lineWidth,
- double threshold, boolean force) {
- KnuthParagraph knuthPara = new KnuthParagraph(par);
- int lines = knuthPara.findBreakPoints(lineWidth, threshold, force);
- if (lines == 0) {
- return false;
- }
-
- for (int i = lines-1; i >= 0; i--) {
- int line = i+1;
- if (log.isTraceEnabled()) {
- log.trace("Making line from " + knuthPara.getStart(i) + " to " +
- knuthPara.getEnd(i));
- }
- // compute indent and adjustment ratio, according to
- // the value of text-align and text-align-last
-
- int difference = knuthPara.getDifference(i);
- if (line == lines) {
- difference += par.lineFillerWidth;
- }
- int textAlign = (line < lines)
- ? textAlignment : textAlignmentLast;
- int indent = (textAlign == EN_CENTER)
- ? difference / 2
- : (textAlign == EN_END) ? difference : 0;
- indent += (line == 1 && knuthParagraphs.indexOf(par) == 0)
- ? textIndent.getValue(this) : 0;
- double ratio = (textAlign == EN_JUSTIFY)
- ? knuthPara.getAdjustRatio(i) : 0;
-
- int start = knuthPara.getStart(i);
- int end = knuthPara.getEnd(i);
- makeLineBreakPosition(par, start, end, 0, ratio, indent);
- }
- return true;
- }
-
- private void makeLineBreakPosition(Paragraph par,
- int firstElementIndex, int lastElementIndex,
- int insertIndex, double ratio, int indent) {
- // line height calculation
-
- int halfLeading = (lineHeight - lead - follow) / 2;
- // height above the main baseline
- int lineLead = lead + halfLeading;
- // maximum size of top and bottom alignment
- int lineFollow = follow + halfLeading;
-
- ListIterator inlineIterator
- = par.listIterator(firstElementIndex);
- for (int j = firstElementIndex;
- j <= lastElementIndex;
- j++) {
- KnuthElement element = (KnuthElement) inlineIterator.next();
- if (element.isBox()) {
- KnuthInlineBox box = (KnuthInlineBox)element;
- if (box.getLead() > lineLead) {
- lineLead = box.getLead();
- }
- if (box.getTotal() > lineFollow) {
- lineFollow = box.getTotal();
- }
- if (box.getMiddle() > lineLead + middleShift) {
- lineLead += box.getMiddle()
- - lineLead - middleShift;
- }
- if (box.getMiddle() > middlefollow - middleShift) {
- middlefollow += box.getMiddle()
- - middlefollow + middleShift;
- }
- }
- }
-
- if (lineFollow - lineLead > middlefollow) {
- middlefollow = lineFollow - lineLead;
- }
-
- breakpoints.add(insertIndex,
- new LineBreakPosition(this,
- knuthParagraphs.indexOf(par),
- lastElementIndex ,
- ratio, 0, indent,
- lineLead + middlefollow,
- lineLead));
- }*/
-
-
- /**
- * Phase 2 of Knuth algorithm: find optimal break points.
- * @param alignment alignment in BP direction of the paragraph
- * @param context the layout context
- * @return a list of Knuth elements representing broken lines
- */
- private LinkedList createLineBreaks(int alignment, LayoutContext context) {
-
- // find the optimal line breaking points for each paragraph
- ListIterator paragraphsIterator
- = knuthParagraphs.listIterator(knuthParagraphs.size());
- lineLayoutsList = new ArrayList(knuthParagraphs.size());
- LineLayoutPossibilities llPoss;
- while (paragraphsIterator.hasPrevious()) {
- KnuthSequence seq = (KnuthSequence) paragraphsIterator.previous();
- if (!seq.isInlineSequence()) {
- // This set of line layout possibilities does not matter;
- // we only need an entry in lineLayoutsList.
- llPoss = new LineLayoutPossibilities();
- } else {
- llPoss = findOptimalBreakingPoints(alignment, (Paragraph) seq);
- }
- lineLayoutsList.add(0, llPoss);
- }
-
- setFinished(true);
-
- //Post-process the line breaks found
- return postProcessLineBreaks(alignment, context);
- }
-
- /**
- * Fint the optimal linebreaks for a paragraph
- * @param alignment alignment of the paragraph
- * @param currPar the Paragraph for which the linebreaks are found
- * @return the line layout possibilities for the paragraph
- */
- private LineLayoutPossibilities findOptimalBreakingPoints(int alignment, Paragraph currPar) {
- // use the member lineLayouts, which is read by LineBreakingAlgorithm.updateData1 and 2
- lineLayouts = new LineLayoutPossibilities();
- double maxAdjustment = 1;
- int iBPcount = 0;
- LineBreakingAlgorithm alg = new LineBreakingAlgorithm(alignment,
- textAlignment, textAlignmentLast,
- textIndent.getValue(this), currPar.lineFiller.opt,
- lineHeight.getValue(this), lead, follow,
- (knuthParagraphs.indexOf(currPar) == 0),
- hyphenationLadderCount.getEnum() == EN_NO_LIMIT
- ? 0 : hyphenationLadderCount.getValue(),
- this);
-
- if (hyphenationProperties.hyphenate == EN_TRUE
- && fobj.getWrapOption() != EN_NO_WRAP) {
- findHyphenationPoints(currPar);
- }
-
- // first try
- int allowedBreaks;
- if (wrapOption == EN_NO_WRAP) {
- allowedBreaks = BreakingAlgorithm.ONLY_FORCED_BREAKS;
- } else {
- allowedBreaks = BreakingAlgorithm.NO_FLAGGED_PENALTIES;
- }
- alg.setConstantLineWidth(iLineWidth);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, false, allowedBreaks);
- if (iBPcount == 0 || alignment == EN_JUSTIFY) {
- // if the first try found a set of breaking points, save them
- if (iBPcount > 0) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(false);
- } else {
- // the first try failed
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
- }
-
- // now try something different
- log.debug("Hyphenation possible? " + (hyphenationProperties.hyphenate == EN_TRUE));
- if (hyphenationProperties.hyphenate == EN_TRUE
- && !(allowedBreaks == BreakingAlgorithm.ONLY_FORCED_BREAKS)) {
- // consider every hyphenation point as a legal break
- allowedBreaks = BreakingAlgorithm.ALL_BREAKS;
- } else {
- // try with a higher threshold
- maxAdjustment = 5;
- }
-
- if ((iBPcount
- = alg.findBreakingPoints(currPar,
- maxAdjustment, false, allowedBreaks)) == 0) {
- // the second try failed too, try with a huge threshold
- // and force the algorithm to find
- // a set of breaking points
- log.debug("No set of breaking points found with maxAdjustment = "
- + maxAdjustment
- + (hyphenationProperties.hyphenate == EN_TRUE
- ? " and hyphenation" : ""));
- maxAdjustment = 20;
- iBPcount
- = alg.findBreakingPoints(currPar,
- maxAdjustment, true, allowedBreaks);
- }
-
- // use non-hyphenated breaks, when possible
- lineLayouts.restorePossibilities();
-
- /* extension (not in the XSL FO recommendation): if vertical alignment
- is justify and the paragraph has only one layout, try using
- shorter or longer lines */
- //TODO This code snippet is disabled. Reenable?
- if (false && alignment == EN_JUSTIFY && textAlignment == EN_JUSTIFY) {
- //log.debug("LLM.getNextKnuthElements> layouts with more lines? " + lineLayouts.canUseMoreLines());
- //log.debug(" layouts with fewer lines? " + lineLayouts.canUseLessLines());
- if (!lineLayouts.canUseMoreLines()) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(true);
- // try with shorter lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 0.95);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, true, allowedBreaks);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
- }
- if (!lineLayouts.canUseLessLines()) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(true);
- // try with longer lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 1.05);
- alg.setConstantLineWidth(iLineWidth);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, true, allowedBreaks);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
- }
- //log.debug("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
- //log.debug(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
- }
- }
- return lineLayouts;
- }
-
- /**
- * Creates the element list in BP direction for the broken lines.
- * @param alignment the currently applicable vertical alignment
- * @param context the layout context
- * @return the newly built element list
- */
- private LinkedList postProcessLineBreaks(int alignment, LayoutContext context) {
-
- LinkedList returnList = new LinkedList();
-
- for (int p = 0; p < knuthParagraphs.size(); p++) {
- // null penalty between paragraphs
- if (p > 0 && !((BlockLevelLayoutManager) parentLM).mustKeepTogether()) {
- returnList.add(new BreakElement(
- new Position(this), 0, context));
- //returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
- }
-
- LineLayoutPossibilities llPoss;
- llPoss = (LineLayoutPossibilities) lineLayoutsList.get(p);
- KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(p);
-
- if (!seq.isInlineSequence()) {
- LinkedList targetList = new LinkedList();
- ListIterator listIter = seq.listIterator();
- while (listIter.hasNext()) {
- ListElement tempElement;
- tempElement = (ListElement) listIter.next();
- if (tempElement.getLayoutManager() != this) {
- tempElement.setPosition(notifyPos(new NonLeafPosition(this,
- tempElement.getPosition())));
- }
- targetList.add(tempElement);
- }
- returnList.addAll(targetList);
- } else if (seq.isInlineSequence() && alignment == EN_JUSTIFY) {
- /* justified vertical alignment (not in the XSL FO recommendation):
- create a multi-layout sequence whose elements will contain
- a conventional Position */
- Position returnPosition = new LeafPosition(this, p);
- createElements(returnList, llPoss, returnPosition);
- } 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();
- i++) {
- if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
- && i >= fobj.getOrphans()
- && i <= llPoss.getChosenLineCount() - fobj.getWidows()
- && returnList.size() > 0) {
- // null penalty allowing a page break between lines
- returnList.add(new BreakElement(
- returnPosition, 0, context));
- //returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
- }
- int endIndex
- = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos();
- // create a list of the FootnoteBodyLM handling footnotes
- // whose citations are in this line
- LinkedList footnoteList = new LinkedList();
- ListIterator elementIterator = seq.listIterator(startIndex);
- while (elementIterator.nextIndex() <= endIndex) {
- KnuthElement element = (KnuthElement) elementIterator.next();
- if (element instanceof KnuthInlineBox
- && ((KnuthInlineBox) element).isAnchor()) {
- footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
- } else if (element instanceof KnuthBlockBox) {
- footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs());
- }
- }
- startIndex = endIndex + 1;
- LineBreakPosition lbp
- = (LineBreakPosition) llPoss.getChosenPosition(i);
- returnList.add(new KnuthBlockBox
- (lbp.lineHeight + lbp.spaceBefore + lbp.spaceAfter,
- footnoteList, lbp, false));
- /* // add stretch and shrink to the returnlist
- if (!seq.isInlineSequence()
- && lbp.availableStretch != 0 || lbp.availableShrink != 0) {
- returnList.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
- false, new Position(this), false));
- returnList.add(new KnuthGlue(0, lbp.availableStretch, lbp.availableShrink,
- new Position(this), false));
- }
- */
- }
- }
- }
-
- return returnList;
- }
-
-
- private void createElements(List list, LineLayoutPossibilities llPoss,
- Position elementPosition) {
- /* number of normal, inner lines */
- int nInnerLines = 0;
- /* number of lines that can be used in order to fill more space */
- int nOptionalLines = 0;
- /* number of lines that can be used in order to fill more space
- only if the paragraph is not parted */
- int nConditionalOptionalLines = 0;
- /* number of lines that can be omitted in order to fill less space */
- int nEliminableLines = 0;
- /* number of lines that can be omitted in order to fill less space
- only if the paragraph is not parted */
- int nConditionalEliminableLines = 0;
- /* number of the first unbreakable lines */
- int nFirstLines = fobj.getOrphans();
- /* number of the last unbreakable lines */
- int nLastLines = fobj.getWidows();
- /* sub-sequence used to separate the elements representing different lines */
- List breaker = new LinkedList();
-
- /* comment out the next lines in order to test particular situations */
- if (fobj.getOrphans() + fobj.getWidows() <= llPoss.getMinLineCount()) {
- nInnerLines = llPoss.getMinLineCount()
- - (fobj.getOrphans() + fobj.getWidows());
- nOptionalLines = llPoss.getMaxLineCount()
- - llPoss.getOptLineCount();
- nEliminableLines = llPoss.getOptLineCount()
- - llPoss.getMinLineCount();
- } else if (fobj.getOrphans() + fobj.getWidows() <= llPoss.getOptLineCount()) {
- nOptionalLines = llPoss.getMaxLineCount()
- - llPoss.getOptLineCount();
- nEliminableLines = llPoss.getOptLineCount()
- - (fobj.getOrphans() + fobj.getWidows());
- nConditionalEliminableLines = (fobj.getOrphans() + fobj.getWidows())
- - llPoss.getMinLineCount();
- } else if (fobj.getOrphans() + fobj.getWidows() <= llPoss.getMaxLineCount()) {
- nOptionalLines = llPoss.getMaxLineCount()
- - (fobj.getOrphans() + fobj.getWidows());
- nConditionalOptionalLines = (fobj.getOrphans() + fobj.getWidows())
- - llPoss.getOptLineCount();
- nConditionalEliminableLines = llPoss.getOptLineCount()
- - llPoss.getMinLineCount();
- nFirstLines -= nConditionalOptionalLines;
- } else {
- nConditionalOptionalLines = llPoss.getMaxLineCount()
- - llPoss.getOptLineCount();
- nConditionalEliminableLines = llPoss.getOptLineCount()
- - llPoss.getMinLineCount();
- nFirstLines = llPoss.getOptLineCount();
- nLastLines = 0;
- }
- /* comment out the previous lines in order to test particular situations */
-
- /* use these lines to test particular situations
- nInnerLines = 0;
- nOptionalLines = 1;
- nConditionalOptionalLines = 2;
- nEliminableLines = 0;
- nConditionalEliminableLines = 0;
- nFirstLines = 1;
- nLastLines = 3;
- */
-
- if (nLastLines != 0
- && (nConditionalOptionalLines > 0 || nConditionalEliminableLines > 0)) {
- breaker.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
- breaker.add(new KnuthGlue(0, -nConditionalOptionalLines * constantLineHeight,
- -nConditionalEliminableLines * constantLineHeight,
- LINE_NUMBER_ADJUSTMENT, elementPosition, false));
- breaker.add(new KnuthPenalty(nConditionalOptionalLines * constantLineHeight,
- 0, false, elementPosition, false));
- breaker.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
- nConditionalEliminableLines * constantLineHeight,
- LINE_NUMBER_ADJUSTMENT, elementPosition, false));
- } else if (nLastLines != 0) {
- breaker.add(new KnuthPenalty(0, 0, false, elementPosition, false));
- }
-
- //log.debug("first=" + nFirstLines + " inner=" + nInnerLines
- // + " optional=" + nOptionalLines + " eliminable=" + nEliminableLines
- // + " last=" + nLastLines
- // + " (condOpt=" + nConditionalOptionalLines + " condEl=" + nConditionalEliminableLines + ")");
-
- // creation of the elements:
- // first group of lines
- list.add(new KnuthBox(nFirstLines * constantLineHeight, elementPosition,
- (nLastLines == 0
- && nConditionalOptionalLines == 0
- && nConditionalEliminableLines == 0 ? true : false)));
- if (nConditionalOptionalLines > 0
- || nConditionalEliminableLines > 0) {
- list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
- list.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
- nConditionalEliminableLines * constantLineHeight,
- LINE_NUMBER_ADJUSTMENT, elementPosition, false));
- list.add(new KnuthBox(0, elementPosition,
- (nLastLines == 0 ? true : false)));
- }
-
- // optional lines
- for (int i = 0; i < nOptionalLines; i++) {
- list.addAll(breaker);
- list.add(new KnuthBox(0, elementPosition, false));
- list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
- list.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
- LINE_NUMBER_ADJUSTMENT, elementPosition, false));
- list.add(new KnuthBox(0, elementPosition, false));
- }
-
- // eliminable lines
- for (int i = 0; i < nEliminableLines; i++) {
- list.addAll(breaker);
- list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
- list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
- list.add(new KnuthGlue(0, 0, 1 * constantLineHeight,
- LINE_NUMBER_ADJUSTMENT, elementPosition, false));
- list.add(new KnuthBox(0, elementPosition, false));
- }
-
- // inner lines
- for (int i = 0; i < nInnerLines; i++) {
- list.addAll(breaker);
- list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
- }
-
- // last group of lines
- if (nLastLines > 0) {
- list.addAll(breaker);
- list.add(new KnuthBox(nLastLines * constantLineHeight,
- elementPosition, true));
- }
- }
-
- /**
- * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepTogether
- */
- public boolean mustKeepTogether() {
- return ((BlockLevelLayoutManager) getParent()).mustKeepTogether();
- }
-
- /**
- * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithPrevious
- */
- public boolean mustKeepWithPrevious() {
- return false;
- }
-
- /**
- * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#mustKeepWithNext
- */
- public boolean mustKeepWithNext() {
- return false;
- }
-
- /**
- * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement)
- */
- public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
- LeafPosition pos = (LeafPosition)lastElement.getPosition();
- int totalAdj = adj;
- //if (lastElement.isPenalty()) {
- // totalAdj += lastElement.getW();
- //}
- //int lineNumberDifference = (int)((double) totalAdj / constantLineHeight);
- int lineNumberDifference = (int) Math.round((double) totalAdj / constantLineHeight
- + (adj > 0 ? - 0.4 : 0.4));
- //log.debug(" LLM> variazione calcolata = " + ((double) totalAdj / constantLineHeight) + " variazione applicata = " + lineNumberDifference);
- LineLayoutPossibilities llPoss;
- llPoss = (LineLayoutPossibilities) lineLayoutsList.get(pos.getLeafPos());
- lineNumberDifference = llPoss.applyLineCountAdjustment(lineNumberDifference);
- return lineNumberDifference * constantLineHeight;
- }
-
- /**
- * @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#discardSpace(KnuthGlue)
- */
- public void discardSpace(KnuthGlue spaceGlue) {
- }
-
- /**
- * @see org.apache.fop.layoutmgr.LayoutManager#getChangedKnuthElements(List, int)
- */
- public LinkedList getChangedKnuthElements(List oldList, int alignment) {
- LinkedList returnList = new LinkedList();
- for (int p = 0; p < knuthParagraphs.size(); p++) {
- LineLayoutPossibilities llPoss;
- llPoss = (LineLayoutPossibilities)lineLayoutsList.get(p);
- //log.debug("demerits of the chosen layout: " + llPoss.getChosenDemerits());
- for (int i = 0; i < llPoss.getChosenLineCount(); i++) {
- if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
- && i >= fobj.getOrphans()
- && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
- // null penalty allowing a page break between lines
- returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
- }
- LineBreakPosition lbp = (LineBreakPosition) llPoss.getChosenPosition(i);
- //log.debug("LLM.getChangedKnuthElements> lineWidth= " + lbp.lineWidth + " difference= " + lbp.difference);
- //log.debug(" shrink= " + lbp.availableShrink + " stretch= " + lbp.availableStretch);
-
- //log.debug("linewidth= " + lbp.lineWidth + " difference= " + lbp.difference + " indent= " + lbp.startIndent);
- MinOptMax contentIPD;
- if (alignment == EN_JUSTIFY) {
- contentIPD = new MinOptMax(
- lbp.lineWidth - lbp.difference - lbp.availableShrink,
- lbp.lineWidth - lbp.difference,
- lbp.lineWidth - lbp.difference + lbp.availableStretch);
- } else if (alignment == EN_CENTER) {
- contentIPD = new MinOptMax(lbp.lineWidth - 2 * lbp.startIndent);
- } else if (alignment == EN_END) {
- contentIPD = new MinOptMax(lbp.lineWidth - lbp.startIndent);
- } else {
- contentIPD = new MinOptMax(lbp.lineWidth - lbp.difference + lbp.startIndent);
- }
- returnList.add(new KnuthBlockBox(lbp.lineHeight,
- contentIPD,
- (lbp.ipdAdjust != 0
- ? lbp.lineWidth - lbp.difference : 0),
- lbp, false));
- }
- }
- return returnList;
- }
-
- /**
- * find hyphenation points for every word int the current paragraph
- * @ param currPar the paragraph whose words will be hyphenated
- */
- private void findHyphenationPoints(Paragraph currPar) {
- // hyphenate every word
- ListIterator currParIterator
- = currPar.listIterator(currPar.ignoreAtStart);
- // list of TLM involved in hyphenation
- LinkedList updateList = new LinkedList();
- KnuthElement firstElement = null;
- KnuthElement nextElement = null;
- // current InlineLevelLayoutManager
- InlineLevelLayoutManager currLM = null;
- // number of KnuthBox elements containing word fragments
- int boxCount;
- // number of auxiliary KnuthElements between KnuthBoxes
- int auxCount;
- StringBuffer sbChars = null;
-
- // find all hyphenation points
- while (currParIterator.hasNext()) {
- firstElement = (KnuthElement) currParIterator.next();
- //
- if (firstElement.getLayoutManager() != currLM) {
- currLM = (InlineLevelLayoutManager) firstElement.getLayoutManager();
- if (currLM != null) {
- updateList.add(new Update(currLM, currParIterator.previousIndex()));
- } else {
- break;
- }
- } else if (currLM == null) {
- break;
- }
- //TODO Something's not right here. See block_hyphenation_linefeed_preserve.xml
-
- // collect word fragments, ignoring auxiliary elements;
- // each word fragment was created by a different TextLM
- if (firstElement.isBox() && !firstElement.isAuxiliary()) {
- boxCount = 1;
- auxCount = 0;
- sbChars = new StringBuffer();
- currLM.getWordChars(sbChars, firstElement.getPosition());
- // look if next elements are boxes too
- while (currParIterator.hasNext()) {
- nextElement = (KnuthElement) currParIterator.next();
- if (nextElement.isBox() && !nextElement.isAuxiliary()) {
- // a non-auxiliary KnuthBox: append word chars
- if (currLM != nextElement.getLayoutManager()) {
- currLM = (InlineLevelLayoutManager) nextElement.getLayoutManager();
- updateList.add(new Update(currLM, currParIterator.previousIndex()));
- }
- // append text to recreate the whole word
- boxCount++;
- currLM.getWordChars(sbChars, nextElement.getPosition());
- } else if (!nextElement.isAuxiliary()) {
- // a non-auxiliary non-box KnuthElement: stop
- // go back to the last box or auxiliary element
- currParIterator.previous();
- break;
- } else {
- if (currLM != nextElement.getLayoutManager()) {
- currLM = (InlineLevelLayoutManager) nextElement.getLayoutManager();
- updateList.add(new Update(currLM, currParIterator.previousIndex()));
- }
- // an auxiliary KnuthElement: simply ignore it
- auxCount++;
- }
- }
- log.trace(" Word to hyphenate: " + sbChars.toString());
- // find hyphenation points
- HyphContext hc = getHyphenContext(sbChars);
- // ask each LM to hyphenate its word fragment
- if (hc != null) {
- KnuthElement element = null;
- for (int i = 0; i < (boxCount + auxCount); i++) {
- currParIterator.previous();
- }
- for (int i = 0; i < (boxCount + auxCount); i++) {
- element = (KnuthElement) currParIterator.next();
- if (element.isBox() && !element.isAuxiliary()) {
- ((InlineLevelLayoutManager)
- element.getLayoutManager()).hyphenate(element.getPosition(), hc);
- } else {
- // nothing to do, element is an auxiliary KnuthElement
- }
- }
- }
- }
- }
-
- // create iterator for the updateList
- ListIterator updateListIterator = updateList.listIterator();
- Update currUpdate = null;
- //int iPreservedElements = 0;
- int iAddedElements = 0;
- //int iRemovedElements = 0;
-
- while (updateListIterator.hasNext()) {
- // ask the LMs to apply the changes and return
- // the new KnuthElements to replace the old ones
- currUpdate = (Update) updateListIterator.next();
- int fromIndex = currUpdate.iFirstIndex;
- int toIndex;
- if (updateListIterator.hasNext()) {
- Update nextUpdate = (Update) updateListIterator.next();
- toIndex = nextUpdate.iFirstIndex;
- updateListIterator.previous();
- } else {
- // maybe this is not always correct!
- toIndex = currPar.size() - currPar.ignoreAtEnd
- - iAddedElements;
- }
-
- // applyChanges() returns true if the LM modifies its data,
- // so it must return new KnuthElements to replace the old ones
- if (((InlineLevelLayoutManager) currUpdate.inlineLM)
- .applyChanges(currPar.subList(fromIndex + iAddedElements,
- toIndex + iAddedElements))) {
- // insert the new KnuthElements
- LinkedList newElements = null;
- newElements
- = currUpdate.inlineLM.getChangedKnuthElements
- (currPar.subList(fromIndex + iAddedElements,
- toIndex + iAddedElements),
- /*flaggedPenalty,*/ effectiveAlignment);
- // remove the old elements
- currPar.subList(fromIndex + iAddedElements,
- toIndex + iAddedElements).clear();
- // insert the new elements
- currPar.addAll(fromIndex + iAddedElements, newElements);
- iAddedElements += newElements.size() - (toIndex - fromIndex);
- }
- }
- updateListIterator = null;
- updateList.clear();
- }
-
- /**
- * Line area is always considered to act as a fence.
- * @param isNotFirst ignored
- * @return always true
- */
- protected boolean hasLeadingFence(boolean isNotFirst) {
- return true;
- }
-
- /**
- * Line area is always considered to act as a fence.
- * @param isNotLast ignored
- * @return always true
- */
- protected boolean hasTrailingFence(boolean isNotLast) {
- return true;
- }
-
- private HyphContext getHyphenContext(StringBuffer sbChars) {
- // Find all hyphenation points in this word
- // (get in an array of offsets)
- // hyphenationProperties are from the block level?.
- // Note that according to the spec,
- // they also "apply to" fo:character.
- // I don't know what that means, since
- // if we change language in the middle of a "word",
- // the effect would seem quite strange!
- // Or perhaps in that case, we say that it's several words.
- // We probably should bring the hyphenation props up from the actual
- // TextLM which generate the hyphenation buffer,
- // since these properties inherit and could be specified
- // on an inline or wrapper below the block level.
- Hyphenation hyph
- = Hyphenator.hyphenate(hyphenationProperties.language,
- hyphenationProperties.country,
- getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(),
- sbChars.toString(),
- hyphenationProperties.hyphenationRemainCharacterCount,
- hyphenationProperties.hyphenationPushCharacterCount);
- // They hyph structure contains the information we need
- // Now start from prev: reset to that position, ask that LM to get
- // a Position for the first hyphenation offset. If the offset isn't in
- // its characters, it returns null,
- // but must tell how many chars it had.
- // Keep looking at currentBP using next hyphenation point until the
- // returned size is greater than the available size
- // or no more hyphenation points remain. Choose the best break.
- if (hyph != null) {
- return new HyphContext(hyph.getHyphenationPoints());
- } else {
- return null;
- }
- }
-
- /**
- * Reset the positions to the given position.
- *
- * @param resetPos the position to reset to
- */
- public void resetPosition(Position resetPos) {
- if (resetPos == null) {
- setFinished(false);
- iReturnedLBP = 0;
- } else {
- if (isFinished()) {
- // if isFinished is true, iReturned LBP == breakpoints.size()
- // and breakpoints.get(iReturnedLBP) would generate
- // an IndexOutOfBoundException
- setFinished(false);
- iReturnedLBP--;
- }
- // It is not clear that the member lineLayouts has the correct value;
- // because the method is not called, this cannot be checked.
- while ((LineBreakPosition) lineLayouts.getChosenPosition(iReturnedLBP)
- != (LineBreakPosition) resetPos) {
- iReturnedLBP--;
- }
- iReturnedLBP++;
- }
- }
-
- /**
- * Add the areas with the break points.
- *
- * @param parentIter the iterator of break positions
- * @param context the context for adding areas
- */
- public void addAreas(PositionIterator parentIter,
- LayoutContext context) {
- while (parentIter.hasNext()) {
- Position pos = (Position) parentIter.next();
- boolean isLastPosition = !parentIter.hasNext();
- if (pos instanceof LineBreakPosition) {
- addInlineArea(context, pos, isLastPosition);
- } else if ((pos instanceof NonLeafPosition) && pos.generatesAreas()) {
- addBlockArea(context, pos, isLastPosition);
- } else {
- /*
- * pos was the Position inside a penalty item, nothing to do;
- * or Pos does not generate an area,
- * i.e. it stand for spaces, borders and padding.
- */
- }
- }
- setCurrentArea(null); // ?? necessary
- }
-
- /**
- * Add a line with inline content
- * @param context the context for adding areas
- * @param pos the position for which the line is generated
- * @param isLastPosition true if this is the last position of this LM
- */
- private void addInlineArea(LayoutContext context, Position pos, boolean isLastPosition) {
- ListIterator seqIterator = null;
- KnuthElement tempElement = null;
- // the TLM which created the last KnuthElement in this line
- LayoutManager lastLM = null;
-
- LineBreakPosition lbp = (LineBreakPosition) pos;
- int iCurrParIndex;
- iCurrParIndex = lbp.iParIndex;
- KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(iCurrParIndex);
- int iStartElement = lbp.iStartIndex;
- int iEndElement = lbp.getLeafPos();
-
- LineArea lineArea
- = new LineArea((lbp.getLeafPos() < seq.size() - 1
- ? textAlignment : textAlignmentLast),
- lbp.difference, lbp.availableStretch, lbp.availableShrink);
- if (lbp.startIndent != 0) {
- lineArea.addTrait(Trait.START_INDENT, new Integer(lbp.startIndent));
- }
- lineArea.setBPD(lbp.lineHeight);
- lineArea.setIPD(lbp.lineWidth);
- lineArea.addTrait(Trait.SPACE_BEFORE, new Integer(lbp.spaceBefore));
- lineArea.addTrait(Trait.SPACE_AFTER, new Integer(lbp.spaceAfter));
- alignmentContext.resizeLine(lbp.lineHeight, lbp.baseline);
-
- if (seq instanceof Paragraph) {
- Paragraph currPar = (Paragraph) seq;
- // ignore the first elements added by the LineLayoutManager
- iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
-
- // if this is the last line area that for this paragraph,
- // ignore the last elements added by the LineLayoutManager and
- // subtract the last-line-end-indent from the area ipd
- if (iEndElement == (currPar.size() - 1)) {
- iEndElement -= currPar.ignoreAtEnd;
- lineArea.setIPD(lineArea.getIPD() - lastLineEndIndent.getValue(this));
- }
- }
-
- // Remove trailing spaces if allowed so
- if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
- || whiteSpaceTreament == EN_IGNORE
- || whiteSpaceTreament == EN_IGNORE_IF_BEFORE_LINEFEED) {
- // ignore the last element in the line if it is a KnuthGlue object
- seqIterator = seq.listIterator(iEndElement);
- tempElement = (KnuthElement) seqIterator.next();
- if (tempElement.isGlue()) {
- iEndElement--;
- // this returns the same KnuthElement
- seqIterator.previous();
- if (seqIterator.hasPrevious()) {
- tempElement = (KnuthElement) seqIterator.previous();
- } else {
- tempElement = null;
- }
- }
- if (tempElement != null) {
- lastLM = tempElement.getLayoutManager();
- }
- }
-
- // Remove leading spaces if allowed so
- if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
- || whiteSpaceTreament == EN_IGNORE
- || whiteSpaceTreament == EN_IGNORE_IF_AFTER_LINEFEED) {
- // ignore KnuthGlue and KnuthPenalty objects
- // at the beginning of the line
- seqIterator = seq.listIterator(iStartElement);
- tempElement = (KnuthElement) seqIterator.next();
- while (!tempElement.isBox() && seqIterator.hasNext()) {
- tempElement = (KnuthElement) seqIterator.next();
- iStartElement++;
- }
- }
- // Add the inline areas to lineArea
- PositionIterator inlinePosIter
- = new KnuthPossPosIter(seq, iStartElement, iEndElement + 1);
-
- iStartElement = lbp.getLeafPos() + 1;
- if (iStartElement == seq.size()) {
- // advance to next paragraph
- iStartElement = 0;
- }
-
- LayoutContext lc = new LayoutContext(0);
- lc.setAlignmentContext(alignmentContext);
- lc.setSpaceAdjust(lbp.dAdjust);
- lc.setIPDAdjust(lbp.ipdAdjust);
- lc.setLeadingSpace(new SpaceSpecifier(true));
- lc.setTrailingSpace(new SpaceSpecifier(false));
- lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
-
- /*
- * extension (not in the XSL FO recommendation): if the left and right margins
- * have been optimized, recompute indents and / or adjust ratio, according
- * to the paragraph horizontal alignment
- */
- if (false && textAlignment == EN_JUSTIFY) {
- // re-compute space adjust ratio
- int updatedDifference = context.getStackLimit().opt
- - lbp.lineWidth + lbp.difference;
- double updatedRatio = 0.0;
- if (updatedDifference > 0) {
- updatedRatio = (float) updatedDifference / lbp.availableStretch;
- } else if (updatedDifference < 0) {
- updatedRatio = (float) updatedDifference / lbp.availableShrink;
- }
- lc.setIPDAdjust(updatedRatio);
- //log.debug("LLM.addAreas> old difference = " + lbp.difference + " new difference = " + updatedDifference);
- //log.debug(" old ratio = " + lbp.ipdAdjust + " new ratio = " + updatedRatio);
- } else if (false && textAlignment == EN_CENTER) {
- // re-compute indent
- int updatedIndent = lbp.startIndent
- + (context.getStackLimit().opt - lbp.lineWidth) / 2;
- lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
- } else if (false && textAlignment == EN_END) {
- // re-compute indent
- int updatedIndent = lbp.startIndent
- + (context.getStackLimit().opt - lbp.lineWidth);
- lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
- }
-
- setCurrentArea(lineArea);
- setChildContext(lc);
- LayoutManager childLM;
- while ((childLM = inlinePosIter.getNextChildLM()) != null) {
- lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
- childLM.addAreas(inlinePosIter, lc);
- lc.setLeadingSpace(lc.getTrailingSpace());
- lc.setTrailingSpace(new SpaceSpecifier(false));
- }
-
- // when can this be null?
- // if display-align is distribute, add space after
- if (context.getSpaceAfter() > 0
- && (!context.isLastArea() || !isLastPosition)) {
- lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
- }
- lineArea.finalise();
- parentLM.addChildArea(lineArea);
- }
-
- /**
- * Add a line with block content
- * @param context the context for adding areas
- * @param pos the position for which the line is generated
- * @param isLastPosition true if this is the last position of this LM
- */
- private void addBlockArea(LayoutContext context, Position pos, boolean isLastPosition) {
- /* Nested block-level content;
- * go down the LM stack again;
- * "unwrap" the positions and put the child positions in a new list.
- * The positionList must contain one area-generating position,
- * which creates one line area.
- */
- List positionList = new ArrayList(1);
- Position innerPosition;
- innerPosition = ((NonLeafPosition) pos).getPosition();
- positionList.add(innerPosition);
-
- // do we have the last LM?
- LayoutManager lastLM = null;
- if (isLastPosition) {
- lastLM = innerPosition.getLM();
- }
-
- LineArea lineArea = new LineArea();
- setCurrentArea(lineArea);
- LayoutContext lc = new LayoutContext(0);
- lc.setAlignmentContext(alignmentContext);
- setChildContext(lc);
-
- PositionIterator childPosIter = new StackingIter(positionList.listIterator());
- LayoutContext blocklc = new LayoutContext(0);
- blocklc.setLeadingSpace(new SpaceSpecifier(true));
- blocklc.setTrailingSpace(new SpaceSpecifier(false));
- blocklc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
- LayoutManager childLM;
- while ((childLM = childPosIter.getNextChildLM()) != null) {
- // set last area flag
- blocklc.setFlags(LayoutContext.LAST_AREA,
- (context.isLastArea() && childLM == lastLM));
- blocklc.setStackLimit(context.getStackLimit());
- // Add the line areas to Area
- childLM.addAreas(childPosIter, blocklc);
- blocklc.setLeadingSpace(blocklc.getTrailingSpace());
- blocklc.setTrailingSpace(new SpaceSpecifier(false));
- }
- lineArea.updateExtentsFromChildren();
- parentLM.addChildArea(lineArea);
- }
-
- /**
- * @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
- */
- public void addChildArea(Area childArea) {
- // Make sure childArea is inline area
- if (childArea instanceof InlineArea) {
- Area parent = getCurrentArea();
- if (getContext().resolveLeadingSpace()) {
- addSpace(parent,
- getContext().getLeadingSpace().resolve(false),
- getContext().getSpaceAdjust());
- }
- parent.addChildArea(childArea);
- }
- }
-
- // --------- Property Resolution related functions --------- //
-
- /**
- * @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesBlockArea
- */
- public boolean getGeneratesBlockArea() {
- return true;
- }
-
- /**
- * @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesLineArea
- */
- public boolean getGeneratesLineArea() {
- return true;
- }
- }
- ]]>
- </fo:block>
- </fo:flow>
- </fo:page-sequence>
- </fo:root>
- </fo>
- <checks>
- <!-- Not a proper test !! -->
- <eval expected="0 0 720000 360000" xpath="/areaTree/pageSequence/pageViewport/@bounds" desc="page size"/>
- </checks>
- </testcase>
|