Browse Source

Added (limited) support for Unicode UAX#14 compliant line breaking. Thanks to Joerg Pietschman who supplied the core code for the Unicode line breaking algorithm

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@489585 13f79535-47bb-0310-9956-ffa450edef68
pull/25/head
Manuel Mall 17 years ago
parent
commit
395c6fa486
43 changed files with 2557 additions and 592 deletions
  1. 58
    21
      build.xml
  2. 0
    0
      src/codegen/fo/colorkw.xml
  3. 0
    0
      src/codegen/fo/constants.xml
  4. 0
    0
      src/codegen/fo/constants.xsl
  5. 0
    0
      src/codegen/fo/fo-property-mapping.xsl
  6. 0
    0
      src/codegen/fo/foelements.xml
  7. 0
    0
      src/codegen/fo/foproperties.xml
  8. 0
    0
      src/codegen/fo/properties.dtd
  9. 0
    0
      src/codegen/fo/property-sets.xsl
  10. 0
    0
      src/codegen/fo/propinc.xsl
  11. 0
    0
      src/codegen/fo/propmaker.xsl
  12. 0
    0
      src/codegen/fonts/Courier.xml
  13. 0
    0
      src/codegen/fonts/CourierBold.xml
  14. 0
    0
      src/codegen/fonts/CourierBoldOblique.xml
  15. 0
    0
      src/codegen/fonts/CourierOblique.xml
  16. 0
    0
      src/codegen/fonts/Helvetica.xml
  17. 0
    0
      src/codegen/fonts/HelveticaBold.xml
  18. 0
    0
      src/codegen/fonts/HelveticaBoldOblique.xml
  19. 0
    0
      src/codegen/fonts/HelveticaOblique.xml
  20. 0
    0
      src/codegen/fonts/Symbol.xml
  21. 0
    0
      src/codegen/fonts/TimesBold.xml
  22. 0
    0
      src/codegen/fonts/TimesBoldItalic.xml
  23. 0
    0
      src/codegen/fonts/TimesItalic.xml
  24. 0
    0
      src/codegen/fonts/TimesRoman.xml
  25. 0
    0
      src/codegen/fonts/ZapfDingbats.xml
  26. 0
    0
      src/codegen/fonts/charlist.xml
  27. 0
    0
      src/codegen/fonts/code-point-mapping.xsl
  28. 0
    0
      src/codegen/fonts/encodings.xml
  29. 0
    0
      src/codegen/fonts/font-file.xsl
  30. 0
    0
      src/codegen/fonts/glyphlist.xml
  31. 0
    0
      src/codegen/fonts/t1font-file.xsl
  32. 0
    0
      src/codegen/fonts/ttffontfile.xsl
  33. 28
    0
      src/codegen/unicode/data/LineBreakPairTable.txt
  34. 659
    0
      src/codegen/unicode/java/org/apache/fop/text/linebreak/GenerateLineBreakUtils.java
  35. 355
    287
      src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
  36. 160
    0
      src/java/org/apache/fop/text/linebreak/LineBreakStatus.java
  37. 669
    0
      src/java/org/apache/fop/text/linebreak/LineBreakUtils.java
  38. 3
    0
      status.xml
  39. 351
    0
      test/java/org/apache/fop/text/linebreak/LineBreakStatusTest.java
  40. 74
    0
      test/java/org/apache/fop/text/linebreak/LineBreakUtilsTest.java
  41. 188
    0
      test/layoutengine/standard-testcases/block_uax14_linebreaking.xml
  42. 0
    272
      test/layoutengine/standard-testcases/block_white-space_4.xml
  43. 12
    12
      test/layoutengine/standard-testcases/inline_border_padding_conditionality_2.xml

+ 58
- 21
build.xml View File

@@ -162,6 +162,7 @@ list of possible build targets.
<property name="src.dir" value="${basedir}/src"/>
<property name="src.codegen.dir" value="${src.dir}/codegen"/>
<property name="src.codegen.fonts.dir" value="${src.codegen.dir}/fonts"/>
<property name="src.java.dir" value="${src.dir}/java"/>
<property name="src.sandbox.dir" value="${src.dir}/sandbox"/>
<property name="src.viewer.resources.dir" value="${src.java.dir}/org/apache/fop/render/awt/viewer/resources"/>
@@ -178,6 +179,7 @@ list of possible build targets.
<property name="build.gensrc.dir" value="${build.dir}/gensrc"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="build.sandbox-classes.dir" value="${build.dir}/sandbox-classes"/>
<property name="build.codegen-classes.dir" value="${build.dir}/codegen-classes"/>
<property name="build.javadocs.dir" value="${build.dir}/javadocs"/>
<property name="build.examples.dir" value="${build.dir}/examples"/>

@@ -319,69 +321,69 @@ list of possible build targets.
<mkdir dir="${build.gensrc.dir}"/>
<mkdir dir="${build.gensrc.dir}/org/apache/fop/fonts/base14"/>

<style in="${src.codegen.dir}/encodings.xml"
style="${src.codegen.dir}/code-point-mapping.xsl"
<style in="${src.codegen.fonts.dir}/encodings.xml"
style="${src.codegen.fonts.dir}/code-point-mapping.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/CodePointMapping.java"/>
<!-- Task unrolled because of a bug in Xalan included in some
JDK 1.4 releases
<style basedir="src/codegen" includes="Helvetica*.xml,Times*.xml,Courier*.xml"
style="${src.codegen.dir}/font-file.xsl"
style="${src.codegen.fonts.dir}/font-file.xsl"
destdir="${build.gensrc.dir}/org/apache/fop/fonts/base14" extension=".java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
-->
<style in="${src.codegen.dir}/Courier.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/Courier.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/Courier.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/CourierOblique.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/CourierOblique.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/CourierOblique.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/CourierBold.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/CourierBold.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/CourierBold.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/CourierBoldOblique.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/CourierBoldOblique.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/CourierBoldOblique.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/Helvetica.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/Helvetica.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
destdir="${build.gensrc.dir}/org/apache/fop/fonts/base14"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/Helvetica.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/HelveticaBold.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/HelveticaBold.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/HelveticaBold.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/HelveticaOblique.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/HelveticaOblique.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/HelveticaOblique.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/HelveticaBoldOblique.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/HelveticaBoldOblique.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/HelveticaBoldOblique.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/TimesRoman.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/TimesRoman.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/TimesRoman.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/TimesItalic.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/TimesItalic.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/TimesItalic.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/TimesBold.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/TimesBold.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/TimesBold.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/TimesBoldItalic.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/TimesBoldItalic.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/TimesBoldItalic.java">
<param name="encoding" expression="WinAnsiEncoding"/>
</style>
<style in="${src.codegen.dir}/Symbol.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/Symbol.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/Symbol.java"/>
<style in="${src.codegen.dir}/ZapfDingbats.xml" style="${src.codegen.dir}/font-file.xsl"
<style in="${src.codegen.fonts.dir}/ZapfDingbats.xml" style="${src.codegen.fonts.dir}/font-file.xsl"
out="${build.gensrc.dir}/org/apache/fop/fonts/base14/ZapfDingbats.java"/>

</target>
@@ -901,7 +903,26 @@ list of possible build targets.
</junit>
</target>

<target name="junit" depends="junit-basic, junit-transcoder, junit-layout, junit-fotree, junit-intermediate-format" description="Runs all of FOP's JUnit tests" if="junit.present">
<target name="junit-text-linebreak" depends="junit-compile" description="Runs FOP's JUnit unicode linebreak tests" if="junit.present">
<echo message="Running tests for Unicode UAX#14 support"/>
<junit dir="${basedir}" haltonfailure="${junit.haltonfailure}" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<formatter type="brief" usefile="false"/>
<formatter type="plain" usefile="true"/>
<formatter type="xml" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-build-classpath"/>
<fileset dir="build">
<include name="fop.jar"/>
</fileset>
</classpath>
<test name="org.apache.fop.text.linebreak.LineBreakStatusTest" todir="${junit.reports.dir}"/>
</junit>
</target>

<target name="junit" depends="junit-basic, junit-transcoder, junit-text-linebreak, junit-layout, junit-fotree, junit-intermediate-format" description="Runs all of FOP's JUnit tests" if="junit.present">
<fail>
<condition>
<or>
@@ -1260,13 +1281,29 @@ NOTE:
<!-- and may have updates that will *not* be generated by below. This -->
<!-- target should never be part of the normal build process. -->
<!-- =================================================================== -->
<target name="xsltToJava" >
<style in="src\codegen\constants.xml" style="src\codegen\constants.xsl"
<target name="codegen-fo" >
<style in="${src.codegen.dir}/fo/constants.xml" style="${src.codegen.dir}/fo/constants.xsl"
out="Constants.java"/>
<style in="src/codegen/foelements.xml" style="src/codegen/property-sets.xsl"
<style in="${src.codegen.dir}/fo/foelements.xml" style="${src.codegen.dir}/fo/property-sets.xsl"
out="PropertySets.java"/>
</target>

<!-- =================================================================== -->
<!-- Helper task to generate source files that have already been -->
<!-- checked into CVS. For these files, CVS version is the official one -->
<!-- and may have updates that will *not* be generated by below. This -->
<!-- target should never be part of the normal build process. -->
<!-- =================================================================== -->
<target name="codegen-unicode" >
<mkdir dir="${build.codegen-classes.dir}"/>
<javac destdir="${build.codegen-classes.dir}" fork="${javac.fork}" debug="${javac.debug}"
deprecation="${javac.deprecation}" optimize="${javac.optimize}"
source="${javac.source}" target="${javac.target}">
<src path="${src.codegen.dir}/unicode/java"/>
</javac>
<java classname="org.apache.fop.text.linebreak.GenerateLineBreakUtils" classpath="${build.codegen-classes.dir}" />
</target>

<!-- =================================================================== -->
<!-- Special target for Gump -->
<!-- =================================================================== -->

src/codegen/colorkw.xml → src/codegen/fo/colorkw.xml View File


src/codegen/constants.xml → src/codegen/fo/constants.xml View File


src/codegen/constants.xsl → src/codegen/fo/constants.xsl View File


src/codegen/fo-property-mapping.xsl → src/codegen/fo/fo-property-mapping.xsl View File


src/codegen/foelements.xml → src/codegen/fo/foelements.xml View File


src/codegen/foproperties.xml → src/codegen/fo/foproperties.xml View File


src/codegen/properties.dtd → src/codegen/fo/properties.dtd View File


src/codegen/property-sets.xsl → src/codegen/fo/property-sets.xsl View File


src/codegen/propinc.xsl → src/codegen/fo/propinc.xsl View File


src/codegen/propmaker.xsl → src/codegen/fo/propmaker.xsl View File


src/codegen/Courier.xml → src/codegen/fonts/Courier.xml View File


src/codegen/CourierBold.xml → src/codegen/fonts/CourierBold.xml View File


src/codegen/CourierBoldOblique.xml → src/codegen/fonts/CourierBoldOblique.xml View File


src/codegen/CourierOblique.xml → src/codegen/fonts/CourierOblique.xml View File


src/codegen/Helvetica.xml → src/codegen/fonts/Helvetica.xml View File


src/codegen/HelveticaBold.xml → src/codegen/fonts/HelveticaBold.xml View File


src/codegen/HelveticaBoldOblique.xml → src/codegen/fonts/HelveticaBoldOblique.xml View File


src/codegen/HelveticaOblique.xml → src/codegen/fonts/HelveticaOblique.xml View File


src/codegen/Symbol.xml → src/codegen/fonts/Symbol.xml View File


src/codegen/TimesBold.xml → src/codegen/fonts/TimesBold.xml View File


src/codegen/TimesBoldItalic.xml → src/codegen/fonts/TimesBoldItalic.xml View File


src/codegen/TimesItalic.xml → src/codegen/fonts/TimesItalic.xml View File


src/codegen/TimesRoman.xml → src/codegen/fonts/TimesRoman.xml View File


src/codegen/ZapfDingbats.xml → src/codegen/fonts/ZapfDingbats.xml View File


src/codegen/charlist.xml → src/codegen/fonts/charlist.xml View File


src/codegen/code-point-mapping.xsl → src/codegen/fonts/code-point-mapping.xsl View File


src/codegen/encodings.xml → src/codegen/fonts/encodings.xml View File


src/codegen/font-file.xsl → src/codegen/fonts/font-file.xsl View File


src/codegen/glyphlist.xml → src/codegen/fonts/glyphlist.xml View File


src/codegen/t1font-file.xsl → src/codegen/fonts/t1font-file.xsl View File


src/codegen/ttffontfile.xsl → src/codegen/fonts/ttffontfile.xsl View File


+ 28
- 0
src/codegen/unicode/data/LineBreakPairTable.txt View File

@@ -0,0 +1,28 @@
OP CL QU GL NS EX SY IS PR PO NU AL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT
OP ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ @ ^ ^ ^ ^ ^ ^
CL _ ^ % % ^ ^ ^ ^ % % % % _ _ % % _ _ ^ # ^ _ _ _ _ _
QU ^ ^ % % % ^ ^ ^ % % % % % % % % % % ^ # ^ % % % % %
GL % ^ % % % ^ ^ ^ % % % % % % % % % % ^ # ^ % % % % %
NS _ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _
EX _ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _
SY _ ^ % % % ^ ^ ^ _ _ % _ _ _ % % _ _ ^ # ^ _ _ _ _ _
IS _ ^ % % % ^ ^ ^ _ _ % % _ _ % % _ _ ^ # ^ _ _ _ _ _
PR % ^ % % % ^ ^ ^ _ _ % % % _ % % _ _ ^ # ^ % % % % %
PO % ^ % % % ^ ^ ^ _ _ % % _ _ % % _ _ ^ # ^ _ _ _ _ _
NU % ^ % % % ^ ^ ^ % % % % _ % % % _ _ ^ # ^ _ _ _ _ _
AL % ^ % % % ^ ^ ^ _ _ % % _ % % % _ _ ^ # ^ _ _ _ _ _
ID _ ^ % % % ^ ^ ^ _ % _ _ _ % % % _ _ ^ # ^ _ _ _ _ _
IN _ ^ % % % ^ ^ ^ _ _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _
HY _ ^ % % % ^ ^ ^ _ _ % _ _ _ % % _ _ ^ # ^ _ _ _ _ _
BA _ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _
BB % ^ % % % ^ ^ ^ % % % % % % % % % % ^ # ^ % % % % %
B2 _ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % _ ^ ^ # ^ _ _ _ _ _
ZW _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ^ _ _ _ _ _ _ _
CM _ ^ % % % ^ ^ ^ _ _ % % _ % % % _ _ ^ # ^ _ _ _ _ _
WJ % ^ % % % ^ ^ ^ % % % % % % % % % % ^ # ^ % % % % %
H2 _ ^ % % % ^ ^ ^ _ % _ _ _ % % % _ _ ^ # ^ _ _ _ % %
H3 _ ^ % % % ^ ^ ^ _ % _ _ _ % % % _ _ ^ # ^ _ _ _ _ %
JL _ ^ % % % ^ ^ ^ _ % _ _ _ % % % _ _ ^ # ^ % % % % _
JV _ ^ % % % ^ ^ ^ _ % _ _ _ % % % _ _ ^ # ^ _ _ _ % %
JT _ ^ % % % ^ ^ ^ _ % _ _ _ % % % _ _ ^ # ^ _ _ _ _ %

+ 659
- 0
src/codegen/unicode/java/org/apache/fop/text/linebreak/GenerateLineBreakUtils.java View File

@@ -0,0 +1,659 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.text.linebreak;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

