]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Added missing support for Next Line (NEL, 0x0085) and Line Separator (LS, 0x2028... fop-0_95 fop-0_95
authorJeremias Maerki <jeremias@apache.org>
Tue, 23 Sep 2008 12:14:22 +0000 (12:14 +0000)
committerJeremias Maerki <jeremias@apache.org>
Tue, 23 Sep 2008 12:14:22 +0000 (12:14 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_95@698151 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
src/java/org/apache/fop/util/CharUtilities.java
status.xml
test/layoutengine/standard-testcases/block_uax14_linebreaking_bk.xml [new file with mode: 0644]

index 40e1c087a95a28066f3638fc6acea9136cacd4e2..e451a659ab439fc10434716778e8e6cdca01ff4c 100644 (file)
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -26,6 +26,7 @@ import java.util.ListIterator;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+
 import org.apache.fop.area.Trait;
 import org.apache.fop.area.inline.TextArea;
 import org.apache.fop.fo.Constants;
@@ -81,7 +82,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             this.isSpace = isSpace;
             this.breakOppAfter = breakOppAfter;
         }
-        
+
         public String toString() {
             return "[ lscnt=" +  iLScount
                 + ", wscnt=" + iWScount
@@ -120,7 +121,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
 
     /** Used to reduce instantiation of MinOptMax with zero length. Do not modify! */
     private static final MinOptMax ZERO_MINOPTMAX = new MinOptMax(0);
-    
+
     private FOText foText;
     private char[] textArray;
     /**
@@ -130,8 +131,6 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
      */
     private MinOptMax[] letterAdjustArray; //size = textArray.length + 1
 
-    private static final char NEWLINE = '\n';
-
     private Font font = null;
     /** Start index of first character in this parent Area */
     private short iAreaStart = 0;
@@ -152,7 +151,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
     /** 1/2 of word-spacing value */
     private SpaceVal halfWS;
     /** 1/2 of letter-spacing value */
-    private SpaceVal halfLS; 
+    private SpaceVal halfLS;
     /** Number of space characters after previous possible break position. */
     private int iNbSpacesPending;
 
@@ -166,7 +165,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
 
     private int lineStartBAP = 0;
     private int lineEndBAP = 0;
-    
+
     private boolean keepTogether;
 
     /**
@@ -177,7 +176,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
     public TextLayoutManager(FOText node) {
         super();
         foText = node;
-        
+
         textArray = new char[node.endIndex - node.startIndex];
         System.arraycopy(node.ca, node.startIndex, textArray, 0,
             node.endIndex - node.startIndex);
@@ -185,22 +184,22 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
 
         vecAreaInfo = new java.util.ArrayList();
     }
-    
+
     /** {@inheritDoc} */
     public void initialize() {
         FontInfo fi = foText.getFOEventHandler().getFontInfo();
         FontTriplet[] fontkeys = foText.getCommonFont().getFontState(fi);
         font = fi.getFontInstance(fontkeys[0], foText.getCommonFont().fontSize.getValue(this));
-        
+
         // With CID fonts, space isn't neccesary currentFontState.width(32)
         spaceCharIPD = font.getCharWidth(' ');
         // Use hyphenationChar property
         hyphIPD = foText.getCommonHyphenation().getHyphIPD(font);
-        
+
         SpaceVal ls = SpaceVal.makeLetterSpacing(foText.getLetterSpacing());
         halfLS = new SpaceVal(MinOptMax.multiply(ls.getSpace(), 0.5),
                 ls.isConditional(), ls.isForcing(), ls.getPrecedence());
-        
+
         ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, font);
         // Make half-space: <space> on either side of a word-space)
         halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5),
@@ -219,7 +218,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         // in the SpaceVal.makeWordSpacing() method
         letterSpaceIPD = ls.getSpace();
         wordSpaceIPD = MinOptMax.add(new MinOptMax(spaceCharIPD), ws.getSpace());
-        
+
         keepTogether = foText.getKeepTogether().getWithinLine().getEnum() == Constants.EN_ALWAYS;
 
     }
@@ -298,9 +297,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             realWidth.add(MinOptMax.multiply(letterSpaceIPD, -1));
             iLScount--;
         }
