Browse Source

initial implementation of line area layout processing

all inline area and their managers are managed by the
LineLayoutManager. This class fills a line with inline
areas and then does the alignment on all the inline areas.
elements which create inline areas add their managers to the
list that is used by the line layout. These managers have
a retrievable index of inline areas.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194747 13f79535-47bb-0310-9956-ffa450edef68
pull/30/head
Keiron Liddle 22 years ago
parent
commit
6619da7ea0
32 changed files with 1155 additions and 612 deletions
  1. 0
    1
      src/org/apache/fop/apps/CommandLineStarter.java
  2. 13
    0
      src/org/apache/fop/area/Block.java
  3. 4
    0
      src/org/apache/fop/area/LineArea.java
  4. 14
    4
      src/org/apache/fop/area/inline/Stretch.java
  5. 51
    52
      src/org/apache/fop/fo/FOText.java
  6. 58
    53
      src/org/apache/fop/fo/FObj.java
  7. 29
    17
      src/org/apache/fop/fo/FObjMixed.java
  8. 6
    0
      src/org/apache/fop/fo/flow/BasicLink.java
  9. 62
    4
      src/org/apache/fop/fo/flow/BidiOverride.java
  10. 198
    194
      src/org/apache/fop/fo/flow/Block.java
  11. 19
    7
      src/org/apache/fop/fo/flow/Character.java
  12. 3
    2
      src/org/apache/fop/fo/flow/ExternalGraphic.java
  13. 32
    30
      src/org/apache/fop/fo/flow/Flow.java
  14. 12
    0
      src/org/apache/fop/fo/flow/Footnote.java
  15. 1
    1
      src/org/apache/fop/fo/flow/Inline.java
  16. 31
    2
      src/org/apache/fop/fo/flow/InlineContainer.java
  17. 7
    2
      src/org/apache/fop/fo/flow/InstreamForeignObject.java
  18. 17
    6
      src/org/apache/fop/fo/flow/Leader.java
  19. 23
    1
      src/org/apache/fop/fo/flow/PageNumber.java
  20. 47
    32
      src/org/apache/fop/fo/flow/PageNumberCitation.java
  21. 30
    17
      src/org/apache/fop/layoutmgr/AbstractLayoutManager.java
  22. 53
    16
      src/org/apache/fop/layoutmgr/BlockLayoutManager.java
  23. 25
    20
      src/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
  24. 2
    2
      src/org/apache/fop/layoutmgr/FlowLayoutManager.java
  25. 5
    0
      src/org/apache/fop/layoutmgr/LayoutInfo.java
  26. 3
    3
      src/org/apache/fop/layoutmgr/LayoutManager.java
  27. 23
    6
      src/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java
  28. 328
    116
      src/org/apache/fop/layoutmgr/LineLayoutManager.java
  29. 14
    6
      src/org/apache/fop/layoutmgr/PageLayoutManager.java
  30. 31
    18
      src/org/apache/fop/layoutmgr/TextLayoutManager.java
  31. 10
    0
      src/org/apache/fop/render/pdf/PDFRenderer.java
  32. 4
    0
      src/org/apache/fop/svg/SVGElement.java

+ 0
- 1
src/org/apache/fop/apps/CommandLineStarter.java View File

@@ -26,7 +26,6 @@ import org.apache.fop.configuration.Configuration;
*
* Modified to use new streaming API by Mark Lillywhite, mark-fop@inomial.com
*/