/**
* <p>Utility for generating a Java class representing line break properties
* from the Unicode property files.</p>
* <p>Customizations:
* <ul>
* <li>The pair table file is a cut+paste of the sample table from the TR14
* HTML file into a text file.</li>
* <li>Because the sample table does not cover all line break classes, check the
* 'not in pair table' list of property value short names.</li>
* <li>Check MAX_LINE_LENGTH.</li>
* </ul>
*
*/
public class GenerateLineBreakUtils {

private static final int MAX_LINE_LENGTH = 110;

private static final byte DIRECT_BREAK = 0; // _ in table
private static final byte INDIRECT_BREAK = 1; // % in table
private static final byte COMBINING_INDIRECT_BREAK = 2; // # in table
private static final byte COMBINING_PROHIBITED_BREAK = 3; // @ in table
private static final byte PROHIBITED_BREAK = 4; // ^ in table
private static final byte EXPLICIT_BREAK = 5; // ! in rules
private static final String notInPairTable[] = { "AI", "BK", "CB", "CR", "LF", "NL", "SA", "SG", "SP", "XX" };

private static final byte lineBreakProperties[] = new byte[0x10000];
private static final Map lineBreakPropertyValues = new HashMap();
private static final List lineBreakPropertyShortNames = new ArrayList();
private static final List lineBreakPropertyLongNames = new ArrayList();

/**
* Generate a class managing line break properties for Unicode characters and a sample
* table for the table driven line breaking algorithm described in
* <a href="http://unicode.org/reports/tr14/#PairBasedImplementation">UTR #14</a>.
* TODO: Code points above the base plane are simply ignored.
*
* @param lineBreakFileName Name of line break property file (part of Unicode files).
* @param propertyValueFileName Name of property values alias file (part of Unicode files).
* @param breakPairFileName Name of pair table file (<i>not</i> part of the unicode files).
* @param outFileName Name of the output file.
* @throws Exception in case anything goes wrong.
*/
private static void convertLineBreakProperties(
String lineBreakFileName,
String propertyValueFileName,
String breakPairFileName,
String outFileName)
throws Exception {

readLineBreakProperties(lineBreakFileName, propertyValueFileName);
// read break pair table
int lineBreakPropertyValueCount = lineBreakPropertyValues.size();
int tableSize = lineBreakPropertyValueCount - notInPairTable.length;
Map notInPairTableMap = new HashMap(notInPairTable.length);
for (int i = 0; i < notInPairTable.length; i++) {
Object v = lineBreakPropertyValues.get(notInPairTable[i]);
if (v == null) {
throw new Exception("'not in pair table' property not found: " + notInPairTable[i]);
}
notInPairTableMap.put(notInPairTable[i], v);
}
byte pairTable[][] = new byte[tableSize][];
byte columnHeader[] = new byte[tableSize];
byte rowHeader[] = new byte[tableSize];
byte columnMap[] = new byte[lineBreakPropertyValueCount + 1];
Arrays.fill(columnMap, (byte)255);
byte rowMap[] = new byte[lineBreakPropertyValueCount + 1];
Arrays.fill(rowMap, (byte)255);
BufferedReader b = new BufferedReader(new FileReader(breakPairFileName));
String line = b.readLine();
int lineNumber = 1;
// read header
if (line != null) {
StringTokenizer tok = new StringTokenizer(line);
byte columnNumber = 0;
while (tok.hasMoreTokens()) {
String name = tok.nextToken();
if (columnNumber >= columnHeader.length) {
throw new Exception(breakPairFileName + ':' + lineNumber + ": unexpected column header " + name);
}
if (notInPairTableMap.get(name) != null) {
throw new Exception(breakPairFileName + ':' + lineNumber + ": invalid column header " + name);
}
Byte v = (Byte)lineBreakPropertyValues.get(name);
if (v != null) {
byte vv = v.byteValue();
columnHeader[columnNumber] = vv;
columnMap[vv] = columnNumber;
} else {
throw new Exception(breakPairFileName + ':' + lineNumber + ": unknown column header " + name);
}
columnNumber++;
}
if (columnNumber < columnHeader.length) {
StringBuffer missing = new StringBuffer();
for (int j = 0; j < lineBreakPropertyShortNames.size(); j++) {
boolean found = false;
for (int k = 0; k < columnNumber; k++) {
if (columnHeader[k] == j + 1) {
found = true;
break;
}
}
if (!found) {
if (missing.length() > 0) {
missing.append(", ");
}
missing.append((String)lineBreakPropertyShortNames.get(j));
}
}
throw new Exception(
breakPairFileName + ':' + lineNumber + ": missing column for properties: " + missing.toString());
}
} else {
throw new Exception(breakPairFileName + ':' + lineNumber + ": can't read table header");
}
line = b.readLine().trim();
lineNumber++;
byte rowNumber = 0;
while (line != null && line.length() > 0) {
if (rowNumber >= rowHeader.length) {
throw new Exception(breakPairFileName + ':' + lineNumber + ": unexpected row " + line);
}
pairTable[rowNumber] = new byte[tableSize];
StringTokenizer tok = new StringTokenizer(line);
if (tok.hasMoreTokens()) {
String name = tok.nextToken();
if (notInPairTableMap.get(name) != null) {
throw new Exception(breakPairFileName + ':' + lineNumber + ": invalid row header " + name);
}
Byte v = (Byte)lineBreakPropertyValues.get(name);
if (v != null) {
byte vv = v.byteValue();
rowHeader[rowNumber] = vv;
rowMap[vv] = rowNumber;
} else {
throw new Exception(breakPairFileName + ':' + lineNumber + ": unknown row header " + name);
}
} else {
throw new Exception(breakPairFileName + ':' + lineNumber + ": can't read row header");
}
int columnNumber = 0;
while (tok.hasMoreTokens()) {
String token = tok.nextToken();
if (token.length() == 1) {
switch (token.charAt(0)) {
case '^' :
pairTable[rowNumber][columnNumber] = PROHIBITED_BREAK;
break;
case '%' :
pairTable[rowNumber][columnNumber] = INDIRECT_BREAK;
break;
case '_' :
pairTable[rowNumber][columnNumber] = DIRECT_BREAK;
break;
case '#' :
pairTable[rowNumber][columnNumber] = COMBINING_INDIRECT_BREAK;
break;
case '@' :
pairTable[rowNumber][columnNumber] = COMBINING_PROHIBITED_BREAK;
break;
default :
throw new Exception(breakPairFileName + ':' + lineNumber + ": unexpected token: " + token);
}
} else {
throw new Exception(breakPairFileName + ':' + lineNumber + ": token too long: " + token);
}
columnNumber++;
}
line = b.readLine().trim();
lineNumber++;
rowNumber++;
}
if (rowNumber < rowHeader.length) {
StringBuffer missing = new StringBuffer();
for (int j = 0; j < lineBreakPropertyShortNames.size(); j++) {
boolean found = false;
for (int k = 0; k < rowNumber; k++) {
if (rowHeader[k] == j + 1) {
found = true;
break;
}
}
if (!found) {
if (missing.length() > 0) {
missing.append(", ");
}
missing.append((String)lineBreakPropertyShortNames.get(j));
}
}
throw new Exception(
breakPairFileName + ':' + lineNumber + ": missing row for properties: " + missing.toString());
}

// generate class
int rowsize = 512;
int blocksize = lineBreakProperties.length / rowsize;
byte row[][] = new byte[rowsize][];
int idx = 0;
StringBuffer doStaticLinkCode = new StringBuffer();
PrintWriter out = new PrintWriter(new FileWriter(outFileName));
out.println("/*");
out.println(" * Licensed to the Apache Software Foundation (ASF) under one or more");
out.println(" * contributor license agreements. See the NOTICE file distributed with");
out.println(" * this work for additional information regarding copyright ownership.");
out.println(" * The ASF licenses this file to You under the Apache License, Version 2.0");
out.println(" * (the \"License\"); you may not use this file except in compliance with");
out.println(" * the License. You may obtain a copy of the License at");
out.println(" * ");
out.println(" * http://www.apache.org/licenses/LICENSE-2.0");
out.println(" * ");
out.println(" * Unless required by applicable law or agreed to in writing, software");
out.println(" * distributed under the License is distributed on an \"AS IS\" BASIS,");
out.println(" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
out.println(" * See the License for the specific language governing permissions and");
out.println(" * limitations under the License.");
out.println(" */");
out.println();
out.println("/* $Id$ */");
out.println();
out.println("package org.apache.commons.text.linebreak;");
out.println();
out.println("/* ");
out.println(" * This is a generated file, DO NOT CHANGE!");
out.println(" */");
out.println();
out.println("class LineBreakUtils {");
out.println();
out.println(" public static final byte DIRECT_BREAK = " + DIRECT_BREAK + ';');
out.println(" public static final byte INDIRECT_BREAK = " + INDIRECT_BREAK + ';');
out.println(" public static final byte COMBINING_INDIRECT_BREAK = " + COMBINING_INDIRECT_BREAK + ';');
out.println(" public static final byte COMBINING_PROHIBITED_BREAK = " + COMBINING_PROHIBITED_BREAK + ';');
out.println(" public static final byte PROHIBITED_BREAK = " + PROHIBITED_BREAK + ';');
out.println(" public static final byte EXPLICIT_BREAK = " + EXPLICIT_BREAK + ';');
out.println();
out.println(" private static final byte PAIR_TABLE[][] = {");
boolean printComma = false;
for (int i = 1; i <= lineBreakPropertyValueCount; i++) {
if (printComma) {
out.println(',');
} else {
printComma = true;
}
out.print(" {");
boolean localPrintComma = false;
for (int j = 1; j <= lineBreakPropertyValueCount; j++) {
if (localPrintComma) {
out.print(',');
} else {
localPrintComma = true;
}
if (columnMap[j] != -1 && rowMap[i] != -1) {
out.print(pairTable[rowMap[i]][columnMap[j]]);
} else {
out.print('0');
}
}
out.print('}');
}
out.println("};");
out.println();
out.println(" private static byte lineBreakProperties[][] = new byte[" + rowsize + "][];");
out.println();
out.println(" private static void init_0() {");
int rowsPrinted = 0;
int initSections = 0;
for (int i = 0; i < rowsize; i++) {
boolean found = false;
for (int j = 0; j < i; j++) {
if (row[j] != null) {
boolean matched = true;
for (int k = 0; k < blocksize; k++) {
if (row[j][k] != lineBreakProperties[idx + k]) {
matched = false;
break;
}
}
if (matched) {
found = true;
doStaticLinkCode.append(" lineBreakProperties[");
doStaticLinkCode.append(i);
doStaticLinkCode.append("]=lineBreakProperties[");
doStaticLinkCode.append(j);
doStaticLinkCode.append("];\n");
break;
}
}
}
if (!found) {
if (rowsPrinted >= 64) {
out.println(" };");
out.println();
initSections++;
out.println(" private static void init_" + initSections + "() {");
rowsPrinted = 0;
}
row[i] = new byte[blocksize];
boolean printLocalComma = false;
out.print(" lineBreakProperties[" + i + "] = new byte[] { ");
for (int k = 0; k < blocksize; k++) {
row[i][k] = lineBreakProperties[idx + k];
if (printLocalComma) {
out.print(',');
} else {
printLocalComma = true;
}
out.print(row[i][k]);
}
out.println("};");
rowsPrinted++;
}
idx += blocksize;
}
out.println(" };");
out.println();
out.println(" static {");
for (int i = 0; i <= initSections; i++) {
out.println(" init_" + i + "();");
}
out.print(doStaticLinkCode);
out.println(" };");
out.println();
for (int i = 0; i < lineBreakPropertyShortNames.size(); i++) {
String shortName = (String)lineBreakPropertyShortNames.get(i);
out.print(" public static final byte LINE_BREAK_PROPERTY_");
out.print(shortName);
out.print('=');
out.print(i + 1);
out.println(';');
}
out.println();
final String shortNamePrefix = " private static String lineBreakPropertyShortNames[] = {";
out.print(shortNamePrefix);
int lineLength = shortNamePrefix.length();
printComma = false;
for (int i = 0; i < lineBreakPropertyShortNames.size(); i++) {
String name = (String)lineBreakPropertyShortNames.get(i);
if (printComma) {
out.print(',');
lineLength++;
} else {
printComma = true;
}
if (lineLength > MAX_LINE_LENGTH) {
out.println();
out.print(" ");
lineLength = 8;
}
out.print('"');
out.print(name);
out.print('"');
lineLength += (2 + name.length());
}
out.println("};");
out.println();
final String longNamePrefix = " private static String lineBreakPropertyLongNames[] = {";
out.print(longNamePrefix);
lineLength = longNamePrefix.length();
printComma = false;
for (int i = 0; i < lineBreakPropertyLongNames.size(); i++) {
String name = (String)lineBreakPropertyLongNames.get(i);
if (printComma) {
out.print(',');
lineLength++;
} else {
printComma = true;
}
if (lineLength > MAX_LINE_LENGTH) {
out.println();
out.print(" ");
lineLength = 8;
}
out.print('"');
out.print(name);
out.print('"');
lineLength += (2 + name.length());
}
out.println("};");
out.println();
out.println(" public static String getLineBreakPropertyShortName(byte i) {");
out.println(" if (i>0 && i<=lineBreakPropertyShortNames.length) {");
out.println(" return lineBreakPropertyShortNames[i-1];");
out.println(" } else {");
out.println(" return null;");
out.println(" }");
out.println(" }");
out.println();
out.println(" public static String getLineBreakPropertyLongName(byte i) {");
out.println(" if (i>0 && i<=lineBreakPropertyLongNames.length) {");
out.println(" return lineBreakPropertyLongNames[i-1];");
out.println(" } else {");
out.println(" return null;");
out.println(" }");
out.println(" }");
out.println();
out.println(" public static byte getLineBreakProperty(char c) {");
out.println(" return lineBreakProperties[c/" + blocksize + "][c%" + blocksize + "];");
out.println(" }");
out.println();
out.println(
" public static byte getLineBreakPairProperty(int lineBreakPropertyBefore,int lineBreakPropertyAfter) {");
out.println(" return PAIR_TABLE[lineBreakPropertyBefore-1][lineBreakPropertyAfter-1];");
out.println(" }");
out.println();
out.println("};");
out.flush();
out.close();
}

/**
* Read line break property value names and the actual properties for the Unicode
* characters from the respective Unicode files.
* TODO: Code points above the base plane are simply ignored.
*
* @param lineBreakFileName Name of line break property file.
* @param propertyValueFileName Name of property values alias file.
* @throws Exception in case anything goes wrong.
*/
private static void readLineBreakProperties(String lineBreakFileName, String propertyValueFileName)
throws Exception {
// read property names
BufferedReader b = new BufferedReader(new InputStreamReader(new URL(propertyValueFileName).openStream()));
String line = b.readLine();
int lineNumber = 1;
byte propertyIndex = 1;
byte indexForUnknown = 0;
while (line != null) {
if (line.startsWith("lb")) {
String shortName;
String longName = null;
int semi = line.indexOf(';');
if (semi < 0) {
throw new Exception(
propertyValueFileName + ':' + lineNumber + ": missing property short name in " + line);
}
line = line.substring(semi + 1);
semi = line.indexOf(';');
if (semi > 0) {
shortName = line.substring(0, semi).trim();
longName = line.substring(semi + 1).trim();
semi = longName.indexOf(';');
if (semi > 0) {
longName = longName.substring(0, semi).trim();
}
} else {
shortName = line.trim();
}
if (shortName.equals("XX")) {
indexForUnknown = propertyIndex;
}
lineBreakPropertyValues.put(shortName, new Byte((byte)propertyIndex));
lineBreakPropertyShortNames.add(shortName);
lineBreakPropertyLongNames.add(longName);
propertyIndex++;
if (propertyIndex <= 0) {
throw new Exception(propertyValueFileName + ':' + lineNumber + ": property rolled over in " + line);
}
}
line = b.readLine();
lineNumber++;
}
if (indexForUnknown == 0) {
throw new Exception("index for XX (unknown) line break property value not found");
}

// read property values
Arrays.fill(lineBreakProperties, (byte)0);
b = new BufferedReader(new InputStreamReader(new URL(lineBreakFileName).openStream()));
line = b.readLine();
lineNumber = 1;
while (line != null) {
int idx = line.indexOf('#');
if (idx >= 0) {
line = line.substring(0, idx);
}
line = line.trim();
if (line.length() > 0) {
idx = line.indexOf(';');
if (idx <= 0) {
throw new Exception(lineBreakFileName + ':' + lineNumber + ": No field delimiter in " + line);
}
Byte v = (Byte)lineBreakPropertyValues.get(line.substring(idx + 1).trim());
if (v == null) {
throw new Exception(lineBreakFileName + ':' + lineNumber + ": Unknown property value in " + line);
}
String codepoint = line.substring(0, idx);
int low, high;
idx = codepoint.indexOf("..");
try {
if (idx >= 0) {
low = Integer.parseInt(codepoint.substring(0, idx), 16);
high = Integer.parseInt(codepoint.substring(idx + 2), 16);
} else {
low = Integer.parseInt(codepoint, 16);
high = low;
}
} catch (NumberFormatException e) {
throw new Exception(lineBreakFileName + ':' + lineNumber + ": Invalid codepoint number in " + line);
}
if (high > 0xFFFF) {
// ignore non-baseplane characters for now

} else {
if (low < 0 || high < 0) {
throw new Exception(
lineBreakFileName + ':' + lineNumber + ": Negative codepoint(s) in " + line);
}
byte vv = v.byteValue();
for (int i = low; i <= high; i++) {
if (lineBreakProperties[i] != 0) {
throw new Exception(
lineBreakFileName
+ ':'
+ lineNumber
+ ": Property already set for "
+ ((char)i)
+ " in "
+ line);
}
lineBreakProperties[i] = vv;
}
}
}
line = b.readLine();
lineNumber++;
}
}

/**
* Determine a good block size for the two stage optimized storage of the
* line breaking properties. Note: the memory utilization calculation is a rule of thumb,
* don't take it too serious.
*
* @param lineBreakFileName Name of line break property file.
* @param propertyValueFileName Name of property values alias file.
* @throws Exception in case anything goes wrong.
*/
private static void optimizeBlocks(String lineBreakFileName, String propertyValueFileName) throws Exception {
readLineBreakProperties(lineBreakFileName, propertyValueFileName);
for (int i = 0; i < 16; i++) {
int rowsize = 1 << i;
int blocksize = lineBreakProperties.length / (rowsize);
byte row[][] = new byte[rowsize][];
int idx = 0;
int nrOfDistinctBlocks = 0;
for (int j = 0; j < rowsize; j++) {
byte block[] = new byte[blocksize];
for (int k = 0; k < blocksize; k++) {
block[k] = lineBreakProperties[idx];
idx++;
}
boolean found = false;
for (int k = 0; k < j; k++) {
if (row[k] != null) {
boolean matched = true;
for (int l = 0; l < blocksize; l++) {
if (row[k][l] != block[l]) {
matched = false;
break;
}
}
if (matched) {
found = true;
break;
}
}
}
if (!found) {
row[j] = block;
nrOfDistinctBlocks++;
} else {
row[j] = null;
}
}
int size = rowsize * 4 + nrOfDistinctBlocks * blocksize;
System.out.println(
"i=" + i + " blocksize=" + blocksize + " blocks=" + nrOfDistinctBlocks + " size=" + size);
}
}

public static void main(String[] args) {
String lineBreakFileName = "http://www.unicode.org/Public/UNIDATA/LineBreak.txt";
String propertyValueFileName = "http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt";
String breakPairFileName = "src/codegen/unicode/data/LineBreakPairTable.txt";
String outFileName = "LineBreakUtils.java";
boolean ok = true;
for (int i = 0; i < args.length; i = i + 2) {
if (i + 1 == args.length) {
ok = false;
} else {
String opt = args[i];
if ("-l".equals(opt)) {
lineBreakFileName = args[i+1];
} else if ("-p".equals(opt)) {
propertyValueFileName = args[i+1];
} else if ("-b".equals(opt)) {
breakPairFileName = args[i+1];
} else if("-o".equals(opt)) {
outFileName = args[i+1];
} else {
ok = false;
}
}
}
if (!ok) {
System.out.println("Usage: GenerateLineBreakUtils [-l <lineBreakFile>] [-p <propertyValueFile>] [-b <breakPairFile>] [-o <outputFile>]");
System.out.println(" defaults:");
System.out.println(" <lineBreakFile>: " + lineBreakFileName);
System.out.println(" <propertyValueFile>: " + propertyValueFileName);
System.out.println(" <breakPairFile>: " + breakPairFileName);
System.out.println(" <outputFile>: " + outFileName);
} else {
try {
convertLineBreakProperties(lineBreakFileName, propertyValueFileName, breakPairFileName, outFileName);
System.out.println("Generated " + outFileName + " from");
System.out.println(" <lineBreakFile>: " + lineBreakFileName);
System.out.println(" <propertyValueFile>: " + propertyValueFileName);
System.out.println(" <breakPairFile>: " + breakPairFileName);
} catch (Exception e) {
System.out.println("An unexpected error occured");
e.printStackTrace();
}
}
}
}

+ 355
- 287
src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java View File

@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.NoSuchElementException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -43,6 +44,7 @@ import org.apache.fop.layoutmgr.LeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.text.linebreak.LineBreakStatus;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
import org.apache.fop.util.CharUtilities;
@@ -543,133 +545,201 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
AreaInfo ai = null;
returnList.add(sequence);

LineBreakStatus lbs = new LineBreakStatus();
iThisStart = iNextStart;
boolean inWord = false;
boolean inWhitespace = false;
char ch = 0;
while (iNextStart < textArray.length) {
char ch = textArray[iNextStart];
if (ch == CharUtilities.SPACE
&& foText.getWhitespaceTreatment() != Constants.EN_PRESERVE) {
// normal non preserved space - collect them all
// advance to the next character
iThisStart = iNextStart;
iNextStart++;
while (iNextStart < textArray.length
&& textArray[iNextStart] == CharUtilities.SPACE) {
iNextStart++;
}
// create the AreaInfo object
ai = new AreaInfo(iThisStart, (short) (iNextStart),
(short) (iNextStart - iThisStart), (short) 0,
MinOptMax.multiply(wordSpaceIPD, iNextStart - iThisStart),
false, true);
vecAreaInfo.add(ai);
ch = textArray[iNextStart];
boolean breakOpportunity = false;
byte breakAction = lbs.nextChar(ch);
switch (breakAction) {
case LineBreakStatus.COMBINING_PROHIBITED_BREAK:
case LineBreakStatus.PROHIBITED_BREAK:
break;
case LineBreakStatus.EXPLICIT_BREAK:
break;
case LineBreakStatus.COMBINING_INDIRECT_BREAK:
case LineBreakStatus.DIRECT_BREAK:
case LineBreakStatus.INDIRECT_BREAK:
breakOpportunity = true;
break;
default:
log.error("Unexpected breakAction: " + breakAction);
}
if (inWord) {
if (breakOpportunity || isSpace(ch) || ch == NEWLINE) {
//Word boundary found, process widths and kerning
int wordLength = iNextStart - iThisStart;
boolean kerning = font.hasKerning();
MinOptMax wordIPD = new MinOptMax(0);
for (int i = iThisStart; i < iNextStart; i++) {
char c = textArray[i];

//character width
int charWidth = font.getCharWidth(c);
wordIPD.add(charWidth);

//kerning
int kern = 0;
if (kerning && (i > iThisStart)) {
char previous = textArray[i - 1];
kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
if (kern != 0) {
//log.info("Kerning between " + previous + " and " + c + ": " + kern);
addToLetterAdjust(i, kern);
}
wordIPD.add(kern);
}
}
int iLetterSpaces = wordLength - 1;
// if the last character is '-' or '/' and the next one
// is not a space, it could be used as a line end;
// add one more letter space, in case other text follows
if (breakOpportunity && !isSpace(ch)) {
iLetterSpaces++;
}
wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));

// create the elements
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));
// create the AreaInfo object
ai = new AreaInfo(iThisStart, iNextStart, (short) 0,
(short) iLetterSpaces,
wordIPD, false, false);
vecAreaInfo.add(ai);
iTempStart = iNextStart;

} else if (ch == CharUtilities.SPACE || ch == CharUtilities.NBSPACE) {
// create the elements
sequence.addAll(createElementsForAWordFragment(alignment, ai,
vecAreaInfo.size() - 1, letterSpaceIPD, breakOpportunity));
ai = null;

iThisStart = iNextStart;
}
} else if (inWhitespace) {
if (ch != CharUtilities.SPACE || breakOpportunity) {
// End of whitespace
// create the AreaInfo object
ai = new AreaInfo(iThisStart, (short) (iNextStart),
(short) (iNextStart - iThisStart), (short) 0,
MinOptMax.multiply(wordSpaceIPD, iNextStart - iThisStart),
false, true);
vecAreaInfo.add(ai);

// create the elements
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1, breakOpportunity));
ai = null;

