Index: java/src/org/apache/fop/prototype/breaking/CompletedPart.java
===================================================================
--- java/src/org/apache/fop/prototype/breaking/CompletedPart.java	(revision 1)
+++ java/src/org/apache/fop/prototype/breaking/CompletedPart.java	(revision 6)
@@ -20,8 +20,11 @@
 package org.apache.fop.prototype.breaking;
 
 import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
 
 import org.apache.fop.prototype.breaking.layout.Layout;
+import org.apache.fop.prototype.knuth.KnuthElement;
 
 /**
  * TODO javadoc
@@ -35,6 +38,8 @@
     int difference;
 
     Collection<Alternative> alternatives;
+    
+    boolean needRollback; // Best fit line
 
     /**
      * @param layout
@@ -46,6 +51,7 @@
         this.demerits = demerits;
         this.difference = difference;
         this.alternatives = alternatives;
+        this.needRollback = false; // Best fit line
     }
 
     /**
@@ -75,4 +81,14 @@
     public Collection<Alternative> getAlternatives() {
         return alternatives;
     }
+
+	/* Needed for best fit line */
+	public boolean isNeedRollback() {
+		return needRollback;
+	}
+
+	/* Needed for best fit line */
+	public void setNeedRollback(boolean needRollback) {
+		this.needRollback = needRollback;
+	}
 }
Index: java/src/org/apache/fop/prototype/breaking/KnuthIterator.java
===================================================================
--- java/src/org/apache/fop/prototype/breaking/KnuthIterator.java	(revision 1)
+++ java/src/org/apache/fop/prototype/breaking/KnuthIterator.java	(revision 6)
@@ -21,7 +21,9 @@
 
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Stack;
 
 import org.apache.fop.prototype.Dot;
 import org.apache.fop.prototype.breaking.layout.Layout;
@@ -69,5 +71,43 @@
         } while (contentIter.hasNext());
         return null;
     }
+    
+    /* Needed for best fit line */
+    public Collection<CompletedPart> next(Stack<KnuthElement> rollbackElements, boolean rollback) {
+        assert hasNext();
+        if (!rollback) {
+	        do { // Normal execution
+	            KnuthElement e = contentIter.next();
+	        	rollbackElements.push(e);
+	        	if (e.isBox() || e.isGlue()) {
+	                layouts.updateLayouts(e);
+	            } else if (e.isPenalty()) {
+	                Penalty p = (Penalty) e;
+	                if (p.getPenalty() < Penalty.INFINITE) {
+	                    return legalBreakHandler.considerBreak(p, layouts);
+	                }
+	            }
+	        } while (contentIter.hasNext());
+        } else { // Special execution for roll back
+        	Stack<KnuthElement> elements = new Stack<KnuthElement>();
+    		do {
+    			elements.push(rollbackElements.pop());
+    		} while (!elements.empty() && elements.peek().isPenalty());
+        	
+        	do {
+	            KnuthElement e = elements.pop();
+	        	rollbackElements.push(e);
+	        	if (e.isBox() || e.isGlue()) {
+	                layouts.updateLayouts(e);
+	            } else if (e.isPenalty()) {
+	                Penalty p = (Penalty) e;
+	                if (p.getPenalty() < Penalty.INFINITE) {
+	                    return legalBreakHandler.considerBreak(p, layouts);
+	                }
+	            }
+	        } while (!elements.empty());
+        }
+        return null;
+    }
 
 }
Index: java/src/org/apache/fop/prototype/breaking/LegalBreakHandler.java
===================================================================
--- java/src/org/apache/fop/prototype/breaking/LegalBreakHandler.java	(revision 1)
+++ java/src/org/apache/fop/prototype/breaking/LegalBreakHandler.java	(revision 6)
@@ -22,10 +22,13 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.LinkedList;
 
 import org.apache.fop.prototype.breaking.FeasibleBreaks.BestBreak;
 import org.apache.fop.prototype.breaking.layout.Layout;
 import org.apache.fop.prototype.breaking.layout.ProgressInfo;
+import org.apache.fop.prototype.breaking.layout.StandardLayout;
+import org.apache.fop.prototype.knuth.KnuthElement;
 import org.apache.fop.prototype.knuth.Penalty;
 
 