-        
+
         for (int i = ai.iStartIndex; i < ai.iBreakIndex; i++) {
-            MinOptMax ladj = letterAdjustArray[i + 1]; 
+            MinOptMax ladj = letterAdjustArray[i + 1];
             if (ladj != null && ladj.isElastic()) {
                 iLScount++;
             }
@@ -327,7 +326,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             iDifference = (int) ((double) (realWidth.opt - realWidth.min)
                                 * dIPDAdjust);
         }
-        
+
         // set letter space adjustment
         if (dIPDAdjust > 0.0) {
             iLetterSpaceDim
@@ -341,7 +340,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         iTotalAdjust += (iLetterSpaceDim - letterSpaceIPD.opt) * iLScount;
 
         // set word space adjustment
-        // 
+        //
         if (iWScount > 0) {
             iWordSpaceDim += (int) ((iDifference - iTotalAdjust) / iWScount);
         } else {
@@ -370,7 +369,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         // the last character of a word and to space characters: in order
         // to avoid this, we must subtract the letter space width twice;
         // the renderer will compute the space width as:
-        //   space width = 
+        //   space width =
         //     = "normal" space width + letterSpaceAdjust + wordSpaceAdjust
         //     = spaceCharIPD + letterSpaceAdjust +
         //       + (iWordSpaceDim - spaceCharIPD -  2 * letterSpaceAdjust)
@@ -395,7 +394,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
      * @param context the layout context
      * @param spaceDiff unused
      * @param firstIndex the index of the first AreaInfo used for the TextArea
-     * @param lastIndex the index of the last AreaInfo used for the TextArea 
+     * @param lastIndex the index of the last AreaInfo used for the TextArea
      * @param isLastArea is this TextArea the last in a line?
      * @return the new text area
      */
@@ -450,7 +449,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     // here ends a new word
                     // add a word to the TextArea
                     if (isLastArea
-                        && i == lastIndex 
+                        && i == lastIndex
                         && areaInfo.bHyphenated) {
                         len++;
                     }
@@ -475,7 +474,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     }
                     // String wordChars = new String(textArray, wordStartIndex, len);
                     if (isLastArea
-                        && i == lastIndex 
+                        && i == lastIndex
                         && areaInfo.bHyphenated) {
                         // add the hyphenation character
                         wordChars.append(foText.getCommonHyphenation().getHyphChar(font));
@@ -487,12 +486,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         }
         TraitSetter.addFontTraits(textArea, font);
         textArea.addTrait(Trait.COLOR, foText.getColor());
-        
+
         TraitSetter.addTextDecoration(textArea, foText.getTextDecoration());
-        
+
         return textArea;
     }