iThisStart = iNextStart;
}
} else {
if (ai != null) {
vecAreaInfo.add(ai);
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1, ch == CharUtilities.SPACE || breakOpportunity));
ai = null;
}
if (breakAction == LineBreakStatus.EXPLICIT_BREAK) {
if (lineEndBAP != 0) {
sequence.add
(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), true));
}
sequence.endSequence();
sequence = new InlineKnuthSequence();
returnList.add(sequence);
}
}
if (ch == CharUtilities.SPACE && foText.getWhitespaceTreatment() == Constants.EN_PRESERVE || ch == CharUtilities.NBSPACE) {
// preserved space or non-breaking space:
// create the AreaInfo object
ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false, true);
vecAreaInfo.add(ai);

// create the elements
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));

// advance to the next character
iNextStart++;
wordSpaceIPD, false, true);
iThisStart = (short) (iNextStart + 1);
} else if (CharUtilities.isFixedWidthSpace(ch)) {
// create the AreaInfo object
MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 0, (short) 0,
ipd, false, true);
vecAreaInfo.add(ai);

// create the elements
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));

// advance to the next character
iNextStart++;
iThisStart = (short) (iNextStart + 1);
} else if (ch == NEWLINE) {
// linefeed; this can happen when linefeed-treatment="preserve"
// add a penalty item to the list and start a new sequence
if (lineEndBAP != 0) {
sequence.add
(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), true));
}
sequence.endSequence();
sequence = new InlineKnuthSequence();
returnList.add(sequence);
iThisStart = (short) (iNextStart + 1);
}
inWord = !isSpace(ch) && ch != NEWLINE;
inWhitespace = ch == CharUtilities.SPACE && foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
iNextStart++;
} // end of while
// Process any last elements
if (inWord) {
int wordLength = iNextStart - iThisStart;
boolean kerning = font.hasKerning();
MinOptMax wordIPD = new MinOptMax(0);
for (int i = iThisStart; i < iNextStart; i++) {
char c = textArray[i];

// advance to the next character
iNextStart++;
} else {
// the beginning of a word
iThisStart = iNextStart;
iTempStart = iNextStart;
for (; iTempStart < textArray.length
&& !isSpace(textArray[iTempStart])
&& textArray[iTempStart] != NEWLINE
&& !(iTempStart > iNextStart
&& isBreakChar(textArray[iTempStart - 1]));
iTempStart++) {
//nop, just find the word boundary
}
//Word boundary found, process widths and kerning
int wordLength = iTempStart - iThisStart;
boolean kerning = font.hasKerning();
MinOptMax wordIPD = new MinOptMax(0);
for (int i = iThisStart; i < iTempStart; i++) {
char c = textArray[i];
//character width
int charWidth = font.getCharWidth(c);
wordIPD.add(charWidth);
//kerning
int kern = 0;
if (kerning && (i > iThisStart)) {
char previous = textArray[i - 1];
kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
if (kern != 0) {
//log.info("Kerning between " + previous + " and " + c + ": " + kern);
addToLetterAdjust(i, kern);
}
wordIPD.add(kern);
//character width
int charWidth = font.getCharWidth(c);
wordIPD.add(charWidth);

//kerning
int kern = 0;
if (kerning && (i > iThisStart)) {
char previous = textArray[i - 1];
kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
if (kern != 0) {
//log.info("Kerning between " + previous + " and " + c + ": " + kern);
addToLetterAdjust(i, kern);
}
wordIPD.add(kern);
}
int iLetterSpaces = wordLength - 1;
// if the last character is '-' or '/' and the next one
// is not a space, it could be used as a line end;
// add one more letter space, in case other text follows
if (isBreakChar(textArray[iTempStart - 1])
&& iTempStart < textArray.length
&& !isSpace(textArray[iTempStart])) {
iLetterSpaces++;
}
wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));

// create the AreaInfo object
ai = new AreaInfo(iThisStart, iTempStart, (short) 0,
(short) iLetterSpaces,
wordIPD, false, false);
vecAreaInfo.add(ai);

// create the elements
sequence.addAll(createElementsForAWordFragment(alignment, ai,
vecAreaInfo.size() - 1, letterSpaceIPD));

// advance to the next character
iNextStart = iTempStart;
}
} // end of while
int iLetterSpaces = wordLength - 1;
wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));

// create the AreaInfo object
ai = new AreaInfo(iThisStart, iNextStart, (short) 0,
(short) iLetterSpaces,
wordIPD, false, false);
vecAreaInfo.add(ai);
iTempStart = iNextStart;

// create the elements
sequence.addAll(createElementsForAWordFragment(alignment, ai,
vecAreaInfo.size() - 1, letterSpaceIPD, false));
ai = null;
} else if (inWhitespace) {
ai = new AreaInfo(iThisStart, (short) (iNextStart),
(short) (iNextStart - iThisStart), (short) 0,
MinOptMax.multiply(wordSpaceIPD, iNextStart - iThisStart),
false, true);
vecAreaInfo.add(ai);

// create the elements
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1, true));
ai = null;
} else if (ai != null) {
vecAreaInfo.add(ai);
sequence.addAll
(createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1, ch == CharUtilities.ZERO_WIDTH_SPACE));
ai = null;
} else if (ch == NEWLINE) {
if (lineEndBAP != 0) {
sequence.add
(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), true));
}
sequence.endSequence();
sequence = new InlineKnuthSequence();
returnList.add(sequence);
}

if (((List)returnList.getLast()).size() == 0) {
//Remove an empty sequence because of a trailing newline
returnList.removeLast();
@@ -872,11 +942,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
if (ai.iWScount == 0) {
// ai refers either to a word or a word fragment
returnList.addAll
(createElementsForAWordFragment(alignment, ai, iReturnedIndex, letterSpaceIPD));
(createElementsForAWordFragment(alignment, ai, iReturnedIndex, letterSpaceIPD, false));
} else {
// ai refers to a space
returnList.addAll
(createElementsForASpace(alignment, ai, iReturnedIndex));
(createElementsForASpace(alignment, ai, iReturnedIndex, textArray[ai.iStartIndex] == CharUtilities.SPACE));
}
iReturnedIndex++;
} // end of while
@@ -896,13 +966,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}