@@ -48,16 +51,36 @@
     }
 
     public Collection<CompletedPart> considerBreak(Penalty p, ActiveLayouts<L> layouts) {
+
+        boolean bestFitLine = false; // Enable best fit at line level algorithm
+    	boolean endOfLine = false; // There are no more possible layouts for this line
+    	int countLayoutClass = 0; // There are other layouts class?
+    	boolean removed = false; // Rollback done
+    	
         Collection<CompletedPart> completedParts = new ArrayList<CompletedPart>();
         for (Iterator<Iterator<L>> classIter = layouts.getClassIterator(); classIter.hasNext();) {
             FeasibleBreaks<L> feasibleBreaks = new FeasibleBreaks<L>();
-            for (Iterator<L> layoutIter = classIter.next(); layoutIter.hasNext();) {
+            countLayoutClass++; // Best fit line
+            
+        	for (Iterator<L> layoutIter = classIter.next(); layoutIter.hasNext();) {
+            	
                 L layout = layoutIter.next();
                 int difference = layout.getDifference() - p.getLength();
                 double ratio = computeAdjustmentRatio(layout.getProgress(), difference);
                 if (ratio < -1.0 || p.isForcedBreak()) {
                     difference = 0; // TODO
-                    layoutIter.remove();
+                    /* Best fit line */
+                    if ((!bestFitLine) || (countLayoutClass > 1) || (classIter.hasNext())) {
+                    	layoutIter.remove();
+                    } else {
+                    	StandardLayout sLayout = (StandardLayout) layout;
+                    	sLayout.removeElement();
+                    	removed = true;
+                        double d = computeDemerits(p, ratio) + layout.getDemerits();
+                        feasibleBreaks.add(layout, d, difference);
+                    }
+                    endOfLine = true;
+                    /**/
                 }
                 if (-1.0 <= ratio && ratio <= threshold) {
                     double d = computeDemerits(p, ratio) + layout.getDemerits();
@@ -66,10 +89,31 @@
             }
             BestBreak<L> best = feasibleBreaks.getBest();
             if (best != null) {
-                completedParts.add(new CompletedPart(best.layout, best.demerits, best.difference,
-                        feasibleBreaks.getAlternatives()));
+            	/* Best fit line */
+            	CompletedPart cp = new CompletedPart(best.layout, best.demerits, best.difference,
+               			feasibleBreaks.getAlternatives());
+            	if (removed) {
+            		cp.setNeedRollback(true);
+            		layouts.clear();
+            	}
+            	completedParts.add(cp);
+            	/**/
             }
         }
+        
+        /* Best fit line */
+        if (bestFitLine && endOfLine && !removed) {
+        	L bestLayout = null;
+            for (L l: layouts) {
+            	if ((bestLayout == null) || (l.getDemerits() < bestLayout.getDemerits())) {
+            		bestLayout = l;
+            	}
+        	}
+            
+            layouts.clear();
+            layouts.add(bestLayout);
+        }
+        /**/
         return completedParts;
     }
 
Index: java/src/org/apache/fop/prototype/breaking/layout/ProgressInfo.java
===================================================================
--- java/src/org/apache/fop/prototype/breaking/layout/ProgressInfo.java	(revision 1)
+++ java/src/org/apache/fop/prototype/breaking/layout/ProgressInfo.java	(revision 6)
@@ -87,7 +87,19 @@
         totalStretch += stretch;
         totalShrink += shrink;
     }
+    
+    /* Needed for best fit line */
+    void rollback(int length) {
+        totalLength -= length;
+    }
 
+    /* Needed for best fit line */
+    void rollback(int length, int stretch, int shrink) {
+        rollback(length);
+        totalStretch -= stretch;
+        totalShrink -= shrink;
+    }
+
     /** {@inheritDoc} */
     @Override
     public boolean equals(Object o) {
Index: java/src/org/apache/fop/prototype/breaking/layout/StandardLayout.java
===================================================================
--- java/src/org/apache/fop/prototype/breaking/layout/StandardLayout.java	(revision 1)
+++ java/src/org/apache/fop/prototype/breaking/layout/StandardLayout.java	(revision 6)
@@ -159,6 +159,18 @@
             elements.add(e);
         }
     }