-    
+
     private void addToLetterAdjust(int index, int width) {
         if (letterAdjustArray[index] == null) {
             letterAdjustArray[index] = new MinOptMax(width);
@@ -519,7 +518,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             || CharUtilities.isNonBreakableSpace(ch)
             || CharUtilities.isFixedWidthSpace(ch);
     }
-    
+
     /** {@inheritDoc} */
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         lineStartBAP = context.getLineStartBorderAndPaddingWidth();
@@ -536,11 +535,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         iThisStart = iNextStart;
         boolean inWord = false;
         boolean inWhitespace = false;
-        char ch = 0; 
+        char ch = 0;
         while (iNextStart < textArray.length) {
-            ch = textArray[iNextStart]; 
+            ch = textArray[iNextStart];
             boolean breakOpportunity = false;
-            byte breakAction = keepTogether? LineBreakStatus.PROHIBITED_BREAK : lbs.nextChar(ch);
+            byte breakAction = keepTogether ? LineBreakStatus.PROHIBITED_BREAK : lbs.nextChar(ch);
             switch (breakAction) {
                 case LineBreakStatus.COMBINING_PROHIBITED_BREAK:
                 case LineBreakStatus.PROHIBITED_BREAK:
@@ -556,7 +555,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     log.error("Unexpected breakAction: " + breakAction);
             }
             if (inWord) {
-                if (breakOpportunity || isSpace(ch) || ch == NEWLINE) {
+                if (breakOpportunity || isSpace(ch) || CharUtilities.isLineBreakCharacter(ch)) {
                     //Word boundary found, process widths and kerning
                     int lastIndex = iNextStart;
                     while (lastIndex > 0 && textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) {
@@ -626,7 +625,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     ai = new AreaInfo(iThisStart, (short) (iNextStart),
                             (short) (iNextStart - iThisStart), (short) 0,
                             MinOptMax.multiply(wordSpaceIPD, iNextStart - iThisStart),
-                            false, true, breakOpportunity); 
+                            false, true, breakOpportunity);
                     vecAreaInfo.add(ai);
                     prevAi = ai;
 
@@ -657,9 +656,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     returnList.add(sequence);
                 }
             }
-            
-            if ((ch == CharUtilities.SPACE 
-                    && foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) 
+
+            if ((ch == CharUtilities.SPACE
+                    && foText.getWhitespaceTreatment() == Constants.EN_PRESERVE)
                     || ch == CharUtilities.NBSPACE) {
                 // preserved space or non-breaking space:
                 // create the AreaInfo object
@@ -672,17 +671,17 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
                 ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
                         (short) 0, (short) 0,
-                        ipd, false, true, breakOpportunity); 
+                        ipd, false, true, breakOpportunity);
                 iThisStart = (short) (iNextStart + 1);
-            } else if (ch == NEWLINE) {
+            } else if (CharUtilities.isLineBreakCharacter(ch)) {
                 // linefeed; this can happen when linefeed-treatment="preserve"
                 iThisStart = (short) (iNextStart + 1);
             }
-            inWord = !isSpace(ch) && ch != NEWLINE;
+            inWord = !isSpace(ch) && !CharUtilities.isLineBreakCharacter(ch);
             inWhitespace = ch == CharUtilities.SPACE && foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
             iNextStart++;
         } // end of while
-        
+
         // Process any last elements
         if (inWord) {
             int lastIndex = iNextStart;
@@ -734,7 +733,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             ai = new AreaInfo(iThisStart, (short) (iNextStart),
                     (short) (iNextStart - iThisStart), (short) 0,
                     MinOptMax.multiply(wordSpaceIPD, iNextStart - iThisStart),
-                    false, true, true); 
+                    false, true, true);
             vecAreaInfo.add(ai);
 
             // create the elements
@@ -747,7 +746,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             sequence.addAll
                 (createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));
             ai = null;