private LinkedList createElementsForASpace(int alignment,
AreaInfo ai, int leafValue) {
AreaInfo ai, int leafValue, boolean breakOpportunity) {
LinkedList spaceElements = new LinkedList();
LeafPosition mainPosition = new LeafPosition(this, leafValue);
if (textArray[ai.iStartIndex] == CharUtilities.NBSPACE) {
if (!breakOpportunity) {
// a non-breaking space
//TODO: other kinds of non-breaking spaces
if (alignment == EN_JUSTIFY) {
// the space can stretch and shrink, and must be preserved
// when starting a line
@@ -918,215 +987,215 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
spaceElements.add(new KnuthInlineBox(ai.ipdArea.opt, null,
mainPosition, true));
}
} else if (textArray[ai.iStartIndex] == CharUtilities.SPACE
&& foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
// a breaking space that needs to be preserved
switch (alignment) {
case EN_CENTER:
// centered text:
// 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,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements
.add(new KnuthPenalty(
0,
(textArray[ai.iStartIndex] == CharUtilities.NBSPACE
? KnuthElement.INFINITE
: 0), false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
- (lineStartBAP + lineEndBAP), -6
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0, KnuthElement.INFINITE,
false, new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt + lineStartBAP,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
mainPosition, false));
break;

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
// add a constant amount of stretch at the end of a line, otherwise
// they don't add any stretch
spaceElements.add(new KnuthGlue(lineEndBAP,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
- (lineStartBAP + lineEndBAP), -3
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt + lineStartBAP, 0, 0,
mainPosition, false));
break;

case EN_JUSTIFY:
// justified text:
// the stretch and shrink depends on the space width
spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
- (lineStartBAP + lineEndBAP), ai.ipdArea.max
- ai.ipdArea.opt, ai.ipdArea.opt - ai.ipdArea.min,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP + ai.ipdArea.opt, 0, 0,
mainPosition, false));
break;

default:
// last line justified, the other lines unjustified:
// use only the space stretch
spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
- (lineStartBAP + lineEndBAP), ai.ipdArea.max
- ai.ipdArea.opt, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
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
// 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,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements
.add(new KnuthPenalty(
0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt
- (lineStartBAP + lineEndBAP), -6
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
mainPosition, false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0, KnuthElement.INFINITE,
false, new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
break;

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
// add a constant amount of stretch at the end of a line, otherwise
// they don't add any stretch
if (lineStartBAP != 0 || lineEndBAP != 0) {
if (textArray[ai.iStartIndex] != CharUtilities.SPACE
|| foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
// a breaking space that needs to be preserved
switch (alignment) {
case EN_CENTER:
// centered text:
// 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,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements
.add(new KnuthPenalty(
0,
0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
- (lineStartBAP + lineEndBAP), -6
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0, KnuthElement.INFINITE,
false, new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt + lineStartBAP,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
mainPosition, false));
break;

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
// add a constant amount of stretch at the end of a line, otherwise
// they don't add any stretch
spaceElements.add(new KnuthGlue(lineEndBAP,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt
spaceElements.add(new KnuthGlue(
- (lineStartBAP + lineEndBAP), -3
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
mainPosition, false));
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP, 0, 0,
new LeafPosition(this, -1), false));
} else {
spaceElements.add(new KnuthGlue(0,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt, -3
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
spaceElements.add(new KnuthGlue(ai.ipdArea.opt + lineStartBAP, 0, 0,
mainPosition, false));
}
break;
break;

case EN_JUSTIFY:
// justified text:
// the stretch and shrink depends on the space width
if (lineStartBAP != 0 || lineEndBAP != 0) {
case EN_JUSTIFY:
// justified text:
// the stretch and shrink depends on the space width
spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
ai.ipdArea.opt - (lineStartBAP + lineEndBAP),
ai.ipdArea.max - ai.ipdArea.opt,
ai.ipdArea.opt - ai.ipdArea.min,
mainPosition, false));
- (lineStartBAP + lineEndBAP), ai.ipdArea.max
- ai.ipdArea.opt, ai.ipdArea.opt - ai.ipdArea.min,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP, 0, 0,
new LeafPosition(this, -1), false));
} else {
spaceElements.add(new KnuthGlue(ai.ipdArea.opt,
ai.ipdArea.max - ai.ipdArea.opt,
ai.ipdArea.opt - ai.ipdArea.min,
spaceElements.add(new KnuthGlue(lineStartBAP + ai.ipdArea.opt, 0, 0,
mainPosition, false));
}
break;
break;

default:
// last line justified, the other lines unjustified:
// use only the space stretch
if (lineStartBAP != 0 || lineEndBAP != 0) {
default:
// last line justified, the other lines unjustified:
// use only the space stretch
spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
ai.ipdArea.opt - (lineStartBAP + lineEndBAP),
ai.ipdArea.max - ai.ipdArea.opt,
0, mainPosition, false));
- (lineStartBAP + lineEndBAP), ai.ipdArea.max
- ai.ipdArea.opt, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP, 0, 0,
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
// 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,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
} else {
spaceElements.add(new KnuthGlue(ai.ipdArea.opt,
ai.ipdArea.max - ai.ipdArea.opt, 0,
spaceElements
.add(new KnuthPenalty(
0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt
- (lineStartBAP + lineEndBAP), -6
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
mainPosition, false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0, KnuthElement.INFINITE,
false, new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
break;

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
// add a constant amount of stretch at the end of a line, otherwise
// they don't add any stretch
if (lineStartBAP != 0 || lineEndBAP != 0) {
spaceElements.add(new KnuthGlue(lineEndBAP,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt
- (lineStartBAP + lineEndBAP), -3
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
mainPosition, false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP, 0, 0,
new LeafPosition(this, -1), false));
} else {
spaceElements.add(new KnuthGlue(0,
3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt, -3
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
mainPosition, false));
}
break;

case EN_JUSTIFY:
// justified text:
// the stretch and shrink depends on the space width
if (lineStartBAP != 0 || lineEndBAP != 0) {
spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
ai.ipdArea.opt - (lineStartBAP + lineEndBAP),
ai.ipdArea.max - ai.ipdArea.opt,
ai.ipdArea.opt - ai.ipdArea.min,
mainPosition, false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP, 0, 0,
new LeafPosition(this, -1), false));
} else {
spaceElements.add(new KnuthGlue(ai.ipdArea.opt,
ai.ipdArea.max - ai.ipdArea.opt,
ai.ipdArea.opt - ai.ipdArea.min,
mainPosition, false));
}
break;

default:
// last line justified, the other lines unjustified:
// use only the space stretch
if (lineStartBAP != 0 || lineEndBAP != 0) {
spaceElements.add(new KnuthGlue(lineEndBAP, 0, 0,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(
ai.ipdArea.opt - (lineStartBAP + lineEndBAP),
ai.ipdArea.max - ai.ipdArea.opt,
0, mainPosition, false));
spaceElements.add(new KnuthInlineBox(0, null,
notifyPos(new LeafPosition(this, -1)), false));
spaceElements.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false, new LeafPosition(
this, -1), false));
spaceElements.add(new KnuthGlue(lineStartBAP, 0, 0,
new LeafPosition(this, -1), false));
} else {
spaceElements.add(new KnuthGlue(ai.ipdArea.opt,
ai.ipdArea.max - ai.ipdArea.opt, 0,
mainPosition, false));
}
}
}
}
@@ -1135,16 +1204,14 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}

private LinkedList createElementsForAWordFragment(int alignment,
AreaInfo ai, int leafValue, MinOptMax letterSpaceWidth) {
AreaInfo ai, int leafValue, MinOptMax letterSpaceWidth, boolean breakOpportunity) {
LinkedList wordElements = new LinkedList();
LeafPosition mainPosition = new LeafPosition(this, leafValue);

// if the last character of the word fragment is '-' or '/',
// the fragment could end a line; in this case, it loses one
// of its letter spaces;
boolean bSuppressibleLetterSpace
= /*ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)
&&*/ isBreakChar(textArray[ai.iBreakIndex - 1]);
boolean bSuppressibleLetterSpace = breakOpportunity;

if (letterSpaceWidth.min == letterSpaceWidth.max) {
// constant letter spacing
@@ -1366,5 +1433,6 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
return hyphenElements;
}
}


+ 160
- 0
src/java/org/apache/fop/text/linebreak/LineBreakStatus.java View File

@@ -0,0 +1,160 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.text.linebreak;

/**
* This class is meant for supporting the Unicode line breaking algorithm.
* See <a href="http://unicode.org/reports/tr14/">UTR 14</a>.
*
*/
public class LineBreakStatus {

/** Constant indicating a Direct Break */
public static final byte DIRECT_BREAK = LineBreakUtils.DIRECT_BREAK;
/** Constant indicating an Indirect Break */
public static final byte INDIRECT_BREAK = LineBreakUtils.INDIRECT_BREAK;
/** Constant indicating a Combining Indirect Break */
public static final byte COMBINING_INDIRECT_BREAK = LineBreakUtils.COMBINING_INDIRECT_BREAK;
/** Constant indicating a Combining Prohibited Break */
public static final byte COMBINING_PROHIBITED_BREAK = LineBreakUtils.COMBINING_PROHIBITED_BREAK;
/** Constant indicating a Prohibited Break */
public static final byte PROHIBITED_BREAK = LineBreakUtils.PROHIBITED_BREAK;
/** Constant indicating a Explicit Break */
public static final byte EXPLICIT_BREAK = LineBreakUtils.EXPLICIT_BREAK;

private byte leftClass;
private boolean hadSpace;

/**
* Resets the class to the same state as if new LineBreakStatus() had just been called.
*/
public LineBreakStatus() {
reset();
}
/**
* Reset the status.
* This method will reset the status to the initial state. It is meant
* for recycling objects.
*/
public void reset() {
leftClass = -1;
hadSpace = false;
}

/**
* Check whether a line break may happen.
* The function returns the line breaking status of the point before the given character.
* The algorithm is the table driven algorithm described in the Unicode
* <a href="http://unicode.org/reports/tr14/#PairBasedImplementation">technical report #14</a>.
* The pair table is taken from @see LineBreakUtils
*
* TODO: Better handling for AI, SA, CB and other line break classes.
*
* @param c The character.
* @return the break action to be taken
*/
public byte nextChar(char c) {
byte currentClass = LineBreakUtils.getLineBreakProperty(c);
if (currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_AI
|| leftClass == LineBreakUtils.LINE_BREAK_PROPERTY_XX) {
currentClass = LineBreakUtils.LINE_BREAK_PROPERTY_AL;
} else if (currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_NL) {
currentClass = LineBreakUtils.LINE_BREAK_PROPERTY_BK;
}
if (leftClass == -1) {
if (currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_LF) {
leftClass = LineBreakUtils.LINE_BREAK_PROPERTY_BK;
} else {
leftClass = currentClass;
if (leftClass == LineBreakUtils.LINE_BREAK_PROPERTY_CM) {
leftClass = LineBreakUtils.LINE_BREAK_PROPERTY_ID;
}
}
// LB 2a
return PROHIBITED_BREAK;
} else if (!(leftClass != LineBreakUtils.LINE_BREAK_PROPERTY_BK
&& (leftClass != LineBreakUtils.LINE_BREAK_PROPERTY_CR
|| currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_LF)
)) {
reset();
if (currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_LF) {
leftClass = LineBreakUtils.LINE_BREAK_PROPERTY_BK;
}
return EXPLICIT_BREAK;
} else if (currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_BK
|| currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_LF) {
leftClass = LineBreakUtils.LINE_BREAK_PROPERTY_BK;
return PROHIBITED_BREAK;
} else if (currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_CR) {
leftClass = LineBreakUtils.LINE_BREAK_PROPERTY_CR;
return PROHIBITED_BREAK;
} else if (currentClass == LineBreakUtils.LINE_BREAK_PROPERTY_SP) {
hadSpace = true;
return PROHIBITED_BREAK;
} else {
boolean savedHadSpace = hadSpace;
hadSpace = false;
switch (LineBreakUtils.getLineBreakPairProperty(leftClass, currentClass)) {
case LineBreakUtils.PROHIBITED_BREAK :
leftClass = currentClass;
return PROHIBITED_BREAK;
case LineBreakUtils.DIRECT_BREAK :
leftClass = currentClass;
return DIRECT_BREAK;
case LineBreakUtils.INDIRECT_BREAK :
leftClass = currentClass;
if (savedHadSpace) {
return INDIRECT_BREAK;
} else {
return PROHIBITED_BREAK;
}
case LineBreakUtils.COMBINING_INDIRECT_BREAK :
if (savedHadSpace) {
leftClass = currentClass;
return COMBINING_INDIRECT_BREAK;
} else {
return PROHIBITED_BREAK;
}
case LineBreakUtils.COMBINING_PROHIBITED_BREAK :
if (savedHadSpace) {
leftClass = currentClass;
}
return COMBINING_PROHIBITED_BREAK;
default :
throw new RuntimeException("duh");
}

}
}
/**
* for debugging only
*/
/*
public static void main(String args[]) {
LineBreakStatus lbs = new LineBreakStatus();
lbs.nextChar('\n');
lbs.nextChar('\n');
lbs.nextChar('x');
}
*/
}

+ 669
- 0
src/java/org/apache/fop/text/linebreak/LineBreakUtils.java View File

@@ -0,0 +1,669 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.commons.text.linebreak;

/*
* This is a generated file, DO NOT CHANGE!
*/

class LineBreakUtils {

public static final byte DIRECT_BREAK = 0;
public static final byte INDIRECT_BREAK = 1;
public static final byte COMBINING_INDIRECT_BREAK = 2;
public static final byte COMBINING_PROHIBITED_BREAK = 3;
public static final byte PROHIBITED_BREAK = 4;
public static final byte EXPLICIT_BREAK = 5;

private static final byte PAIR_TABLE[][] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,0,0,0,0,1,1,1,0,0,1,0,0,0,4,4,0,4},
{0,0,4,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,0,0,0,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,0,0,0,0,1,0,0,0,4,4,0,4},
{0,1,1,1,1,0,0,4,2,0,4,1,1,1,1,1,1,4,1,1,1,0,0,1,1,1,1,1,1,0,0,0,4,4,0,4},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,4,1,0,1,1,1,0,0,0,4,4,0,4},
{0,1,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,0,0,0,0,1,1,0,0,0,1,0,0,0,4,4,0,4},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,0,0,0,0,1,0,0,0,4,4,0,4},
{0,1,1,1,1,0,0,4,2,0,4,1,1,1,1,1,1,4,1,1,1,0,0,1,1,1,1,1,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,1,1,0,0,1,0,0,1,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,1,0,0,0,1,0,0,1,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,1,0,0,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,0,0,0,0,1,0,0,1,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,0,0,0,0,1,0,0,0,0,1,0,0,0,4,4,0,4},
{0,1,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,1,0,0,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,1,1,1,0,1,4,1,0,1,0,0,1,0,0,1,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,1,0,0,0,1,0,0,1,0,1,0,0,0,4,4,0,4},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,1,1,0,0,1,0,0,1,0,1,0,0,0,4,4,0,4},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,0,0,0,0,1,0,0,0,4,4,0,4},
{0,1,0,1,0,0,0,4,2,0,4,1,0,0,1,0,1,4,0,0,0,0,0,1,1,1,1,1,1,0,0,0,4,4,0,4},
{0,4,4,4,4,0,0,4,3,0,4,4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,4,4,0,0,0,4,4,0,4},
{0,1,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,1,1,0,0,1,0,0,0,4,4,0,4},
{0,1,0,1,0,0,0,4,2,0,4,1,1,1,1,1,0,4,1,1,1,0,0,1,1,1,0,0,1,0,0,0,4,4,0,4},
{0,1,1,1,1,0,0,4,2,0,4,1,1,1,1,1,1,4,1,1,1,0,0,1,1,4,1,1,1,0,0,0,4,4,0,4},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,4,2,0,4,1,0,0,1,0,0,4,0,0,0,0,0,1,1,0,0,0,1,0,0,0,4,4,0,4},
{0,1,1,1,1,0,0,4,2,0,4,1,1,1,1,1,1,4,1,1,1,0,0,1,1,1,1,1,1,0,0,0,4,4,0,4},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4}};

private static byte lineBreakProperties[][] = new byte[512][];