public class CommandLineStarter extends Starter {

CommandLineOptions commandLineOptions;

+ 13
- 0
src/org/apache/fop/area/Block.java View File

@@ -10,6 +10,7 @@ package org.apache.fop.area;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.awt.geom.Rectangle2D;

// block areas hold either more block areas or line
@@ -54,6 +55,18 @@ public class Block extends BlockParent implements Serializable {
children.add(line);
}

public MinOptMax getContentBPD() {
MinOptMax bpd = new MinOptMax();
if(children != null) {
for(Iterator iter = children.iterator(); iter.hasNext(); ) {
Area area = (Area)iter.next();
MinOptMax mom = area.getContentBPD();
bpd.add(mom);
}
}
return bpd;
}

public int getPositioning() {
return positioning;
}

+ 4
- 0
src/org/apache/fop/area/LineArea.java View File

@@ -39,6 +39,10 @@ public class LineArea extends Area {
return lineHeight;
}

public MinOptMax getContentBPD() {
return new MinOptMax(lineHeight);
}

public void addInlineArea(InlineArea area) {
inlineAreas.add(area);
}

+ 14
- 4
src/org/apache/fop/area/inline/Stretch.java View File

@@ -7,11 +7,21 @@

package org.apache.fop.area.inline;

import org.apache.fop.area.MinOptMax;

public class Stretch extends InlineArea {
MinOptMax contentIPD;

// min size
// set size
// get size
// height 0
public void setAllocationIPD(MinOptMax mom) {
contentIPD = mom;
}

public MinOptMax getAllocationIPD() {
// Should also account for any borders and padding in the
// inline progression dimension
if (contentIPD != null) {
return contentIPD;
}
return super.getAllocationIPD();
}
}

+ 51
- 52
src/org/apache/fop/fo/FOText.java View File

@@ -19,6 +19,7 @@ import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.TextLayoutManager;

import java.util.NoSuchElementException;
import java.util.List;

/**
* a text node in the formatting object tree
@@ -41,21 +42,21 @@ public class FOText extends FObj {
super(null);
this.start = 0;
this.ca = new char[e - s];
System.arraycopy(chars, s, ca, 0, e-s);
System.arraycopy(chars, s, ca, 0, e - s);
this.length = e - s;
textInfo = ti;
}

public boolean willCreateArea() {
if (textInfo.whiteSpaceCollapse == WhiteSpaceCollapse.FALSE
&& length > 0) {
if (textInfo.whiteSpaceCollapse == WhiteSpaceCollapse.FALSE &&
length > 0) {
return true;
}

for (int i = start; i < start + length; i++) {
char ch = ca[i];
if (!((ch == ' ') || (ch == '\n') || (ch == '\r')
|| (ch == '\t'))) { // whitespace
if (!((ch == ' ') || (ch == '\n') || (ch == '\r') ||
(ch == '\t'))) { // whitespace
return true;
}
}
@@ -65,61 +66,59 @@ public class FOText extends FObj {
// Just to keep PageNumber and PageNumber citation happy for now.
// The real code is moved to TextLayoutManager!

public static int addText(BlockArea ba, FontState fontState, float red,
float green, float blue, int wrapOption,
LinkSet ls, int whiteSpaceCollapse,
char data[], int start, int end,
TextState textState, int vAlign) {
return 0;
public static int addText(BlockArea ba, FontState fontState,
float red, float green, float blue, int wrapOption,
LinkSet ls, int whiteSpaceCollapse, char data[],
int start, int end, TextState textState, int vAlign) {
return 0;
}

public LayoutManager getLayoutManager() {
// What if nothing left (length=0)?
if (length < ca.length) {
char[] tmp = ca;
ca = new char[length];
System.arraycopy(tmp, 0, ca, 0, length);
}
return new TextLayoutManager(this, ca, textInfo);
public void addLayoutManager(List list) {
// What if nothing left (length=0)?
if (length < ca.length) {
char[] tmp = ca;
ca = new char[length];
System.arraycopy(tmp, 0, ca, 0, length);
}
list.add(new TextLayoutManager(this, ca, textInfo));
}

public CharIterator charIterator() {
return new TextCharIterator();
return new TextCharIterator();
}

private class TextCharIterator extends AbstractCharIterator {
int curIndex = 0;
public boolean hasNext() {
return (curIndex < length);
}

public char nextChar() {
if (curIndex < length) {
// Just a char class? Don't actually care about the value!
return ca[curIndex++];
}
else throw new NoSuchElementException();
}

public void remove() {
if (curIndex>0 && curIndex < length) {
// copy from curIndex to end to curIndex-1
System.arraycopy(ca, curIndex, ca, curIndex-1,
length-curIndex);
length--;
curIndex--;
}
else if (curIndex == length) {
curIndex = --length;
}
}


public void replaceChar(char c) {
if (curIndex>0 && curIndex <= length) {
ca[curIndex-1]=c;
}
}
int curIndex = 0;
public boolean hasNext() {
return (curIndex < length);
}

public char nextChar() {
if (curIndex < length) {
// Just a char class? Don't actually care about the value!
return ca[curIndex++];
} else
throw new NoSuchElementException();
}

public void remove() {
if (curIndex > 0 && curIndex < length) {
// copy from curIndex to end to curIndex-1
System.arraycopy(ca, curIndex, ca, curIndex - 1,
length - curIndex);
length--;
curIndex--;
} else if (curIndex == length) {
curIndex = --length;
}
}


public void replaceChar(char c) {
if (curIndex > 0 && curIndex <= length) {
ca[curIndex - 1] = c;
}
}


}

+ 58
- 53
src/org/apache/fop/fo/FObj.java View File

@@ -26,6 +26,7 @@ import org.xml.sax.Attributes;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;

/**
@@ -53,7 +54,7 @@ public class FObj extends FONode {
*/
protected int marker = START;

protected ArrayList children = new ArrayList(); // made public for searching for id's
protected ArrayList children = new ArrayList(); // made public for searching for id's

protected boolean isInTableCell = false;

@@ -75,7 +76,7 @@ public class FObj extends FONode {
super(parent);
markers = new HashMap();
if (parent instanceof FObj)
this.areaClass = ((FObj)parent).areaClass;
this.areaClass = ((FObj) parent).areaClass;
}

public void setName(String str) {
@@ -85,14 +86,16 @@ public class FObj extends FONode {
protected static PropertyListBuilder plb = null;

protected PropertyListBuilder getListBuilder() {
if(plb == null) {
if (plb == null) {
plb = new PropertyListBuilder();
plb.addList(FOPropertyMapping.getGenericMappings());

for (Iterator iter = FOPropertyMapping.getElementMappings().iterator();
iter.hasNext(); ) {
String elem = (String)iter.next();
plb.addElementList(elem, FOPropertyMapping.getElementMapping(elem));
for (Iterator iter =
FOPropertyMapping.getElementMappings().iterator();
iter.hasNext();) {
String elem = (String) iter.next();
plb.addElementList(elem,
FOPropertyMapping.getElementMapping(elem));
}
}
return plb;
@@ -106,22 +109,22 @@ public class FObj extends FONode {
public void handleAttrs(Attributes attlist) throws FOPException {
String uri = "http://www.w3.org/1999/XSL/Format";
FONode par = parent;
while(par != null && !(par instanceof FObj)) {
while (par != null && !(par instanceof FObj)) {
par = par.parent;
}
PropertyList props = null;
if(par != null) {
props = ((FObj)par).properties;
if (par != null) {
props = ((FObj) par).properties;
}
properties =
getListBuilder().makeList(uri, name, attlist,
props, (FObj)par);
properties = getListBuilder().makeList(uri, name, attlist, props,
(FObj) par);
properties.setFObj(this);
this.propMgr = makePropertyManager(properties);
setWritingMode();
}

protected PropertyManager makePropertyManager(PropertyList propertyList) {
protected PropertyManager makePropertyManager(
PropertyList propertyList) {
return new PropertyManager(propertyList);
}

@@ -158,15 +161,16 @@ public class FObj extends FONode {
* @param idReferences the id to remove
*/
public void removeID(IDReferences idReferences) {
if (((FObj)this).properties.get("id") == null
|| ((FObj)this).properties.get("id").getString() == null)
if (((FObj) this).properties.get("id") == null ||
((FObj) this).properties.get("id").getString() == null)
return;
idReferences.removeID(((FObj)this).properties.get("id").getString());
idReferences.removeID(
((FObj) this).properties.get("id").getString());
int numChildren = this.children.size();
for (int i = 0; i < numChildren; i++) {
FONode child = (FONode)children.get(i);
FONode child = (FONode) children.get(i);
if ((child instanceof FObj)) {
((FObj)child).removeID(idReferences);
((FObj) child).removeID(idReferences);
}
}
}
@@ -189,18 +193,19 @@ public class FObj extends FONode {
protected void setWritingMode() {
FObj p;
FONode parent;
for (p = this;
!p.generatesReferenceAreas() && (parent = p.getParent()) != null && (parent instanceof FObj);
p = (FObj)parent);
this.properties.setWritingMode(p.getProperty("writing-mode").getEnum());
for (p = this; !p.generatesReferenceAreas() &&
(parent = p.getParent()) != null &&
(parent instanceof FObj); p = (FObj) parent)
;
this.properties.setWritingMode(
p.getProperty("writing-mode").getEnum());
}

/**
* Return a LayoutManager responsible for laying out this FObj's content.
* Must override in subclasses if their content can be laid out.
*/
public LayoutManager getLayoutManager() {
return null;
public void addLayoutManager(List list) {
}

/**
@@ -208,7 +213,7 @@ public class FObj extends FONode {
* @return A ListIterator.
*/
public ListIterator getChildren() {
return children.listIterator();
return children.listIterator();
}

/**
@@ -219,11 +224,11 @@ public class FObj extends FONode {
* this FObj.
*/
public ListIterator getChildren(FONode childNode) {
int i = children.indexOf(childNode);
if (i >= 0) {
return children.listIterator(i);
}
else return null;
int i = children.indexOf(childNode);
if (i >= 0) {
return children.listIterator(i);
} else
return null;
}

public void setIsInTableCell() {
@@ -231,20 +236,20 @@ public class FObj extends FONode {
// made recursive by Eric Schaeffer
for (int i = 0; i < this.children.size(); i++) {
Object obj = this.children.get(i);
if(obj instanceof FObj) {
FObj child = (FObj)obj;
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.setIsInTableCell();
}
}
}
public void forceStartOffset(int offset) {
this.forcedStartOffset = offset;
this.forcedStartOffset = offset;
// made recursive by Eric Schaeffer
for (int i = 0; i < this.children.size(); i++) {
Object obj = this.children.get(i);
if(obj instanceof FObj) {
FObj child = (FObj)obj;
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.forceStartOffset(offset);
}
}
@@ -255,8 +260,8 @@ public class FObj extends FONode {
// made recursive by Eric Schaeffer
for (int i = 0; i < this.children.size(); i++) {
Object obj = this.children.get(i);
if(obj instanceof FObj) {
FObj child = (FObj)obj;
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.forceWidth(width);
}
}
@@ -267,8 +272,8 @@ public class FObj extends FONode {
int numChildren = this.children.size();
for (int i = 0; i < numChildren; i++) {
Object obj = this.children.get(i);
if(obj instanceof FObj) {
FObj child = (FObj)obj;
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.resetMarker();
}
}
@@ -277,7 +282,7 @@ public class FObj extends FONode {
public void setWidows(int wid) {
widows = wid;
}
public void setOrphans(int orph) {
orphans = orph;
}
@@ -290,8 +295,8 @@ public class FObj extends FONode {
this.linkSet = linkSet;
for (int i = 0; i < this.children.size(); i++) {
Object obj = this.children.get(i);
if(obj instanceof FObj) {
FObj child = (FObj)obj;
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.setLinkSet(linkSet);
}
}
@@ -317,7 +322,8 @@ public class FObj extends FONode {
else if (children.isEmpty())
return snapshot;
else
return ((FObj)children.get(this.marker)).getMarkerSnapshot(snapshot);
return ( (FObj) children.get(this.marker)).getMarkerSnapshot(
snapshot);
}

/**
@@ -327,7 +333,7 @@ public class FObj extends FONode {
* @param snapshot the ArrayList of saved markers (Integers)
*/
public void rollback(ArrayList snapshot) {
this.marker = ((Integer)snapshot.get(0)).intValue();
this.marker = ((Integer) snapshot.get(0)).intValue();
snapshot.remove(0);

if (this.marker == START) {
@@ -345,12 +351,12 @@ public class FObj extends FONode {

for (int i = this.marker + 1; i < numChildren; i++) {
Object obj = this.children.get(i);
if(obj instanceof FObj) {
FObj child = (FObj)obj;
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.resetMarker();
}
}
((FObj)children.get(this.marker)).rollback(snapshot);
((FObj) children.get(this.marker)).rollback(snapshot);
}


@@ -359,10 +365,9 @@ public class FObj extends FONode {
if (!markers.containsKey(mcname) && children.isEmpty()) {
markers.put(mcname, marker);
} else {
log.error("fo:marker must be an initial child,"
+ "and 'marker-class-name' must be unique for same parent");
throw new FOPException("fo:marker must be an initial child,"
+ "and 'marker-class-name' must be unique for same parent");
log.error("fo:marker must be an initial child," + "and 'marker-class-name' must be unique for same parent");
throw new FOPException(
"fo:marker must be an initial child," + "and 'marker-class-name' must be unique for same parent");
}
}


+ 29
- 17
src/org/apache/fop/fo/FObjMixed.java View File

@@ -14,6 +14,7 @@ import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.StreamRenderer;
import org.apache.fop.datatypes.ColorType;

import java.util.List;

/**
* base class for representation of mixed content formatting objects
@@ -21,37 +22,48 @@ import org.apache.fop.datatypes.ColorType;
*/
public class FObjMixed extends FObj {
TextInfo textInfo = null;
protected FontInfo fontInfo=null;
protected FontInfo fontInfo = null;

public FObjMixed(FONode parent) {
super(parent);
}

public void setStreamRenderer(StreamRenderer st) {
fontInfo = st.getFontInfo();
fontInfo = st.getFontInfo();
}

protected void addCharacters(char data[], int start, int length) {
if(textInfo == null) {
textInfo = new TextInfo();
public void addLayoutManager(List lms) {
// set start and end properties for this element, id, etc.
int numChildren = this.children.size();
for (int i = 0; i < numChildren; i++) {
Object o = children.get(i);
if (o instanceof FObj) {
FObj fo = (FObj) o;
fo.addLayoutManager(lms);
}
}
}

try {
textInfo.fs = propMgr.getFontState(fontInfo);
} catch (FOPException fopex) {
log.error("Error setting FontState for characters: " +
fopex.getMessage());
}
protected void addCharacters(char data[], int start, int length) {
if (textInfo == null) {
textInfo = new TextInfo();

try {
textInfo.fs = propMgr.getFontState(fontInfo);
} catch (FOPException fopex) {
log.error("Error setting FontState for characters: " +
fopex.getMessage());
}

ColorType c = getProperty("color").getColorType();
textInfo.color = c;

textInfo.verticalAlign =
getProperty("vertical-align").getEnum();
getProperty("vertical-align").getEnum();

textInfo.wrapOption =
getProperty("wrap-option").getEnum();
textInfo.wrapOption = getProperty("wrap-option").getEnum();
textInfo.whiteSpaceCollapse =
getProperty("white-space-collapse").getEnum();
getProperty("white-space-collapse").getEnum();

}

@@ -82,7 +94,7 @@ public class FObjMixed extends FObj {

int numChildren = this.children.size();
for (int i = this.marker; i < numChildren; i++) {
FONode fo = (FONode)children.get(i);
FONode fo = (FONode) children.get(i);
Status status;
if ((status = fo.layout(area)).isIncomplete()) {
this.marker = i;
@@ -93,7 +105,7 @@ public class FObjMixed extends FObj {
}

public CharIterator charIterator() {
return new RecursiveCharIterator(this);
return new RecursiveCharIterator(this);
}

}

+ 6
- 0
src/org/apache/fop/fo/flow/BasicLink.java View File

@@ -17,6 +17,7 @@ import org.apache.fop.datatypes.ColorType;
// Java
import java.util.Enumeration;
import java.awt.Rectangle;
import java.util.List;

public class BasicLink extends Inline {

@@ -24,6 +25,11 @@ public class BasicLink extends Inline {
super(parent);
}

// add start and end properties for the link
public void addLayoutManager(List lms) {
super.addLayoutManager(lms);
}

public Status layout(Area area) throws FOPException {
String destination;
int linkType;

+ 62
- 4
src/org/apache/fop/fo/flow/BidiOverride.java View File

@@ -9,21 +9,48 @@ package org.apache.fop.fo.flow;

// FOP
import org.apache.fop.fo.*;
import org.apache.fop.layout.*;
import org.apache.fop.layout.AuralProps;
import org.apache.fop.layout.RelativePositionProps;
import org.apache.fop.fo.flow.*;
import org.apache.fop.fo.properties.*;
import org.apache.fop.layout.AreaTree;
import org.apache.fop.apps.FOPException;

import org.apache.fop.layoutmgr.LeafNodeLayoutManager;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.Word;

import java.util.List;
import java.util.ArrayList;

/**
*/
public class BidiOverride extends ToBeImplementedElement {
public class BidiOverride extends FObjMixed {

public BidiOverride(FONode parent) {
super(parent);
}

public Status layout(Area area) throws FOPException {
public void addLayoutManager(List list) {
if (false) {
super.addLayoutManager(list);
} else {
ArrayList childList = new ArrayList();
super.addLayoutManager(childList);
for (int count = childList.size() - 1; count >= 0; count--) {
LayoutManager lm = (LayoutManager) childList.get(count);
if (lm.generatesInlineAreas()) {
list.add( new BidiLayoutManager(this,
(LeafNodeLayoutManager) lm));
} else {
list.add(lm);
}
}
}
}

public void setup() {

// Common Aural Properties
AuralProps mAurProps = propMgr.getAuralProps();
@@ -46,6 +73,37 @@ public class BidiOverride extends ToBeImplementedElement {
// this.properties.get("unicode-bidi");
// this.properties.get("word-spacing");

return super.layout(area);
}

/**
* If this bidi has a different writing mode direction
* ltr or rtl than its parent writing mode then this
* reverses the inline areas (at the character level).
*/
class BidiLayoutManager extends LeafNodeLayoutManager {
List childs;

BidiLayoutManager(FObj obj, LeafNodeLayoutManager cLM) {
super(obj);
childs = new ArrayList();
for (int count = cLM.size() - 1; count >= 0; count--) {
InlineArea ia = cLM.get(count);
if (ia instanceof Word) {
// reverse word
Word word = (Word) ia;
StringBuffer sb = new StringBuffer(word.getWord());
word.setWord(sb.reverse().toString());
}
childs.add(ia);
}
}

public int size() {
return childs.size();
}

public InlineArea get(int index) {
return (InlineArea) childs.get(index);
}
}
}

+ 198
- 194
src/org/apache/fop/fo/flow/Block.java View File

@@ -20,6 +20,8 @@ import org.apache.fop.apps.StreamRenderer;

import org.xml.sax.Attributes;

import java.util.List;

/*
Modified by Mark Lillywhite mark-fop@inomial.com. The changes
here are based on memory profiling and do not change functionality.
@@ -31,9 +33,9 @@ import org.xml.sax.Attributes;
the reference to BlockArea was made local, the required information
is now stored (instead of a reference to the complex BlockArea object)
and it appears that there are a lot of changes in this file, in fact
there are only a few sematic changes; mostly I just got rid of
there are only a few sematic changes; mostly I just got rid of
"this." from blockArea since BlockArea is now local.
*/
*/

public class Block extends FObjMixed {

@@ -76,10 +78,13 @@ public class Block extends FObjMixed {
public void handleAttrs(Attributes attlist) throws FOPException {
super.handleAttrs(attlist);
this.span = this.properties.get("span").getEnum();
this.wsTreatment = this.properties.get("white-space-treatment").getEnum();
this.bWScollapse = (this.properties.get("white-space-collapse").getEnum() ==
Constants.TRUE);
this.lfTreatment = this.properties.get("linefeed-treatment").getEnum();
this.wsTreatment =
this.properties.get("white-space-treatment").getEnum();
this.bWScollapse =
(this.properties.get("white-space-collapse").getEnum()
== Constants.TRUE);
this.lfTreatment =
this.properties.get("linefeed-treatment").getEnum();
}

public Status layout(Area area) throws FOPException {
@@ -114,7 +119,8 @@ public class Block extends FObjMixed {
MarginProps mProps = propMgr.getMarginProps();

// Common Relative Position Properties
RelativePositionProps mRelProps = propMgr.getRelativePositionProps();
RelativePositionProps mRelProps =
propMgr.getRelativePositionProps();

// this.properties.get("break-after");
// this.properties.get("break-before");
@@ -145,29 +151,30 @@ public class Block extends FObjMixed {
// this.properties.get("z-index");

this.align = this.properties.get("text-align").getEnum();
this.alignLast = this.properties.get("text-align-last").getEnum();
this.alignLast =
this.properties.get("text-align-last").getEnum();
this.breakAfter = this.properties.get("break-after").getEnum();
this.lineHeight =
this.properties.get("line-height").getLength().mvalue();
this.startIndent =
this.properties.get("start-indent").getLength().mvalue();
this.endIndent =
this.properties.get("end-indent").getLength().mvalue();
this.spaceBefore =
this.properties.get("space-before.optimum").getLength().mvalue();
this.spaceAfter =
this.properties.get("space-after.optimum").getLength().mvalue();
this.textIndent =
this.properties.get("text-indent").getLength().mvalue();
this.lineHeight = this.properties.get(
"line-height").getLength().mvalue();
this.startIndent = this.properties.get(
"start-indent").getLength().mvalue();
this.endIndent = this.properties.get(
"end-indent").getLength().mvalue();
this.spaceBefore = this.properties.get(
"space-before.optimum").getLength().mvalue();
this.spaceAfter = this.properties.get(
"space-after.optimum").getLength().mvalue();
this.textIndent = this.properties.get(
"text-indent").getLength().mvalue();
this.keepWithNext =
this.properties.get("keep-with-next").getEnum();
this.backgroundColor =
this.properties.get("background-color").getColorType();
this.properties.get("keep-with-next").getEnum();
this.backgroundColor = this.properties.get(
"background-color").getColorType();

this.blockWidows =
this.properties.get("widows").getNumber().intValue();
this.properties.get("widows").getNumber().intValue();
this.blockOrphans =
this.properties.get("orphans").getNumber().intValue();
this.properties.get("orphans").getNumber().intValue();

this.id = this.properties.get("id").getString();

@@ -189,9 +196,9 @@ public class Block extends FObjMixed {

int numChildren = this.children.size();
for (int i = 0; i < numChildren; i++) {
FONode fo = (FONode)children.get(i);
FONode fo = (FONode) children.get(i);
if (fo instanceof FOText) {
if (((FOText)fo).willCreateArea()) {
if (((FOText) fo).willCreateArea()) {
//fo.setWidows(blockWidows);
break;
} else {
@@ -206,9 +213,9 @@ public class Block extends FObjMixed {
}

for (int i = numChildren - 1; i >= 0; i--) {
FONode fo = (FONode)children.get(i);
FONode fo = (FONode) children.get(i);
if (fo instanceof FOText) {
if (((FOText)fo).willCreateArea()) {
if (((FOText) fo).willCreateArea()) {
//fo.setOrphans(blockOrphans);
break;
}
@@ -232,11 +239,10 @@ public class Block extends FObjMixed {
}

int spaceLeft = area.spaceLeft();
blockArea =
new BlockArea(propMgr.getFontState(area.getFontInfo()),
area.getAllocationWidth(), area.spaceLeft(),
startIndent, endIndent, textIndent, align,
alignLast, lineHeight);
blockArea = new BlockArea( propMgr.getFontState(area.getFontInfo()),
area.getAllocationWidth(), area.spaceLeft(),
startIndent, endIndent, textIndent, align, alignLast,
lineHeight);
blockArea.setGeneratedBy(this);
this.areasGenerated++;
if (this.areasGenerated == 1)
@@ -246,9 +252,9 @@ public class Block extends FObjMixed {

// markers
//if (this.hasMarkers())
//blockArea.addMarkers(this.getMarkers());
//blockArea.addMarkers(this.getMarkers());

blockArea.setParent(area); // BasicLink needs it
blockArea.setParent(area); // BasicLink needs it
blockArea.setPage(area.getPage());
blockArea.setBackgroundColor(backgroundColor);
blockArea.setBorderAndPadding(propMgr.getBorderAndPadding());
@@ -262,7 +268,7 @@ public class Block extends FObjMixed {

int numChildren = this.children.size();
for (int i = this.marker; i < numChildren; i++) {
FONode fo = (FONode)children.get(i);
FONode fo = (FONode) children.get(i);
Status status;
if ((status = fo.layout(blockArea)).isIncomplete()) {
this.marker = i;
@@ -280,14 +286,15 @@ public class Block extends FObjMixed {
if ((i != 0)) {
status = new Status(Status.AREA_FULL_SOME);
area.addChild(blockArea);
area.setMaxHeight(area.getMaxHeight() - spaceLeft
+ blockArea.getMaxHeight());
area.setMaxHeight(area.getMaxHeight() -
spaceLeft + blockArea.getMaxHeight());
area.increaseHeight(blockArea.getHeight());
area.setAbsoluteHeight(blockArea.getAbsoluteHeight());
area.setAbsoluteHeight(
blockArea.getAbsoluteHeight());
anythingLaidOut = true;

return status;
} else // i == 0 nothing was laid out..
} else // i == 0 nothing was laid out..
{
anythingLaidOut = false;
return status;
@@ -296,8 +303,8 @@ public class Block extends FObjMixed {

// blockArea.end();
area.addChild(blockArea);
area.setMaxHeight(area.getMaxHeight() - spaceLeft
+ blockArea.getMaxHeight());
area.setMaxHeight(area.getMaxHeight() - spaceLeft +
blockArea.getMaxHeight());
area.increaseHeight(blockArea.getHeight());
area.setAbsoluteHeight(blockArea.getAbsoluteHeight());
anythingLaidOut = true;
@@ -308,8 +315,8 @@ public class Block extends FObjMixed {

blockArea.end();

area.setMaxHeight(area.getMaxHeight() - spaceLeft
+ blockArea.getMaxHeight());
area.setMaxHeight(area.getMaxHeight() - spaceLeft +
blockArea.getMaxHeight());

area.addChild(blockArea);

@@ -327,8 +334,8 @@ public class Block extends FObjMixed {
}
// This is not needed any more and it consumes a LOT
// of memory. So we release it for the GC.
areaHeight= blockArea.getHeight();
contentWidth= blockArea.getContentWidth();
areaHeight = blockArea.getHeight();
contentWidth = blockArea.getContentWidth();

// no break if last in area tree, or trailing in context
// area
@@ -359,7 +366,7 @@ public class Block extends FObjMixed {
* Return the content width of the boxes generated by this FO.
*/
public int getContentWidth() {
return contentWidth; // getAllocationWidth()??
return contentWidth; // getAllocationWidth()??
}


@@ -367,26 +374,25 @@ public class Block extends FObjMixed {
return this.span;
}

public LayoutManager getLayoutManager() {
BlockLayoutManager blm = new BlockLayoutManager(this);
TextInfo ti = new TextInfo();
public void addLayoutManager(List list) {
BlockLayoutManager blm = new BlockLayoutManager(this);
TextInfo ti = new TextInfo();

try {
ti.fs = propMgr.getFontState(fontInfo);
} catch (FOPException fopex) {
log.error("Error setting FontState for characters: " +
fopex.getMessage());
}
ti.lineHeight = this.lineHeight;
try {
ti.fs = propMgr.getFontState(fontInfo);
} catch (FOPException fopex) {
log.error("Error setting FontState for characters: " +
fopex.getMessage());
}
ti.lineHeight = this.lineHeight;

ColorType c = getProperty("color").getColorType();
ti.color = c;
ColorType c = getProperty("color").getColorType();
ti.color = c;

ti.verticalAlign =
getProperty("vertical-align").getEnum();
ti.verticalAlign = getProperty("vertical-align").getEnum();

blm.setBlockTextInfo(ti);
return blm;
blm.setBlockTextInfo(ti);
list.add(blm);
}

public boolean generatesInlineAreas() {
@@ -394,144 +400,142 @@ blm.setBlockTextInfo(ti);
}

public void addChild(FONode child) {
// Handle whitespace based on values of properties
// Handle a sequence of inline-producing children in
// one pass
if (((FObj)child).generatesInlineAreas()) {
if (firstInlineChild == null) {
firstInlineChild = child;
}
// lastInlineChild = children.size();
}
else {
// Handle whitespace in preceeding inline areas if any
handleWhiteSpace();
}
super.addChild(child);
// Handle whitespace based on values of properties
// Handle a sequence of inline-producing children in
// one pass
if (((FObj) child).generatesInlineAreas()) {
if (firstInlineChild == null) {
firstInlineChild = child;
}
// lastInlineChild = children.size();
} else {
// Handle whitespace in preceeding inline areas if any
handleWhiteSpace();
}
super.addChild(child);
}

public void end() {
handleWhiteSpace();
handleWhiteSpace();
}

private void handleWhiteSpace() {
log.debug("fo:block: handleWhiteSpace");
if (firstInlineChild != null) {
boolean bInWS=false;
boolean bPrevWasLF=false;
RecursiveCharIterator charIter =
new RecursiveCharIterator(this, firstInlineChild);
LFchecker lfCheck = new LFchecker(charIter);
while (charIter.hasNext()) {
switch (CharUtilities.classOf(charIter.nextChar())) {
case CharUtilities.XMLWHITESPACE:
/* Some kind of whitespace character, except linefeed. */
boolean bIgnore=false;
switch (wsTreatment) {
case Constants.IGNORE:
bIgnore=true;
break;
case Constants.IGNORE_IF_BEFORE_LINEFEED:
bIgnore = lfCheck.nextIsLF();
break;
case Constants.IGNORE_IF_SURROUNDING_LINEFEED:
bIgnore = (bPrevWasLF || lfCheck.nextIsLF());
break;
case Constants.IGNORE_IF_AFTER_LINEFEED:
bIgnore = bPrevWasLF;
break;
}
// Handle ignore
if (bIgnore) {
charIter.remove();
}
else if (bWScollapse) {
if (bInWS || (lfTreatment == Constants.PRESERVE &&
(bPrevWasLF || lfCheck.nextIsLF()))) {
charIter.remove();
}
else {
bInWS = true;
}
}
break;
case CharUtilities.LINEFEED:
/* A linefeed */
lfCheck.reset();
bPrevWasLF=true; // for following whitespace
switch (lfTreatment) {
case Constants.IGNORE:
charIter.remove();
break;
case Constants.TREAT_AS_SPACE:
if (bInWS) {
// only if bWScollapse=true
charIter.remove();
}
else {
if (bWScollapse) bInWS=true;
charIter.replaceChar('\u0020');
}
break;
case Constants.TREAT_AS_ZERO_WIDTH_SPACE:
charIter.replaceChar('\u200b');
// Fall through: this isn't XML whitespace
case Constants.PRESERVE:
bInWS=false;
break;
}
break;
case CharUtilities.EOT:
// A "boundary" objects such as non-character inline
// or nested block object was encountered.
// If any whitespace run in progress, finish it.
// FALL THROUGH
case CharUtilities.UCWHITESPACE: // Non XML-whitespace
case CharUtilities.NONWHITESPACE:
/* Any other character */
bInWS = bPrevWasLF=false;
lfCheck.reset();
break;
}
}
firstInlineChild = null;
}
log.debug("fo:block: handleWhiteSpace");
if (firstInlineChild != null) {
boolean bInWS = false;
boolean bPrevWasLF = false;
RecursiveCharIterator charIter =
new RecursiveCharIterator(this, firstInlineChild);
LFchecker lfCheck = new LFchecker(charIter);
while (charIter.hasNext()) {
switch (CharUtilities.classOf(charIter.nextChar())) {
case CharUtilities.XMLWHITESPACE:
/* Some kind of whitespace character, except linefeed. */
boolean bIgnore = false;
switch (wsTreatment) {
case Constants.IGNORE:
bIgnore = true;
break;
case Constants.IGNORE_IF_BEFORE_LINEFEED:
bIgnore = lfCheck.nextIsLF();
break;
case Constants.IGNORE_IF_SURROUNDING_LINEFEED:
bIgnore = (bPrevWasLF ||
lfCheck.nextIsLF());
break;
case Constants.IGNORE_IF_AFTER_LINEFEED:
bIgnore = bPrevWasLF;
break;
}
// Handle ignore
if (bIgnore) {
charIter.remove();
} else if (bWScollapse) {
if (bInWS || (lfTreatment ==
Constants.PRESERVE &&
(bPrevWasLF || lfCheck.nextIsLF()))) {
charIter.remove();
} else {
bInWS = true;
}
}
break;
case CharUtilities.LINEFEED:
/* A linefeed */
lfCheck.reset();
bPrevWasLF = true; // for following whitespace
switch (lfTreatment) {
case Constants.IGNORE:
charIter.remove();
break;
case Constants.TREAT_AS_SPACE:
if (bInWS) {
// only if bWScollapse=true
charIter.remove();
} else {
if (bWScollapse)
bInWS = true;
charIter.replaceChar('\u0020');
}
break;
case Constants.TREAT_AS_ZERO_WIDTH_SPACE:
charIter.replaceChar('\u200b');
// Fall through: this isn't XML whitespace
case Constants.PRESERVE:
bInWS = false;
break;
}
break;
case CharUtilities.EOT:
// A "boundary" objects such as non-character inline
// or nested block object was encountered.
// If any whitespace run in progress, finish it.
// FALL THROUGH
case CharUtilities.UCWHITESPACE: // Non XML-whitespace
case CharUtilities.NONWHITESPACE:
/* Any other character */
bInWS = bPrevWasLF = false;
lfCheck.reset();
break;
}
}
firstInlineChild = null;
}
}

private static class LFchecker {
private boolean bNextIsLF=false;
private RecursiveCharIterator charIter;
LFchecker(RecursiveCharIterator charIter) {
this.charIter = charIter;
}

boolean nextIsLF() {
if (bNextIsLF==false) {
CharIterator lfIter = charIter.mark();
while (lfIter.hasNext()) {
char c = lfIter.nextChar();
if (c == '\n') {
bNextIsLF=true;
break;
}
else if (CharUtilities.classOf(c) !=
CharUtilities.XMLWHITESPACE) {
break;
}
}
}
return bNextIsLF;
}

void reset() {
bNextIsLF=false;
}
private boolean bNextIsLF = false;
private RecursiveCharIterator charIter;

LFchecker(RecursiveCharIterator charIter) {
this.charIter = charIter;
}

boolean nextIsLF() {
if (bNextIsLF == false) {
CharIterator lfIter = charIter.mark();
while (lfIter.hasNext()) {
char c = lfIter.nextChar();
if (c == '\n') {
bNextIsLF = true;
break;
} else if (CharUtilities.classOf(c) !=
CharUtilities.XMLWHITESPACE) {
break;
}
}
}
return bNextIsLF;
}

void reset() {
bNextIsLF = false;
}
}
}

+ 19
- 7
src/org/apache/fop/fo/flow/Character.java View File

@@ -24,6 +24,7 @@ import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LeafNodeLayoutManager;

import java.util.List;

/**
* this class represents the flow object 'fo:character'. Its use is defined by
@@ -48,13 +49,23 @@ public class Character extends FObj {
super(parent);
}

public LayoutManager getLayoutManager() {
LeafNodeLayoutManager lm = new LeafNodeLayoutManager(this);
lm.setCurrentArea(getInlineArea());
return lm;
public void addLayoutManager(List list) {
InlineArea inline = getInlineArea();
if (inline != null) {
LeafNodeLayoutManager lm = new LeafNodeLayoutManager(this);
lm.setCurrentArea(inline);
list.add(lm);
}
}

protected InlineArea getInlineArea() {
String str = this.properties.get("character").getString();
if (str.length() == 1) {
org.apache.fop.area.inline.Character ch =
new org.apache.fop.area.inline.Character(
str.charAt(0));
return ch;
}
return null;
}

@@ -77,7 +88,8 @@ public class Character extends FObj {
MarginInlineProps mProps = propMgr.getMarginInlineProps();

// Common Relative Position Properties
RelativePositionProps mRelProps = propMgr.getRelativePositionProps();
RelativePositionProps mRelProps =
propMgr.getRelativePositionProps();

// this.properties.get("alignment-adjust");
// this.properties.get("treat-as-word-space");
@@ -105,8 +117,8 @@ public class Character extends FObj {
}

public CharIterator charIterator() {
return new OneCharIterator(characterValue);
// But what it the character is ignored due to white space handling?
return new OneCharIterator(characterValue);
// But what it the character is ignored due to white space handling?
}



+ 3
- 2
src/org/apache/fop/fo/flow/ExternalGraphic.java View File

@@ -22,6 +22,7 @@ import org.apache.fop.area.inline.Viewport;
// Java
import java.net.URL;
import java.net.MalformedURLException;
import java.util.List;

public class ExternalGraphic extends FObj {
String url;
@@ -41,10 +42,10 @@ public class ExternalGraphic extends FObj {
super(parent);
}

public LayoutManager getLayoutManager() {
public void addLayoutManager(List list) {
LeafNodeLayoutManager lm = new LeafNodeLayoutManager(this);
lm.setCurrentArea(getInlineArea());
return lm;
list.add(lm);
}

protected InlineArea getInlineArea() {

+ 32
- 30
src/org/apache/fop/fo/flow/Flow.java View File

@@ -19,6 +19,7 @@ import org.apache.fop.layoutmgr.FlowLayoutManager;

// Java
import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;

@@ -59,36 +60,35 @@ public class Flow extends FObj {
public void handleAttrs(Attributes attlist) throws FOPException {
super.handleAttrs(attlist);
if (parent.getName().equals("fo:page-sequence")) {
this.pageSequence = (PageSequence)parent;
this.pageSequence = (PageSequence) parent;
} else {
throw new FOPException("flow must be child of "
+ "page-sequence, not "
+ parent.getName());
throw new FOPException("flow must be child of " +
"page-sequence, not " + parent.getName());
}
// according to communication from Paul Grosso (XSL-List,
// 001228, Number 406), confusion in spec section 6.4.5 about
// multiplicity of fo:flow in XSL 1.0 is cleared up - one (1)
// fo:flow per fo:page-sequence only.

/* if (pageSequence.isFlowSet()) {
if (this.name.equals("fo:flow")) {
throw new FOPException("Only a single fo:flow permitted"
+ " per fo:page-sequence");
} else {
throw new FOPException(this.name
+ " not allowed after fo:flow");
}
}
*/
/* if (pageSequence.isFlowSet()) {
if (this.name.equals("fo:flow")) {
throw new FOPException("Only a single fo:flow permitted"
+ " per fo:page-sequence");
} else {
throw new FOPException(this.name
+ " not allowed after fo:flow");
}
}
*/
setFlowName(getProperty("flow-name").getString());
// Now done in addChild of page-sequence
// Now done in addChild of page-sequence
//pageSequence.addFlow(this);
}

protected void setFlowName(String name) throws FOPException {
if (name == null || name.equals("")) {
throw new FOPException("A 'flow-name' is required for "
+ getName());
throw new FOPException("A 'flow-name' is required for " +
getName());
} else {
_flowName = name;
}
@@ -109,7 +109,7 @@ public class Flow extends FObj {
}

// flow is *always* laid out into a BodyAreaContainer
BodyAreaContainer bac = (BodyAreaContainer)area;
BodyAreaContainer bac = (BodyAreaContainer) area;

boolean prevChildMustKeepWithNext = false;
ArrayList pageMarker = this.getMarkerSnapshot(new ArrayList());
@@ -119,7 +119,7 @@ public class Flow extends FObj {
throw new FOPException("fo:flow must contain block-level children");
}
for (int i = this.marker; i < numChildren; i++) {
FObj fo = (FObj)children.get(i);
FObj fo = (FObj) children.get(i);

if (bac.isBalancingRequired(fo)) {
// reset the the just-done span area in preparation
@@ -139,8 +139,8 @@ public class Flow extends FObj {
this.marker = i;
markerSnapshot = this.getMarkerSnapshot(new ArrayList());
}
// Set current content width for percent-based lengths in children
setContentWidth(currentArea.getContentWidth());
// Set current content width for percent-based lengths in children
setContentWidth(currentArea.getContentWidth());

_status = fo.layout(currentArea);

@@ -155,9 +155,10 @@ public class Flow extends FObj {
* }
*/
if (_status.isIncomplete()) {
if ((prevChildMustKeepWithNext) && (_status.laidOutNone())) {
if ((prevChildMustKeepWithNext) &&
(_status.laidOutNone())) {
this.marker = i - 1;
FObj prevChild = (FObj)children.get(this.marker);
FObj prevChild = (FObj) children.get(this.marker);
prevChild.removeAreas();
prevChild.resetMarker();
prevChild.removeID(area.getIDReferences());
@@ -169,8 +170,8 @@ public class Flow extends FObj {
if (bac.isLastColumn())
if (_status.getCode() == Status.FORCE_COLUMN_BREAK) {
this.marker = i;
_status =
new Status(Status.FORCE_PAGE_BREAK); // same thing
_status = new Status(Status.FORCE_PAGE_BREAK);
// same thing
return _status;
} else {
this.marker = i;
@@ -183,7 +184,8 @@ public class Flow extends FObj {
return _status;
}
// I don't much like exposing this. (AHS 001217)
((org.apache.fop.layout.ColumnArea)currentArea).incrementSpanIndex();
((org.apache.fop.layout.ColumnArea) currentArea).
incrementSpanIndex();
i--;
}
}
@@ -197,14 +199,14 @@ public class Flow extends FObj {
}

protected void setContentWidth(int contentWidth) {
this.contentWidth = contentWidth;
this.contentWidth = contentWidth;
}
/**
* Return the content width of this flow (really of the region
* in which it is flowing).
*/
public int getContentWidth() {
return this.contentWidth;
return this.contentWidth;
}

public Status getStatus() {
@@ -215,8 +217,8 @@ public class Flow extends FObj {
return true;
}

public LayoutManager getLayoutManager() {
return new FlowLayoutManager(this);
public void addLayoutManager(List list) {
list.add(new FlowLayoutManager(this));
}

}

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

@@ -12,6 +12,11 @@ import org.apache.fop.fo.*;
import org.apache.fop.layout.*;
import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.properties.*;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LeafNodeLayoutManager;

import java.util.List;

// Java
import java.util.ArrayList;
@@ -22,6 +27,13 @@ public class Footnote extends FObj {
super(parent);
}

public void addLayoutManager(List lms) {
// add inlines layout manager
//inline.addLayoutManager(lms);
// set start and end footnote reference
}


public Status layout(Area area) throws FOPException {
FONode inline = null;
FONode fbody = null;

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

@@ -89,7 +89,7 @@ public class Inline extends FObjMixed {


public CharIterator charIterator() {
return new InlineCharIterator(this, propMgr.getBorderAndPadding());
return new InlineCharIterator(this, propMgr.getBorderAndPadding());
}

}

+ 31
- 2
src/org/apache/fop/fo/flow/InlineContainer.java View File

@@ -13,17 +13,28 @@ import org.apache.fop.fo.flow.*;
import org.apache.fop.fo.properties.*;
import org.apache.fop.layout.*;
import org.apache.fop.apps.FOPException;
import org.apache.fop.layoutmgr.LeafNodeLayoutManager;
import org.apache.fop.area.inline.InlineArea;

import org.xml.sax.Attributes;

import java.util.List;
import java.util.ArrayList;

/**
*/
public class InlineContainer extends ToBeImplementedElement {
public class InlineContainer extends FObj {

public InlineContainer(FONode parent) {
super(parent);
}

public void addLayoutManager(List lms) {
ArrayList childList = new ArrayList();
super.addLayoutManager(childList);
lms.add(new ICLayoutManager(this, childList));
}

public void handleAttrs(Attributes attlist) throws FOPException {
super.handleAttrs(attlist);
// Common Border, Padding, and Background Properties
@@ -34,7 +45,8 @@ public class InlineContainer extends ToBeImplementedElement {
MarginInlineProps mProps = propMgr.getMarginInlineProps();

// Common Relative Position Properties
RelativePositionProps mRelProps = propMgr.getRelativePositionProps();
RelativePositionProps mRelProps =
propMgr.getRelativePositionProps();

// this.properties.get("alignment-adjust");
// this.properties.get("alignment-baseline");
@@ -57,4 +69,21 @@ public class InlineContainer extends ToBeImplementedElement {
// this.properties.get("writing-mode");
}

/**
* This creates a single inline container area after
* laying out the child block areas. All footnotes, floats
* and id areas are maintained for later retrieval.
*/
class ICLayoutManager extends LeafNodeLayoutManager {
List childrenLM;

ICLayoutManager(FObj obj, List childLM) {
super(obj);
childrenLM = childLM;
}

public InlineArea get(int index) {
return null;
}
}
}

+ 7
- 2
src/org/apache/fop/fo/flow/InstreamForeignObject.java View File

@@ -29,6 +29,7 @@ import org.apache.fop.layoutmgr.LayoutInfo;
import org.w3c.dom.Document;

import java.awt.geom.Point2D;
import java.util.List;

public class InstreamForeignObject extends FObj {

@@ -60,10 +61,10 @@ public class InstreamForeignObject extends FObj {
super(parent);
}

public LayoutManager getLayoutManager() {
public void addLayoutManager(List list) {
LeafNodeLayoutManager lm = new LeafNodeLayoutManager(this);
lm.setCurrentArea(getInlineArea());
return lm;
list.add(lm);
}

/**
@@ -144,6 +145,10 @@ public class InstreamForeignObject extends FObj {
return areaCurrent;
}

public boolean generatesInlineAreas() {
return true;
}

/**
* layout this formatting object.
*

+ 17
- 6
src/org/apache/fop/fo/flow/Leader.java View File

@@ -20,6 +20,9 @@ import org.apache.fop.layout.FontState;
import org.apache.fop.apps.FOPException;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LeafNodeLayoutManager;
import org.apache.fop.area.MinOptMax;

import java.util.List;

/**
* Implements fo:leader; main property of leader leader-pattern.
@@ -32,14 +35,22 @@ public class Leader extends FObjMixed {
super(parent);
}

public LayoutManager getLayoutManager() {
LeafNodeLayoutManager lm = new LeafNodeLayoutManager(this);
lm.setCurrentArea(getInlineArea());
return lm;
public void addLayoutManager(List list) {
list.add(new LeafNodeLayoutManager(this) {
public InlineArea get(int index) {
if(index > 0)
return null;
int contentIPD = parentLM.getContentIPD();
return getInlineArea(contentIPD);
}
});
}

protected InlineArea getInlineArea() {
return null;
protected InlineArea getInlineArea(int maxIPD) {
org.apache.fop.area.inline.Leader leader = new org.apache.fop.area.inline.Leader();
leader.setWidth(maxIPD / 2);
leader.setAllocationIPD(new MinOptMax(0, maxIPD / 2, maxIPD));
return leader;
}

public Status layout(Area area) throws FOPException {

+ 23
- 1
src/org/apache/fop/fo/flow/PageNumber.java View File

@@ -15,8 +15,12 @@ import org.apache.fop.fo.properties.*;
import org.apache.fop.layout.*;
import org.apache.fop.apps.FOPException;

import org.apache.fop.layoutmgr.LeafNodeLayoutManager;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.Word;

// Java
import java.util.Enumeration;
import java.util.List;

public class PageNumber extends FObj {

@@ -31,6 +35,24 @@ public class PageNumber extends FObj {
super(parent);
}

public void addLayoutManager(List lms) {
lms.add(new LeafNodeLayoutManager(this) {
public InlineArea get(int index) {
if(index > 0)
return null;
// get page string from parent, build area
Word inline = new Word();
//String parentLM.getCurrentPageNumber();
inline.setWord("01");
return inline;
}

public boolean resolved() {
return true;
}
});
}

public Status layout(Area area) throws FOPException {
if (!(area instanceof BlockArea)) {
log.warn("page-number outside block area");

+ 47
- 32
src/org/apache/fop/fo/flow/PageNumberCitation.java View File

@@ -14,7 +14,11 @@ import org.apache.fop.datatypes.*;
import org.apache.fop.fo.properties.*;
import org.apache.fop.layout.*;
import org.apache.fop.apps.FOPException;
import org.apache.fop.layoutmgr.LeafNodeLayoutManager;
import org.apache.fop.area.inline.InlineArea;

import java.util.List;
import java.util.ArrayList;

/**
* 6.6.11 fo:page-number-citation
@@ -88,6 +92,18 @@ public class PageNumberCitation extends FObj {
super(parent);
}

public void addLayoutManager(List lms) {
LeafNodeLayoutManager lnlm = new LeafNodeLayoutManager(this);
lnlm.setCurrentArea(getInlineArea());
lms.add(lnlm);
}

// is id can be resolved then simply return a word, otherwise
// return a resolveable area
private InlineArea getInlineArea() {
return null;
}

public Status layout(Area area) throws FOPException {
if (!(area instanceof BlockArea)) {
log.warn("page-number-citation outside block area");
@@ -98,37 +114,38 @@ public class PageNumberCitation extends FObj {
this.area = area;
if (this.marker == START) {

// Common Accessibility Properties
// Common Accessibility Properties
AccessibilityProps mAccProps = propMgr.getAccessibilityProps();

// Common Aural Properties
AuralProps mAurProps = propMgr.getAuralProps();
// Common Aural Properties
AuralProps mAurProps = propMgr.getAuralProps();

// Common Border, Padding, and Background Properties
BorderAndPadding bap = propMgr.getBorderAndPadding();
BackgroundProps bProps = propMgr.getBackgroundProps();
// Common Border, Padding, and Background Properties
BorderAndPadding bap = propMgr.getBorderAndPadding();
BackgroundProps bProps = propMgr.getBackgroundProps();

// Common Font Properties
//this.fontState = propMgr.getFontState(area.getFontInfo());
// Common Font Properties
//this.fontState = propMgr.getFontState(area.getFontInfo());

// Common Margin Properties-Inline
MarginInlineProps mProps = propMgr.getMarginInlineProps();
// Common Margin Properties-Inline
MarginInlineProps mProps = propMgr.getMarginInlineProps();

// Common Relative Position Properties
RelativePositionProps mRelProps = propMgr.getRelativePositionProps();
// Common Relative Position Properties
RelativePositionProps mRelProps =
propMgr.getRelativePositionProps();

// this.properties.get("alignment-adjust");
// this.properties.get("alignment-baseline");
// this.properties.get("baseline-shift");
// this.properties.get("dominant-baseline");
// this.properties.get("id");
// this.properties.get("keep-with-next");
// this.properties.get("alignment-adjust");
// this.properties.get("alignment-baseline");
// this.properties.get("baseline-shift");
// this.properties.get("dominant-baseline");
// this.properties.get("id");
// this.properties.get("keep-with-next");
// this.properties.get("keep-with-previous");
// this.properties.get("letter-spacing");
// this.properties.get("line-height");
// this.properties.get("line-height-shift-adjustment");
// this.properties.get("ref-id");
// this.properties.get("score-spaces");
// this.properties.get("line-height-shift-adjustment");
// this.properties.get("ref-id");
// this.properties.get("score-spaces");
// this.properties.get("text-decoration");
// this.properties.get("text-shadow");
// this.properties.get("text-transform");
@@ -141,7 +158,7 @@ public class PageNumberCitation extends FObj {

this.wrapOption = this.properties.get("wrap-option").getEnum();
this.whiteSpaceCollapse =
this.properties.get("white-space-collapse").getEnum();
this.properties.get("white-space-collapse").getEnum();

this.refId = this.properties.get("ref-id").getString();

@@ -164,16 +181,14 @@ public class PageNumberCitation extends FObj {

pageNumber = idReferences.getPageNumber(refId);

if (pageNumber != null) { // if we already know the page number
this.marker =
FOText.addText((BlockArea)area,
propMgr.getFontState(area.getFontInfo()), red,
green, blue, wrapOption, null,
whiteSpaceCollapse, pageNumber.toCharArray(),
0, pageNumber.length(), ts,
VerticalAlign.BASELINE);
} else { // add pageNumberCitation to area to be resolved during rendering
BlockArea blockArea = (BlockArea)area;
if (pageNumber != null) { // if we already know the page number
this.marker = FOText.addText((BlockArea) area,
propMgr.getFontState(area.getFontInfo()), red,
green, blue, wrapOption, null, whiteSpaceCollapse,
pageNumber.toCharArray(), 0, pageNumber.length(),
ts, VerticalAlign.BASELINE);
} else { // add pageNumberCitation to area to be resolved during rendering
BlockArea blockArea = (BlockArea) area;
LineArea la = blockArea.getCurrentLineArea();
if (la == null) {
return new Status(Status.AREA_FULL_NONE);

+ 30
- 17
src/org/apache/fop/layoutmgr/AbstractLayoutManager.java View File

@@ -12,6 +12,7 @@ import org.apache.fop.fo.FONode;
import org.apache.fop.area.Area;

import java.util.ListIterator;
import java.util.ArrayList;

/**
* The base class for all LayoutManagers.
@@ -20,6 +21,12 @@ public abstract class AbstractLayoutManager implements LayoutManager {
protected LayoutManager parentLM;
protected FObj fobj;

protected LayoutPos curPos = new LayoutPos();

static class LayoutPos {
int lmIndex = 0;
int subIndex = 0;
}

public AbstractLayoutManager(FObj fobj) {
this.fobj = fobj;
@@ -39,19 +46,27 @@ public abstract class AbstractLayoutManager implements LayoutManager {
* children of its FO, asks each for its LayoutManager and calls
* its generateAreas method.
*/
public void generateAreas() {
ListIterator children = fobj.getChildren();
while (children.hasNext()) {
FONode node = (FONode) children.next();
if (node instanceof FObj) {
LayoutManager lm = ((FObj) node).getLayoutManager();
if (lm != null) {
lm.setParentLM(this);
lm.generateAreas();
public boolean generateAreas() {
ArrayList lms = new ArrayList();
if (fobj != null) {
ListIterator children = fobj.getChildren();
while (children.hasNext()) {
FONode node = (FONode) children.next();
if (node instanceof FObj) {
((FObj) node).addLayoutManager(lms);
}
}
fobj = null;
}

for (int count = 0; count < lms.size(); count++) {
LayoutManager lm = (LayoutManager) lms.get(count);
lm.setParentLM(this);
if (lm.generateAreas()) {
break;
}
}
flush(); // Add last area to parent
return flush(); // Add last area to parent
}

// /**
@@ -77,7 +92,7 @@ public abstract class AbstractLayoutManager implements LayoutManager {
/**
* Force current area to be added to parent area.
*/
abstract protected void flush();
abstract protected boolean flush();


/**
@@ -93,18 +108,16 @@ public abstract class AbstractLayoutManager implements LayoutManager {
abstract public Area getParentArea(Area childArea);



// public boolean generatesInlineAreas() {
// return false;
// }

public boolean generatesInlineAreas() {
return false;
}

/**
* Add a child area to the current area. If this causes the maximum
* dimension of the current area to be exceeded, the parent LM is called
* to add it.
*/
abstract public void addChild(Area childArea);
abstract public boolean addChild(Area childArea);

/** Do nothing */
public boolean splitArea(Area areaToSplit, SplitContext context) {

+ 53
- 16
src/org/apache/fop/layoutmgr/BlockLayoutManager.java View File

@@ -13,8 +13,10 @@ import org.apache.fop.area.Area;
import org.apache.fop.area.BlockParent;
import org.apache.fop.area.Block;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.MinOptMax;

import java.util.ListIterator;
import java.util.ArrayList;

/**
* LayoutManager for a block FO.
@@ -45,7 +47,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager {
*/
public int getContentIPD() {
// adjust for side floats and indents
//getParentArea(null); // make if not existing
getParentArea(null); // make if not existing
return curBlockArea.getIPD();
}

@@ -53,23 +55,46 @@ public class BlockLayoutManager extends BlockStackingLayoutManager {
* Generate areas by tellings all layout managers for its FO's
* children to generate areas.
*/
public void generateAreas() {
ListIterator children = fobj.getChildren();
public boolean generateAreas() {
ArrayList lms = new ArrayList();
LayoutManager lm = null;
while (children.hasNext()) {
FObj childFO = (FObj) children.next();
if (childFO.generatesInlineAreas()) {
children.previous();
lm = new LineLayoutManager(children, lineHeight, lead, follow);
} else {
lm = childFO.getLayoutManager();

if (fobj != null) {
ListIterator children = fobj.getChildren();
while (children.hasNext()) {
FObj childFO = (FObj) children.next();
childFO.addLayoutManager(lms);
}
fobj = null;
}

for (int count = 0; count < lms.size(); count++) {
lm = (LayoutManager) lms.get(count);
if (lm.generatesInlineAreas()) {
ArrayList inlines = new ArrayList();
inlines.add(lm);
//lms.remove(count);
while (count + 1 < lms.size()) {
lm = (LayoutManager) lms.get(count + 1);
if (lm.generatesInlineAreas()) {
inlines.add(lm);
lms.remove(count + 1);
} else {
break;
}
}
lm = new LineLayoutManager(inlines, lineHeight, lead,
follow);
lms.set(count, lm);
}
if (lm != null) {
lm.setParentLM(this);
lm.generateAreas();
lm.setParentLM(this);
if (lm.generateAreas()) {
if (flush()) {
return true;
}
}
}
flush(); // Add last area to parent
return flush(); // Add last area to parent
}


@@ -98,16 +123,28 @@ public class BlockLayoutManager extends BlockStackingLayoutManager {
}


public void addChild(Area childArea) {
public boolean addChild(Area childArea) {
if (curBlockArea != null) {
if (childArea instanceof LineArea) {
// Something about widows and orphans
// Position the line area and calculate size...
curBlockArea.addLineArea((LineArea) childArea);

MinOptMax targetDim = parentArea.getAvailBPD();
MinOptMax currentDim = curBlockArea.getContentBPD();
//if(currentDim.min > targetDim.max) {
// return true;
//}

return false;
} else {
super.addChild(childArea);
curBlockArea.addBlock((Block) childArea);
//return super.addChild(childArea);

return false;
}
}
return false;
}



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

@@ -30,12 +30,10 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
super(fobj);
}



public boolean splitArea(Area area, SplitContext splitContext) {
// Divide area so that it will be within targetLength if possible
// If not, it can be shorter, but not longer.
/* Iterate over contents of the area. */
/* Iterate over contents of the area. *

// Need to figure out if we can do this generically
// Logically a BlockStacking LM only handles Block-type areas
@@ -66,13 +64,13 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
/* Split 'area', placing all children after
* minBreakCost.getArea() into a new area,
* which we store in the splitContext.
*/
*
// splitContext.nextArea = area.splitAfter(minBreakCost.getArea());
} else {
/* This area will be shorter than the desired minimum.
* Split before the current childArea (which will be
* the first area in the newly created Area.
*/
*
//splitContext.nextArea = area.splitBefore(childArea);
}
} else
@@ -94,7 +92,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
}
// True if some part of area can be placed, false if none is placed
return (splitContext.nextArea != area);

*/
return false;
}

private BreakCost evaluateBreakCost(Area parent, Area child) {
@@ -136,11 +135,11 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
* @param childArea the area to add: will be some block-stacked Area.
* @param parentArea the area in which to add the childArea
*/
protected void addChildToArea(Area childArea, BlockParent parentArea) {
protected boolean addChildToArea(Area childArea, BlockParent parentArea) {
// This should be a block-level Area (Block in the generic sense)
if (!(childArea instanceof Block)) {
System.err.println("Child not a Block in BlockStackingLM!");
return;
return false;
}

// See if the whole thing fits, including space before
@@ -151,23 +150,28 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
if (targetDim.max >= childArea.getAllocationBPD().min) {
//parentArea.addBlock(new InterBlockSpace(spaceBefore));
parentArea.addBlock((Block) childArea);
return;
return false;
} else {
parentArea.addBlock((Block) childArea);
flush(); // hand off current area to parent
// Probably need something like max BPD so we don't get into
// infinite loops with large unbreakable chunks
SplitContext splitContext = new SplitContext(targetDim);
//SplitContext splitContext = new SplitContext(targetDim);

LayoutManager childLM =
/*LayoutManager childLM =
childArea.getGeneratingFObj(). getLayoutManager();
if (childLM.splitArea(childArea, splitContext)) {
//parentArea.addBlock(new InterBlockSpace(spaceBefore));
parentArea.addBlock((Block) childArea);
}
flush(); // hand off current area to parent
getParentArea(splitContext.nextArea);
}*/
//flush(); // hand off current area to parent
//getParentArea(splitContext.nextArea);
//getParentArea(childArea);
// Check that reference IPD hasn't changed!!!
// If it has, we must "reflow" the content
addChild(splitContext.nextArea);
//addChild(splitContext.nextArea);
//addChild(childArea);
return true;
}
}

@@ -180,17 +184,18 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager {
* If so, add it. Otherwise initiate breaking.
* @param childArea the area to add: will be some block-stacked Area.
*/
public void addChild(Area childArea) {
addChildToArea(childArea, getCurrentArea());
public boolean addChild(Area childArea) {
return addChildToArea(childArea, getCurrentArea());
}

/**
* Force current area to be added to parent area.
*/
protected void flush() {
protected boolean flush() {
if (getCurrentArea() != null)
parentLM.addChild(getCurrentArea());
return parentLM.addChild(getCurrentArea());
return false;
}


}


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

@@ -38,8 +38,8 @@ public class FlowLayoutManager extends BlockStackingLayoutManager {
* area class. A Flow can fill at most one area container of any class
* at any one time. The actual work is done by BlockStackingLM.
*/
public void addChild(Area childArea) {
addChildToArea(childArea,
public boolean addChild(Area childArea) {
return addChildToArea(childArea,
this.currentAreas[childArea.getAreaClass()]);
}


+ 5
- 0
src/org/apache/fop/layoutmgr/LayoutInfo.java View File

@@ -14,6 +14,11 @@ public class LayoutInfo {
public int alignment;
public int lead;
public boolean blOffset = false;
public boolean breakAfter = false;

public boolean keepNext = false;
public boolean keepPrev = false;
public boolean isText = false;

public LayoutInfo() {
}

+ 3
- 3
src/org/apache/fop/layoutmgr/LayoutManager.java View File

@@ -14,10 +14,10 @@ import org.apache.fop.area.Area;
* The interface for all LayoutManagers.
*/
public interface LayoutManager {
public void generateAreas();
//public boolean generatesInlineAreas();
public boolean generateAreas();
public boolean generatesInlineAreas();
public Area getParentArea (Area childArea);
public void addChild (Area childArea);
public boolean addChild (Area childArea);
public boolean splitArea(Area areaToSplit, SplitContext context);
public void setParentLM(LayoutManager lm);
public int getContentIPD();

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

@@ -19,29 +19,46 @@ import org.apache.fop.area.inline.InlineArea;
*/
public class LeafNodeLayoutManager extends AbstractLayoutManager {

private InlineArea curArea;
private InlineArea curArea = null;

public LeafNodeLayoutManager(FObj fobj) {
super(fobj);
}

public int size() {
return 1;
}

public InlineArea get(int index) {
if(index > 0)
return null;
return curArea;
}

public boolean generatesInlineAreas() {
return true;
}

public boolean resolved() {
return false;
}

public void setCurrentArea(InlineArea ia) {
curArea = ia;
}

public void generateAreas() {
flush();
public boolean generateAreas() {
return flush();
}

protected void flush() {
parentLM.addChild(curArea);
protected boolean flush() {
return false;
}

/**
* This is a leaf-node, so this method is never called.
*/
public void addChild(Area childArea) {}
public boolean addChild(Area childArea) {return false;}


/**

+ 328
- 116
src/org/apache/fop/layoutmgr/LineLayoutManager.java View File

@@ -16,150 +16,342 @@ import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.fo.properties.VerticalAlign;

import org.apache.fop.area.inline.Word;
import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.Character;

import java.util.ListIterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
* LayoutManager for lines. It builds one or more lines containing
* inline areas generated by its sub layout managers.
*
* The line layout manager does the following things:
* receives a list of inline creating layout managers
* adds the inline areas retrieved from the child layout managers
* finds the best line break position
* adds complete line to parent
* stores the starting position for each line in case of recreation
* if ipd not changed but line contains resolved values (eg. page number), redoes from that line
* when freeing memory, release all layout managers and inline areas before current position
* As each child layout manager is used it gets the start, end and normal references for id area, footnotes, floats, links, colour-back properties
* first line properties are set and used by the child when retrieving the inline area(s)
*
* Hyphenation is handled by asking the child to split the words then this
* adds the hyph char. If redone then exra char ignored.
*
* How do we handle Unicode BIDI?
*/
public class LineLayoutManager extends AbstractLayoutManager {
/** Reference to FO whose areas it's managing or to the traits
* of the FO.
*/
private ListIterator fobjIter;
private LineArea lineArea = null;
private boolean bFirstLine;
private LayoutManager curLM;
private MinOptMax remainingIPD;
private LineInfo currentLine = null;
private boolean bFirstLine = true;
private MinOptMax totalIPD;
// the following values must be set by the block
// these are the dominant basline and lineheight values
private int lineHeight;
private int lead;
private int follow;

public LineLayoutManager(ListIterator fobjIter, int lh, int l, int f) {
List lmList;
List lines = new ArrayList();

private LayoutPos bestPos = null;
private MinOptMax bestIPD = null;

static class LineInfo {
LayoutPos startPos;
LineArea area;
boolean hasResolved = false;
boolean noJustify = false;
// footnotes, floats?
}

public LineLayoutManager(List lms, int lh, int l, int f) {
super(null);
this.fobjIter = fobjIter;
lmList = lms;
lineHeight = lh;
lead = l;
follow = f;
}

public int getContentIPD() {
return parentLM.getContentIPD();
}

/**
* Call child layout managers to generate content as long as they
* generate inline areas. If a block-level generating LM is found,
* finish any line being filled and return to the parent LM.
*/
public void generateAreas() {
this.bFirstLine = true;
while (fobjIter.hasNext()) {
FObj childFO = (FObj) fobjIter.next();
if (childFO.generatesInlineAreas() == false) {
// It generates blocks, pass back to parent
// Back up one
fobjIter.previous();
break;
} else { // generates inline area
curLM = childFO.getLayoutManager();
if (curLM != null) {
curLM.setParentLM(this);
curLM.generateAreas();
public boolean generateAreas() {
// if a side float is added and the line contains content
// where the ipd depends on the line width then restart
// the line with the adjusted length

while (curPos.lmIndex < lmList.size()) {
LeafNodeLayoutManager curLM =
(LeafNodeLayoutManager) lmList.get(curPos.lmIndex);
curLM.setParentLM(this);

LeafNodeLayoutManager nextLM = null;
if (curPos.lmIndex + 1 < lmList.size()) {
nextLM = (LeafNodeLayoutManager) lmList.get(
curPos.lmIndex + 1);
while (nextLM.size() == 0) {
lmList.remove(curPos.lmIndex + 1);
if (curPos.lmIndex + 1 == lmList.size()) {
nextLM = null;
break;
}
nextLM = (LeafNodeLayoutManager) lmList.get(
curPos.lmIndex + 1);

}
}
if (nextLM != null) {
nextLM.setParentLM(this);
}
if (curLM.resolved()) {
currentLine.hasResolved = true;
}
while (curPos.subIndex < curLM.size()) {
InlineArea ia = curLM.get(curPos.subIndex);
InlineArea next = null;
if (curPos.subIndex + 1 < curLM.size()) {
next = curLM.get(curPos.subIndex + 1);
} else if (curPos.lmIndex + 1 < lmList.size()) {
if (nextLM != null) {
next = nextLM.get(0);
}
}
if (currentLine != null && !currentLine.noJustify &&
(curPos.subIndex + 1 == curLM.size() &&
curPos.lmIndex + 1 == lmList.size())) {
currentLine.noJustify = true;
}
if (addChild(ia, next)) {
if (flush()) {
return true;
}
}
// flush final line in same context as other lines
// handle last line concepts
if (curPos.subIndex + 1 == curLM.size() &&
curPos.lmIndex + 1 == lmList.size()) {
if (flush()) {
return true;
}
if (curPos.subIndex + 1 == curLM.size() &&
curPos.lmIndex + 1 == lmList.size()) {
return false;
}

}
curPos.subIndex++;
}
curPos.lmIndex++;
curPos.subIndex = 0;
}
flush(); // Add last area to parent
return false;
}

/**
* Align and position curLine and add it to parentContainer.
* Set curLine to null.
*/
public void flush() {
if (lineArea != null) {
public boolean flush() {
if (currentLine != null) {
// Adjust spacing as necessary

adjustSpacing();
verticalAlign();

parentLM.addChild(lineArea);
lineArea = null;
boolean res = parentLM.addChild(currentLine.area);

lines.add(currentLine);
currentLine = null;
bestPos = null;
bestIPD = null;

return res;
}
return false;
}

/**
* Do the ipd adjustment for stretch areas etc.
* Consecutive spaces need to be collapsed if possible.
* should this be on the line area so it can finish resolved areas?
*/
private void adjustSpacing() {
List inlineAreas = currentLine.area.getInlineAreas();

// group text elements to split at hyphen if available
// remove collapsable spaces at start or end on line

// backtrack to best position
while (true) {
if (curPos.lmIndex == bestPos.lmIndex &&
curPos.subIndex == bestPos.subIndex) {
break;
}

InlineArea inline =
(InlineArea) inlineAreas.get(inlineAreas.size() - 1);
MinOptMax ipd = inline.getAllocationIPD();
totalIPD.subtract(ipd);

inlineAreas.remove(inlineAreas.size() - 1);
currentLine.noJustify = false;

curPos.subIndex--;
if (curPos.subIndex == -1) {
curPos.lmIndex--;
LeafNodeLayoutManager curLM =
(LeafNodeLayoutManager) lmList.get( curPos.lmIndex);
curPos.subIndex = curLM.size() - 1;
}
}


// for justify also stretch spaces to fill
// stretch to best match
float percentAdjust = 0;
boolean maxSide = false;
int realWidth = bestIPD.opt;
if (bestIPD.opt > parentLM.getContentIPD()) {
if (bestIPD.opt - parentLM.getContentIPD() <
(bestIPD.max - bestIPD.opt)) {
percentAdjust = (bestIPD.opt - parentLM.getContentIPD()) /
(float)(bestIPD.max - bestIPD.opt);
realWidth = parentLM.getContentIPD();
} else {
percentAdjust = 1;
realWidth = bestIPD.max;
}
maxSide = true;
} else {
if (parentLM.getContentIPD() - bestIPD.opt <
bestIPD.opt - bestIPD.min) {
percentAdjust = (parentLM.getContentIPD() - bestIPD.opt) /
(float)(bestIPD.opt - bestIPD.min);
realWidth = parentLM.getContentIPD();
} else {
percentAdjust = 1;
realWidth = bestIPD.min;
}
}
if (percentAdjust > 0) {
for (Iterator iter = inlineAreas.iterator(); iter.hasNext();) {
InlineArea inline = (InlineArea) iter.next();
int width;
MinOptMax iipd = inline.getAllocationIPD();
if (!maxSide) {
width = iipd.opt +
(int)((iipd.max - iipd.opt) * percentAdjust);
} else {
width = iipd.opt -
(int)((iipd.opt - iipd.min) * percentAdjust);
}
inline.setWidth(width);
}
}

// don't justify lines ending with U+000A or last line
if (/*justify && */!currentLine.noJustify &&
realWidth != parentLM.getContentIPD()) {
ArrayList spaces = new ArrayList();
for (Iterator iter = inlineAreas.iterator(); iter.hasNext();) {
InlineArea inline = (InlineArea) iter.next();
if (inline instanceof Space /* && !((Space)inline).fixed*/) {
spaces.add(inline);
}
}
for (Iterator iter = spaces.iterator(); iter.hasNext();) {
Space space = (Space) iter.next();
space.setWidth(space.getWidth() +
(parentLM.getContentIPD() - realWidth) /
spaces.size());
}
}

}

private void verticalAlign() {
int maxHeight = lineHeight;
List inlineAreas = lineArea.getInlineAreas();
List inlineAreas = currentLine.area.getInlineAreas();

// get smallest possible offset to before edge
// this depends on the height of no and middle alignments
int before = lead;
int after = follow;
for(Iterator iter = inlineAreas.iterator(); iter.hasNext(); ) {
InlineArea inline = (InlineArea)iter.next();
int halfLeading = (lineHeight - lead - follow) / 2;
before += halfLeading;
for (Iterator iter = inlineAreas.iterator(); iter.hasNext();) {
InlineArea inline = (InlineArea) iter.next();
LayoutInfo info = inline.info;
int al;
int ld = inline.getHeight();
if(info != null) {
if (info != null) {
al = info.alignment;
ld = info.lead;
} else {
al = VerticalAlign.BASELINE;
}
if(al == VerticalAlign.BASELINE) {
if(ld > before) {
if (al == VerticalAlign.BASELINE) {
if (ld > before) {
before = ld;
}
if(inline.getHeight() > before) {
if (inline.getHeight() > before) {
before = inline.getHeight();
}
} else if(al == VerticalAlign.MIDDLE) {
if(inline.getHeight() / 2 + lead / 2 > before) {
} else if (al == VerticalAlign.MIDDLE) {
if (inline.getHeight() / 2 + lead / 2 > before) {
before = inline.getHeight() / 2 + lead / 2;
}
if(inline.getHeight() / 2 - lead / 2 > after) {
if (inline.getHeight() / 2 - lead / 2 > after) {
after = inline.getHeight() / 2 - lead / 2;
}
} else if(al == VerticalAlign.TOP) {
} else if(al == VerticalAlign.BOTTOM) {
} else if (al == VerticalAlign.TOP) {
} else if (al == VerticalAlign.BOTTOM) {
}
}

// then align all before, no and middle alignment
for(Iterator iter = inlineAreas.iterator(); iter.hasNext(); ) {
InlineArea inline = (InlineArea)iter.next();
for (Iterator iter = inlineAreas.iterator(); iter.hasNext();) {
InlineArea inline = (InlineArea) iter.next();
LayoutInfo info = inline.info;
int al;
int ld = inline.getHeight();
boolean bloffset = false;
if(info != null) {
if (info != null) {
al = info.alignment;
ld = info.lead;
bloffset = info.blOffset;
} else {
al = VerticalAlign.BASELINE;
}
if(al == VerticalAlign.BASELINE) {
if (al == VerticalAlign.BASELINE) {
// the offset position for text is the baseline
if(bloffset) {
if (bloffset) {
inline.setOffset(before);
} else {
inline.setOffset(before - ld);
}
if(inline.getHeight() - ld > after) {
if (inline.getHeight() - ld > after) {
after = inline.getHeight() - ld;
}
} else if(al == VerticalAlign.MIDDLE) {
inline.setOffset(before - inline.getHeight() / 2 - lead / 2);
} else if(al == VerticalAlign.TOP) {
} else if (al == VerticalAlign.MIDDLE) {
inline.setOffset(before - inline.getHeight() / 2 -
lead / 2);
} else if (al == VerticalAlign.TOP) {
inline.setOffset(0);
if(inline.getHeight() - before > after) {
if (inline.getHeight() - before > after) {
after = inline.getHeight() - before;
}
} else if(al == VerticalAlign.BOTTOM) {
if(inline.getHeight() - before > after) {
} else if (al == VerticalAlign.BOTTOM) {
if (inline.getHeight() - before > after) {
after = inline.getHeight() - before;
}
}
@@ -167,26 +359,26 @@ public class LineLayoutManager extends AbstractLayoutManager {

// after alignment depends on maximum height of before
// and middle alignments
for(Iterator iter = inlineAreas.iterator(); iter.hasNext(); ) {
InlineArea inline = (InlineArea)iter.next();
for (Iterator iter = inlineAreas.iterator(); iter.hasNext();) {
InlineArea inline = (InlineArea) iter.next();
LayoutInfo info = inline.info;
int al;
if(info != null) {
int al;
if (info != null) {
al = info.alignment;
} else {
al = VerticalAlign.BASELINE;
}
if(al == VerticalAlign.BASELINE) {
} else if(al == VerticalAlign.MIDDLE) {
} else if(al == VerticalAlign.TOP) {
} else if(al == VerticalAlign.BOTTOM) {
if (al == VerticalAlign.BASELINE) {
} else if (al == VerticalAlign.MIDDLE) {
} else if (al == VerticalAlign.TOP) {
} else if (al == VerticalAlign.BOTTOM) {
inline.setOffset(before + after - inline.getHeight());
}
}
if(before + after > maxHeight) {
lineArea.setHeight(before + after);
if (before + after > maxHeight) {
currentLine.area.setHeight(before + after);
} else {
lineArea.setHeight(maxHeight);
currentLine.area.setHeight(maxHeight);
}
}

@@ -194,25 +386,27 @@ public class LineLayoutManager extends AbstractLayoutManager {
* Return current lineArea or generate a new one if necessary.
*/
public Area getParentArea(Area childArea) {
if (lineArea == null) {
if (currentLine.area == null) {
createLine();
}
return lineArea;
return currentLine.area;
}

private void createLine() {
lineArea = new LineArea();
currentLine = new LineInfo();
currentLine.startPos = curPos;
currentLine.area = new LineArea();
/* Set line IPD from parentArea
* This accounts for indents. What about first line indent?
* Should we set an "isFirst" flag on the lineArea to signal
* that to the parent (Block) LM? That's where indent property
* information will be managed.
*/
Area parent = parentLM.getParentArea(lineArea);
// lineArea.setContentIPD(parent.getContentIPD());
// remainingIPD = parent.getContentIPD();
Area parent = parentLM.getParentArea(currentLine.area);
// currentLine.area.setContentIPD(parent.getContentIPD());
// totalIPD = new MinOptMax();
// OR???
remainingIPD = new MinOptMax(parentLM.getContentIPD());
totalIPD = new MinOptMax();
this.bFirstLine = false;
}

@@ -223,55 +417,73 @@ public class LineLayoutManager extends AbstractLayoutManager {
* This should also handle floats if childArea is an anchor.
* @param childArea the area to add: should be an InlineArea subclass!
*/
public void addChild(Area childArea) {
if ((childArea instanceof InlineArea) == false) {
// SIGNAL AN ERROR!!!
return;
}
InlineArea inlineArea = (InlineArea) childArea;
if (lineArea == null) {
public boolean addChild(InlineArea inlineArea, InlineArea nextArea) {
if (currentLine == null) {
createLine();
}
if (inlineArea.getAllocationIPD().min < remainingIPD.max) {
lineArea.addInlineArea(inlineArea);
remainingIPD.subtract(inlineArea.getAllocationIPD());
// Calculate number of spaces
// Forced line break after this area (ex. ends with LF in nowrap)
/* NOTYET!
if (inlineArea.breakAfter()) {
flush();
}
*/
/* Check if line could end after this area (potential line-break
* character. If not, it must be joined with following inline
* area to make a word. Otherwise, if the line could break here
* and if it is "full", add it to the parent area.
*/
if (remainingIPD.min <= 0) {
flush();
}

// add side floats first

int pIPD = parentLM.getContentIPD();

currentLine.area.addInlineArea(inlineArea);
totalIPD.add(inlineArea.getAllocationIPD());

LayoutInfo info = inlineArea.info;
if (info == null) {
info = new LayoutInfo();
}
else {
/* The inline area won't entirely fit in this line. Ask its
* layout manager to split it (by hyphenation for example),
* in order to fit part of it in the line.
* Note: only the current child LM could have generated this
* area, so we ask it to do the split.
*/
SplitContext splitContext = new SplitContext(remainingIPD);
if (curLM.splitArea(inlineArea, splitContext)) {
// inlineArea should now fit
lineArea.addInlineArea(inlineArea);
flush();
addChild(splitContext.nextArea);
} else {
lineArea.addInlineArea((InlineArea)splitContext.nextArea);
remainingIPD.subtract(inlineArea.getAllocationIPD());
if (remainingIPD.min <= 0) {
flush();
}
LayoutInfo ninfo;
if (nextArea != null && nextArea.info != null) {
ninfo = nextArea.info;
} else {
ninfo = new LayoutInfo();
}

// the best pos cannot be before the first area
if (bestPos == null || bestIPD == null) {
bestPos = new LayoutPos();
bestPos.lmIndex = curPos.lmIndex;
bestPos.subIndex = curPos.subIndex;
MinOptMax imop = inlineArea.getAllocationIPD();
bestIPD = new MinOptMax(imop.min, imop.opt, imop.max);
} else {

// bestPos changed only when it can break
// before/after a space or other atomic inlines
// check keep-with on this and next
// since chars are optimized as words we cannot assume a
// word is complete and therefore hyphenate or break after
// side floats effect the available ipd but do not add to line

if (!ninfo.keepPrev && !info.keepNext &&
!(info.isText && ninfo.isText)) {
if (Math.abs(bestIPD.opt - pIPD) >
Math.abs(totalIPD.opt - pIPD) &&
(totalIPD.min <= pIPD)) {
bestPos.lmIndex = curPos.lmIndex;
bestPos.subIndex = curPos.subIndex;
bestIPD = new MinOptMax(totalIPD.min, totalIPD.opt,
totalIPD.max);
}
}
}

// Forced line break after this area (ex. ends with LF in nowrap)
if (info.breakAfter) {
currentLine.noJustify = true;
return true;
}

if (totalIPD.min > pIPD) {
return true;
}

return false;
}

public boolean addChild(Area childArea) {
return false;
}
}


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

@@ -41,6 +41,7 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
* references?
*/
private AreaTree areaTree;
private PageSequence pageSequence;

/**
* This is the top level layout manager.
@@ -49,6 +50,7 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
public PageLayoutManager(AreaTree areaTree, PageSequence pageseq) {
super(pageseq);
this.areaTree = areaTree;
pageSequence = pageseq;
}


@@ -69,13 +71,14 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
/**
* For now, only handle normal flow areas.
*/
public void addChild(Area childArea) {
public boolean addChild(Area childArea) {
if (childArea == null)
return;
return false;
if (childArea.getAreaClass() == Area.CLASS_NORMAL) {
placeFlowRefArea(childArea);
return placeFlowRefArea(childArea);
} else
; // TODO: all the others!
return false;
}

/**
@@ -85,7 +88,7 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
* current span, so we are just checking to see if the span is "full",
* possibly moving to the next column or to the next page.
*/
protected void placeFlowRefArea(Area area) {
protected boolean placeFlowRefArea(Area area) {
// assert (curSpan != null);
// assert (area == curFlow);
// assert (curFlow == curSpan.getFlow(curSpan.getColumnCount()-1));
@@ -100,13 +103,16 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
// end the page.

// Alternatively the child LM indicates to parent that it's full?
System.out.println("size: " + area.getAllocationBPD().max + ":" + curSpan.getMaxBPD().min);
if (area.getAllocationBPD().max >= curSpan.getMaxBPD().min) {
// Consider it filled
if (curSpan.getColumnCount() == curSpanColumns) {
finishPage();
return true;
} else
curFlow = null; // Create new flow on next getParentArea()
}
return false;
}


@@ -133,7 +139,7 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
private PageViewport makeNewPage(boolean bIsBlank, boolean bIsLast) {
finishPage();
try {
curPage = ((PageSequence) fobj).createPage(bIsBlank, bIsLast);
curPage = pageSequence.createPage(bIsBlank, bIsLast);
} catch (FOPException fopex) { /* ???? */
fopex.printStackTrace();
}
@@ -308,6 +314,7 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
private Flow createFlow() {
curFlow = new Flow();
curFlow.setIPD(curSpan.getIPD()); // adjust for columns
//curFlow.setBPD(100000);
// Set IPD and max BPD on the curFlow from curBody
curSpan.addFlow(curFlow);
return curFlow;
@@ -336,8 +343,9 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable
}

// See finishPage...
protected void flush() {
protected boolean flush() {
finishPage();
return false;
}

}

+ 31
- 18
src/org/apache/fop/layoutmgr/TextLayoutManager.java View File

@@ -11,6 +11,7 @@ import org.apache.fop.fo.FObj;
import org.apache.fop.fo.TextInfo;
import org.apache.fop.area.Area;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.Word;
import org.apache.fop.area.inline.Space;
import org.apache.fop.util.CharUtilities;
@@ -19,6 +20,7 @@ import org.apache.fop.fo.properties.VerticalAlign;
import org.apache.fop.fo.properties.*;

import java.util.ListIterator;
import java.util.ArrayList;

/**
* LayoutManager for text (a sequence of characters) which generates one
@@ -29,6 +31,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
private char[] chars;
private TextInfo textInfo;

ArrayList words = new ArrayList();

private static final char NEWLINE = '\n';
private static final char RETURN = '\r';
private static final char TAB = '\t';
@@ -49,29 +53,36 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
this.textInfo = textInfo;
}

public int size() {
parseChars();
return words.size();
}

public InlineArea get(int index) {
parseChars();
return (InlineArea)words.get(index);
}

/**
* Generate inline areas for words in text.
*/
public void generateAreas() {
public boolean generateAreas() {
// Handle white-space characteristics. Maybe there is no area to
// generate....

// Iterate over characters and make text areas.
// Add each one to parent. Handle word-space.
// Word curWordArea = new Word();
// curWordArea.setWord(new String(chars));
//System.out.println("word:" + new String(chars));
//parentLM.addChild(curWordArea);
parseChars();

//setCurrentArea(curWordArea);
//flush();
return false;
}

protected void parseChars() {
if(chars == null) {
return;
}

int whitespaceWidth;
// With CID fonts, space isn't neccesary currentFontState.width(32)
int whitespaceWidth = CharUtilities.getCharWidth(' ', textInfo.fs);
whitespaceWidth = CharUtilities.getCharWidth(' ', textInfo.fs);

int wordStart = -1;
int wordLength = 0;
@@ -79,9 +90,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
int spaceWidth = 0;

int prev = NOTHING;
int i = 0;

/* iterate over each character */
for (int i = 0; i < chars.length; i++) {
for (; i < chars.length; i++) {
int charWidth;
/* get the character */
char c = chars[i];
@@ -115,8 +127,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
if (spaceWidth > 0) {
Space is = new Space();
is.setWidth(spaceWidth);
parentLM.addChild(is);
spaceWidth = 0;
words.add(is);
}
} else if (c == TAB) {
spaceWidth += 8 * whitespaceWidth;
@@ -127,8 +139,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
if (spaceWidth > 0) {
Space is = new Space();
is.setWidth(spaceWidth);
parentLM.addChild(is);
is.info = new LayoutInfo();
is.info.breakAfter = true;
spaceWidth = 0;
words.add(is);
}
}

@@ -142,8 +156,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
if (spaceWidth > 0) {
Space is = new Space();
is.setWidth(spaceWidth);
parentLM.addChild(is);
spaceWidth = 0;
words.add(is);
}

// add the current word
@@ -153,7 +167,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// spaces. Split the word and add Space
// as necessary. All spaces inside the word
// Have a fixed width.
parentLM.addChild(createWord(new String(chars, wordStart + 1,
words.add(createWord(new String(chars, wordStart + 1,
wordLength), wordWidth));

// reset word width
@@ -190,7 +204,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// textdecoration not used because spaceWidth is 0
Space is = new Space();
is.setWidth(spaceWidth);
parentLM.addChild(is);
words.add(is);
} else if (c == TAB) {
prev = WHITESPACE;
spaceWidth = 8 * whitespaceWidth;
@@ -215,8 +229,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
wordLength = chars.length - 1 - wordStart;
}

parentLM.addChild(createWord(new String(chars, wordStart + 1, wordLength), wordWidth));

words.add(createWord(new String(chars, wordStart + 1, wordLength), wordWidth));
}

chars = null;

+ 10
- 0
src/org/apache/fop/render/pdf/PDFRenderer.java View File

@@ -569,5 +569,15 @@ public class PDFRenderer extends PrintRenderer {
}*/
super.renderViewport(viewport);
}

public void renderLeader(Leader area) {
currentStream.add("ET\n");
currentStream.add((((float)currentBlockIPPosition) / 1000f) + " "
+ ((currentBPPosition + area.getOffset()) / 1000f) + " m\n");
currentStream.add(((currentBlockIPPosition + area.getWidth()) / 1000f) + " " + ((currentBPPosition + area.getOffset()) / 1000f) + " l\n");
currentStream.add("S\n");
currentStream.add("BT\n");
super.renderLeader(area);
}
}


+ 4
- 0
src/org/apache/fop/svg/SVGElement.java View File

@@ -97,6 +97,10 @@ public class SVGElement extends SVGObj {
return new AffineTransform();
}

public AffineTransform getGlobalTransform() {
return new AffineTransform();
}

public float getViewportWidth() {
return (float)view.getX();
}

Loading…
Cancel
Save