+    
+    /* Neede for best fit line */
+    public void removeElement() {
+		KnuthElement e = elements.get(elements.size()-1);
+		if (e.isGlue()) {
+            Glue g = (Glue) e;
+            progress.rollback(g.getLength(), g.getStretch(), g.getShrink());
+        } else {
+            progress.rollback(e.getLength());
+        }
+        elements.remove(e);
+    }
 
     /** {@inheritDoc} */
     @Override
Index: java/src/org/apache/fop/prototype/layoutmgr/ParagraphLayoutManager.java
===================================================================
--- java/src/org/apache/fop/prototype/layoutmgr/ParagraphLayoutManager.java	(revision 1)
+++ java/src/org/apache/fop/prototype/layoutmgr/ParagraphLayoutManager.java	(revision 6)
@@ -23,6 +23,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Stack;
 
 import org.apache.fop.prototype.Log;
 import org.apache.fop.prototype.breaking.ActiveLayouts;
@@ -53,6 +54,15 @@
     private LegalBreakHandler<Layout> blockLevelBreakHandler;
 
     private boolean finalized;
+    
+    /* Best fit line */
+    boolean rollback = false;
+    
+    Stack<KnuthElement> rollbackElements = new Stack<KnuthElement>();
+    /**/
+    
+    // Best fit page
+    private int oldMinPageNum, newMinPageNum;
 
     public ParagraphLayoutManager(Paragraph paragraph) {
         lineIterator = new KnuthIterator<LineLayout>(paragraph.getKnuthElements(),
@@ -88,11 +98,14 @@
     /** {@inheritDoc} */
     public void next() {
         Collection<CompletedPart> lines;
+     
         do {
-            lines = lineIterator.next();
+            lines = lineIterator.next(rollbackElements,rollback);
+        	rollback = false; // Best fit line
         } while (lines.isEmpty());
         newLayouts = new ActiveLayouts<Layout>();
         for (CompletedPart line: lines) {
+        	rollback = line.isNeedRollback(); // Best fit line
             LineLayout completedLayout = (LineLayout) line.getLayout(); // TODO cast
             Log.LOG.info("completed line:\n" + completedLayout);
             List<KnuthElement> elements = new ArrayList<KnuthElement>(completedLayout.getElements());
@@ -113,14 +126,47 @@
         if (lineIterator.hasNext()) {
             Collection<CompletedPart> blocks = blockLevelBreakHandler.considerBreak(
                     Penalty.DEFAULT_PENALTY, newLayouts);
-            for (CompletedPart block: blocks) {
-                Layout newBlockLayout = parent.partCompleted(block);
-                LineLayout newLineLayout = new LineLayout(newBlockLayout);
-                lineLayouts.add(newLineLayout);
+            
+            if (blocks != null) {
+	            
+	            for (CompletedPart block: blocks) {
+	                Layout newBlockLayout = parent.partCompleted(block);
+	                LineLayout newLineLayout = new LineLayout(newBlockLayout);
+	                lineLayouts.add(newLineLayout);
+	            }
+	            
+	            // Best fit for page
+	            // Check if we already have all possible layouts for a page
+	            newMinPageNum = -1;
+	            for (LineLayout l: lineLayouts) {
+	            	if (l.getBlockLayout().getProgress().getPartNumber() < newMinPageNum || newMinPageNum == -1) {
+	            		newMinPageNum = l.getBlockLayout().getProgress().getPartNumber(); 
+	            	}
+	            }
             }
         }
+        
         for (Layout blockLayout: newLayouts) {
             lineLayouts.add(new LineLayout(blockLayout)); // TODO line number
         }
+        
+        /* Best fit for paragraph: when the end of the paragraph is reached choose the best
+         * layout and discard the others.
+         */
+        boolean bestFitParagraph = false; // Enable best fit for paragraph
+        boolean bestFitPage = true; // Enable best fit for page
+        if ((!lineIterator.hasNext() && bestFitParagraph) || //paragraph
+        		((newMinPageNum != oldMinPageNum) && bestFitPage)) { // page
+        	
+        	LineLayout bestLayout = null;
+            for (LineLayout l: lineLayouts) {
+            	if ((bestLayout == null) || (l.getDemerits() < bestLayout.getDemerits())) {
+            		bestLayout = l;
+            	}
+        	}
+            lineLayouts.clear();
+            lineLayouts.add(bestLayout);
+        }
+        oldMinPageNum = newMinPageNum;
     }
 }