private static void init_0() {
lineBreakProperties[0] = new byte[] { 9,9,9,9,9,9,9,9,9,4,22,6,6,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,32,11,29,2,28,27,2,29,26,8,2,28,18,15,18,33,25,25,25,25,25,25,25,25,25,25,18,18,2,2,2,11,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,28,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,4,8,2,9};
lineBreakProperties[1] = new byte[] { 9,9,9,9,9,23,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,12,1,27,28,28,28,2,1,1,2,1,29,2,4,2,2,27,28,1,1,5,2,1,1,1,1,1,29,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2};
lineBreakProperties[2] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[5] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,5,1,1,1,5,1,2,2,1,2,2,2,2,2,2,2,1,1,1,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[6] = new byte[] { 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,12,9,9,9,9,9,9,9,9,9,9,9,9,12,12,12,12,12,12,12,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,2,2,0,0,0,0,2,2,2,2,18,0};
lineBreakProperties[7] = new byte[] { 0,0,0,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[9] = new byte[] { 2,2,2,9,9,9,9,0,9,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[10] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[11] = new byte[] { 2,2,2,2,2,2,2,2,0,18,4,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,4,9,2,9,9,2,9,9,11,9,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[12] = new byte[] { 2,2,2,2,0,0,0,0,0,0,0,27,11,18,2,2,9,9,9,9,9,9,0,0,0,0,0,11,0,0,11,11,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,25,25,25,25,25,25,25,25,25,25,11,25,25,2,2,2,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[13] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,11,2,9,9,9,9,9,9,9,2,9,9,9,9,9,9,9,2,2,9,9,2,9,9,9,9,2,2,25,25,25,25,25,25,25,25,25,25,2,2,2,2,2,2};
lineBreakProperties[14] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[15] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,9,9,9,9,9,9,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,25,25,25,25,25,25,25,25,25,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,9,9,9,9,2,2,2,2,18,11,2,0,0,0,0,0};
lineBreakProperties[16] = new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[18] = new byte[] { 0,9,9,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,9,2,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,2,9,9,9,9,0,0,0,2,2,2,2,2,2,2,2,2,2,9,9,4,4,25,25,25,25,25,25,25,25,25,25,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2};
lineBreakProperties[19] = new byte[] { 0,9,9,9,0,2,2,2,2,2,2,2,2,0,0,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0,0,0,2,2,2,2,0,0,9,2,9,9,9,9,9,9,9,0,0,9,9,0,0,9,9,9,2,0,0,0,0,0,0,0,0,9,0,0,0,0,2,2,0,2,2,2,9,9,0,0,25,25,25,25,25,25,25,25,25,25,2,2,28,28,2,2,2,2,2,2,2,0,0,0,0,0};
lineBreakProperties[20] = new byte[] { 0,9,9,9,0,2,2,2,2,2,2,0,0,0,0,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,0,2,2,0,0,9,0,9,9,9,9,9,0,0,0,0,9,9,0,0,9,9,9,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0,2,0,0,0,0,0,0,0,25,25,25,25,25,25,25,25,25,25,9,9,2,2,2,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[21] = new byte[] { 0,9,9,9,0,2,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,0,0,9,2,9,9,9,9,9,9,9,9,0,9,9,9,0,9,9,9,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,9,9,0,0,25,25,25,25,25,25,25,25,25,25,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[22] = new byte[] { 0,9,9,9,0,2,2,2,2,2,2,2,2,0,0,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,2,2,2,2,2,0,0,9,2,9,9,9,9,9,9,0,0,0,9,9,0,0,9,9,9,0,0,0,0,0,0,0,0,9,9,0,0,0,0,2,2,0,2,2,2,0,0,0,0,25,25,25,25,25,25,25,25,25,25,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[23] = new byte[] { 0,0,9,2,0,2,2,2,2,2,2,0,0,0,2,2,2,0,2,2,2,2,0,0,0,2,2,0,2,0,2,2,0,0,0,2,2,0,0,0,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,9,9,9,9,9,0,0,0,9,9,9,0,9,9,9,9,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,25,25,25,25,25,25,25,25,25,2,2,2,2,2,2,2,2,2,28,2,0,0,0,0,0};
lineBreakProperties[24] = new byte[] { 0,9,9,9,0,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,0,9,9,9,9,9,9,9,0,9,9,9,0,9,9,9,9,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,25,25,25,25,25,25,25,25,25,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[25] = new byte[] { 0,0,9,9,0,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,9,2,9,9,9,9,9,9,9,0,9,9,9,0,9,9,9,9,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,2,0,2,2,9,9,0,0,25,25,25,25,25,25,25,25,25,25,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[26] = new byte[] { 0,0,9,9,0,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,9,9,9,9,9,9,0,0,9,9,9,0,9,9,9,9,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,2,2,0,0,0,0,25,25,25,25,25,25,25,25,25,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[27] = new byte[] { 0,0,9,9,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,0,0,2,2,2,2,2,2,2,0,0,0,9,0,0,0,0,9,9,9,9,9,9,0,9,0,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,2,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[28] = new byte[] { 0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,2,25,25,25,25,25,25,25,25,25,25,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[29] = new byte[] { 0,30,30,0,30,0,0,30,30,0,30,0,0,30,0,0,0,0,0,0,30,30,30,30,0,30,30,30,30,30,30,30,0,30,30,30,0,30,0,30,0,0,30,30,0,30,30,30,30,30,30,30,30,30,30,30,30,30,0,30,30,30,0,0,30,30,30,30,30,0,30,0,30,30,30,30,30,30,0,0,25,25,25,25,25,25,25,25,25,25,0,0,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[30] = new byte[] { 2,5,5,5,5,2,5,5,12,5,5,4,12,11,11,11,11,11,12,2,11,2,2,2,9,9,2,2,2,2,2,2,25,25,25,25,25,25,25,25,25,25,2,2,2,2,2,2,2,2,2,2,4,9,2,9,2,9,26,8,26,8,9,9,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,4};
lineBreakProperties[31] = new byte[] { 9,9,9,9,9,4,9,9,2,2,2,2,0,0,0,0,9,9,9,9,9,9,9,9,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,4,4,2,2,2,2,2,2,9,2,2,2,2,2,2,0,0,2,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[32] = new byte[] { 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,30,30,30,30,30,0,30,30,0,30,30,30,30,30,30,30,0,0,0,30,30,30,30,0,0,0,0,0,0,25,25,25,25,25,25,25,25,25,25,4,4,2,2,2,2,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[33] = new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0};
lineBreakProperties[34] = new byte[] { 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,0,0,0,0,0,19,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21};
lineBreakProperties[35] = new byte[] { 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,0,0,0,0,0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,0,0,0,0,0,0};
lineBreakProperties[36] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[37] = new byte[] { 2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[38] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,9,2,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0};
lineBreakProperties[39] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[40] = new byte[] { 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[44] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0};
lineBreakProperties[45] = new byte[] { 4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,8,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[46] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,9,9,9,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,4,4,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[47] = new byte[] { 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,4,4,24,30,4,2,4,28,30,30,0,0,25,25,25,25,25,25,25,25,25,25,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0};
lineBreakProperties[48] = new byte[] { 2,2,4,4,4,4,5,2,4,4,2,9,9,9,12,0,25,25,25,25,25,25,25,25,25,25,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0};
lineBreakProperties[49] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[50] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,2,0,0,0,11,11,25,25,25,25,25,25,25,25,25,25,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[51] = new byte[] { 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,25,25,25,25,25,25,25,25,25,25,0,0,0,0,30,30,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[52] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,0,0,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[54] = new byte[] { 9,9,9,9,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,2,2,2,2,2,2,2,0,0,0,0,25,25,25,25,25,25,25,25,25,25,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,9,9,9,9,2,2,2,2,2,2,2,2,2,0,0,0};
lineBreakProperties[59] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9};
lineBreakProperties[61] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0};
lineBreakProperties[62] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,0,2,0,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0};
lineBreakProperties[63] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,0,2,2,2,2,2,2,2,2,2,0};
lineBreakProperties[64] = new byte[] { 4,4,4,4,4,4,4,12,4,4,4,36,9,9,9,9,4,12,4,4,3,1,1,2,29,29,26,29,29,29,26,29,1,1,2,2,17,17,17,4,6,6,9,9,9,9,9,12,27,27,27,27,27,27,27,27,2,29,29,1,24,24,2,2,2,2,2,2,18,26,8,24,24,24,2,2,2,2,2,2,2,2,2,2,2,2,4,2,4,4,4,4,2,4,4,4,34,2,2,2,0,0,0,0,0,0,9,9,9,9,9,9,2,2,0,0,1,2,2,2,2,2,2,2,2,26,8,1};
lineBreakProperties[65] = new byte[] { 2,1,1,1,1,2,2,2,2,2,2,2,2,26,8,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,28,28,28,28,28,28,28,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[66] = new byte[] { 2,2,2,27,2,1,2,2,2,27,2,2,2,2,2,2,2,2,2,1,2,2,28,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,1,1,2,2,2,2,2,1,2,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2};
lineBreakProperties[67] = new byte[] { 2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[68] = new byte[] { 1,2,1,1,2,2,2,1,1,2,2,1,2,2,2,1,2,1,28,28,2,1,2,2,2,2,1,2,2,1,1,1,1,2,2,1,2,1,2,1,1,1,1,1,1,2,1,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,1,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,1,1,1,1,2,2,1,1,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[69] = new byte[] { 2,2,1,1,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[70] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[71] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[72] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
lineBreakProperties[73] = new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2};
lineBreakProperties[74] = new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[75] = new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,2,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,1,1,2,2,1,1,2,2,2,2,1,1,2,2,1,1,2,2,2,2,1,1,1,2,2,1,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[76] = new byte[] { 2,2,2,2,2,1,1,2,2,1,2,2,2,2,1,1,2,2,2,2,1,1,1,1,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,1,1,1,2,1,1,1,1,2,1,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
};

private static void init_1() {
lineBreakProperties[77] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[78] = new byte[] { 0,2,2,2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,2,0,2,2,2,29,29,29,29,0,0,2,11,11,2,2,2,2,26,8,26,8,26,8,26,8,26,8,26,8,26,8,1,1,1,1,1,1,1,1,1,1};
lineBreakProperties[79] = new byte[] { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,26,8,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,8,26,8,26,8,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[83] = new byte[] { 2,2,2,26,8,26,8,26,8,26,8,26,8,26,8,26,8,26,8,26,8,26,8,26,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,8,26,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,8,2,2};
lineBreakProperties[86] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[88] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0};
lineBreakProperties[89] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,2,4,4};
lineBreakProperties[90] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[91] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[92] = new byte[] { 29,29,29,29,29,29,29,29,29,29,29,29,29,29,4,4,4,4,4,4,4,4,2,4,0,0,0,0,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[93] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[94] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16};
lineBreakProperties[95] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0};
lineBreakProperties[96] = new byte[] { 16,8,8,16,16,24,16,16,26,8,26,8,26,8,26,8,26,8,16,16,26,8,26,8,26,8,26,8,24,26,8,8,16,16,16,16,16,16,16,16,16,16,9,9,9,9,9,9,16,16,16,16,16,16,16,16,16,16,16,24,24,16,16,16,0,24,16,24,16,24,16,24,16,24,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,24,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16};
lineBreakProperties[97] = new byte[] { 16,16,16,24,16,24,16,24,16,16,16,16,16,16,24,16,16,16,16,16,16,24,24,0,0,9,9,24,24,24,24,16,24,24,16,24,16,24,16,24,16,24,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,24,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,24,16,24,16,24,16,16,16,16,16,16,24,16,16,16,16,16,16,24,24,16,16,16,16,24,24,24,24,16};
lineBreakProperties[98] = new byte[] { 0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16};
lineBreakProperties[99] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24};
lineBreakProperties[100] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16};
lineBreakProperties[101] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0};
lineBreakProperties[155] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[319] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[320] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,24,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16};
lineBreakProperties[329] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[334] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[336] = new byte[] { 2,2,9,2,2,2,9,2,2,2,2,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,9,9,9,9,9,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,11,11,0,0,0,0,0,0,0,0};
lineBreakProperties[344] = new byte[] { 13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14};
lineBreakProperties[345] = new byte[] { 14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14};
lineBreakProperties[346] = new byte[] { 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14};
lineBreakProperties[347] = new byte[] { 14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14};
lineBreakProperties[348] = new byte[] { 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14};
lineBreakProperties[349] = new byte[] { 14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14};
lineBreakProperties[350] = new byte[] { 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14};
lineBreakProperties[431] = new byte[] { 14,14,14,14,14,14,14,14,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[432] = new byte[] { 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31};
lineBreakProperties[448] = new byte[] { 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35};
lineBreakProperties[500] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16};
lineBreakProperties[501] = new byte[] { 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
lineBreakProperties[502] = new byte[] { 2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,2,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,2,0,2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[503] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[506] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,26,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[507] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,27,2,0,0};
lineBreakProperties[508] = new byte[] { 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,18,8,8,18,18,11,11,26,8,17,0,0,0,0,0,0,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,26,8,26,8,26,8,26,8,26,8,26,8,26,8,26,8,16,16,26,8,16,16,16,16,16,16,16,8,16,8,0,24,24,11,11,16,26,8,26,8,26,8,16,16,16,16,16,16,16,16,0,16,28,27,16,0,0,0,0,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[509] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,34};
lineBreakProperties[510] = new byte[] { 0,11,16,16,28,27,16,16,26,8,16,16,8,16,8,16,16,16,16,16,16,16,16,16,16,16,24,24,16,16,16,11,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,26,16,8,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,26,16,8,16,26,8,8,26,8,8,24,2,24,24,24,24,24,24,24,24,24,24,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
lineBreakProperties[511] = new byte[] { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,24,24,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,0,2,2,2,0,0,0,27,28,16,16,16,28,28,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,9,9,9,7,1,0,0};
};

static {
init_0();
init_1();
lineBreakProperties[3]=lineBreakProperties[2];
lineBreakProperties[4]=lineBreakProperties[2];
lineBreakProperties[8]=lineBreakProperties[2];
lineBreakProperties[17]=lineBreakProperties[16];
lineBreakProperties[41]=lineBreakProperties[2];
lineBreakProperties[42]=lineBreakProperties[2];
lineBreakProperties[43]=lineBreakProperties[2];
lineBreakProperties[53]=lineBreakProperties[16];
lineBreakProperties[55]=lineBreakProperties[16];
lineBreakProperties[56]=lineBreakProperties[16];
lineBreakProperties[57]=lineBreakProperties[16];
lineBreakProperties[58]=lineBreakProperties[2];
lineBreakProperties[60]=lineBreakProperties[2];
lineBreakProperties[80]=lineBreakProperties[2];
lineBreakProperties[81]=lineBreakProperties[2];
lineBreakProperties[82]=lineBreakProperties[2];
lineBreakProperties[84]=lineBreakProperties[2];
lineBreakProperties[85]=lineBreakProperties[2];
lineBreakProperties[87]=lineBreakProperties[16];
lineBreakProperties[102]=lineBreakProperties[94];
lineBreakProperties[103]=lineBreakProperties[94];
lineBreakProperties[104]=lineBreakProperties[94];
lineBreakProperties[105]=lineBreakProperties[94];
lineBreakProperties[106]=lineBreakProperties[94];
lineBreakProperties[107]=lineBreakProperties[94];
lineBreakProperties[108]=lineBreakProperties[94];
lineBreakProperties[109]=lineBreakProperties[94];
lineBreakProperties[110]=lineBreakProperties[94];
lineBreakProperties[111]=lineBreakProperties[94];
lineBreakProperties[112]=lineBreakProperties[94];
lineBreakProperties[113]=lineBreakProperties[94];
lineBreakProperties[114]=lineBreakProperties[94];
lineBreakProperties[115]=lineBreakProperties[94];
lineBreakProperties[116]=lineBreakProperties[94];
lineBreakProperties[117]=lineBreakProperties[94];
lineBreakProperties[118]=lineBreakProperties[94];
lineBreakProperties[119]=lineBreakProperties[94];
lineBreakProperties[120]=lineBreakProperties[94];
lineBreakProperties[121]=lineBreakProperties[94];
lineBreakProperties[122]=lineBreakProperties[94];
lineBreakProperties[123]=lineBreakProperties[94];
lineBreakProperties[124]=lineBreakProperties[94];
lineBreakProperties[125]=lineBreakProperties[94];
lineBreakProperties[126]=lineBreakProperties[94];
lineBreakProperties[127]=lineBreakProperties[94];
lineBreakProperties[128]=lineBreakProperties[94];
lineBreakProperties[129]=lineBreakProperties[94];
lineBreakProperties[130]=lineBreakProperties[94];
lineBreakProperties[131]=lineBreakProperties[94];
lineBreakProperties[132]=lineBreakProperties[94];
lineBreakProperties[133]=lineBreakProperties[94];
lineBreakProperties[134]=lineBreakProperties[94];
lineBreakProperties[135]=lineBreakProperties[94];
lineBreakProperties[136]=lineBreakProperties[94];
lineBreakProperties[137]=lineBreakProperties[94];
lineBreakProperties[138]=lineBreakProperties[94];
lineBreakProperties[139]=lineBreakProperties[94];
lineBreakProperties[140]=lineBreakProperties[94];
lineBreakProperties[141]=lineBreakProperties[94];
lineBreakProperties[142]=lineBreakProperties[94];
lineBreakProperties[143]=lineBreakProperties[94];
lineBreakProperties[144]=lineBreakProperties[94];
lineBreakProperties[145]=lineBreakProperties[94];
lineBreakProperties[146]=lineBreakProperties[94];
lineBreakProperties[147]=lineBreakProperties[94];
lineBreakProperties[148]=lineBreakProperties[94];
lineBreakProperties[149]=lineBreakProperties[94];
lineBreakProperties[150]=lineBreakProperties[94];
lineBreakProperties[151]=lineBreakProperties[94];
lineBreakProperties[152]=lineBreakProperties[94];
lineBreakProperties[153]=lineBreakProperties[94];
lineBreakProperties[154]=lineBreakProperties[94];
lineBreakProperties[156]=lineBreakProperties[94];
lineBreakProperties[157]=lineBreakProperties[94];
lineBreakProperties[158]=lineBreakProperties[94];
lineBreakProperties[159]=lineBreakProperties[94];
lineBreakProperties[160]=lineBreakProperties[94];
lineBreakProperties[161]=lineBreakProperties[94];
lineBreakProperties[162]=lineBreakProperties[94];
lineBreakProperties[163]=lineBreakProperties[94];
lineBreakProperties[164]=lineBreakProperties[94];
lineBreakProperties[165]=lineBreakProperties[94];
lineBreakProperties[166]=lineBreakProperties[94];
lineBreakProperties[167]=lineBreakProperties[94];
lineBreakProperties[168]=lineBreakProperties[94];
lineBreakProperties[169]=lineBreakProperties[94];
lineBreakProperties[170]=lineBreakProperties[94];
lineBreakProperties[171]=lineBreakProperties[94];
lineBreakProperties[172]=lineBreakProperties[94];
lineBreakProperties[173]=lineBreakProperties[94];
lineBreakProperties[174]=lineBreakProperties[94];
lineBreakProperties[175]=lineBreakProperties[94];
lineBreakProperties[176]=lineBreakProperties[94];
lineBreakProperties[177]=lineBreakProperties[94];
lineBreakProperties[178]=lineBreakProperties[94];
lineBreakProperties[179]=lineBreakProperties[94];
lineBreakProperties[180]=lineBreakProperties[94];
lineBreakProperties[181]=lineBreakProperties[94];
lineBreakProperties[182]=lineBreakProperties[94];
lineBreakProperties[183]=lineBreakProperties[94];
lineBreakProperties[184]=lineBreakProperties[94];
lineBreakProperties[185]=lineBreakProperties[94];
lineBreakProperties[186]=lineBreakProperties[94];
lineBreakProperties[187]=lineBreakProperties[94];
lineBreakProperties[188]=lineBreakProperties[94];
lineBreakProperties[189]=lineBreakProperties[94];
lineBreakProperties[190]=lineBreakProperties[94];
lineBreakProperties[191]=lineBreakProperties[94];
lineBreakProperties[192]=lineBreakProperties[94];
lineBreakProperties[193]=lineBreakProperties[94];
lineBreakProperties[194]=lineBreakProperties[94];
lineBreakProperties[195]=lineBreakProperties[94];
lineBreakProperties[196]=lineBreakProperties[94];
lineBreakProperties[197]=lineBreakProperties[94];
lineBreakProperties[198]=lineBreakProperties[94];
lineBreakProperties[199]=lineBreakProperties[94];
lineBreakProperties[200]=lineBreakProperties[94];
lineBreakProperties[201]=lineBreakProperties[94];
lineBreakProperties[202]=lineBreakProperties[94];
lineBreakProperties[203]=lineBreakProperties[94];
lineBreakProperties[204]=lineBreakProperties[94];
lineBreakProperties[205]=lineBreakProperties[94];
lineBreakProperties[206]=lineBreakProperties[94];
lineBreakProperties[207]=lineBreakProperties[94];
lineBreakProperties[208]=lineBreakProperties[94];
lineBreakProperties[209]=lineBreakProperties[94];
lineBreakProperties[210]=lineBreakProperties[94];
lineBreakProperties[211]=lineBreakProperties[94];
lineBreakProperties[212]=lineBreakProperties[94];
lineBreakProperties[213]=lineBreakProperties[94];
lineBreakProperties[214]=lineBreakProperties[94];
lineBreakProperties[215]=lineBreakProperties[94];
lineBreakProperties[216]=lineBreakProperties[94];
lineBreakProperties[217]=lineBreakProperties[94];
lineBreakProperties[218]=lineBreakProperties[94];
lineBreakProperties[219]=lineBreakProperties[94];
lineBreakProperties[220]=lineBreakProperties[94];
lineBreakProperties[221]=lineBreakProperties[94];
lineBreakProperties[222]=lineBreakProperties[94];
lineBreakProperties[223]=lineBreakProperties[94];
lineBreakProperties[224]=lineBreakProperties[94];
lineBreakProperties[225]=lineBreakProperties[94];
lineBreakProperties[226]=lineBreakProperties[94];
lineBreakProperties[227]=lineBreakProperties[94];
lineBreakProperties[228]=lineBreakProperties[94];
lineBreakProperties[229]=lineBreakProperties[94];
lineBreakProperties[230]=lineBreakProperties[94];
lineBreakProperties[231]=lineBreakProperties[94];
lineBreakProperties[232]=lineBreakProperties[94];
lineBreakProperties[233]=lineBreakProperties[94];
lineBreakProperties[234]=lineBreakProperties[94];
lineBreakProperties[235]=lineBreakProperties[94];
lineBreakProperties[236]=lineBreakProperties[94];
lineBreakProperties[237]=lineBreakProperties[94];
lineBreakProperties[238]=lineBreakProperties[94];
lineBreakProperties[239]=lineBreakProperties[94];
lineBreakProperties[240]=lineBreakProperties[94];
lineBreakProperties[241]=lineBreakProperties[94];
lineBreakProperties[242]=lineBreakProperties[94];
lineBreakProperties[243]=lineBreakProperties[94];
lineBreakProperties[244]=lineBreakProperties[94];
lineBreakProperties[245]=lineBreakProperties[94];
lineBreakProperties[246]=lineBreakProperties[94];
lineBreakProperties[247]=lineBreakProperties[94];
lineBreakProperties[248]=lineBreakProperties[94];
lineBreakProperties[249]=lineBreakProperties[94];
lineBreakProperties[250]=lineBreakProperties[94];
lineBreakProperties[251]=lineBreakProperties[94];
lineBreakProperties[252]=lineBreakProperties[94];
lineBreakProperties[253]=lineBreakProperties[94];
lineBreakProperties[254]=lineBreakProperties[94];
lineBreakProperties[255]=lineBreakProperties[94];
lineBreakProperties[256]=lineBreakProperties[94];
lineBreakProperties[257]=lineBreakProperties[94];
lineBreakProperties[258]=lineBreakProperties[94];
lineBreakProperties[259]=lineBreakProperties[94];
lineBreakProperties[260]=lineBreakProperties[94];
lineBreakProperties[261]=lineBreakProperties[94];
lineBreakProperties[262]=lineBreakProperties[94];
lineBreakProperties[263]=lineBreakProperties[94];
lineBreakProperties[264]=lineBreakProperties[94];
lineBreakProperties[265]=lineBreakProperties[94];
lineBreakProperties[266]=lineBreakProperties[94];
lineBreakProperties[267]=lineBreakProperties[94];
lineBreakProperties[268]=lineBreakProperties[94];
lineBreakProperties[269]=lineBreakProperties[94];
lineBreakProperties[270]=lineBreakProperties[94];
lineBreakProperties[271]=lineBreakProperties[94];
lineBreakProperties[272]=lineBreakProperties[94];
lineBreakProperties[273]=lineBreakProperties[94];
lineBreakProperties[274]=lineBreakProperties[94];
lineBreakProperties[275]=lineBreakProperties[94];
lineBreakProperties[276]=lineBreakProperties[94];
lineBreakProperties[277]=lineBreakProperties[94];
lineBreakProperties[278]=lineBreakProperties[94];
lineBreakProperties[279]=lineBreakProperties[94];
lineBreakProperties[280]=lineBreakProperties[94];
lineBreakProperties[281]=lineBreakProperties[94];
lineBreakProperties[282]=lineBreakProperties[94];
lineBreakProperties[283]=lineBreakProperties[94];
lineBreakProperties[284]=lineBreakProperties[94];
lineBreakProperties[285]=lineBreakProperties[94];
lineBreakProperties[286]=lineBreakProperties[94];
lineBreakProperties[287]=lineBreakProperties[94];
lineBreakProperties[288]=lineBreakProperties[94];
lineBreakProperties[289]=lineBreakProperties[94];
lineBreakProperties[290]=lineBreakProperties[94];
lineBreakProperties[291]=lineBreakProperties[94];
lineBreakProperties[292]=lineBreakProperties[94];
lineBreakProperties[293]=lineBreakProperties[94];
lineBreakProperties[294]=lineBreakProperties[94];
lineBreakProperties[295]=lineBreakProperties[94];
lineBreakProperties[296]=lineBreakProperties[94];
lineBreakProperties[297]=lineBreakProperties[94];
lineBreakProperties[298]=lineBreakProperties[94];
lineBreakProperties[299]=lineBreakProperties[94];
lineBreakProperties[300]=lineBreakProperties[94];
lineBreakProperties[301]=lineBreakProperties[94];
lineBreakProperties[302]=lineBreakProperties[94];
lineBreakProperties[303]=lineBreakProperties[94];
lineBreakProperties[304]=lineBreakProperties[94];
lineBreakProperties[305]=lineBreakProperties[94];
lineBreakProperties[306]=lineBreakProperties[94];
lineBreakProperties[307]=lineBreakProperties[94];
lineBreakProperties[308]=lineBreakProperties[94];
lineBreakProperties[309]=lineBreakProperties[94];
lineBreakProperties[310]=lineBreakProperties[94];
lineBreakProperties[311]=lineBreakProperties[94];
lineBreakProperties[312]=lineBreakProperties[94];
lineBreakProperties[313]=lineBreakProperties[94];
lineBreakProperties[314]=lineBreakProperties[94];
lineBreakProperties[315]=lineBreakProperties[94];
lineBreakProperties[316]=lineBreakProperties[94];
lineBreakProperties[317]=lineBreakProperties[94];
lineBreakProperties[318]=lineBreakProperties[94];
lineBreakProperties[321]=lineBreakProperties[94];
lineBreakProperties[322]=lineBreakProperties[94];
lineBreakProperties[323]=lineBreakProperties[94];
lineBreakProperties[324]=lineBreakProperties[94];
lineBreakProperties[325]=lineBreakProperties[94];
lineBreakProperties[326]=lineBreakProperties[94];
lineBreakProperties[327]=lineBreakProperties[94];
lineBreakProperties[328]=lineBreakProperties[94];
lineBreakProperties[330]=lineBreakProperties[16];
lineBreakProperties[331]=lineBreakProperties[16];
lineBreakProperties[332]=lineBreakProperties[16];
lineBreakProperties[333]=lineBreakProperties[16];
lineBreakProperties[335]=lineBreakProperties[16];
lineBreakProperties[337]=lineBreakProperties[16];
lineBreakProperties[338]=lineBreakProperties[16];
lineBreakProperties[339]=lineBreakProperties[16];
lineBreakProperties[340]=lineBreakProperties[16];
lineBreakProperties[341]=lineBreakProperties[16];
lineBreakProperties[342]=lineBreakProperties[16];
lineBreakProperties[343]=lineBreakProperties[16];
lineBreakProperties[351]=lineBreakProperties[344];
lineBreakProperties[352]=lineBreakProperties[345];
lineBreakProperties[353]=lineBreakProperties[346];
lineBreakProperties[354]=lineBreakProperties[347];
lineBreakProperties[355]=lineBreakProperties[348];
lineBreakProperties[356]=lineBreakProperties[349];
lineBreakProperties[357]=lineBreakProperties[350];
lineBreakProperties[358]=lineBreakProperties[344];
lineBreakProperties[359]=lineBreakProperties[345];
lineBreakProperties[360]=lineBreakProperties[346];
lineBreakProperties[361]=lineBreakProperties[347];
lineBreakProperties[362]=lineBreakProperties[348];
lineBreakProperties[363]=lineBreakProperties[349];
lineBreakProperties[364]=lineBreakProperties[350];
lineBreakProperties[365]=lineBreakProperties[344];
lineBreakProperties[366]=lineBreakProperties[345];
lineBreakProperties[367]=lineBreakProperties[346];
lineBreakProperties[368]=lineBreakProperties[347];
lineBreakProperties[369]=lineBreakProperties[348];
lineBreakProperties[370]=lineBreakProperties[349];
lineBreakProperties[371]=lineBreakProperties[350];
lineBreakProperties[372]=lineBreakProperties[344];
lineBreakProperties[373]=lineBreakProperties[345];
lineBreakProperties[374]=lineBreakProperties[346];
lineBreakProperties[375]=lineBreakProperties[347];
lineBreakProperties[376]=lineBreakProperties[348];
lineBreakProperties[377]=lineBreakProperties[349];
lineBreakProperties[378]=lineBreakProperties[350];
lineBreakProperties[379]=lineBreakProperties[344];
lineBreakProperties[380]=lineBreakProperties[345];
lineBreakProperties[381]=lineBreakProperties[346];
lineBreakProperties[382]=lineBreakProperties[347];
lineBreakProperties[383]=lineBreakProperties[348];
lineBreakProperties[384]=lineBreakProperties[349];
lineBreakProperties[385]=lineBreakProperties[350];
lineBreakProperties[386]=lineBreakProperties[344];
lineBreakProperties[387]=lineBreakProperties[345];
lineBreakProperties[388]=lineBreakProperties[346];
lineBreakProperties[389]=lineBreakProperties[347];
lineBreakProperties[390]=lineBreakProperties[348];
lineBreakProperties[391]=lineBreakProperties[349];
lineBreakProperties[392]=lineBreakProperties[350];
lineBreakProperties[393]=lineBreakProperties[344];
lineBreakProperties[394]=lineBreakProperties[345];
lineBreakProperties[395]=lineBreakProperties[346];
lineBreakProperties[396]=lineBreakProperties[347];
lineBreakProperties[397]=lineBreakProperties[348];
lineBreakProperties[398]=lineBreakProperties[349];
lineBreakProperties[399]=lineBreakProperties[350];
lineBreakProperties[400]=lineBreakProperties[344];
lineBreakProperties[401]=lineBreakProperties[345];
lineBreakProperties[402]=lineBreakProperties[346];
lineBreakProperties[403]=lineBreakProperties[347];
lineBreakProperties[404]=lineBreakProperties[348];
lineBreakProperties[405]=lineBreakProperties[349];
lineBreakProperties[406]=lineBreakProperties[350];
lineBreakProperties[407]=lineBreakProperties[344];
lineBreakProperties[408]=lineBreakProperties[345];
lineBreakProperties[409]=lineBreakProperties[346];
lineBreakProperties[410]=lineBreakProperties[347];
lineBreakProperties[411]=lineBreakProperties[348];
lineBreakProperties[412]=lineBreakProperties[349];
lineBreakProperties[413]=lineBreakProperties[350];
lineBreakProperties[414]=lineBreakProperties[344];
lineBreakProperties[415]=lineBreakProperties[345];
lineBreakProperties[416]=lineBreakProperties[346];
lineBreakProperties[417]=lineBreakProperties[347];
lineBreakProperties[418]=lineBreakProperties[348];
lineBreakProperties[419]=lineBreakProperties[349];
lineBreakProperties[420]=lineBreakProperties[350];
lineBreakProperties[421]=lineBreakProperties[344];
lineBreakProperties[422]=lineBreakProperties[345];
lineBreakProperties[423]=lineBreakProperties[346];
lineBreakProperties[424]=lineBreakProperties[347];
lineBreakProperties[425]=lineBreakProperties[348];
lineBreakProperties[426]=lineBreakProperties[349];
lineBreakProperties[427]=lineBreakProperties[350];
lineBreakProperties[428]=lineBreakProperties[344];
lineBreakProperties[429]=lineBreakProperties[345];
lineBreakProperties[430]=lineBreakProperties[346];
lineBreakProperties[433]=lineBreakProperties[432];
lineBreakProperties[434]=lineBreakProperties[432];
lineBreakProperties[435]=lineBreakProperties[432];
lineBreakProperties[436]=lineBreakProperties[432];
lineBreakProperties[437]=lineBreakProperties[432];
lineBreakProperties[438]=lineBreakProperties[432];
lineBreakProperties[439]=lineBreakProperties[432];
lineBreakProperties[440]=lineBreakProperties[432];
lineBreakProperties[441]=lineBreakProperties[432];
lineBreakProperties[442]=lineBreakProperties[432];
lineBreakProperties[443]=lineBreakProperties[432];
lineBreakProperties[444]=lineBreakProperties[432];
lineBreakProperties[445]=lineBreakProperties[432];
lineBreakProperties[446]=lineBreakProperties[432];
lineBreakProperties[447]=lineBreakProperties[432];
lineBreakProperties[449]=lineBreakProperties[448];
lineBreakProperties[450]=lineBreakProperties[448];
lineBreakProperties[451]=lineBreakProperties[448];
lineBreakProperties[452]=lineBreakProperties[448];
lineBreakProperties[453]=lineBreakProperties[448];
lineBreakProperties[454]=lineBreakProperties[448];
lineBreakProperties[455]=lineBreakProperties[448];
lineBreakProperties[456]=lineBreakProperties[448];
lineBreakProperties[457]=lineBreakProperties[448];
lineBreakProperties[458]=lineBreakProperties[448];
lineBreakProperties[459]=lineBreakProperties[448];
lineBreakProperties[460]=lineBreakProperties[448];
lineBreakProperties[461]=lineBreakProperties[448];
lineBreakProperties[462]=lineBreakProperties[448];
lineBreakProperties[463]=lineBreakProperties[448];
lineBreakProperties[464]=lineBreakProperties[448];
lineBreakProperties[465]=lineBreakProperties[448];
lineBreakProperties[466]=lineBreakProperties[448];
lineBreakProperties[467]=lineBreakProperties[448];
lineBreakProperties[468]=lineBreakProperties[448];
lineBreakProperties[469]=lineBreakProperties[448];
lineBreakProperties[470]=lineBreakProperties[448];
lineBreakProperties[471]=lineBreakProperties[448];
lineBreakProperties[472]=lineBreakProperties[448];
lineBreakProperties[473]=lineBreakProperties[448];
lineBreakProperties[474]=lineBreakProperties[448];
lineBreakProperties[475]=lineBreakProperties[448];
lineBreakProperties[476]=lineBreakProperties[448];
lineBreakProperties[477]=lineBreakProperties[448];
lineBreakProperties[478]=lineBreakProperties[448];
lineBreakProperties[479]=lineBreakProperties[448];
lineBreakProperties[480]=lineBreakProperties[448];
lineBreakProperties[481]=lineBreakProperties[448];
lineBreakProperties[482]=lineBreakProperties[448];
lineBreakProperties[483]=lineBreakProperties[448];
lineBreakProperties[484]=lineBreakProperties[448];
lineBreakProperties[485]=lineBreakProperties[448];
lineBreakProperties[486]=lineBreakProperties[448];
lineBreakProperties[487]=lineBreakProperties[448];
lineBreakProperties[488]=lineBreakProperties[448];
lineBreakProperties[489]=lineBreakProperties[448];
lineBreakProperties[490]=lineBreakProperties[448];
lineBreakProperties[491]=lineBreakProperties[448];
lineBreakProperties[492]=lineBreakProperties[448];
lineBreakProperties[493]=lineBreakProperties[448];
lineBreakProperties[494]=lineBreakProperties[448];
lineBreakProperties[495]=lineBreakProperties[448];
lineBreakProperties[496]=lineBreakProperties[448];
lineBreakProperties[497]=lineBreakProperties[448];
lineBreakProperties[498]=lineBreakProperties[94];
lineBreakProperties[499]=lineBreakProperties[94];
lineBreakProperties[504]=lineBreakProperties[2];
lineBreakProperties[505]=lineBreakProperties[2];
};

public static final byte LINE_BREAK_PROPERTY_AI=1;
public static final byte LINE_BREAK_PROPERTY_AL=2;
public static final byte LINE_BREAK_PROPERTY_B2=3;
public static final byte LINE_BREAK_PROPERTY_BA=4;
public static final byte LINE_BREAK_PROPERTY_BB=5;
public static final byte LINE_BREAK_PROPERTY_BK=6;
public static final byte LINE_BREAK_PROPERTY_CB=7;
public static final byte LINE_BREAK_PROPERTY_CL=8;
public static final byte LINE_BREAK_PROPERTY_CM=9;
public static final byte LINE_BREAK_PROPERTY_CR=10;
public static final byte LINE_BREAK_PROPERTY_EX=11;
public static final byte LINE_BREAK_PROPERTY_GL=12;
public static final byte LINE_BREAK_PROPERTY_H2=13;
public static final byte LINE_BREAK_PROPERTY_H3=14;
public static final byte LINE_BREAK_PROPERTY_HY=15;
public static final byte LINE_BREAK_PROPERTY_ID=16;
public static final byte LINE_BREAK_PROPERTY_IN=17;
public static final byte LINE_BREAK_PROPERTY_IS=18;
public static final byte LINE_BREAK_PROPERTY_JL=19;
public static final byte LINE_BREAK_PROPERTY_JT=20;
public static final byte LINE_BREAK_PROPERTY_JV=21;
public static final byte LINE_BREAK_PROPERTY_LF=22;
public static final byte LINE_BREAK_PROPERTY_NL=23;
public static final byte LINE_BREAK_PROPERTY_NS=24;
public static final byte LINE_BREAK_PROPERTY_NU=25;
public static final byte LINE_BREAK_PROPERTY_OP=26;
public static final byte LINE_BREAK_PROPERTY_PO=27;
public static final byte LINE_BREAK_PROPERTY_PR=28;
public static final byte LINE_BREAK_PROPERTY_QU=29;
public static final byte LINE_BREAK_PROPERTY_SA=30;
public static final byte LINE_BREAK_PROPERTY_SG=31;
public static final byte LINE_BREAK_PROPERTY_SP=32;
public static final byte LINE_BREAK_PROPERTY_SY=33;
public static final byte LINE_BREAK_PROPERTY_WJ=34;
public static final byte LINE_BREAK_PROPERTY_XX=35;
public static final byte LINE_BREAK_PROPERTY_ZW=36;

private static String lineBreakPropertyShortNames[] = {"AI","AL","B2","BA","BB","BK","CB","CL","CM","CR","EX",
"GL","H2","H3","HY","ID","IN","IS","JL","JT","JV","LF","NL","NS","NU","OP","PO","PR","QU","SA","SG","SP",
"SY","WJ","XX","ZW"};

private static String lineBreakPropertyLongNames[] = {"Ambiguous","Alphabetic","Break_Both","Break_After","Break_Before",
"Mandatory_Break","Contingent_Break","Close_Punctuation","Combining_Mark","Carriage_Return","Exclamation",
"Glue","H2","H3","Hyphen","Ideographic","Inseparable","Infix_Numeric","JL","JT","JV","Line_Feed","Next_Line",
"Nonstarter","Numeric","Open_Punctuation","Postfix_Numeric","Prefix_Numeric","Quotation","Complex_Context",
"Surrogate","Space","Break_Symbols","Word_Joiner","Unknown","ZWSpace"};

public static String getLineBreakPropertyShortName(byte i) {
if (i>0 && i<=lineBreakPropertyShortNames.length) {
return lineBreakPropertyShortNames[i-1];
} else {
return null;
}
}

public static String getLineBreakPropertyLongName(byte i) {
if (i>0 && i<=lineBreakPropertyLongNames.length) {
return lineBreakPropertyLongNames[i-1];
} else {
return null;
}
}

public static byte getLineBreakProperty(char c) {
return lineBreakProperties[c/128][c%128];
}

public static byte getLineBreakPairProperty(int lineBreakPropertyBefore,int lineBreakPropertyAfter) {
return PAIR_TABLE[lineBreakPropertyBefore-1][lineBreakPropertyAfter-1];
}

};

+ 3
- 0
status.xml View File

@@ -28,6 +28,9 @@

<changes>
<release version="FOP Trunk">
<action context="Code" dev="MM" type="add">
Added support for UAX#14 type line breaking. Support does not extend across nested fo:inline elements.
</action>
<action context="Code" dev="SP" type="update" fixes-bug="41044" due-to="Richard Wheeldon">
Commented out unused properties, in order to minimize memory usage.
</action>

+ 351
- 0
test/java/org/apache/fop/text/linebreak/LineBreakStatusTest.java View File

@@ -0,0 +1,351 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.text.linebreak;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
* JUnit test case for the LineBreakStatus class
*/
public class LineBreakStatusTest extends TestCase {

/*
* These symbols are used to indicate the break action returned
* by the paragraph breaking. Their meaning is as per Unicode
* <a href="http://unicode.org/reports/tr14/#PairBasedImplementation">technical
* report #14</a>.
*/
private static final String BREAK_ACTION = "_%#@^!";

/**
* Creates the test with the given name.
* @param testName The name for this test.
*/
public LineBreakStatusTest(String testName) {
super(testName);
}

/**
* Returns an TestSuite constructed from this class.
* @return the TestSuite
* @see junit.framework.TestSuite#TestSuite(class)
*/
public static Test suite() {
TestSuite suite = new TestSuite(LineBreakStatusTest.class);
return suite;
}

/**
* Test of reset method, of class org.apache.commons.text.linebreak.LineBreakStatus.
*/
public void testReset() {
System.out.println("testReset");
// TODO
}

/**
* Test of nextChar method, of class org.apache.commons.text.linebreak.LineBreakStatus.
* Runs tests for most of the Line Breaking Properties defined in the Unicode standard.
*/
public void testNextChar() {
System.out.println("testNextChar");
// AL -- Ordinary Alphabetic and Symbol Characters (XP)
assertTrue(testBreak(
"Nobreak",
"^^^^^^^"
));
// BA -- Break Opportunity After (A)
assertTrue(testBreak(
"Thin Space" + "\u2009" + "break",
"^^^^^%^^^^" + "^" + "_^^^^"
));

assertTrue(testBreak(
"Shy" + "\u00AD" + "break",
"^^^" + "^" + "_^^^^"
));


// BB -- Break opportunites before characters (B)
assertTrue(testBreak(
"Acute Accent" + "\u00B4" + "break",
"^^^^^^%^^^^^" + "_" + "^^^^^"
));

// B2 -- Break Opportunity Before and After (B/A/XP)
assertTrue(testBreak(
"Em Dash" + "\u2014" + "break",
"^^^%^^^" + "_" + "_^^^^"
));

assertTrue(testBreak(
"Em Dash Dash" + "\u2014" + "\u2014" + "break",
"^^^%^^^^%^^^" + "_" + "^" + "_^^^^"
));

// BK Mandatory Break (A) -- normative
assertTrue(testBreak(
"Form Feed" + "\u000C" + "break",
"^^^^^%^^^" + "^" + "!^^^^"
));

assertTrue(testBreak(
"Line Separator" + "\u2028" + "break",
"^^^^^%^^^^^^^^" + "^" + "!^^^^"
));

assertTrue(testBreak(
"Paragraph Separator" + "\u2029" + "break",
"^^^^^^^^^^%^^^^^^^^" + "^" + "!^^^^"
));

// CB Contingent Break Opportunity (B/A) -- normative
// TODO Don't know quite what to do here
// CL -- Closing Punctuation (XB)
assertTrue(testBreak(
"Right Parenthesis ) break",
"^^^^^^%^^^^^^^^^^^^^_^^^^"
));
// CM -- Attached Characters and Combining Marks (XB) -- normative
assertTrue(testBreak(
"Grave Accent" + "\u0300" + " break",
"^^^^^^%^^^^^" + "^" + "^%^^^^"
));
// CR -- Carriage Return (A) -- normative
assertTrue(testBreak(
"CR" + "\r" + "break",
"^^" + "^" + "!^^^^"
));
assertTrue(testBreak(
"CRLF" + "\r\n" + "break",
"^^^^" + "^^" + "!^^^^"
));
// EX -- Exclamation / interrogation (XB)
assertTrue(testBreak(
"EX CL ! ) break",
"^^^%^^^^^^_^^^^"
));
assertTrue(testBreak(
"EX Wave Dash ! " + "\u301C" + " break",
"^^^%^^^^%^^^^^^" + "%" + "^_^^^^"
));
// GL -- Non-breaking ("Glue") (XB/XA) -- normative
assertTrue(testBreak(
"No" + "\u00a0" + "break",
"^^" + "^" + "^^^^^"
));
assertTrue(testBreak(
"Non" + "\u2011" + " Hyphen",
"^^^" + "^" + "^%^^^^^"
));
// H2 -- Hangul LVT Syllable (B/A)
// TODO

// H3 -- Hangul LVT Syllable (B/A)
// TODO

// HY -- Hyphen Minus
assertTrue(testBreak(
"Normal-Hyphen",
"^^^^^^^_^^^^^"
));

assertTrue(testBreak(
"Normal - Hyphen",
"^^^^^^^%^_^^^^^"
));

assertTrue(testBreak(
"123-456",
"^^^^^^^"
));

assertTrue(testBreak(
"123 - 456",
"^^^^%^%^^"
));

// ID -- Ideographic (B/A)
assertTrue(testBreak(
"\u4E00" + "\u3000" + "\u4E02",
"^" + "_" + "_"
));

// IN -- Inseperable characters (XP)
assertTrue(testBreak(
"IN " + "\u2024" + "\u2025" + "\u2026",
"^^^" + "%" + "^" + "^"
));

// IS -- Numeric Separator (Infix) (XB)
assertTrue(testBreak(
"123,456.00 12:59",
"^^^^^^^^^^^%^^^^"
));

// JL -- Hangul L Jamo (B)
// TODO

// JT -- Hangul T Jamo (A)
// TODO

// JV -- Hangul V Jamo (XA/XB)
// TODO

// LF -- Line Feed (A) -- normative
assertTrue(testBreak(
"Simple" + "\n" + "\n" + "break",
"^^^^^^" + "^" + "!" + "!^^^^"
));

// NL -- Next Line (A) -- normative
assertTrue(testBreak(
"NL" + "\u0085" + "break",
"^^" + "^" + "!^^^^"
));

// NS -- Non-starters (XB)
// TODO

// NU -- Numeric (XP)
// Tested as part of IS

// OP -- Opening Punctuation (XA)
assertTrue(testBreak(
"[ Bracket ( Parenthesis",
"^^^^^^^^^^_^^^^^^^^^^^^"
));
// PO -- Postfix (Numeric) (XB)
assertTrue(testBreak(
"(12.00)%",
"^^^^^^^^"
));

// PR -- Prefix (Numeric) (XA)
assertTrue(testBreak(
"$1000.00",
"^^^^^^^^"
));

// QU -- Ambiguous Quotation (XB/XA)
assertTrue(testBreak(
"'In Quotes'",
"^^^^%^^^^^^"
));

assertTrue(testBreak(
"' (In Quotes) '",
"^^^^^^%^^^^^^^%"
));

// SA -- Complex-context Dependent Characters (South East Asian) (P)
// TODO
// SP -- Space (A) -- normative
assertTrue(testBreak(
"Simple break",
"^^^^^^^%^^^^"
));

assertTrue(testBreak(
"Simple break2",
"^^^^^^^^^^%^^^^^"
));

// SY -- Symbols Allowing Break After (A)
assertTrue(testBreak(
"http://xmlgraphics.apache.org/fop",
"^^^^^^^_^^^^^^^^^^^^^^^^^^^^^^_^^"
));

assertTrue(testBreak(
"1/2 31/10/2005",
"^^^^%^^^^^^^^^"
));

// WJ -- Word Joiner (XA/XB) -- (normative)
assertTrue(testBreak(
"http://" + "\u2060" + "xmlgraphics.apache.org/" + "\uFEFF" + "fop",
"^^^^^^^" + "^" + "^^^^^^^^^^^^^^^^^^^^^^^" + "^" + "^^^"
));

assertTrue(testBreak(
"Simple " + "\u2060" + "break",
"^^^^^^^" + "^" + "^^^^^"
));

assertTrue(testBreak(
"Simple" + "\u200B" + "\u2060" + "break",
"^^^^^^" + "^" + "_" + "^^^^^"
));

// XX -- Unknown (XP)
// TODO
// ZW -- Zero Width Space (A) -- (normative)
assertTrue(testBreak(
"Simple" + "\u200B" + "break",
"^^^^^^" + "^" + "_^^^^"
));

}

/**
* Tests the paragraph break status (break actions) returned from calling
* LineBreakStatus.nextChar() on each character of paragraph against
* the expected break actions. There must be a positional match between
* the characters in paragraph and characters in breakAction.
* @param paragraph The text to be analysed for line breaks
* @param breakActions The symbolic representation of the break actions
* expected to be returned.
*/
private boolean testBreak(String paragraph, String breakActions) {
boolean result = true;
int length = paragraph.length();
LineBreakStatus lbs = new LineBreakStatus();
for (int i = 0; i < length; i++) {
byte breakAction = lbs.nextChar(paragraph.charAt(i));
if (BREAK_ACTION.charAt(breakAction) != breakActions.charAt(i)) {
System.err.println(paragraph);
System.err.println(breakActions);
System.err.println("pos = " + i
+ " expected '" + breakActions.charAt(i)
+ "' got '" + BREAK_ACTION.charAt(breakAction) + "'");
result = false;
}
}
return result;
}
}

+ 74
- 0
test/java/org/apache/fop/text/linebreak/LineBreakUtilsTest.java View File

@@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.text.linebreak;

import junit.framework.TestCase;

/**
* TODO add javadoc
*
*
*/
public class LineBreakUtilsTest extends TestCase {

/**
* @param name
*/
public LineBreakUtilsTest(String name) {
super(name);
}

public void testLineBreakProperty() {
assertEquals(LineBreakUtils.getLineBreakProperty('A'), LineBreakUtils.LINE_BREAK_PROPERTY_AL);
assertEquals(LineBreakUtils.getLineBreakProperty('1'), LineBreakUtils.LINE_BREAK_PROPERTY_NU);
assertEquals(LineBreakUtils.getLineBreakProperty('\n'), LineBreakUtils.LINE_BREAK_PROPERTY_LF);
assertEquals(LineBreakUtils.getLineBreakProperty('\r'), LineBreakUtils.LINE_BREAK_PROPERTY_CR);
assertEquals(LineBreakUtils.getLineBreakProperty('('), LineBreakUtils.LINE_BREAK_PROPERTY_OP);
}

public void testLineBreakPair() {
assertEquals(
LineBreakUtils.getLineBreakPairProperty(
LineBreakUtils.LINE_BREAK_PROPERTY_CM,
LineBreakUtils.LINE_BREAK_PROPERTY_CL),
LineBreakUtils.PROHIBITED_BREAK);
assertEquals(
LineBreakUtils.getLineBreakPairProperty(
LineBreakUtils.LINE_BREAK_PROPERTY_CL,
LineBreakUtils.LINE_BREAK_PROPERTY_CM),
LineBreakUtils.COMBINING_INDIRECT_BREAK);
assertEquals(
LineBreakUtils.getLineBreakPairProperty(
LineBreakUtils.LINE_BREAK_PROPERTY_IS,
LineBreakUtils.LINE_BREAK_PROPERTY_PR),
LineBreakUtils.DIRECT_BREAK);
assertEquals(
LineBreakUtils.getLineBreakPairProperty(
LineBreakUtils.LINE_BREAK_PROPERTY_AL,
LineBreakUtils.LINE_BREAK_PROPERTY_OP),
LineBreakUtils.DIRECT_BREAK);
assertEquals(
LineBreakUtils.getLineBreakPairProperty(
LineBreakUtils.LINE_BREAK_PROPERTY_LF,
LineBreakUtils.LINE_BREAK_PROPERTY_CM),
0);
}

}

+ 188
- 0
test/layoutengine/standard-testcases/block_uax14_linebreaking.xml View File

@@ -0,0 +1,188 @@
<?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.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="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">
BA -- Break Opportunity After (A)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
VeryLongWordWithAThinSpace&#x2009;PutInTheMiddleOfIt
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
BB -- Break Opportunity Before (B)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
VeryLongWordWithAnAcuteAccent&#x00B4;PutInTheMiddleOfIt
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
B2 -- Break Opportunity Before and After (B/A)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
&#x2014;Very&#x2014;Long&#x2014;Word&#x2014;With&#x2014;LotsOf&#x2014;Em&#x2014;Dashes&#x2014;Put&#x2014;InBetween&#x2014;And&#x2014;Around&#x2014;
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
B2 -- Break Opportunity Before and After (B/A) - as before but don't break between consecutive Em Dashes
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
AVeryLongWordWithSomeDouble&#x2014; &#x2014;Dashes&#x2014; &#x2014;Put&#x2014; &#x2014;In
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
AVeryLongWordWithSomeDouble&#x2014;&#x2014;Dashes&#x2014;&#x2014;Put&#x2014;&#x2014;In
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
CL -- Closing Punctuation (XB)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
Closing )brackets )even )if )preceeded )by )a )space )are )not )a )break )point
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
EX -- Exclamation / interrogation (XB)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
Question ?marks ?and exclamation !marks !even ?if !preceeded ?by !a ?space !are ?not !a ?break !point
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
HY -- Hyphen Minus (XA)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
Very-Long-Word-With-Lots-Of-Hyphens-Put-In-Between
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
Hyphens-in-numbers-do-not-123-567-890-break
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
ID -- Ideographic (B/A)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 0pt 0pt">
Need&#x3000;A&#x3000;Proper&#x3000;Test&#x3000;Case&#x3000;For&#x3000;This&#x3000;As&#x3000;Here&#x3000;Only&#x3000;The&#x3000;Ideographic&#x3000;Space&#x3000;Is&#x3000;Used
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
IN -- Inseperable characters (XP)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
There is never a break&#x2026;&#x2026;&#x2026;&#x2026;&#x2026;&#x2026;&#x2026;&#x2026;&#x2026;&#x2026;between characters of this class
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
IS -- Numeric Separator (Infix) (XB)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
Numbers containing separators 123,345,678.00 08:00:23.15 are not broken
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
OP -- Opening Punctuation (XA)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
Opening( brackets( even( if( followed( by( a( space( are( not( a( break( point
</fo:block>
<fo:block background-color="silver" font-size="8pt" margin="3pt 0pt 0pt 0pt">
SY -- Symbols Allowing Break After (A)
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
http://a/very/long/url/can/be/broken/after/the/solidus
</fo:block>
<fo:block background-color="yellow" margin="0pt 0pt 3pt 0pt">
No-break-point-in-normal-dates-12/12/2006-or-fractions-12345678/67890112
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="2" xpath="count(//flow/block[2]/lineArea)"/>
<eval expected="141160" xpath="//flow/block[2]/lineArea[1]/text/@ipd"/>
<eval expected="88150" xpath="//flow/block[2]/lineArea[2]/text/@ipd"/>

<eval expected="2" xpath="count(//flow/block[4]/lineArea)"/>
<eval expected="155060" xpath="//flow/block[4]/lineArea[1]/text/@ipd"/>
<eval expected="89480" xpath="//flow/block[4]/lineArea[2]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[6]/lineArea)"/>
<eval expected="166150" xpath="//flow/block[6]/lineArea[1]/text/@ipd"/>
<eval expected="161160" xpath="//flow/block[6]/lineArea[2]/text/@ipd"/>
<eval expected="70030" xpath="//flow/block[6]/lineArea[3]/text/@ipd"/>

<eval expected="2" xpath="count(//flow/block[8]/lineArea)"/>
<eval expected="151160" xpath="//flow/block[8]/lineArea[1]/text/@ipd"/>
<eval expected="125590" xpath="//flow/block[8]/lineArea[2]/text/@ipd"/>

<eval expected="2" xpath="count(//flow/block[9]/lineArea)"/>
<eval expected="151160" xpath="//flow/block[9]/lineArea[1]/text/@ipd"/>
<eval expected="117250" xpath="//flow/block[9]/lineArea[2]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[11]/lineArea)"/>
<eval expected="122250" xpath="//flow/block[11]/lineArea[1]/text/@ipd"/>
<eval expected="166730" xpath="//flow/block[11]/lineArea[2]/text/@ipd"/>
<eval expected="52800" xpath="//flow/block[11]/lineArea[3]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[13]/lineArea)"/>
<eval expected="162290" xpath="//flow/block[13]/lineArea[1]/text/@ipd"/>
<eval expected="158970" xpath="//flow/block[13]/lineArea[2]/text/@ipd"/>
<eval expected="140640" xpath="//flow/block[13]/lineArea[3]/text/@ipd"/>

<eval expected="2" xpath="count(//flow/block[15]/lineArea)"/>
<eval expected="136130" xpath="//flow/block[15]/lineArea[1]/text/@ipd"/>
<eval expected="111710" xpath="//flow/block[15]/lineArea[2]/text/@ipd"/>

<eval expected="2" xpath="count(//flow/block[16]/lineArea)"/>
<eval expected="110580" xpath="//flow/block[16]/lineArea[1]/text/@ipd"/>
<eval expected="102270" xpath="//flow/block[16]/lineArea[2]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[18]/lineArea)"/>
<eval expected="125610" xpath="//flow/block[18]/lineArea[1]/text/@ipd"/>
<eval expected="138380" xpath="//flow/block[18]/lineArea[2]/text/@ipd"/>
<eval expected="133960" xpath="//flow/block[18]/lineArea[3]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[20]/lineArea)"/>
<eval expected="72250" xpath="//flow/block[20]/lineArea[1]/text/@ipd"/>
<eval expected="162810" xpath="//flow/block[20]/lineArea[2]/text/@ipd"/>
<eval expected="101700" xpath="//flow/block[20]/lineArea[3]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[22]/lineArea)"/>
<eval expected="138940" xpath="//flow/block[22]/lineArea[1]/text/@ipd"/>
<eval expected="159010" xpath="//flow/block[22]/lineArea[2]/text/@ipd"/>
<eval expected="30570" xpath="//flow/block[22]/lineArea[3]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[24]/lineArea)"/>
<eval expected="163390" xpath="//flow/block[24]/lineArea[1]/text/@ipd"/>
<eval expected="144490" xpath="//flow/block[24]/lineArea[2]/text/@ipd"/>
<eval expected="27790" xpath="//flow/block[24]/lineArea[3]/text/@ipd"/>

<eval expected="2" xpath="count(//flow/block[26]/lineArea)"/>
<eval expected="156750" xpath="//flow/block[26]/lineArea[1]/text/@ipd"/>
<eval expected="70590" xpath="//flow/block[26]/lineArea[2]/text/@ipd"/>

<eval expected="3" xpath="count(//flow/block[27]/lineArea)"/>
<eval expected="114460" xpath="//flow/block[27]/lineArea[1]/text/@ipd"/>
<eval expected="93380" xpath="//flow/block[27]/lineArea[2]/text/@ipd"/>
<eval expected="132860" xpath="//flow/block[27]/lineArea[3]/text/@ipd"/>
</checks>
</testcase>

+ 0
- 272
test/layoutengine/standard-testcases/block_white-space_4.xml View File

@@ -65,32 +65,6 @@
</fo:root>
</fo>
<checks>
<element-list category="line" id="l-sp">
<box w="6672"/>

<!-- first space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-10008" z="0"/>
<box w="19344"/>
<!-- second space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-10008" z="0"/>
<box w="19344"/>
<!-- third space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-10008" z="0"/>
<box w="6672"/>

<skip>12</skip>
</element-list>
<eval expected="62040" xpath="//block[@prod-id='l-sp']/lineArea/text/@ipd"/>
<eval expected="word" xpath="local-name(//block[@prod-id='l-sp']/lineArea/text/*[1])"/>
<eval expected="space" xpath="local-name(//block[@prod-id='l-sp']/lineArea/text/*[2])"/>
@@ -102,32 +76,6 @@
<true xpath="not(//block[@prod-id='l-sp']/lineArea/text/*[2]/@adj = 'false')"/>
<true xpath="not(//block[@prod-id='l-sp']/lineArea/text/*[6]/@adj = 'false')"/>

<element-list category="line" id="l-thin-space">
<box w="6672"/>

<!-- first space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="2400" y="-10008" z="0"/>
<box w="19344"/>
<!-- second space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-10008" z="0"/>
<box w="19344"/>
<!-- third space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="2400" y="-10008" z="0"/>
<box w="6672"/>

<skip>16</skip>
</element-list>
<eval expected="60168" xpath="//block[@prod-id='l-thin-space']/lineArea/text/@ipd"/>
<eval expected="word" xpath="local-name(//block[@prod-id='l-thin-space']/lineArea/text/*[1])"/>
<eval expected="space" xpath="local-name(//block[@prod-id='l-thin-space']/lineArea/text/*[2])"/>
@@ -139,116 +87,16 @@
<true xpath="//block[@prod-id='l-thin-space']/lineArea/text/*[2]/@adj = 'false'"/>
<true xpath="//block[@prod-id='l-thin-space']/lineArea/text/*[6]/@adj = 'false'"/>

<element-list category="line" id="l-hair-space">
<box w="6672"/>

<!-- first space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="1200" y="-10008" z="0"/>
<box w="19344"/>
<!-- second space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-10008" z="0"/>
<box w="19344"/>
<!-- third space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="1200" y="-10008" z="0"/>
<box w="6672"/>

<skip>16</skip>
</element-list>
<eval expected="57768" xpath="//block[@prod-id='l-hair-space']/lineArea/text/@ipd"/>
<true xpath="//block[@prod-id='l-hair-space']/lineArea/text/*[2]/@adj = 'false'"/>
<true xpath="//block[@prod-id='l-hair-space']/lineArea/text/*[6]/@adj = 'false'"/>

<element-list category="line" id="l-zwsp">
<box w="6672"/>

<!-- first space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="0" y="-10008" z="0"/>
<box w="19344"/>
<!-- second space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-10008" z="0"/>
<box w="19344"/>
<!-- third space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="0" y="-10008" z="0"/>
<box w="6672"/>

<skip>20</skip>
</element-list>
<eval expected="55368" xpath="//block[@prod-id='l-zwsp']/lineArea/text/@ipd"/>
<true xpath="//block[@prod-id='l-zwsp']/lineArea/text/*[2]/@adj = 'false'"/>
<true xpath="//block[@prod-id='l-zwsp']/lineArea/text/*[6]/@adj = 'false'"/>

<element-list category="line" id="l-nosp">
<box w="26016"/>
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-10008" z="0"/>
<box w="26016"/>

<skip>12</skip>
</element-list>
<eval expected="55368" xpath="//block[@prod-id='l-nosp']/lineArea/text/@ipd"/>

<element-list category="line" id="c-thin-space">
<glue w="0" y="10008" z="0"/>

<box w="6672"/>

<!-- first space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="2400" y="-20016" z="0"/>
<box w="0"/>
<penalty w="0" p="INF"/>
<glue w="0" y="10008" z="0"/>
<box w="19344"/>
<!-- second space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="3336" y="-20016" z="0"/>
<box w="0"/>
<penalty w="0" p="INF"/>
<glue w="0" y="10008" z="0"/>
<box w="19344"/>
<!-- third space -->
<glue w="0" y="10008" z="0"/>
<penalty w="0" p="0"/>
<glue w="2400" y="-20016" z="0"/>
<box w="0"/>
<penalty w="0" p="INF"/>
<glue w="0" y="10008" z="0"/>
<box w="6672"/>

<skip>24</skip>
</element-list>
<eval expected="60168" xpath="//block[@prod-id='c-thin-space']/lineArea/text/@ipd"/>
<eval expected="word" xpath="local-name(//block[@prod-id='c-thin-space']/lineArea/text/*[1])"/>
<eval expected="space" xpath="local-name(//block[@prod-id='c-thin-space']/lineArea/text/*[2])"/>
@@ -260,149 +108,29 @@
<true xpath="//block[@prod-id='c-thin-space']/lineArea/text/*[2]/@adj = 'false'"/>
<true xpath="//block[@prod-id='c-thin-space']/lineArea/text/*[6]/@adj = 'false'"/>

<element-list category="line" id="j-sp">
<box w="6672"/>

<!-- first space -->
<glue w="3336" y="1668" z="1112"/>
<box w="19344"/>
<!-- second space -->
<glue w="3336" y="1668" z="1112"/>
<box w="19344"/>
<!-- third space -->
<glue w="3336" y="1668" z="1112"/>
<box w="6672"/>

<skip>6</skip>
</element-list>
<eval expected="190804" xpath="//block[@prod-id='j-sp']/lineArea/text/@ipd"/>
<eval expected="42921" xpath="//block[@prod-id='j-sp']/lineArea/text/@twsadjust"/>

<element-list category="line" id="j-thin-space">
<box w="6672"/>

<!-- first space -->
<glue w="2400" y="0" z="0"/>
<box w="19344"/>
<!-- second space -->
<glue w="3336" y="1668" z="1112"/>
<box w="19344"/>
<!-- third space -->
<glue w="2400" y="0" z="0"/>
<box w="6672"/>

<skip>8</skip>
</element-list>
<eval expected="104277" xpath="//block[@prod-id='j-thin-space']/lineArea/text/@ipd"/>
<eval expected="44109" xpath="//block[@prod-id='j-thin-space']/lineArea/text/@twsadjust"/>
<true xpath="//block[@prod-id='j-thin-space']/lineArea/text/*[2]/@adj = 'false'"/>
<true xpath="//block[@prod-id='j-thin-space']/lineArea/text/*[6]/@adj = 'false'"/>

<element-list category="line" id="j-zwsp">
<box w="6672"/>

<!-- first space -->
<glue w="0" y="0" z="0"/>
<box w="19344"/>
<!-- second space -->
<glue w="3336" y="1668" z="1112"/>
<box w="19344"/>
<!-- third space -->
<glue w="0" y="0" z="0"/>
<box w="6672"/>

<skip>10</skip>
</element-list>
<eval expected="84280" xpath="//block[@prod-id='j-zwsp']/lineArea/text/@ipd"/>
<eval expected="28912" xpath="//block[@prod-id='j-zwsp']/lineArea/text/@twsadjust"/>
<true xpath="//block[@prod-id='j-zwsp']/lineArea/text/*[2]/@adj = 'false'"/>
<true xpath="//block[@prod-id='j-zwsp']/lineArea/text/*[6]/@adj = 'false'"/>

<element-list category="line" id="lsj-sp">
<box w="6672"/>

<!-- first space -->
<glue w="7336" y="1668" z="1112"/>
<box w="25344"/>
<!-- second space -->
<glue w="7336" y="1668" z="1112"/>
<box w="25344"/>
<!-- third space -->
<glue w="7336" y="1668" z="1112"/>
<box w="6672"/>

<skip>6</skip>
</element-list>
<eval expected="182404" xpath="//block[@prod-id='lsj-sp']/lineArea/text/@ipd"/>
<eval expected="32121" xpath="//block[@prod-id='lsj-sp']/lineArea/text/@twsadjust"/>
<eval expected="2000" xpath="//block[@prod-id='lsj-sp']/lineArea/text/@tlsadjust"/>

<element-list category="line" id="lsj-thin-space">
<box w="6672"/>

<!-- first space -->
<glue w="2400" y="0" z="0"/>
<box w="25344"/>
<!-- second space -->
<glue w="7336" y="1668" z="1112"/>
<box w="25344"/>
<!-- third space -->
<glue w="2400" y="0" z="0"/>
<box w="6672"/>

<skip>8</skip>
</element-list>
<eval expected="104777" xpath="//block[@prod-id='lsj-thin-space']/lineArea/text/@ipd"/>
<eval expected="28609" xpath="//block[@prod-id='lsj-thin-space']/lineArea/text/@twsadjust"/>
<eval expected="2000" xpath="//block[@prod-id='lsj-thin-space']/lineArea/text/@tlsadjust"/>
<true xpath="//block[@prod-id='lsj-thin-space']/lineArea/text/*[2]/@adj = 'false'"/>
<true xpath="//block[@prod-id='lsj-thin-space']/lineArea/text/*[6]/@adj = 'false'"/>

<element-list category="line" id="lsj-zwsp">
<box w="6672"/>

<!-- first space -->
<glue w="0" y="0" z="0"/>
<box w="25344"/>
<!-- second space -->
<glue w="7336" y="1668" z="1112"/>
<box w="25344"/>
<!-- third space -->
<glue w="0" y="0" z="0"/>
<box w="6672"/>

<skip>10</skip>
</element-list>
<eval expected="85480" xpath="//block[@prod-id='lsj-zwsp']/lineArea/text/@ipd"/>
<eval expected="14112" xpath="//block[@prod-id='lsj-zwsp']/lineArea/text/@twsadjust"/>
<eval expected="2000" xpath="//block[@prod-id='lsj-zwsp']/lineArea/text/@tlsadjust"/>

+ 12
- 12
test/layoutengine/standard-testcases/inline_border_padding_conditionality_2.xml View File

@@ -249,8 +249,8 @@
<eval expected="3000" xpath="//flow/block[4]/lineArea[3]/inlineparent/@padding-end"/>
<eval expected="5000" xpath="//flow/block[4]/lineArea[3]/inlineparent/@padding-start"/>
<eval expected="183960" xpath="//flow/block[5]/lineArea[1]/inlineparent/@ipd"/>
<eval expected="193960" xpath="//flow/block[5]/lineArea[1]/inlineparent/@ipda"/>
<eval expected="149500" xpath="//flow/block[5]/lineArea[1]/inlineparent/@ipd"/>
<eval expected="159500" xpath="//flow/block[5]/lineArea[1]/inlineparent/@ipda"/>
<eval expected="0" xpath="//flow/block[5]/lineArea[1]/inlineparent/@offset"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[5]/lineArea[1]/inlineparent/@border-after"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[5]/lineArea[1]/inlineparent/@border-before"/>
@@ -260,8 +260,8 @@
<eval expected="1000" xpath="//flow/block[5]/lineArea[1]/inlineparent/@padding-before"/>
<eval expected="3000" xpath="//flow/block[5]/lineArea[1]/inlineparent/@padding-end"/>
<eval expected="5000" xpath="//flow/block[5]/lineArea[1]/inlineparent/@padding-start"/>
<eval expected="255680" xpath="//flow/block[5]/lineArea[2]/inlineparent/@ipd"/>
<eval expected="265680" xpath="//flow/block[5]/lineArea[2]/inlineparent/@ipda"/>
<eval expected="237340" xpath="//flow/block[5]/lineArea[2]/inlineparent/@ipd"/>
<eval expected="247340" xpath="//flow/block[5]/lineArea[2]/inlineparent/@ipda"/>
<eval expected="0" xpath="//flow/block[5]/lineArea[2]/inlineparent/@offset"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[5]/lineArea[2]/inlineparent/@border-after"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[5]/lineArea[2]/inlineparent/@border-before"/>
@@ -271,8 +271,8 @@
<eval expected="1000" xpath="//flow/block[5]/lineArea[2]/inlineparent/@padding-before"/>
<eval expected="3000" xpath="//flow/block[5]/lineArea[2]/inlineparent/@padding-end"/>
<eval expected="5000" xpath="//flow/block[5]/lineArea[2]/inlineparent/@padding-start"/>
<eval expected="186750" xpath="//flow/block[5]/lineArea[3]/inlineparent/@ipd"/>
<eval expected="196750" xpath="//flow/block[5]/lineArea[3]/inlineparent/@ipda"/>
<eval expected="239550" xpath="//flow/block[5]/lineArea[3]/inlineparent/@ipd"/>
<eval expected="249550" xpath="//flow/block[5]/lineArea[3]/inlineparent/@ipda"/>
<eval expected="0" xpath="//flow/block[5]/lineArea[3]/inlineparent/@offset"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[5]/lineArea[3]/inlineparent/@border-after"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[5]/lineArea[3]/inlineparent/@border-before"/>
@@ -283,8 +283,8 @@
<eval expected="3000" xpath="//flow/block[5]/lineArea[3]/inlineparent/@padding-end"/>
<eval expected="5000" xpath="//flow/block[5]/lineArea[3]/inlineparent/@padding-start"/>
<eval expected="172840" xpath="//flow/block[6]/lineArea[1]/inlineparent/@ipd"/>
<eval expected="178840" xpath="//flow/block[6]/lineArea[1]/inlineparent/@ipda"/>
<eval expected="149500" xpath="//flow/block[6]/lineArea[1]/inlineparent/@ipd"/>
<eval expected="155500" xpath="//flow/block[6]/lineArea[1]/inlineparent/@ipda"/>
<eval expected="0" xpath="//flow/block[6]/lineArea[1]/inlineparent/@offset"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[6]/lineArea[1]/inlineparent/@border-after"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[6]/lineArea[1]/inlineparent/@border-before"/>
@@ -292,15 +292,15 @@
<eval expected="1000" xpath="//flow/block[6]/lineArea[1]/inlineparent/@padding-after"/>
<eval expected="1000" xpath="//flow/block[6]/lineArea[1]/inlineparent/@padding-before"/>
<eval expected="5000" xpath="//flow/block[6]/lineArea[1]/inlineparent/@padding-start"/>
<eval expected="266800" xpath="//flow/block[6]/lineArea[2]/inlineparent/@ipd"/>
<eval expected="266800" xpath="//flow/block[6]/lineArea[2]/inlineparent/@ipda"/>
<eval expected="237340" xpath="//flow/block[6]/lineArea[2]/inlineparent/@ipd"/>
<eval expected="237340" xpath="//flow/block[6]/lineArea[2]/inlineparent/@ipda"/>
<eval expected="0" xpath="//flow/block[6]/lineArea[2]/inlineparent/@offset"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[6]/lineArea[2]/inlineparent/@border-after"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[6]/lineArea[2]/inlineparent/@border-before"/>
<eval expected="1000" xpath="//flow/block[6]/lineArea[2]/inlineparent/@padding-after"/>
<eval expected="1000" xpath="//flow/block[6]/lineArea[2]/inlineparent/@padding-before"/>
<eval expected="186750" xpath="//flow/block[6]/lineArea[3]/inlineparent/@ipd"/>
<eval expected="190750" xpath="//flow/block[6]/lineArea[3]/inlineparent/@ipda"/>
<eval expected="239550" xpath="//flow/block[6]/lineArea[3]/inlineparent/@ipd"/>
<eval expected="243550" xpath="//flow/block[6]/lineArea[3]/inlineparent/@ipda"/>
<eval expected="0" xpath="//flow/block[6]/lineArea[3]/inlineparent/@offset"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[6]/lineArea[3]/inlineparent/@border-after"/>
<eval expected="(solid,#ff0000,1000)" xpath="//flow/block[6]/lineArea[3]/inlineparent/@border-before"/>

Loading…
Cancel
Save