-        } else if (ch == NEWLINE) {
+        } else if (CharUtilities.isLineBreakCharacter(ch)) {
             if (lineEndBAP != 0) {
                 sequence.add
                     (new KnuthGlue(lineEndBAP, 0, 0,
@@ -894,7 +893,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                                            : (iStopIndex - iStartIndex))));
 
             if (!(bNothingChanged
-                  && iStopIndex == ai.iBreakIndex 
+                  && iStopIndex == ai.iBreakIndex
                   && bHyphenFollows == false)) {
                 // the new AreaInfo object is not equal to the old one
                 if (changeList == null) {
@@ -991,7 +990,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             AreaInfo ai, int leafValue) {
         LinkedList spaceElements = new LinkedList();
         LeafPosition mainPosition = new LeafPosition(this, leafValue);
-        
+
         if (!ai.breakOppAfter) {
             // a non-breaking space
             if (alignment == EN_JUSTIFY) {
@@ -1001,7 +1000,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                         notifyPos(new LeafPosition(this, -1)), true));
                 spaceElements.add(new KnuthPenalty(0, KnuthElement.INFINITE,
                         false, new LeafPosition(this, -1), false));
-                spaceElements.add(new KnuthGlue(ai.ipdArea.opt, ai.ipdArea.max - ai.ipdArea.opt, 
+                spaceElements.add(new KnuthGlue(ai.ipdArea.opt, ai.ipdArea.max - ai.ipdArea.opt,
                         ai.ipdArea.opt - ai.ipdArea.min, mainPosition, false));
             } else {
                 // the space does not need to stretch or shrink, and must be
@@ -1016,7 +1015,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 switch (alignment) {
                 case EN_CENTER:
                     // centered text:
-                    // if the second element is chosen as a line break these elements 
+                    // if the second element is chosen as a line break these elements
                     // add a constant amount of stretch at the end of a line and at the
                     // beginning of the next one, otherwise they don't add any stretch
                     spaceElements.add(new KnuthGlue(lineEndBAP,
@@ -1043,7 +1042,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 case EN_START: // fall through
                 case EN_END:
                     // left- or right-aligned text:
-                    // if the second element is chosen as a line break these elements 
+                    // if the second element is chosen as a line break these elements
                     // add a constant amount of stretch at the end of a line, otherwise
                     // they don't add any stretch
                     spaceElements.add(new KnuthGlue(lineEndBAP,
@@ -1102,13 +1101,13 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                                     this, -1), false));
                     spaceElements.add(new KnuthGlue(lineStartBAP + ai.ipdArea.opt, 0, 0,
                             mainPosition, false));
-                } 
+                }
             } else {
                 // a (possible block) of breaking spaces
                 switch (alignment) {
                 case EN_CENTER:
                     // centered text:
-                    // if the second element is chosen as a line break these elements 
+                    // if the second element is chosen as a line break these elements
                     // add a constant amount of stretch at the end of a line and at the
                     // beginning of the next one, otherwise they don't add any stretch
                     spaceElements.add(new KnuthGlue(lineEndBAP,
@@ -1134,7 +1133,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 case EN_START: // fall through
                 case EN_END:
                     // left- or right-aligned text:
-                    // if the second element is chosen as a line break these elements 
+                    // if the second element is chosen as a line break these elements
                     // add a constant amount of stretch at the end of a line, otherwise
                     // they don't add any stretch
                     if (lineStartBAP != 0 || lineEndBAP != 0) {
@@ -1221,7 +1220,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 }
             }
         }
-        
+
         return spaceElements;
     }
 
@@ -1239,14 +1238,14 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             // constant letter spacing
             wordElements.add
                 (new KnuthInlineBox(
-                        bSuppressibleLetterSpace 
+                        bSuppressibleLetterSpace
                                 ? ai.ipdArea.opt - letterSpaceWidth.opt
                                 : ai.ipdArea.opt,
                         alignmentContext,
                         notifyPos(mainPosition), false));
         } else {
             // adjustable letter spacing
-            int unsuppressibleLetterSpaces 
+            int unsuppressibleLetterSpaces
                 = bSuppressibleLetterSpace ? ai.iLScount - 1 : ai.iLScount;
             wordElements.add
                 (new KnuthInlineBox(ai.ipdArea.opt
@@ -1265,7 +1264,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 (new KnuthInlineBox(0, null,
                               notifyPos(new LeafPosition(this, -1)), true));
         }
+
         // extra-elements if the word fragment is the end of a syllable,
         // or it ends with a character that can be used as a line break
         if (ai.bHyphenated) {
@@ -1275,7 +1274,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 widthIfNoBreakOccurs = letterAdjustArray[ai.iBreakIndex];
             }
             //if (ai.iBreakIndex)
-            
+
             // the word fragment ends at the end of a syllable:
             // if a break occurs the content width increases,
             // otherwise nothing happens
@@ -1297,7 +1296,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             widthIfNoBreakOccurs = ZERO_MINOPTMAX;
         }
         LinkedList hyphenElements = new LinkedList();
-        
+
         switch (alignment) {
         case EN_CENTER :
             // centered text:
@@ -1347,7 +1346,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 (new KnuthGlue(lineStartBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
                                new LeafPosition(this, -1), true));
             break;
-            
+
         case EN_START  : // fall through
         case EN_END    :
             // left- or right-aligned text:
@@ -1405,7 +1404,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                             new LeafPosition(this, -1), false));
             }
             break;
-            
+
         default:
             // justified text, or last line justified:
             // just a flagged penalty
@@ -1467,10 +1466,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 }
             }
         }
-        
+
         return hyphenElements;
     }
-    
+
 }
 
 
index 4910a371c521108fc9ba122395818011c44b81a1..d1b1bd6e9b82d237462fe9b119184546ea268674 100644 (file)
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -123,7 +123,7 @@ public class CharUtilities {
      * @return true if the character has a fixed-width
      */
     public static boolean isFixedWidthSpace(char c) {
-        return (c >= '\u2000' && c <= '\u200B') 
+        return (c >= '\u2000' && c <= '\u200B')
                 || c == '\u3000';
 //      c == '\u2000'                   // en quad
 //      c == '\u2001'                   // em quad
@@ -167,7 +167,7 @@ public class CharUtilities {
             (c == '\u0020'    // normal space
             || c == NBSPACE); // no-break space
     }
-    
+
     /**
      * Determines if the character represents any kind of space.
      * @param c character to check
@@ -177,7 +177,7 @@ public class CharUtilities {
         boolean ret = (isBreakableSpace(c) || isNonBreakableSpace(c));
         return ret;
     }
-    
+
     /**
      * Indicates whether a character is classified as "Alphabetic" by the Unicode standard.
      * @param ch the character
@@ -201,6 +201,21 @@ public class CharUtilities {
             return false;
         }
     }
-    
+
+    /**
+     * Indicates whether the given character is a line break character as in the
+     * "BK" line breaking class (see UAX #14).
+     * @param ch the character
+     * @return true if the character is in the "BK" line breaking class
+     */
+    public static boolean isLineBreakCharacter(char ch) {
+        return ch == '\n'
+            || (ch == '\u0085') //NEXT LINE (NEL)
+            || (ch == '\u2028'); //LINE SEPARATOR (SP)
+        //maybe also: PARAGRAPH SEPARATOR (PS)
+        //FORM FEED (FF, 000C) and LINE TABULATION (VT, 000B) are in the "BK" class
+        //but are no valid XML characters and therefore left out here.
+    }
+
 }
 
index 0d7bba5473f2707a7bbccb04738f44f75c9052ea..90b14aec7b3d72e24cba9f7c588d6eb239f1d714 100644 (file)
   
   <changes>
     <release version="FOP Trunk" date="TBD">
+      <action context="Layout" dev="JM" type="add">
+        Added missing support for Next Line (NEL, 0x0085)
+        and Line Separator (LS, 0x2028) characters.
+      </action>
       <action context="Renderers" dev="JM" type="fix">
         Fixed text stroking in SVG when the stroke-width is zero.
       </action>
diff --git a/test/layoutengine/standard-testcases/block_uax14_linebreaking_bk.xml b/test/layoutengine/standard-testcases/block_uax14_linebreaking_bk.xml
new file mode 100644 (file)
index 0000000..24e08a1
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks some of the UAX#14 breaking rules
+      (this file: BK: Mandatory Break (A) (Non-tailorable)).
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="2.5in" page-height="10in" margin="5pt">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal" white-space-collapse="true">
+        <fo:flow flow-name="xsl-region-body" font-size="10pt">
+          <fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
+            BK -- Mandatory Break (A) (Non-tailorable)
+          </fo:block>
+          <!-- Form Feed (FF) and LINE TABULATION (VT) no legal XML characters, thus left out -->
+          <fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
+            VeryLongWordWithALineSeparator&#x2028;PutInTheMiddleOfIt
+          </fo:block>
+          <!-- Paragraph Separator &#x2029; left out as it might have to be treated differently from LS -->
+          <fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
+            VeryLongWordWithANEL&#x0085;PutInTheMiddleOfIt
+          </fo:block>
+          <fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt"
+            linefeed-treatment="preserve">VeryLongWordWithACarriageReturn
+            PutInTheMiddleOfIt
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="2" xpath="count(//flow/block[2]/lineArea)"/>
+    <eval expected="30" xpath="string-length(//flow/block[2]/lineArea[1]/text)"/>
+    <eval expected="156170" xpath="//flow/block[2]/lineArea[1]/text/@ipd"/>
+    <eval expected="18" xpath="string-length(//flow/block[2]/lineArea[2]/text)"/>
+    <eval expected="86150" xpath="//flow/block[2]/lineArea[2]/text/@ipd"/>
+
+    <eval expected="2" xpath="count(//flow/block[3]/lineArea)"/>
+    <eval expected="20" xpath="string-length(//flow/block[3]/lineArea[1]/text)"/>
+    <eval expected="112810" xpath="//flow/block[3]/lineArea[1]/text/@ipd"/>
+    <eval expected="18" xpath="string-length(//flow/block[3]/lineArea[2]/text)"/>
+    <eval expected="86150" xpath="//flow/block[3]/lineArea[2]/text/@ipd"/>
+    
+    <eval expected="2" xpath="count(//flow/block[4]/lineArea)"/>
+    <eval expected="31" xpath="string-length(//flow/block[4]/lineArea[1]/text)"/>
+    <eval expected="161710" xpath="//flow/block[4]/lineArea[1]/text/@ipd"/>
+    <eval expected="18" xpath="string-length(//flow/block[4]/lineArea[2]/text)"/>
+    <eval expected="86150" xpath="//flow/block[4]/lineArea[2]/text/@ipd"/>
+    
+  </checks>
+</testcase>