1562429
of trunk
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_FopFontsForSVG@1562866 13f79535-47bb-0310-9956-ffa450edef68pull/22/head
<include name="org/apache/fop/apps/Fop.class"/> | <include name="org/apache/fop/apps/Fop.class"/> | ||||
<include name="org/apache/fop/apps/FOPException.class"/> | <include name="org/apache/fop/apps/FOPException.class"/> | ||||
<include name="org/apache/fop/apps/io/**"/> | <include name="org/apache/fop/apps/io/**"/> | ||||
<include name="org/apache/fop/area/AreaTreeControl*"/> | |||||
<include name="org/apache/fop/complexscripts/fonts/*.class"/> | <include name="org/apache/fop/complexscripts/fonts/*.class"/> | ||||
<include name="org/apache/fop/complexscripts/util/GlyphTester.class"/> | <include name="org/apache/fop/complexscripts/util/GlyphTester.class"/> | ||||
<include name="org/apache/fop/events/EventProducer.class"/> | <include name="org/apache/fop/events/EventProducer.class"/> | ||||
<include name="org/apache/fop/fo/Constants.class"/> | <include name="org/apache/fop/fo/Constants.class"/> | ||||
<include name="org/apache/fop/fo/FOTreeBuilder.class"/> | <include name="org/apache/fop/fo/FOTreeBuilder.class"/> | ||||
<include name="org/apache/fop/area/AreaTreeControl*"/> | |||||
<include name="org/apache/fop/image/loader/batik/BatikImageFlavors*.class"/> | |||||
<include name="org/apache/fop/svg/**"/> | <include name="org/apache/fop/svg/**"/> | ||||
<include name="org/apache/fop/fonts/**"/> | <include name="org/apache/fop/fonts/**"/> | ||||
<include name="org/apache/fop/render/shading/**"/> | |||||
<include name="org/apache/fop/traits/MinOptMax.class"/> | <include name="org/apache/fop/traits/MinOptMax.class"/> | ||||
<include name="org/apache/fop/image/loader/batik/BatikImageFlavors*.class"/> | |||||
<include name="org/apache/fop/util/CMYKColorSpace*.class"/> | <include name="org/apache/fop/util/CMYKColorSpace*.class"/> | ||||
<include name="org/apache/fop/util/Color*.class"/> | <include name="org/apache/fop/util/Color*.class"/> | ||||
<include name="org/apache/fop/util/ASCII*.class"/> | <include name="org/apache/fop/util/ASCII*.class"/> | ||||
<!-- Checkstyle --> | <!-- Checkstyle --> | ||||
<!-- =================================================================== --> | <!-- =================================================================== --> | ||||
<property name="checkstyle.location" value="${lib-tools}/checkstyle-5.5-all.jar" /> | <property name="checkstyle.location" value="${lib-tools}/checkstyle-5.5-all.jar" /> | ||||
<property name="checkstyle.noframes.xslt" value="${basedir}/checkstyle-noframes.xsl" /> | |||||
<property name="checkstyle.config" value="${basedir}/checkstyle-5.5.xml" /> | <property name="checkstyle.config" value="${basedir}/checkstyle-5.5.xml" /> | ||||
<path id="checkstyle-classpath"> | <path id="checkstyle-classpath"> | ||||
<path refid="libs-build-classpath"/> | |||||
<pathelement location="${checkstyle.location}"/> | <pathelement location="${checkstyle.location}"/> | ||||
</path> | </path> | ||||
<condition property="checkstyle.avail"> | <condition property="checkstyle.avail"> | ||||
<available classname="com.puppycrawl.tools.checkstyle.CheckStyleTask"> | <available classname="com.puppycrawl.tools.checkstyle.CheckStyleTask"> | ||||
<classpath refid="checkstyle-classpath"/> | <classpath refid="checkstyle-classpath"/> | ||||
</available> | </available> | ||||
<available file="${checkstyle.noframes.xslt}"/> | |||||
<available file="${checkstyle.config}"/> | <available file="${checkstyle.config}"/> | ||||
</and> | </and> | ||||
</condition> | </condition> | ||||
<target name="checkstyle-avail" unless="checkstyle.avail"> | <target name="checkstyle-avail" unless="checkstyle.avail"> | ||||
<echo message="Checkstyle support NOT present. Please download it from http://checkstyle.sf.net/ and"/> | <echo message="Checkstyle support NOT present. Please download it from http://checkstyle.sf.net/ and"/> | ||||
<echo message="... please provide ${checkstyle.location}"/> | <echo message="... please provide ${checkstyle.location}"/> | ||||
<echo message="... please provide ${checkstyle.noframes.xslt}"/> | |||||
<echo message="... please provide ${checkstyle.config}"/> | <echo message="... please provide ${checkstyle.config}"/> | ||||
</target> | </target> | ||||
<target name="checkstyle" depends="package, checkstyle-avail" if="checkstyle.avail" description="Runs Checkstyle for a code quality report"> | <target name="checkstyle" depends="package, checkstyle-avail" if="checkstyle.avail" description="Runs Checkstyle for a code quality report"> | ||||
<taskdef name="checkstyle" classname="com.puppycrawl.tools.checkstyle.CheckStyleTask" classpathref="checkstyle-classpath"/> | <taskdef name="checkstyle" classname="com.puppycrawl.tools.checkstyle.CheckStyleTask" classpathref="checkstyle-classpath"/> | ||||
<mkdir dir="${build.dir}"/> | <mkdir dir="${build.dir}"/> | ||||
<checkstyle config="${checkstyle.config}" failonviolation="false"> | |||||
<checkstyle config="${checkstyle.config}" failonviolation="true" maxWarnings="0"> | |||||
<classpath> | <classpath> | ||||
<path refid="checkstyle-classpath"/> | <path refid="checkstyle-classpath"/> | ||||
<pathelement location="${build.classes.dir}"/> | <pathelement location="${build.classes.dir}"/> | ||||
<pathelement location="${build.codegen-classes.dir}"/> | <pathelement location="${build.codegen-classes.dir}"/> | ||||
</classpath> | </classpath> | ||||
<fileset dir="${src.dir}" includes="**/*.java"/> | <fileset dir="${src.dir}" includes="**/*.java"/> | ||||
<fileset dir="${test.dir}" includes="**/*.java"/> | |||||
<formatter type="xml" toFile="${build.dir}/report_checkstyle.xml"/> | <formatter type="xml" toFile="${build.dir}/report_checkstyle.xml"/> | ||||
<formatter type="plain"/> | |||||
</checkstyle> | </checkstyle> | ||||
<xslt in="${build.dir}/report_checkstyle.xml" out="${build.dir}/report_checkstyle.html" style="${checkstyle.noframes.xslt}"/> | |||||
</target> | </target> | ||||
<!-- =================================================================== --> | <!-- =================================================================== --> | ||||
<!-- PMD --> | <!-- PMD --> | ||||
<path refid="libs-tools-build-classpath"/> | <path refid="libs-tools-build-classpath"/> | ||||
</classpath> | </classpath> | ||||
</taskdef> | </taskdef> | ||||
<mkdir dir="${build.dir}"/> | |||||
<pmd shortFilenames="true" targetjdk="${javac.target}"> | <pmd shortFilenames="true" targetjdk="${javac.target}"> | ||||
<ruleset>basic</ruleset> | <ruleset>basic</ruleset> | ||||
<ruleset>rulesets/migrating_to_14.xml</ruleset> | <ruleset>rulesets/migrating_to_14.xml</ruleset> | ||||
<!-- Special target for Gump --> | <!-- Special target for Gump --> | ||||
<!-- =================================================================== --> | <!-- =================================================================== --> | ||||
<target name="gump" depends="package,transcoder-pkg"/> | <target name="gump" depends="package,transcoder-pkg"/> | ||||
<target name="gump-test" depends="junit-all"> | |||||
<target name="gump-test" depends="junit-all,checkstyle"> | |||||
<fail> | <fail> | ||||
<condition> | <condition> | ||||
<or> | <or> |
<!-- ===================================================================================================== --> | <!-- ===================================================================================================== --> | ||||
<module name="SuppressionCommentFilter"> | <module name="SuppressionCommentFilter"> | ||||
<property name="offCommentFormat" value="CSOFF\: ([\w\|]+)"/> | |||||
<property name="offCommentFormat" value="CSOFF\: (LineLength)"/> | |||||
<property name="onCommentFormat" value="CSON\: ([\w\|]+)"/> | <property name="onCommentFormat" value="CSON\: ([\w\|]+)"/> | ||||
<property name="checkFormat" value="$1"/> | <property name="checkFormat" value="$1"/> | ||||
</module> | </module> | ||||
<!-- ===================================================================================================== --> | <!-- ===================================================================================================== --> | ||||
<module name="SuppressionFilter"> | |||||
<property name="file" value="${samedir}/checkstyle-suppressions.xml"/> | |||||
</module> | |||||
<!-- ===================================================================================================== --> | <!-- ===================================================================================================== --> | ||||
<module name="TreeWalker"> | <module name="TreeWalker"> | ||||
<!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | |||||
<module name="LineLength"> | |||||
<property name="max" value="120"/> | |||||
</module> | |||||
<!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | |||||
<!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | <!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | ||||
<module name="AnnotationUseStyle"/> | <module name="AnnotationUseStyle"/> | ||||
<!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | <!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | ||||
<property name="allowLineBreaks" value="false"/> | <property name="allowLineBreaks" value="false"/> | ||||
<property name="tokens" value="BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/> | <property name="tokens" value="BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/> | ||||
</module> | </module> | ||||
<module name="NoWhitespaceAfter"> | |||||
<property name="allowLineBreaks" value="true"/> | |||||
<property name="tokens" value="ARRAY_INIT"/> | |||||
</module> | |||||
<!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | <!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | ||||
<!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> | <!-- ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... --> |
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN" "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"> | <!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN" "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"> | ||||
<suppressions> | <suppressions> | ||||
<suppress files="org/apache/fop/fo/FOPropertyMapping.java" checks="FileLengthCheck"/> | |||||
<suppress files="org/apache/fop/complexscripts/fonts/GlyphPositioningTable.java" checks="FileLengthCheck"/> | |||||
<suppress files="org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java" checks="FileLengthCheck"/> | |||||
<suppress files="org/apache/fop/Version.java" lines="40-50" checks="LineLengthCheck"/> | |||||
<suppress files="org/apache/fop/afp/fonts/CharactersetEncoder.java" checks="FinalClass"/> | |||||
<suppress files="org/apache/fop/complexscripts/bidi/BidiClass.java" checks="WhitespaceAfter"/> | |||||
<suppress files="org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java" checks="SimplifyBooleanReturn"/> | |||||
<suppress files="org/apache/fop/complexscripts/scripts/ArabicScriptProcessor.java" checks="SimplifyBooleanReturn"/> | |||||
<suppress files="org/apache/fop/complexscripts/util/CharScript.java" checks="SimplifyBooleanReturn"/> | |||||
<suppress files="org/apache/fop/render/rtf/rtflib/testdocs/MergedTableCells.java" checks="AvoidNestedBlocks"/> | |||||
<suppress files="org/apache/fop/render/rtf/rtflib/testdocs/NestedTable.java" checks="AvoidNestedBlocks"/> | |||||
<suppress files="org/apache/fop/fo/flow/MarkersTestCase.java" checks="LocalVariableName"/> | |||||
</suppressions> | </suppressions> |
<!-- examples for the use of the fo leader --> | <!-- examples for the use of the fo leader --> | ||||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="sans-serif"> | |||||
<fo:layout-master-set> | <fo:layout-master-set> | ||||
<fo:list-item> | <fo:list-item> | ||||
<!-- insert a bullet --> | <!-- insert a bullet --> | ||||
<fo:list-item-label end-indent="label-end()"> | <fo:list-item-label end-indent="label-end()"> | ||||
<fo:block><fo:inline font-size="10pt" font-family="Symbol">·</fo:inline></fo:block> | |||||
<fo:block><fo:inline font-size="10pt">·</fo:inline></fo:block> | |||||
</fo:list-item-label> | </fo:list-item-label> | ||||
<!-- list text --> | <!-- list text --> | ||||
<fo:list-item-body start-indent="body-start()"> | <fo:list-item-body start-indent="body-start()"> | ||||
<fo:list-item> | <fo:list-item> | ||||
<!-- insert a bullet --> | <!-- insert a bullet --> | ||||
<fo:list-item-label end-indent="label-end()"> | <fo:list-item-label end-indent="label-end()"> | ||||
<fo:block><fo:inline font-size="10pt" font-family="Symbol">·</fo:inline></fo:block> | |||||
<fo:block><fo:inline font-size="10pt">·</fo:inline></fo:block> | |||||
</fo:list-item-label> | </fo:list-item-label> | ||||
<!-- list text --> | <!-- list text --> | ||||
<fo:list-item-body start-indent="body-start()"> | <fo:list-item-body start-indent="body-start()"> | ||||
<fo:table-row line-height="12pt"> | <fo:table-row line-height="12pt"> | ||||
<fo:table-cell><fo:block text-align="end">A) </fo:block></fo:table-cell> | <fo:table-cell><fo:block text-align="end">A) </fo:block></fo:table-cell> | ||||
<fo:table-cell><fo:block text-align="start">This is some longer sample text<fo:leader leader-pattern="dots" | |||||
<fo:table-cell><fo:block text-align="start" text-align-last="justify">This is some longer sample text<fo:leader leader-pattern="dots" | |||||
leader-pattern-width="8pt" | leader-pattern-width="8pt" | ||||
leader-alignment="reference-area" | leader-alignment="reference-area" | ||||
/></fo:block></fo:table-cell> | /></fo:block></fo:table-cell> | ||||
<fo:table-row line-height="12pt"> | <fo:table-row line-height="12pt"> | ||||
<fo:table-cell><fo:block text-align="end">B) </fo:block></fo:table-cell> | <fo:table-cell><fo:block text-align="end">B) </fo:block></fo:table-cell> | ||||
<fo:table-cell><fo:block text-align="start">Some text<fo:leader leader-pattern="dots" | |||||
<fo:table-cell><fo:block text-align="start" text-align-last="justify">Some text<fo:leader leader-pattern="dots" | |||||
leader-pattern-width="8pt" | leader-pattern-width="8pt" | ||||
leader-alignment="reference-area" | leader-alignment="reference-area" | ||||
/></fo:block></fo:table-cell> | /></fo:block></fo:table-cell> | ||||
<fo:table-row line-height="12pt"> | <fo:table-row line-height="12pt"> | ||||
<fo:table-cell><fo:block text-align="end" >C) </fo:block></fo:table-cell> | <fo:table-cell><fo:block text-align="end" >C) </fo:block></fo:table-cell> | ||||
<fo:table-cell><fo:block text-align="start">Text<fo:leader leader-pattern="dots" | |||||
<fo:table-cell><fo:block text-align="start" text-align-last="justify">Text<fo:leader leader-pattern="dots" | |||||
leader-pattern-width="8pt" | leader-pattern-width="8pt" | ||||
leader-alignment="reference-area" | leader-alignment="reference-area" | ||||
/></fo:block></fo:table-cell> | /></fo:block></fo:table-cell> | ||||
<fo:table-row line-height="12pt"> | <fo:table-row line-height="12pt"> | ||||
<fo:table-cell><fo:block text-align="end">D) </fo:block></fo:table-cell> | <fo:table-cell><fo:block text-align="end">D) </fo:block></fo:table-cell> | ||||
<fo:table-cell><fo:block text-align="start">This text is even longer than the first entry <fo:leader leader-pattern="dots" | |||||
<fo:table-cell><fo:block text-align="start" text-align-last="justify">This text is even longer than the first entry <fo:leader leader-pattern="dots" | |||||
leader-pattern-width="8pt" | leader-pattern-width="8pt" | ||||
leader-alignment="reference-area" | leader-alignment="reference-area" | ||||
/></fo:block></fo:table-cell> | /></fo:block></fo:table-cell> | ||||
<fo:table-row line-height="12pt"> | <fo:table-row line-height="12pt"> | ||||
<fo:table-cell><fo:block text-align="end">E) </fo:block></fo:table-cell> | <fo:table-cell><fo:block text-align="end">E) </fo:block></fo:table-cell> | ||||
<fo:table-cell><fo:block text-align="start">Shorter text example<fo:leader leader-pattern="dots" | |||||
<fo:table-cell><fo:block text-align="start" text-align-last="justify">Shorter text example<fo:leader leader-pattern="dots" | |||||
leader-pattern-width="8pt" | leader-pattern-width="8pt" | ||||
leader-alignment="reference-area" | leader-alignment="reference-area" | ||||
/></fo:block></fo:table-cell> | /></fo:block></fo:table-cell> |
<?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||
<FindBugsFilter> | <FindBugsFilter> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.layoutmgr.inline.TextLayoutManager$TextAreaBuilder"/> | |||||
<Method name="getMappingBidiLevels"/> | |||||
<Bug pattern="PZLA_PREFER_ZERO_LENGTH_ARRAYS"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.svg.PDFTextPainter"/> | |||||
<Field name="pdf"/> | |||||
<Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.render.ps.PSTextPainter"/> | |||||
<Or> | |||||
<Field name="gen"/> | |||||
<Field name="ps"/> | |||||
<Field name="psRun"/> | |||||
<Field name="textUtil"/> | |||||
</Or> | |||||
<Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.GlyphMapping"/> | |||||
<Method name="<init>"/> | |||||
<Bug pattern="EI_EXPOSE_REP2"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.MultiByteFont"/> | |||||
<Method name="setBBoxArray"/> | |||||
<Bug pattern="EI_EXPOSE_REP2"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.truetype.TTFFile$1"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont$1"/> | |||||
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/> | <Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Method name="buildCIDSet"/> | <Method name="buildCIDSet"/> | ||||
<Bug pattern="OS_OPEN_STREAM"/> | <Bug pattern="OS_OPEN_STREAM"/> | ||||
</Match> | </Match> | ||||
<Match> | |||||
<Class name="org.apache.fop.pdf.PDFFactory"/> | |||||
<Method name="makeFont"/> | |||||
<Bug pattern="BC_UNCONFIRMED_CAST_OF_RETURN_VALUE"/> | |||||
</Match> | |||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.pdf.PDFOutputIntent"/> | <Class name="org.apache.fop.pdf.PDFOutputIntent"/> | ||||
<Method name="toPDF"/> | <Method name="toPDF"/> | ||||
<Bug pattern="BIT_IOR_OF_SIGNED_BYTE"/> | <Bug pattern="BIT_IOR_OF_SIGNED_BYTE"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFDirTabEntry"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OFDirTabEntry"/> | |||||
<Method name="toString"/> | <Method name="toString"/> | ||||
<Bug pattern="DMI_INVOKING_TOSTRING_ON_ARRAY"/> | <Bug pattern="DMI_INVOKING_TOSTRING_ON_ARRAY"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="UWF_UNWRITTEN_FIELD"/> | <Bug pattern="UWF_UNWRITTEN_FIELD"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFDirTabEntry"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OFDirTabEntry"/> | |||||
<Field name="checksum"/> | <Field name="checksum"/> | ||||
<Bug pattern="UWF_UNWRITTEN_FIELD"/> | <Bug pattern="UWF_UNWRITTEN_FIELD"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="glyphToUnicode"/> | <Method name="glyphToUnicode"/> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="initAnsiWidths"/> | <Method name="initAnsiWidths"/> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="readKerning"/> | <Method name="readKerning"/> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="readUnicodeCmap"/> | <Method name="readUnicodeCmap"/> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="unicodeToGlyph"/> | <Method name="unicodeToGlyph"/> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="unicodeToWinAnsi"/> | <Method name="unicodeToWinAnsi"/> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile$UnicodeMapping"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont$UnicodeMapping"/> | |||||
<Method name="<init>"/> | <Method name="<init>"/> | ||||
<Bug pattern="DM_NUMBER_CTOR"/> | <Bug pattern="DM_NUMBER_CTOR"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="ITA_INEFFICIENT_TO_ARRAY"/> | <Bug pattern="ITA_INEFFICIENT_TO_ARRAY"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="unicodeToWinAnsi"/> | <Method name="unicodeToWinAnsi"/> | ||||
<Bug pattern="ITA_INEFFICIENT_TO_ARRAY"/> | <Bug pattern="ITA_INEFFICIENT_TO_ARRAY"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/> | <Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile$UnicodeMapping"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont$UnicodeMapping"/> | |||||
<!--Neither method nor field--> | <!--Neither method nor field--> | ||||
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_NEEDS_THIS"/> | <Bug pattern="SIC_INNER_SHOULD_BE_STATIC_NEEDS_THIS"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="UPM_UNCALLED_PRIVATE_METHOD"/> | <Bug pattern="UPM_UNCALLED_PRIVATE_METHOD"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="printMaxMin"/> | <Method name="printMaxMin"/> | ||||
<Bug pattern="UPM_UNCALLED_PRIVATE_METHOD"/> | <Bug pattern="UPM_UNCALLED_PRIVATE_METHOD"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="WMI_WRONG_MAP_ITERATOR"/> | <Bug pattern="WMI_WRONG_MAP_ITERATOR"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="readKerning"/> | <Method name="readKerning"/> | ||||
<Bug pattern="WMI_WRONG_MAP_ITERATOR"/> | <Bug pattern="WMI_WRONG_MAP_ITERATOR"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="DLS_DEAD_LOCAL_STORE"/> | <Bug pattern="DLS_DEAD_LOCAL_STORE"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFFile"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Method name="readFont"/> | <Method name="readFont"/> | ||||
<Bug pattern="DLS_DEAD_LOCAL_STORE"/> | <Bug pattern="DLS_DEAD_LOCAL_STORE"/> | ||||
</Match> | </Match> | ||||
<Bug pattern="EI_EXPOSE_REP"/> | <Bug pattern="EI_EXPOSE_REP"/> | ||||
</Match> | </Match> | ||||
<Match> | <Match> | ||||
<Class name="org.apache.fop.fonts.truetype.TTFDirTabEntry"/> | |||||
<Class name="org.apache.fop.fonts.truetype.OFDirTabEntry"/> | |||||
<Method name="getTag"/> | <Method name="getTag"/> | ||||
<Bug pattern="EI_EXPOSE_REP"/> | <Bug pattern="EI_EXPOSE_REP"/> | ||||
</Match> | </Match> | ||||
</Or> | </Or> | ||||
<Bug pattern="BC_UNCONFIRMED_CAST"/> | <Bug pattern="BC_UNCONFIRMED_CAST"/> | ||||
</Match> | </Match> | ||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.fo.properties.CommonAural"/> | |||||
<Class name="org.apache.fop.fo.properties.CommonMarginInline"/> | |||||
<Class name="org.apache.fop.render.pdf.PDFSVGHandler$PDFInfo"/> | |||||
<Class name="org.apache.fop.fo.properties.CommonRelativePosition"/> | |||||
</Or> | |||||
<Or> | |||||
<Bug pattern="UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD"/> | |||||
<Bug pattern="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.forms.FormLayoutManagerMakerProvider$CheckBoxLayoutManagerMaker"/> | |||||
<Class name="org.apache.fop.forms.FormLayoutManagerMakerProvider$ComboBoxLayoutManagerMaker"/> | |||||
<Class name="org.apache.fop.forms.FormLayoutManagerMakerProvider$InputLayoutManagerMaker"/> | |||||
<Class name="org.apache.fop.forms.FormLayoutManagerMakerProvider$MultilineInputLayoutManagerMaker"/> | |||||
<Class name="org.apache.fop.forms.FormLayoutManagerMakerProvider$RadioButtonLayoutManagerMaker"/> | |||||
<Class name="org.apache.fop.forms.FormLayoutManagerMakerProvider$TriggerLayoutManagerMaker"/> | |||||
<Class name="org.apache.fop.render.intermediate.IFRenderer$1"/> | |||||
<Class name="org.apache.fop.render.intermediate.IFRenderer$3"/> | |||||
<Class name="org.apache.fop.render.intermediate.IFRenderer$4"/> | |||||
<Class name="org.apache.fop.render.intermediate.IFRenderer$5"/> | |||||
<Class name="org.apache.fop.render.intermediate.IFRenderer$6"/> | |||||
<Class name="org.apache.fop.render.pdf.PDFPainter$InputPainter"/> | |||||
<Class name="org.apache.fop.render.pdf.PDFPainter$MultilineInputPainter"/> | |||||
<Class name="org.apache.fop.render.pdf.PDFPainter$RadioButtonPainter"/> | |||||
<Class name="org.apache.fop.render.pdf.PDFPainter$TriggerPainter"/> | |||||
<Class name="org.apache.fop.render.pdf.PDFPainter$ComboBoxPainter"/> | |||||
<Class name="org.apache.fop.render.pdf.PDFPainter$CheckboxPainter"/> | |||||
</Or> | |||||
<Or> | |||||
<Bug pattern="BC_UNCONFIRMED_CAST"/> | |||||
<Bug pattern="BC_UNCONFIRMED_CAST_OF_RETURN_VALUE"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.fo.flow.Float"/> | |||||
<Class name="org.apache.fop.fo.flow.MultiCase"/> | |||||
<Class name="org.apache.fop.fo.flow.MultiProperties"/> | |||||
<Class name="org.apache.fop.fo.flow.MultiPropertySet"/> | |||||
<Class name="org.apache.fop.fo.flow.MultiSwitch"/> | |||||
<Class name="org.apache.fop.fo.flow.MultiToggle"/> | |||||
<Class name="org.apache.fop.fo.flow.table.TableAndCaption"/> | |||||
<Class name="org.apache.fop.fo.flow.table.TableCaption"/> | |||||
<Class name="org.apache.fop.fonts.apps.AbstractFontReader"/> | |||||
<Class name="org.apache.fop.render.rtf.rtflib.rtfdoc.RtfElement"/> | |||||
</Or> | |||||
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/> | |||||
</Match> | |||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.pdf.PDFFunction"/> | |||||
<Class name="org.apache.fop.pdf.PDFGoTo"/> | |||||
<Class name="org.apache.fop.pdf.PDFLink"/> | |||||
<Class name="org.apache.fop.pdf.PDFPattern"/> | |||||
<Class name="org.apache.fop.svg.ACIUtils"/> | |||||
<Class name="org.apache.fop.svg.PDFTextPainter"/> | |||||
</Or> | |||||
<Bug pattern="FE_FLOATING_POINT_EQUALITY"/> | |||||
</Match> | |||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.area.BodyRegion"/> | |||||
<Class name="org.apache.fop.area.Page"/> | |||||
<Class name="org.apache.fop.area.PageViewport"/> | |||||
<Class name="org.apache.fop.area.RegionReference"/> | |||||
<Class name="org.apache.fop.area.RegionViewport"/> | |||||
<Class name="org.apache.fop.hyphenation.CharVector"/> | |||||
<Class name="org.apache.fop.hyphenation.TernaryTree"/> | |||||
<Class name="org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes"/> | |||||
</Or> | |||||
<Bug pattern="CN_IDIOM_NO_SUPER_CALL"/> | |||||
</Match> | |||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.forms.CheckBoxArea"/> | |||||
<Class name="org.apache.fop.forms.ComboBox"/> | |||||
<Class name="org.apache.fop.forms.RadioButtonArea"/> | |||||
</Or> | |||||
<Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/> | |||||
</Match> | |||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.layoutmgr.PageBreaker"/> | |||||
<Class name="org.apache.fop.layoutmgr.BlockContainerLayoutManager"/> | |||||
</Or> | |||||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.layoutmgr.BlockContainerLayoutManager"/> | |||||
<Bug pattern="NP_LOAD_OF_KNOWN_NULL_VALUE"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.truetype.OpenFont"/> | |||||
<Bug pattern="DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.apps.io.ResourceResolverFactory$FileDeletingInputStream"/> | |||||
<Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fo.properties.FontFamilyProperty"/> | |||||
<Bug pattern="EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.render.ps.PSImageObject"/> | |||||
<Or> | |||||
<Bug pattern="EI_EXPOSE_REP"/> | |||||
<Bug pattern="EI_EXPOSE_REP2"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.cff.CFFDataReader"/> | |||||
<Bug pattern="DM_DEFAULT_ENCODING"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.cff.CFFDataReader$CFFIndexData"/> | |||||
<Or> | |||||
<Bug pattern="SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH"/> | |||||
<Bug pattern="SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH_TO_THROW"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.cff.CFFDataReader$CFFSubTable"/> | |||||
<Or> | |||||
<Bug pattern="EI_EXPOSE_REP"/> | |||||
<Bug pattern="EI_EXPOSE_REP2"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.cff.CFFDataReader$DICTEntry"/> | |||||
<Or> | |||||
<Bug pattern="EI_EXPOSE_REP"/> | |||||
<Bug pattern="EI_EXPOSE_REP2"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.truetype.OTFFile"/> | |||||
<Or> | |||||
<Bug pattern="ITA_INEFFICIENT_TO_ARRAY"/> | |||||
<Bug pattern="DM_DEFAULT_ENCODING"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.truetype.OTFSubSetFile"/> | |||||
<Or> | |||||
<Bug pattern="ITA_INEFFICIENT_TO_ARRAY"/> | |||||
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC"/> | |||||
<Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"/> | |||||
<Bug pattern="DM_DEFAULT_ENCODING"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.truetype.OTFSubSetFile$1"/> | |||||
<Or> | |||||
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC"/> | |||||
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/> | |||||
</Or> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.fonts.truetype.OTFSubSetFile$FDIndexReference"/> | |||||
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.render.ps.PSFontUtils"/> | |||||
<Bug pattern="DM_DEFAULT_ENCODING"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.forms.IField$Field"/> | |||||
<Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/> | |||||
</Match> | |||||
<Match> | |||||
<Or> | |||||
<Class name="org.apache.fop.forms.IField$Field"/> | |||||
<Class name="org.apache.fop.forms.TriggerArea"/> | |||||
<Class name="org.apache.fop.forms.traits.AdditionalActionTrait"/> | |||||
</Or> | |||||
<Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.render.pdf.extensions.PDFExtensionHandlerFactory"/> | |||||
<Method name="getSupportedNamespaces"/> | |||||
<Bug pattern="EI_EXPOSE_REP"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.render.pdf.extensions.PDFDictionaryEntryExtension"/> | |||||
<Method name="getValueAsNumber"/> | |||||
<Bug pattern="FE_FLOATING_POINT_EQUALITY"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.render.pdf.extensions.PDFDictionaryType"/> | |||||
<Method name="hasValueOfElementName"/> | |||||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/> | |||||
</Match> | |||||
<Match> | |||||
<Class name="org.apache.fop.render.pdf.extensions.PDFDictionaryEntryType"/> | |||||
<Method name="hasValueOfElementName"/> | |||||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/> | |||||
</Match> | |||||
</FindBugsFilter> | </FindBugsFilter> |
Index: fontbox/src/test/java/org/apache/fontbox/cff/CharStringRendererTest.java | |||||
=================================================================== | |||||
--- fontbox/src/test/java/org/apache/fontbox/cff/CharStringRendererTest.java (revision 0) | |||||
+++ fontbox/src/test/java/org/apache/fontbox/cff/CharStringRendererTest.java (revision 0) | |||||
@@ -0,0 +1,28 @@ | |||||
+package org.apache.fontbox.cff; | |||||
+ | |||||
+import java.util.ArrayList; | |||||
+import java.util.List; | |||||
+ | |||||
+import org.junit.Test; | |||||
+ | |||||
+import static org.junit.Assert.assertTrue; | |||||
+ | |||||
+public class CharStringRendererTest { | |||||
+ | |||||
+ @Test | |||||
+ public void testArgumentValidation() { | |||||
+ CharStringRenderer renderer = new CharStringRenderer(); | |||||
+ List<Integer> numbers = new ArrayList<Integer>(); | |||||
+ for (int i = 0;i < 4;i++) { | |||||
+ numbers.add(1); | |||||
+ } | |||||
+ assertTrue(renderer.hasValidArguments("vhcurveto", numbers)); | |||||
+ numbers.add(1); | |||||
+ assertTrue(renderer.hasValidArguments("vvcurveto", numbers)); | |||||
+ for (int i = 0;i < 3;i++) { | |||||
+ numbers.add(1); | |||||
+ } | |||||
+ assertTrue(renderer.hasValidArguments("rcurveline", numbers)); | |||||
+ } | |||||
+ | |||||
+} | |||||
Index: fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java | |||||
=================================================================== | |||||
--- fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java (revision 1546564) | |||||
+++ fontbox/src/main/java/org/apache/fontbox/cff/AFMFormatter.java (working copy) | |||||
@@ -27,7 +27,7 @@ | |||||
/** | |||||
* This class creates all needed AFM font metric data from a CFFFont ready to be read from a AFMPaser. | |||||
- * | |||||
+ * | |||||
* @author Villu Ruusmann | |||||
* @version $Revision$ | |||||
*/ | |||||
@@ -125,7 +125,7 @@ | |||||
metric.name = mapping.getName(); | |||||
renderer.render(mapping.toType1Sequence()); | |||||
metric.width = renderer.getWidth(); | |||||
- metric.bounds = renderer.getBounds(); | |||||
+ metric.bounds = renderer.getBounds2D(); | |||||
metrics.add(metric); | |||||
} | |||||
return metrics; | |||||
@@ -150,7 +150,7 @@ | |||||
} | |||||
/** | |||||
- * This class represents the metric of one single character. | |||||
+ * This class represents the metric of one single character. | |||||
* | |||||
*/ | |||||
private static class CharMetric implements Comparable<CharMetric> | |||||
Index: fontbox/src/main/java/org/apache/fontbox/cff/CharStringRenderer.java | |||||
=================================================================== | |||||
--- fontbox/src/main/java/org/apache/fontbox/cff/CharStringRenderer.java (revision 1546564) | |||||
+++ fontbox/src/main/java/org/apache/fontbox/cff/CharStringRenderer.java (working copy) | |||||
@@ -16,9 +16,11 @@ | |||||
*/ | |||||
package org.apache.fontbox.cff; | |||||
+import java.awt.Point; | |||||
import java.awt.geom.GeneralPath; | |||||
import java.awt.geom.Point2D; | |||||
import java.awt.geom.Rectangle2D; | |||||
+import java.util.HashMap; | |||||
import java.util.List; | |||||
import org.apache.commons.logging.Log; | |||||
@@ -33,7 +35,7 @@ | |||||
{ | |||||
// TODO CharStringRenderer as abstract Class with two inherited classes according to the Charsstring type.... | |||||
private static final Log LOG = LogFactory.getLog(CharStringRenderer.class); | |||||
- | |||||
+ | |||||
private boolean isCharstringType1 = true; | |||||
private boolean isFirstCommand = true; | |||||
@@ -42,6 +44,8 @@ | |||||
private Point2D referencePoint = null; | |||||
private int width = 0; | |||||
private boolean hasNonEndCharOp = false; | |||||
+ private int[] bbox = {0,0,0,0}; | |||||
+ private HashMap<String, String> vStrings; | |||||
/** | |||||
* Constructor for the char string renderer. | |||||
@@ -100,7 +104,7 @@ | |||||
private void handleCommandType2(List<Integer> numbers, CharStringCommand command) | |||||
{ | |||||
String name = CharStringCommand.TYPE2_VOCABULARY.get(command.getKey()); | |||||
- | |||||
+ checkArguments(name, numbers); | |||||
if (!hasNonEndCharOp) | |||||
{ | |||||
hasNonEndCharOp = !"endchar".equals(name); | |||||
@@ -176,7 +180,7 @@ | |||||
setWidth(numbers.get(0)); | |||||
rmoveTo(numbers.get(1), numbers.get(2)); | |||||
} | |||||
- else | |||||
+ else if (numbers.size() == 2) | |||||
{ | |||||
rmoveTo(numbers.get(0), numbers.get(1)); | |||||
} | |||||
@@ -192,7 +196,7 @@ | |||||
setWidth(numbers.get(0)); | |||||
rmoveTo(numbers.get(1), Integer.valueOf(0)); | |||||
} | |||||
- else | |||||
+ else if (numbers.size() == 1) | |||||
{ | |||||
rmoveTo(numbers.get(0), Integer.valueOf(0)); | |||||
} | |||||
@@ -284,6 +288,61 @@ | |||||
} | |||||
} | |||||
+ void checkArguments(String name, List<Integer> numbers) { | |||||
+ if (name == null) { | |||||
+ return; | |||||
+ } | |||||
+ boolean valid = hasValidArguments(name, numbers); | |||||
+ if (!valid) { | |||||
+ //Initialize the validation strings if not already done | |||||
+ if (vStrings == null) { | |||||
+ vStrings = new HashMap<String, String>(); | |||||
+ vStrings.put("vmoveto", "1 || 2"); | |||||
+ vStrings.put("rlineto", "3 || % 2"); | |||||
+ vStrings.put("rrcurveto", "7 || % 6"); | |||||
+ vStrings.put("rlinecurve", "% 2 || 6 + % 2"); | |||||
+ vStrings.put("rcurveline", "% 6 || 2 + % 6"); | |||||
+ vStrings.put("rmoveto", "2 || 3"); | |||||
+ vStrings.put("hmoveto", "1 || 2"); | |||||
+ vStrings.put("vhcurveto", "% 4 || 1 + % 4"); | |||||
+ vStrings.put("hvcurveto", "% 4 || 1 + % 4"); | |||||
+ vStrings.put("vvcurveto", "% 4 || 1 + % 4"); | |||||
+ } | |||||
+ LOG.info(String.format("Font has an unexpected number of parameters for operator '%s'. Arguments "+ | |||||
+ "size %d did not match pattern '%s'", name, numbers.size(), | |||||
+ vStrings.get(name))); | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ boolean hasValidArguments(String name, List<Integer> numbers) { | |||||
+ boolean valid = true; | |||||
+ if (name.equals("vmoveto")) { | |||||
+ valid = (numbers.size() == 1 || numbers.size() == 2); | |||||
+ } | |||||
+ if (name.equals("rlineto")) { | |||||
+ valid = (numbers.size() == 3 || numbers.size() % 2 == 0); | |||||
+ } | |||||
+ if (name.equals("rrcurveto")) { | |||||
+ valid = (numbers.size() == 7 || numbers.size() % 6 == 0); | |||||
+ } | |||||
+ if (name.equals("rlinecurve")) { | |||||
+ valid = (numbers.size() % 2 == 0 || (numbers.size() - 6) % 2 == 0); | |||||
+ } | |||||
+ if (name.equals("rcurveline")) { | |||||
+ valid = (numbers.size() % 6 == 0 || (numbers.size() - 2) % 6 == 0); | |||||
+ } | |||||
+ if (name.equals("rmoveto")) { | |||||
+ valid = (numbers.size() == 2 || numbers.size() == 3); | |||||
+ } | |||||
+ if (name.equals("hmoveto")) { | |||||
+ valid = (numbers.size() == 1 || numbers.size() == 2); | |||||
+ } | |||||
+ if (name.equals("vvcurveto") || name.equals("vhcurveto") || name.equals("hvcurveto")) { | |||||
+ valid = (numbers.size() % 4 == 0 || (numbers.size() - 1) % 4 == 0); | |||||
+ } | |||||
+ return valid; | |||||
+ } | |||||
+ | |||||
/** | |||||
* | |||||
* @param numbers | |||||
@@ -353,11 +412,14 @@ | |||||
Point2D point = referencePoint; | |||||
if (point == null) | |||||
{ | |||||
- point = path.getCurrentPoint(); | |||||
- if (point == null) | |||||
+ if (path.getCurrentPoint() == null) | |||||
{ | |||||
point = sidebearingPoint; | |||||
} | |||||
+ else | |||||
+ { | |||||
+ point = path.getCurrentPoint(); | |||||
+ } | |||||
} | |||||
referencePoint = null; | |||||
path.moveTo((float)(point.getX() + dx.doubleValue()), | |||||
@@ -397,15 +459,20 @@ | |||||
private void rlineTo(Number dx, Number dy) | |||||
{ | |||||
Point2D point = path.getCurrentPoint(); | |||||
- path.lineTo((float)(point.getX() + dx.doubleValue()), | |||||
- (float)(point.getY() + dy.doubleValue())); | |||||
+ if (point != null) { | |||||
+ updateBBox(dx.intValue(), dy.intValue()); | |||||
+ path.lineTo((float)(point.getX() + dx.doubleValue()), | |||||
+ (float)(point.getY() + dy.doubleValue())); | |||||
+ } | |||||
} | |||||
private void rrlineTo(List<Integer> numbers) | |||||
{ | |||||
for (int i = 0;i < numbers.size();i += 2) | |||||
{ | |||||
- rlineTo(numbers.get(i), numbers.get(i + 1)); | |||||
+ if (numbers.size() - i >= 2) { | |||||
+ rlineTo(numbers.get(i), numbers.get(i + 1)); | |||||
+ } | |||||
} | |||||
} | |||||
@@ -415,13 +482,15 @@ | |||||
{ | |||||
for (int i = 0;i < numbers.size();i += 6) | |||||
{ | |||||
- float x1 = numbers.get(i); | |||||
- float y1 = numbers.get(i + 1); | |||||
- float x2 = numbers.get(i + 2); | |||||
- float y2 = numbers.get(i + 3); | |||||
- float x3 = numbers.get(i + 4); | |||||
- float y3 = numbers.get(i + 5); | |||||
- rrcurveTo(x1, y1, x2, y2, x3, y3); | |||||
+ if (numbers.size() - i >= 6) { | |||||
+ float x1 = numbers.get(i); | |||||
+ float y1 = numbers.get(i + 1); | |||||
+ float x2 = numbers.get(i + 2); | |||||
+ float y2 = numbers.get(i + 3); | |||||
+ float x3 = numbers.get(i + 4); | |||||
+ float y3 = numbers.get(i + 5); | |||||
+ rrcurveTo(x1, y1, x2, y2, x3, y3); | |||||
+ } | |||||
} | |||||
} | |||||
} | |||||
@@ -429,14 +498,42 @@ | |||||
private void rrcurveTo(Number dx1, Number dy1, Number dx2, Number dy2, | |||||
Number dx3, Number dy3) | |||||
{ | |||||
- Point2D point = path.getCurrentPoint(); | |||||
- float x1 = (float) point.getX() + dx1.floatValue(); | |||||
- float y1 = (float) point.getY() + dy1.floatValue(); | |||||
- float x2 = x1 + dx2.floatValue(); | |||||
- float y2 = y1 + dy2.floatValue(); | |||||
- float x3 = x2 + dx3.floatValue(); | |||||
- float y3 = y2 + dy3.floatValue(); | |||||
- path.curveTo(x1, y1, x2, y2, x3, y3); | |||||
+ Point2D p0 = path.getCurrentPoint(); | |||||
+ if (p0 != null) { | |||||
+ float x1 = (float) p0.getX() + dx1.floatValue(); | |||||
+ float y1 = (float) p0.getY() + dy1.floatValue(); | |||||
+ float x2 = x1 + dx2.floatValue(); | |||||
+ float y2 = y1 + dy2.floatValue(); | |||||
+ float x3 = x2 + dx3.floatValue(); | |||||
+ float y3 = y2 + dy3.floatValue( ); | |||||
+ | |||||
+ Point p1 = new Point((int)x1, (int)y1); | |||||
+ Point p2 = new Point((int)x2, (int)y2); | |||||
+ Point p3 = new Point((int)x3, (int)y3); | |||||
+ | |||||
+ updateBBox((int)p0.getX(), (int)p0.getY()); | |||||
+ updateBBox((int)p3.getX(), (int)p3.getY()); | |||||
+ | |||||
+ int[] abc = calculateABC((int)p0.getX(), p1.x, p2.x, p3.x); | |||||
+ double[] txs = getT(abc); | |||||
+ for (double tx : txs) { | |||||
+ if (tx > 0 && tx < 1) { | |||||
+ int[] XandY = getXandY(tx, new Point((int)p0.getX(), (int)p0.getY()), p1, p2, p3); | |||||
+ updateBBox(XandY[0], XandY[1]); | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ abc = calculateABC((int)p0.getY(), p1.y, p2.y, p3.y); | |||||
+ double[] tys = getT(abc); | |||||
+ for (double ty : tys) { | |||||
+ if (ty > 0 && ty < 1) { | |||||
+ int[] XandY = getXandY(ty, new Point((int)p0.getX(), (int)p0.getY()), p1, p2, p3); | |||||
+ updateBBox(XandY[0], XandY[1]); | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ path.curveTo(x1, y1, x2, y2, x3, y3); | |||||
+ } | |||||
} | |||||
@@ -646,7 +743,9 @@ | |||||
private void closePath() | |||||
{ | |||||
referencePoint = path.getCurrentPoint(); | |||||
- path.closePath(); | |||||
+ if (referencePoint != null) { | |||||
+ path.closePath(); | |||||
+ } | |||||
} | |||||
private void pointSb(Number x, Number y) | |||||
@@ -658,11 +757,15 @@ | |||||
* Returns the bounds of the renderer path. | |||||
* @return the bounds as Rectangle2D | |||||
*/ | |||||
- public Rectangle2D getBounds() | |||||
+ public int[] getBounds() | |||||
{ | |||||
- return path.getBounds2D(); | |||||
+ return bbox; | |||||
} | |||||
+ public Rectangle2D getBounds2D() { | |||||
+ return path.getBounds2D(); | |||||
+ } | |||||
+ | |||||
/** | |||||
* Returns the width of the current command. | |||||
* @return the width | |||||
@@ -676,4 +779,61 @@ | |||||
{ | |||||
this.width = aWidth; | |||||
} | |||||
-} | |||||
\ No newline at end of file | |||||
+ | |||||
+ private int[] calculateABC(int p0, int p1, int p2, int p3) { | |||||
+ int[] abc = new int[3]; | |||||
+ abc[0] = p0 - 3 * p1 + 3 * p2 - p3; | |||||
+ abc[1] = 2 * (-p0 + 2 * p1 - p2); | |||||
+ abc[2] = p0 - p1; | |||||
+ return abc; | |||||
+ } | |||||
+ | |||||
+ private double[] getT(int[] abc) { | |||||
+ double[] t = {-1, -1}; | |||||
+ int a = abc[0]; | |||||
+ int b = abc[1]; | |||||
+ int c = abc[2]; | |||||
+ double s = Math.pow(b, 2) - 4 * a * c; | |||||
+ if (a == 0) { | |||||
+ if (b != 0) { | |||||
+ t[0] = -c / b; | |||||
+ } | |||||
+ return t; | |||||
+ } else if (s > 0) { | |||||
+ t[0] = (-b + Math.sqrt(s)) / 2 / a; | |||||
+ t[1] = (-b - Math.sqrt(s)) / 2 / a; | |||||
+ return t; | |||||
+ } else if (s == 0) { | |||||
+ t[0] = -b / 2 / a; | |||||
+ return t; | |||||
+ } else { | |||||
+ return t; | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ private int[] getXandY(double t, Point p0, Point p1, Point p2, Point p3) { | |||||
+ int[] XandY = new int[2]; | |||||
+ double p0Coeff = Math.pow(1 - t, 3); | |||||
+ double p1Coeff = 3 * t * Math.pow(1 - t, 2); | |||||
+ double p2Coeff = 3 * Math.pow(t, 2) * (1 - t); | |||||
+ double p3Coeff = Math.pow(t, 3); | |||||
+ double x = p0Coeff * p0.x + p1Coeff * p1.x + p2Coeff * p2.x + p3Coeff * p3.x; | |||||
+ double y = p0Coeff * p0.y + p1Coeff * p1.y + p2Coeff * p2.y + p3Coeff * p3.y; | |||||
+ XandY[0] = (int)x; | |||||
+ XandY[1] = (int)y; | |||||
+ return XandY; | |||||
+ } | |||||
+ | |||||
+ private void updateBBox(int x, int y) { | |||||
+ if (x < bbox[0]) { | |||||
+ bbox[0] = x; | |||||
+ } else if (x > bbox[2]) { | |||||
+ bbox[2] = x; | |||||
+ } | |||||
+ if (y < bbox[1]) { | |||||
+ bbox[1] = y; | |||||
+ } else if (y > bbox[3]) { | |||||
+ bbox[3] = y; | |||||
+ } | |||||
+ } | |||||
+} |
Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java | |||||
=================================================================== | |||||
--- fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java (revision 1546564) | |||||
+++ fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java (working copy) | |||||
@@ -36,7 +36,7 @@ | |||||
import org.apache.fontbox.cff.encoding.CFFStandardEncoding; | |||||
/** | |||||
- * This class represents a parser for a CFF font. | |||||
+ * This class represents a parser for a CFF font. | |||||
* @author Villu Ruusmann | |||||
* @version $Revision: 1.0 $ | |||||
*/ | |||||
@@ -107,7 +107,11 @@ | |||||
{ | |||||
input.setPosition(0); | |||||
} | |||||
+ return parse(input); | |||||
+ } | |||||
+ public List<CFFFont> parse(CFFDataInput input) throws IOException { | |||||
+ this.input = input; | |||||
header = readHeader(input); | |||||
nameIndex = readIndexData(input); | |||||
topDictIndex = readIndexData(input); | |||||
@@ -119,6 +123,7 @@ | |||||
{ | |||||
CFFFont font = parseFont(i); | |||||
font.setGlobalSubrIndex(globalSubrIndex); | |||||
+ font.constructMappings(); | |||||
fonts.add(font); | |||||
} | |||||
return fonts; | |||||
@@ -145,7 +150,7 @@ | |||||
return cffHeader; | |||||
} | |||||
- private static IndexData readIndexData(CFFDataInput input) throws IOException | |||||
+ public static IndexData readIndexData(CFFDataInput input) throws IOException | |||||
{ | |||||
int count = input.readCard16(); | |||||
IndexData index = new IndexData(count); | |||||
@@ -179,7 +184,8 @@ | |||||
return dict; | |||||
} | |||||
- private static DictData.Entry readEntry(CFFDataInput input) throws IOException | |||||
+ private static DictData.Entry readEntry(CFFDataInput input) | |||||
+ throws IOException | |||||
{ | |||||
DictData.Entry entry = new DictData.Entry(); | |||||
while (true) | |||||
@@ -211,13 +217,15 @@ | |||||
return entry; | |||||
} | |||||
- private static CFFOperator readOperator(CFFDataInput input, int b0) throws IOException | |||||
+ private static CFFOperator readOperator(CFFDataInput input, int b0) | |||||
+ throws IOException | |||||
{ | |||||
CFFOperator.Key key = readOperatorKey(input, b0); | |||||
return CFFOperator.getOperator(key); | |||||
} | |||||
- private static CFFOperator.Key readOperatorKey(CFFDataInput input, int b0) throws IOException | |||||
+ private static CFFOperator.Key readOperatorKey(CFFDataInput input, int b0) | |||||
+ throws IOException | |||||
{ | |||||
if (b0 == 12) | |||||
{ | |||||
@@ -227,7 +235,8 @@ | |||||
return new CFFOperator.Key(b0); | |||||
} | |||||
- private static Integer readIntegerNumber(CFFDataInput input, int b0) throws IOException | |||||
+ private static Integer readIntegerNumber(CFFDataInput input, int b0) | |||||
+ throws IOException | |||||
{ | |||||
if (b0 == 28) | |||||
{ | |||||
@@ -263,7 +272,8 @@ | |||||
} | |||||
} | |||||
- private static Double readRealNumber(CFFDataInput input, int b0) throws IOException | |||||
+ private static Double readRealNumber(CFFDataInput input, int b0) | |||||
+ throws IOException | |||||
{ | |||||
StringBuffer sb = new StringBuffer(); | |||||
boolean done = false; | |||||
@@ -446,9 +456,9 @@ | |||||
throw new IOException("FDArray is missing for a CIDKeyed Font."); | |||||
} | |||||
- int fontDictOffset = fdArrayEntry.getNumber(0).intValue(); | |||||
- input.setPosition(fontDictOffset); | |||||
- IndexData fdIndex = readIndexData(input); | |||||
+ int fontDictOffset = fdArrayEntry.getNumber(0).intValue(); | |||||
+ input.setPosition(fontDictOffset); | |||||
+ IndexData fdIndex = readIndexData(input); | |||||
List<Map<String, Object>> privateDictionaries = new LinkedList<Map<String, Object>>(); | |||||
List<Map<String, Object>> fontDictionaries = new LinkedList<Map<String, Object>>(); | |||||
@@ -577,8 +587,8 @@ | |||||
{ | |||||
return CFFStandardString.getName(index); | |||||
} | |||||
- if (index - 391 <= stringIndex.getCount()) | |||||
- { | |||||
+ if (index - 391 < stringIndex.getCount()) | |||||
+ { | |||||
DataInput dataInput = new DataInput(stringIndex.getBytes(index - 391)); | |||||
return dataInput.getString(); | |||||
} | |||||
@@ -620,7 +630,8 @@ | |||||
return entry != null ? entry.getArray() : defaultValue; | |||||
} | |||||
- private CFFEncoding readEncoding(CFFDataInput dataInput, int[] gids) throws IOException | |||||
+ private CFFEncoding readEncoding(CFFDataInput dataInput, int[] gids) | |||||
+ throws IOException | |||||
{ | |||||
int format = dataInput.readCard8(); | |||||
int baseFormat = format & 0x7f; | |||||
@@ -639,7 +650,8 @@ | |||||
} | |||||
} | |||||
- private Format0Encoding readFormat0Encoding(CFFDataInput dataInput, int format, int[] gids) throws IOException | |||||
+ private Format0Encoding readFormat0Encoding(CFFDataInput dataInput, int format, | |||||
+ int[] gids) throws IOException | |||||
{ | |||||
Format0Encoding encoding = new Format0Encoding(); | |||||
encoding.format = format; | |||||
@@ -657,7 +669,8 @@ | |||||
return encoding; | |||||
} | |||||
- private Format1Encoding readFormat1Encoding(CFFDataInput dataInput, int format, int[] gids) throws IOException | |||||
+ private Format1Encoding readFormat1Encoding(CFFDataInput dataInput, int format, | |||||
+ int[] gids) throws IOException | |||||
{ | |||||
Format1Encoding encoding = new Format1Encoding(); | |||||
encoding.format = format; | |||||
@@ -683,7 +696,8 @@ | |||||
return encoding; | |||||
} | |||||
- private void readSupplement(CFFDataInput dataInput, EmbeddedEncoding encoding) throws IOException | |||||
+ private void readSupplement(CFFDataInput dataInput, EmbeddedEncoding encoding) | |||||
+ throws IOException | |||||
{ | |||||
encoding.nSups = dataInput.readCard8(); | |||||
encoding.supplement = new EmbeddedEncoding.Supplement[encoding.nSups]; | |||||
@@ -738,15 +752,14 @@ | |||||
fdselect.fds = new int[nGlyphs]; | |||||
for (int i = 0; i < fdselect.fds.length; i++) | |||||
{ | |||||
- fdselect.fds[i] = dataInput.readCard8(); | |||||
- | |||||
+ fdselect.fds[i] = dataInput.readCard8(); | |||||
} | |||||
return fdselect; | |||||
} | |||||
/** | |||||
* Read the Format 3 of the FDSelect data structure. | |||||
- * | |||||
+ * | |||||
* @param dataInput | |||||
* @param format | |||||
* @param nGlyphs | |||||
@@ -768,7 +781,6 @@ | |||||
r3.first = dataInput.readCard16(); | |||||
r3.fd = dataInput.readCard8(); | |||||
fdselect.range3[i] = r3; | |||||
- | |||||
} | |||||
fdselect.sentinel = dataInput.readCard16(); | |||||
@@ -902,7 +914,8 @@ | |||||
} | |||||
} | |||||
- private CFFCharset readCharset(CFFDataInput dataInput, int nGlyphs) throws IOException | |||||
+ private CFFCharset readCharset(CFFDataInput dataInput, int nGlyphs) | |||||
+ throws IOException | |||||
{ | |||||
int format = dataInput.readCard8(); | |||||
if (format == 0) | |||||
@@ -923,7 +936,8 @@ | |||||
} | |||||
} | |||||
- private Format0Charset readFormat0Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException | |||||
+ private Format0Charset readFormat0Charset(CFFDataInput dataInput, int format, | |||||
+ int nGlyphs) throws IOException | |||||
{ | |||||
Format0Charset charset = new Format0Charset(); | |||||
charset.format = format; | |||||
@@ -936,7 +950,8 @@ | |||||
return charset; | |||||
} | |||||
- private Format1Charset readFormat1Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException | |||||
+ private Format1Charset readFormat1Charset(CFFDataInput dataInput, int format, | |||||
+ int nGlyphs) throws IOException | |||||
{ | |||||
Format1Charset charset = new Format1Charset(); | |||||
charset.format = format; | |||||
@@ -957,7 +972,8 @@ | |||||
return charset; | |||||
} | |||||
- private Format2Charset readFormat2Charset(CFFDataInput dataInput, int format, int nGlyphs) throws IOException | |||||
+ private Format2Charset readFormat2Charset(CFFDataInput dataInput, int format, | |||||
+ int nGlyphs) throws IOException | |||||
{ | |||||
Format2Charset charset = new Format2Charset(); | |||||
charset.format = format; | |||||
@@ -981,7 +997,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class holding the header of a CFF font. | |||||
+ * Inner class holding the header of a CFF font. | |||||
*/ | |||||
private static class Header | |||||
{ | |||||
@@ -999,7 +1015,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class holding the DictData of a CFF font. | |||||
+ * Inner class holding the DictData of a CFF font. | |||||
*/ | |||||
private static class DictData | |||||
{ | |||||
@@ -1030,7 +1046,7 @@ | |||||
} | |||||
/** | |||||
- * {@inheritDoc} | |||||
+ * {@inheritDoc} | |||||
*/ | |||||
public String toString() | |||||
{ | |||||
@@ -1038,7 +1054,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class holding an operand of a CFF font. | |||||
+ * Inner class holding an operand of a CFF font. | |||||
*/ | |||||
private static class Entry | |||||
{ | |||||
@@ -1100,7 +1116,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing an embedded CFF encoding. | |||||
+ * Inner class representing an embedded CFF encoding. | |||||
*/ | |||||
abstract static class EmbeddedEncoding extends CFFEncoding | |||||
{ | |||||
@@ -1124,7 +1140,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a supplement for an encoding. | |||||
+ * Inner class representing a supplement for an encoding. | |||||
*/ | |||||
static class Supplement | |||||
{ | |||||
@@ -1150,7 +1166,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a Format0 encoding. | |||||
+ * Inner class representing a Format0 encoding. | |||||
*/ | |||||
private static class Format0Encoding extends EmbeddedEncoding | |||||
{ | |||||
@@ -1167,7 +1183,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a Format1 encoding. | |||||
+ * Inner class representing a Format1 encoding. | |||||
*/ | |||||
private static class Format1Encoding extends EmbeddedEncoding | |||||
{ | |||||
@@ -1183,7 +1199,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a range of an encoding. | |||||
+ * Inner class representing a range of an encoding. | |||||
*/ | |||||
private static class Range1 | |||||
{ | |||||
@@ -1193,13 +1209,20 @@ | |||||
@Override | |||||
public String toString() | |||||
{ | |||||
- return getClass().getName() + "[first=" + first + ", nLeft=" + nLeft + "]"; | |||||
+ return getClass().getName() + "[first=" + first + ", nLeft=" | |||||
+ + nLeft + "]"; | |||||
} | |||||
+ | |||||
+ @Override | |||||
+ public boolean equals(Object obj) { | |||||
+ Range1 r = (Range1)obj; | |||||
+ return (first == r.first && nLeft == r.nLeft); | |||||
+ } | |||||
} | |||||
} | |||||
/** | |||||
- * Inner class representing an embedded CFF charset. | |||||
+ * Inner class representing an embedded CFF charset. | |||||
*/ | |||||
abstract static class EmbeddedCharset extends CFFCharset | |||||
{ | |||||
@@ -1211,7 +1234,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a Format0 charset. | |||||
+ * Inner class representing a Format0 charset. | |||||
*/ | |||||
private static class Format0Charset extends EmbeddedCharset | |||||
{ | |||||
@@ -1226,7 +1249,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a Format1 charset. | |||||
+ * Inner class representing a Format1 charset. | |||||
*/ | |||||
private static class Format1Charset extends EmbeddedCharset | |||||
{ | |||||
@@ -1240,7 +1263,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a range of a charset. | |||||
+ * Inner class representing a range of a charset. | |||||
*/ | |||||
private static class Range1 | |||||
{ | |||||
@@ -1256,7 +1279,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a Format2 charset. | |||||
+ * Inner class representing a Format2 charset. | |||||
*/ | |||||
private static class Format2Charset extends EmbeddedCharset | |||||
{ | |||||
@@ -1270,7 +1293,7 @@ | |||||
} | |||||
/** | |||||
- * Inner class representing a range of a charset. | |||||
+ * Inner class representing a range of a charset. | |||||
*/ | |||||
private static class Range2 | |||||
{ | |||||
@@ -1284,4 +1307,8 @@ | |||||
} | |||||
} | |||||
} | |||||
+ | |||||
+ public IndexData getStringIndex() { | |||||
+ return stringIndex; | |||||
+ } | |||||
} | |||||
Index: fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java | |||||
=================================================================== | |||||
--- fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java (revision 1546564) | |||||
+++ fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java (working copy) | |||||
@@ -31,7 +31,7 @@ | |||||
/** | |||||
* This class represents a CFF/Type2 Font. | |||||
- * | |||||
+ * | |||||
* @author Villu Ruusmann | |||||
* @version $Revision$ | |||||
*/ | |||||
@@ -44,6 +44,8 @@ | |||||
private CFFEncoding fontEncoding = null; | |||||
private CFFCharset fontCharset = null; | |||||
private Map<String, byte[]> charStringsDict = new LinkedHashMap<String, byte[]>(); | |||||
+ Map<Integer, Mapping> sidMappings = null; | |||||
+ ArrayList<Mapping> gidMappings = null; | |||||
private IndexData globalSubrIndex = null; | |||||
private IndexData localSubrIndex = null; | |||||
@@ -97,6 +99,7 @@ | |||||
topDict.put(name, value); | |||||
} | |||||
} | |||||
+ | |||||
/** | |||||
* Returns the top dictionary. | |||||
* @return the dictionary | |||||
@@ -107,7 +110,7 @@ | |||||
} | |||||
/** | |||||
- * Adds the given key/value pair to the private dictionary. | |||||
+ * Adds the given key/value pair to the private dictionary. | |||||
* @param name the given key | |||||
* @param value the given value | |||||
*/ | |||||
@@ -118,7 +121,8 @@ | |||||
privateDict.put(name, value); | |||||
} | |||||
} | |||||
- /** | |||||
+ | |||||
+ /** | |||||
* Returns the private dictionary. | |||||
* @return the dictionary | |||||
*/ | |||||
@@ -127,14 +131,60 @@ | |||||
return privateDict; | |||||
} | |||||
+ /** | |||||
+ * Returns a mapping for a given GID | |||||
+ * @param GID The given GID | |||||
+ * @return The found mapping | |||||
+ */ | |||||
+ public Mapping getMapping(int GID) { | |||||
+ return sidMappings.get(GID); | |||||
+ } | |||||
+ | |||||
/** | |||||
- * Get the mapping (code/SID/charname/bytes) for this font. | |||||
- * @return mappings for codes < 256 and for codes > = 256 | |||||
- */ | |||||
- public Collection<Mapping> getMappings() | |||||
+ * Get the mapping (code/SID/charname/bytes) for this font. | |||||
+ * @return mappings for codes < 256 and for codes > = 256 | |||||
+ */ | |||||
+ public Collection<Mapping> getMappings() { | |||||
+ constructMappings(); | |||||
+ return sidMappings.values(); | |||||
+ } | |||||
+ | |||||
+ /** | |||||
+ * Gets the GID mappings list. | |||||
+ */ | |||||
+ public ArrayList<Mapping> getGIDMappings() { | |||||
+ return gidMappings; | |||||
+ } | |||||
+ | |||||
+ private void constructGIDMap() { | |||||
+ gidMappings = new ArrayList<Mapping>(); | |||||
+ Mapping notdef = new Mapping(); | |||||
+ notdef.setName(".notdef"); | |||||
+ gidMappings.add(notdef); | |||||
+ for (CFFCharset.Entry entry : fontCharset.getEntries()) | |||||
+ { | |||||
+ String name = entry.getName(); | |||||
+ byte[] bytes = this.charStringsDict.get(name); | |||||
+ if (bytes == null) | |||||
+ { | |||||
+ continue; | |||||
+ } | |||||
+ Mapping mapping = new Mapping(); | |||||
+ mapping.setSID(entry.getSID()); | |||||
+ mapping.setName(name); | |||||
+ mapping.setBytes(bytes); | |||||
+ gidMappings.add(mapping); | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ /** | |||||
+ * Construct the mappings. | |||||
+ */ | |||||
+ public void constructMappings() | |||||
{ | |||||
- List<Mapping> mappings = new ArrayList<Mapping>(); | |||||
- Set<String> mappedNames = new HashSet<String>(); | |||||
+ constructGIDMap(); | |||||
+ sidMappings = new LinkedHashMap<Integer, Mapping>(); | |||||
+ Set<String> mappedNames = new HashSet<String>(); | |||||
for (CFFEncoding.Entry entry : fontEncoding.getEntries()) | |||||
{ | |||||
String charName = fontCharset.getName(entry.getSID()); | |||||
@@ -153,7 +203,7 @@ | |||||
mapping.setSID(entry.getSID()); | |||||
mapping.setName(charName); | |||||
mapping.setBytes(bytes); | |||||
- mappings.add(mapping); | |||||
+ sidMappings.put(mapping.getSID(), mapping); | |||||
mappedNames.add(charName); | |||||
} | |||||
if (fontEncoding instanceof CFFParser.EmbeddedEncoding) | |||||
@@ -177,7 +227,7 @@ | |||||
mapping.setSID(supplement.getGlyph()); | |||||
mapping.setName(charName); | |||||
mapping.setBytes(bytes); | |||||
- mappings.add(mapping); | |||||
+ sidMappings.put(mapping.getSID(), mapping); | |||||
mappedNames.add(charName); | |||||
} | |||||
} | |||||
@@ -185,7 +235,7 @@ | |||||
int code = 256; | |||||
for (CFFCharset.Entry entry : fontCharset.getEntries()) | |||||
{ | |||||
- String name = entry.getName(); | |||||
+ String name = entry.getName(); | |||||
if (mappedNames.contains(name)) | |||||
{ | |||||
continue; | |||||
@@ -201,11 +251,10 @@ | |||||
mapping.setName(name); | |||||
mapping.setBytes(bytes); | |||||
- mappings.add(mapping); | |||||
+ sidMappings.put(mapping.getSID(), mapping); | |||||
mappedNames.add(name); | |||||
} | |||||
- return mappings; | |||||
} | |||||
/** | |||||
@@ -215,34 +264,43 @@ | |||||
* @return -1 if the SID is missing from the Font. | |||||
* @throws IOException | |||||
*/ | |||||
- public int getWidth(int SID) throws IOException { | |||||
- int nominalWidth = privateDict.containsKey("nominalWidthX") ? ((Number)privateDict.get("nominalWidthX")).intValue() : 0; | |||||
- int defaultWidth = privateDict.containsKey("defaultWidthX") ? ((Number)privateDict.get("defaultWidthX")).intValue() : 1000 ; | |||||
- | |||||
- for (Mapping m : getMappings() ){ | |||||
- if (m.getSID() == SID) { | |||||
+ public int getWidth(int SID) throws IOException { | |||||
+ int nominalWidth = privateDict.containsKey("nominalWidthX") ? ((Number) privateDict.get("nominalWidthX")).intValue() : 0; | |||||
+ int defaultWidth = privateDict.containsKey("defaultWidthX") ? ((Number) privateDict.get("defaultWidthX")).intValue() : 1000; | |||||
+ Mapping m = sidMappings.get(SID); | |||||
+ if (m != null) { | |||||
+ CharStringRenderer csr = getRendererForMapping(m); | |||||
+ // ---- If the CharString has a Width nominalWidthX must be added, | |||||
+ // otherwise it is the default width. | |||||
+ return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth; | |||||
+ } | |||||
- CharStringRenderer csr = null; | |||||
- if (((Number)getProperty("CharstringType")).intValue() == 2 ) { | |||||
- List<Object> lSeq = m.toType2Sequence(); | |||||
- csr = new CharStringRenderer(false); | |||||
- csr.render(lSeq); | |||||
- } else { | |||||
- List<Object> lSeq = m.toType1Sequence(); | |||||
- csr = new CharStringRenderer(); | |||||
- csr.render(lSeq); | |||||
- } | |||||
+ // ---- SID Width not found, return the nodef width | |||||
+ return getNotDefWidth(defaultWidth, nominalWidth); | |||||
+ } | |||||
- // ---- If the CharString has a Width nominalWidthX must be added, | |||||
- // otherwise it is the default width. | |||||
- return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth; | |||||
- } | |||||
- } | |||||
+ private CharStringRenderer getRendererForMapping(Mapping m) throws IOException { | |||||
+ CharStringRenderer csr = null; | |||||
+ if (((Number) getProperty("CharstringType")).intValue() == 2) { | |||||
+ List<Object> lSeq = m.toType2Sequence(); | |||||
+ csr = new CharStringRenderer(false); | |||||
+ csr.render(lSeq); | |||||
+ } else { | |||||
+ List<Object> lSeq = m.toType1Sequence(); | |||||
+ csr = new CharStringRenderer(); | |||||
+ csr.render(lSeq); | |||||
+ } | |||||
+ return csr; | |||||
+ } | |||||
- // ---- SID Width not found, return the nodef width | |||||
- return getNotDefWidth(defaultWidth, nominalWidth); | |||||
- } | |||||
- | |||||
+ /** | |||||
+ * Returns the witdth of the .notdef character. | |||||
+ * | |||||
+ * @param defaultWidth default width | |||||
+ * @param nominalWidth nominal width | |||||
+ * @return the calculated width for the .notdef character | |||||
+ * @throws IOException if something went wrong | |||||
+ */ | |||||
protected int getNotDefWidth(int defaultWidth, int nominalWidth) throws IOException { | |||||
CharStringRenderer csr; | |||||
byte[] glyphDesc = this.getCharStringsDict().get(".notdef"); | |||||
@@ -260,6 +318,36 @@ | |||||
return csr.getWidth() != 0 ? csr.getWidth() + nominalWidth : defaultWidth; | |||||
} | |||||
+ /** | |||||
+ * Return the Width value of the given Glyph identifier | |||||
+ * | |||||
+ * @param SID | |||||
+ * @return -1 if the SID is missing from the Font. | |||||
+ * @throws IOException | |||||
+ */ | |||||
+ public int[] getBoundingBox(int SID) throws IOException { | |||||
+ Mapping m = sidMappings.get(SID); | |||||
+ if (m != null) { | |||||
+ CharStringRenderer csr = getRendererForMapping(m); | |||||
+ return csr.getBounds(); | |||||
+ } | |||||
+ // ---- SID Width not found, return the nodef width | |||||
+ return new int[4]; | |||||
+ } | |||||
+ | |||||
+ /** | |||||
+ * Gets the name of a character from the given SID | |||||
+ * @param SID The given SID | |||||
+ * @return The name of the found character | |||||
+ */ | |||||
+ public String getNameOfCharFromCode(int SID) { | |||||
+ if (sidMappings.get(SID) != null) { | |||||
+ return sidMappings.get(SID).getName(); | |||||
+ } else { | |||||
+ return ""; | |||||
+ } | |||||
+ } | |||||
+ | |||||
/** | |||||
* Returns the CFFEncoding of the font. | |||||
* @return the encoding | |||||
@@ -336,50 +424,51 @@ | |||||
+ charStringsDict + "]"; | |||||
} | |||||
+ /** | |||||
+ * Sets the global subroutine index data. | |||||
+ * @param globalSubrIndex the IndexData object containing the global subroutines | |||||
+ */ | |||||
+ public void setGlobalSubrIndex(IndexData globalSubrIndexValue) { | |||||
+ globalSubrIndex = globalSubrIndexValue; | |||||
+ } | |||||
- /** | |||||
- * Sets the global subroutine index data. | |||||
- * @param globalSubrIndex the IndexData object containing the global subroutines | |||||
- */ | |||||
- public void setGlobalSubrIndex(IndexData globalSubrIndex) { | |||||
- this.globalSubrIndex = globalSubrIndex; | |||||
- } | |||||
+ /** | |||||
+ * Returns the global subroutine index data. | |||||
+ * @return the dictionary | |||||
+ */ | |||||
+ public IndexData getGlobalSubrIndex() | |||||
+ { | |||||
+ return globalSubrIndex; | |||||
+ } | |||||
- /** | |||||
- * Returns the global subroutine index data. | |||||
- * @return the dictionary | |||||
- */ | |||||
- public IndexData getGlobalSubrIndex() { | |||||
- return globalSubrIndex; | |||||
- } | |||||
+ /** | |||||
+ * Returns the local subroutine index data. | |||||
+ * @return the dictionary | |||||
+ */ | |||||
+ public IndexData getLocalSubrIndex() | |||||
+ { | |||||
+ return localSubrIndex; | |||||
+ } | |||||
- /** | |||||
- * Returns the local subroutine index data. | |||||
- * @return the dictionary | |||||
- */ | |||||
- public IndexData getLocalSubrIndex() { | |||||
- return localSubrIndex; | |||||
- } | |||||
+ /** | |||||
+ * Sets the local subroutine index data. | |||||
+ * @param localSubrIndexValue the IndexData object containing the local subroutines | |||||
+ */ | |||||
+ public void setLocalSubrIndex(IndexData localSubrIndexValue) { | |||||
+ localSubrIndex = localSubrIndexValue; | |||||
+ } | |||||
- /** | |||||
- * Sets the local subroutine index data. | |||||
- * @param localSubrIndex the IndexData object containing the local subroutines | |||||
- */ | |||||
- public void setLocalSubrIndex(IndexData localSubrIndex) { | |||||
- this.localSubrIndex = localSubrIndex; | |||||
- } | |||||
+ /** | |||||
+ * This class is used for the font mapping. | |||||
+ * | |||||
+ */ | |||||
+ public class Mapping | |||||
+ { | |||||
+ private int mappedCode; | |||||
+ private int mappedSID; | |||||
+ private String mappedName; | |||||
+ private byte[] mappedBytes; | |||||
- /** | |||||
- * This class is used for the font mapping. | |||||
- * | |||||
- */ | |||||
- public class Mapping | |||||
- { | |||||
- private int mappedCode; | |||||
- private int mappedSID; | |||||
- private String mappedName; | |||||
- private byte[] mappedBytes; | |||||
- | |||||
/** | |||||
* Converts the mapping into a Type1-sequence. | |||||
* @return the Type1-sequence | |||||
@@ -458,4 +547,4 @@ | |||||
this.mappedBytes = bytes; | |||||
} | |||||
} | |||||
-} | |||||
\ No newline at end of file | |||||
+} |
import org.apache.fop.util.License; | import org.apache.fop.util.License; | ||||
// CSOFF: LineLength | // CSOFF: LineLength | ||||
// CSOFF: NoWhitespaceAfter | |||||
/** | /** | ||||
* <p>Utility for generating a Java class representing bidirectional | * <p>Utility for generating a Java class representing bidirectional | ||||
sb.setLength(0); | sb.setLength(0); | ||||
out.println("private static byte[] bcL1 = {"); | out.println("private static byte[] bcL1 = {"); | ||||
for (int i = 0; i < bcL1.length; i++) { | for (int i = 0; i < bcL1.length; i++) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(","); | sb.append(","); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.setLength(0); | sb.setLength(0); | ||||
out.println("private static byte[] bcR1 = {"); | out.println("private static byte[] bcR1 = {"); | ||||
for (int i = 0; i < bcR1.length; i++) { | for (int i = 0; i < bcR1.length; i++) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(","); | sb.append(","); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.setLength(0); | sb.setLength(0); | ||||
out.println("private static int[] bcS1 = {"); | out.println("private static int[] bcS1 = {"); | ||||
for (int i = 0; i < bcS1.length; i++) { | for (int i = 0; i < bcS1.length; i++) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(","); | sb.append(","); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.setLength(0); | sb.setLength(0); | ||||
out.println("private static int[] bcE1 = {"); | out.println("private static int[] bcE1 = {"); | ||||
for (int i = 0; i < bcE1.length; i++) { | for (int i = 0; i < bcE1.length; i++) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(","); | sb.append(","); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.setLength(0); | sb.setLength(0); | ||||
out.println("private static byte[] bcC1 = {"); | out.println("private static byte[] bcC1 = {"); | ||||
for (int i = 0; i < bcC1.length; i++) { | for (int i = 0; i < bcC1.length; i++) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(","); | sb.append(","); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
if (k >= 0) { | if (k >= 0) { | ||||
return ca [ k ]; | return ca [ k ]; | ||||
} else { | } else { | ||||
k = - (k + 1); | |||||
k = -(k + 1); | |||||
if (k == 0) { | if (k == 0) { | ||||
return BidiConstants.L; | return BidiConstants.L; | ||||
} else if (ch <= ea [ k - 1 ]) { | } else if (ch <= ea [ k - 1 ]) { |
import org.apache.fop.util.License; | import org.apache.fop.util.License; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
// CSOFF: EmptyForIteratorPadCheck | |||||
/** | /** | ||||
* <p>Utility for generating a Java class and associated data files representing | * <p>Utility for generating a Java class and associated data files representing | ||||
String ucName = sa[1]; | String ucName = sa[1]; | ||||
if (isBlockStart(ucName)) { | if (isBlockStart(ucName)) { | ||||
String ucBlock = getBlockName(ucName); | String ucBlock = getBlockName(ucName); | ||||
if (! im.containsKey(ucBlock)) { | |||||
if (!im.containsKey(ucBlock)) { | |||||
im.put(ucBlock, new int[] { uc, -1, bc }); | im.put(ucBlock, new int[] { uc, -1, bc }); | ||||
} else { | } else { | ||||
throw new IllegalArgumentException("duplicate start of block '" + ucBlock + "' at entry: " + line); | throw new IllegalArgumentException("duplicate start of block '" + ucBlock + "' at entry: " + line); | ||||
} else { | } else { | ||||
Integer k = Integer.valueOf(bc); | Integer k = Integer.valueOf(bc); | ||||
List sl; | List sl; | ||||
if (! sm.containsKey(k)) { | |||||
if (!sm.containsKey(k)) { | |||||
sl = new ArrayList(); | sl = new ArrayList(); | ||||
sm.put(k, sl); | sm.put(k, sl); | ||||
} else { | } else { | ||||
} | } | ||||
} | } | ||||
// populate intervals from (block) interval map | // populate intervals from (block) interval map | ||||
if (! im.isEmpty()) { | |||||
if (!im.isEmpty()) { | |||||
for (Iterator it = im.values().iterator(); it.hasNext(); ) { | for (Iterator it = im.values().iterator(); it.hasNext(); ) { | ||||
int[] ba = (int[]) it.next(); | int[] ba = (int[]) it.next(); | ||||
assert (ba != null) && (ba.length > 2); | assert (ba != null) && (ba.length > 2); | ||||
continue; | continue; | ||||
} else if (line.startsWith("#")) { | } else if (line.startsWith("#")) { | ||||
continue; | continue; | ||||
} else if (line.startsWith(PFX_TYPE) && ! ignoreDeprecatedTypeData) { | |||||
} else if (line.startsWith(PFX_TYPE) && !ignoreDeprecatedTypeData) { | |||||
List lines = new ArrayList(); | List lines = new ArrayList(); | ||||
if ((n = readType(line, b, lines)) < 0) { | if ((n = readType(line, b, lines)) < 0) { | ||||
break; | break; | ||||
// dump instrumentation | // dump instrumentation | ||||
if (verbose) { | if (verbose) { | ||||
System.out.println(); | System.out.println(); | ||||
if (! ignoreDeprecatedTypeData) { | |||||
if (!ignoreDeprecatedTypeData) { | |||||
System.out.println("Read type ranges : " + numTypeRanges); | System.out.println("Read type ranges : " + numTypeRanges); | ||||
} | } | ||||
System.out.println("Read level specs : " + numLevelSpecs); | System.out.println("Read level specs : " + numLevelSpecs); | ||||
System.out.println("Read test specs : " + numTestSpecs); | System.out.println("Read test specs : " + numTestSpecs); | ||||
System.out.println("Read lines : " + lineNumber); | System.out.println("Read lines : " + lineNumber); | ||||
} | } | ||||
if (! ignoreDeprecatedTypeData) { | |||||
if (!ignoreDeprecatedTypeData) { | |||||
td = (int[][]) tdl.toArray(new int [ tdl.size() ] []); | td = (int[][]) tdl.toArray(new int [ tdl.size() ] []); | ||||
} | } | ||||
ld = (int[][]) ldl.toArray(new int [ ldl.size() ] []); | ld = (int[][]) ldl.toArray(new int [ ldl.size() ] []); | ||||
boolean done = false; | boolean done = false; | ||||
int n = 0; | int n = 0; | ||||
lines.add(line); | lines.add(line); | ||||
while (! done) { | |||||
while (!done) { | |||||
switch (testPrefix(b, PFX_LEVELS)) { | switch (testPrefix(b, PFX_LEVELS)) { | ||||
case 0: // within current levels | case 0: // within current levels | ||||
if ((line = b.readLine()) != null) { | if ((line = b.readLine()) != null) { | ||||
n++; | n++; | ||||
if ((line.length() > 0) && ! line.startsWith("#")) { | |||||
if ((line.length() > 0) && !line.startsWith("#")) { | |||||
lines.add(line); | lines.add(line); | ||||
} | } | ||||
} else { | } else { | ||||
CharacterIterator ci = new StringCharacterIterator(charRanges); | CharacterIterator ci = new StringCharacterIterator(charRanges); | ||||
// read initial list delimiter | // read initial list delimiter | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if (! readStartOfList(ci)) { | |||||
if (!readStartOfList(ci)) { | |||||
badRangeSpec("missing initial list delimiter", charRanges); | badRangeSpec("missing initial list delimiter", charRanges); | ||||
} | } | ||||
// read negation token if present | // read negation token if present | ||||
String s; | String s; | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if ((s = maybeReadSeparator(ci)) != null) { | if ((s = maybeReadSeparator(ci)) != null) { | ||||
if ((s.length() != 0) && ! s.equals("||")) { | |||||
if ((s.length() != 0) && !s.equals("||")) { | |||||
badRangeSpec("invalid item separator \"" + s + "\"", charRanges); | badRangeSpec("invalid item separator \"" + s + "\"", charRanges); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// read terminating list delimiter | // read terminating list delimiter | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if (! readEndOfList(ci)) { | |||||
if (!readEndOfList(ci)) { | |||||
badRangeSpec("missing terminating list delimiter", charRanges); | badRangeSpec("missing terminating list delimiter", charRanges); | ||||
} | } | ||||
if (! atEnd(ci)) { | |||||
if (!atEnd(ci)) { | |||||
badRangeSpec("extraneous content prior to end of line", ci); | badRangeSpec("extraneous content prior to end of line", ci); | ||||
} | } | ||||
if (negated) { | if (negated) { | ||||
} | } | ||||
private static void skipSpace(CharacterIterator ci) { | private static void skipSpace(CharacterIterator ci) { | ||||
while (! atEnd(ci)) { | |||||
while (!atEnd(ci)) { | |||||
char c = ci.current(); | char c = ci.current(); | ||||
if (! Character.isWhitespace(c)) { | |||||
if (!Character.isWhitespace(c)) { | |||||
break; | break; | ||||
} else { | } else { | ||||
ci.next(); | ci.next(); | ||||
} | } | ||||
private static boolean maybeReadNext(CharacterIterator ci, char next) { | private static boolean maybeReadNext(CharacterIterator ci, char next) { | ||||
while (! atEnd(ci)) { | |||||
while (!atEnd(ci)) { | |||||
char c = ci.current(); | char c = ci.current(); | ||||
if (c == next) { | if (c == next) { | ||||
ci.next(); | ci.next(); | ||||
List ll = new ArrayList(); | List ll = new ArrayList(); | ||||
// read prefix | // read prefix | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if (! maybeReadToken(ci, PFX_LEVELS)) { | |||||
if (!maybeReadToken(ci, PFX_LEVELS)) { | |||||
badLevelSpec("missing prefix \"" + PFX_LEVELS + "\"", ci); | badLevelSpec("missing prefix \"" + PFX_LEVELS + "\"", ci); | ||||
} | } | ||||
// read level values | // read level values | ||||
} | } | ||||
// read to end of line | // read to end of line | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if (! atEnd(ci)) { | |||||
if (!atEnd(ci)) { | |||||
badLevelSpec("extraneous content prior to end of line", ci); | badLevelSpec("extraneous content prior to end of line", ci); | ||||
} | } | ||||
if (ll.size() == 0) { | if (ll.size() == 0) { | ||||
List rl = new ArrayList(); | List rl = new ArrayList(); | ||||
// read prefix | // read prefix | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if (! maybeReadToken(ci, PFX_REORDER)) { | |||||
if (!maybeReadToken(ci, PFX_REORDER)) { | |||||
badReorderSpec("missing prefix \"" + PFX_REORDER + "\"", ci); | badReorderSpec("missing prefix \"" + PFX_REORDER + "\"", ci); | ||||
} | } | ||||
// read reorder values | // read reorder values | ||||
} | } | ||||
// read to end of line | // read to end of line | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if (! atEnd(ci)) { | |||||
if (!atEnd(ci)) { | |||||
badReorderSpec("extraneous content prior to end of line", ci); | badReorderSpec("extraneous content prior to end of line", ci); | ||||
} | } | ||||
return createReorderArray(rl, levels); | return createReorderArray(rl, levels); | ||||
CharacterIterator ci = new StringCharacterIterator(line); | CharacterIterator ci = new StringCharacterIterator(line); | ||||
List cl = new ArrayList(); | List cl = new ArrayList(); | ||||
// read bidi class identifier sequence | // read bidi class identifier sequence | ||||
while (! atEnd(ci) && ! maybeReadNext(ci, ';')) { | |||||
while (!atEnd(ci) && !maybeReadNext(ci, ';')) { | |||||
skipSpace(ci); | skipSpace(ci); | ||||
int bc; | int bc; | ||||
if ((bc = maybeReadBidiClass(ci)) >= 0) { | if ((bc = maybeReadBidiClass(ci)) >= 0) { | ||||
} | } | ||||
// read to end of line | // read to end of line | ||||
skipSpace(ci); | skipSpace(ci); | ||||
if (! atEnd(ci)) { | |||||
if (!atEnd(ci)) { | |||||
badTestSpec("extraneous content prior to end of line", ci); | badTestSpec("extraneous content prior to end of line", ci); | ||||
} | } | ||||
return createTestArray(cl, bs, levels); | return createTestArray(cl, bs, levels); | ||||
ok = false; | ok = false; | ||||
} | } | ||||
} | } | ||||
if (! ok) { | |||||
if (!ok) { | |||||
System.out.println("Usage: GenerateBidiTestData [-v] [-i] [-d <ucdFile>] [-b <bidiFile>] [-o <outputFile>]"); | System.out.println("Usage: GenerateBidiTestData [-v] [-i] [-d <ucdFile>] [-b <bidiFile>] [-o <outputFile>]"); | ||||
System.out.println(" defaults:"); | System.out.println(" defaults:"); | ||||
if (ignoreDeprecatedTypeData) { | if (ignoreDeprecatedTypeData) { |
<xs:complexContent> | <xs:complexContent> | ||||
<xs:extension base="mf:contentType"> | <xs:extension base="mf:contentType"> | ||||
<xs:attribute name="transform" type="xs:string"/> | <xs:attribute name="transform" type="xs:string"/> | ||||
<xs:attribute name="layer" type="xs:string"/> | |||||
</xs:extension> | </xs:extension> | ||||
</xs:complexContent> | </xs:complexContent> | ||||
</xs:complexType> | </xs:complexType> |
org.apache.fop.render.afp.extensions.AFPExtensionHandlerFactory | org.apache.fop.render.afp.extensions.AFPExtensionHandlerFactory | ||||
org.apache.fop.render.pdf.extensions.PDFExtensionHandlerFactory | |||||
org.apache.fop.render.ps.extensions.PSExtensionHandlerFactory | org.apache.fop.render.ps.extensions.PSExtensionHandlerFactory | ||||
org.apache.fop.fo.extensions.xmp.XMPContentHandlerFactory | org.apache.fop.fo.extensions.xmp.XMPContentHandlerFactory |
} | } | ||||
if (version == null) { | if (version == null) { | ||||
//Fallback if FOP is used in a development environment | //Fallback if FOP is used in a development environment | ||||
String headURL | |||||
= "$HeadURL$"; | |||||
// CSOFF: LineLength | |||||
String headURL = "$HeadURL$"; | |||||
// CSON: LineLength | |||||
version = headURL; | version = headURL; | ||||
final String pathPrefix = "/xmlgraphics/fop/"; | final String pathPrefix = "/xmlgraphics/fop/"; | ||||
int pos = version.indexOf(pathPrefix); | int pos = version.indexOf(pathPrefix); |
try { | try { | ||||
// Have to do this so we can resolve data URIs | // Have to do this so we can resolve data URIs | ||||
StreamSource src = new StreamSource(resourceResolver.getResource(uri)); | StreamSource src = new StreamSource(resourceResolver.getResource(uri)); | ||||
src.setSystemId(uri); | |||||
src.setSystemId(new File(uri).toURI().toURL().toExternalForm()); | |||||
return src; | return src; | ||||
} catch (URISyntaxException use) { | } catch (URISyntaxException use) { | ||||
return null; | return null; |
*/ | */ | ||||
public FopConfParser(InputStream fopConfStream, EnvironmentProfile enviro) | public FopConfParser(InputStream fopConfStream, EnvironmentProfile enviro) | ||||
throws SAXException, IOException { | throws SAXException, IOException { | ||||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); | |||||
Configuration cfg; | |||||
try { | |||||
cfg = cfgBuilder.build(fopConfStream); | |||||
} catch (ConfigurationException e) { | |||||
throw new FOPException(e); | |||||
} | |||||
// The default base URI is taken from the directory in which the fopConf resides | |||||
fopFactoryBuilder = new FopFactoryBuilder(enviro).setConfiguration(cfg); | |||||
configure(enviro.getDefaultBaseURI(), enviro.getResourceResolver(), cfg); | |||||
this(fopConfStream, enviro.getDefaultBaseURI(), enviro); | |||||
} | } | ||||
/** | /** | ||||
*/ | */ | ||||
public FopConfParser(InputStream fopConfStream, URI defaultBaseURI, | public FopConfParser(InputStream fopConfStream, URI defaultBaseURI, | ||||
ResourceResolver resourceResolver) throws SAXException, IOException { | ResourceResolver resourceResolver) throws SAXException, IOException { | ||||
this(fopConfStream, EnvironmentalProfileFactory.createDefault(defaultBaseURI, resourceResolver)); | |||||
this(fopConfStream, defaultBaseURI, | |||||
EnvironmentalProfileFactory.createDefault(defaultBaseURI, resourceResolver)); | |||||
} | } | ||||
/** | /** | ||||
this(fopConfFile, ResourceResolverFactory.createDefaultResourceResolver()); | this(fopConfFile, ResourceResolverFactory.createDefaultResourceResolver()); | ||||
} | } | ||||
/** | |||||
* Constructor that takes the FOP conf and a default base URI and uses the default URI resolver. | |||||
* | |||||
* @param fopConfFile the FOP conf file | |||||
* @param defaultBaseURI the default base URI | |||||
* @throws SAXException if a SAX error was thrown parsing the FOP conf | |||||
* @throws IOException if an I/O error is thrown while parsing the FOP conf | |||||
*/ | |||||
public FopConfParser(File fopConfFile, URI defaultBaseURI) throws SAXException, IOException { | |||||
this(new FileInputStream(fopConfFile), fopConfFile.toURI(), | |||||
EnvironmentalProfileFactory.createDefault(defaultBaseURI, | |||||
ResourceResolverFactory.createDefaultResourceResolver())); | |||||
} | |||||
/** | /** | ||||
* Constructor that parses the FOP conf and uses the URI resolver given. | * Constructor that parses the FOP conf and uses the URI resolver given. | ||||
* | * | ||||
*/ | */ | ||||
public FopConfParser(File fopConfFile, ResourceResolver resourceResolver) | public FopConfParser(File fopConfFile, ResourceResolver resourceResolver) | ||||
throws SAXException, IOException { | throws SAXException, IOException { | ||||
this(new FileInputStream(fopConfFile), | |||||
fopConfFile.getAbsoluteFile().getParentFile().toURI(), resourceResolver); | |||||
this(new FileInputStream(fopConfFile), fopConfFile.toURI(), resourceResolver); | |||||
} | |||||
private FopConfParser(InputStream fopConfStream, URI baseURI, EnvironmentProfile enviro) | |||||
throws SAXException, IOException { | |||||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); | |||||
Configuration cfg; | |||||
try { | |||||
cfg = cfgBuilder.build(fopConfStream); | |||||
} catch (ConfigurationException e) { | |||||
throw new FOPException(e); | |||||
} | |||||
// The default base URI is taken from the directory in which the fopConf resides | |||||
fopFactoryBuilder = new FopFactoryBuilder(enviro).setConfiguration(cfg); | |||||
configure(baseURI, enviro.getResourceResolver(), cfg); | |||||
} | } | ||||
private void configure(final URI defaultBaseURI, final ResourceResolver resourceResolver, | |||||
private void configure(final URI baseURI, final ResourceResolver resourceResolver, | |||||
Configuration cfg) throws FOPException { | Configuration cfg) throws FOPException { | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug("Initializing FopFactory Configuration"); | log.debug("Initializing FopFactory Configuration"); | ||||
if (cfg.getChild("base", false) != null) { | if (cfg.getChild("base", false) != null) { | ||||
try { | try { | ||||
URI confUri = InternalResourceResolver.getBaseURI(cfg.getChild("base").getValue(null)); | URI confUri = InternalResourceResolver.getBaseURI(cfg.getChild("base").getValue(null)); | ||||
fopFactoryBuilder.setBaseURI(defaultBaseURI.resolve(confUri)); | |||||
fopFactoryBuilder.setBaseURI(baseURI.resolve(confUri)); | |||||
} catch (URISyntaxException use) { | } catch (URISyntaxException use) { | ||||
LogUtil.handleException(log, use, strict); | LogUtil.handleException(log, use, strict); | ||||
} | } | ||||
} | } | ||||
// configure font manager | // configure font manager | ||||
new FontManagerConfigurator(cfg, fopFactoryBuilder.getBaseURI(), resourceResolver).configure( | |||||
fopFactoryBuilder.getFontManager(), strict); | |||||
new FontManagerConfigurator(cfg, baseURI, fopFactoryBuilder.getBaseURI(), resourceResolver) | |||||
.configure(fopFactoryBuilder.getFontManager(), strict); | |||||
// configure image loader framework | // configure image loader framework | ||||
configureImageLoading(cfg.getChild("image-loading", false), strict); | configureImageLoading(cfg.getChild("image-loading", false), strict); |
import org.apache.fop.area.Trait.Background; | import org.apache.fop.area.Trait.Background; | ||||
import org.apache.fop.area.Trait.InternalLink; | import org.apache.fop.area.Trait.InternalLink; | ||||
import org.apache.fop.area.inline.AbstractTextArea; | import org.apache.fop.area.inline.AbstractTextArea; | ||||
import org.apache.fop.area.inline.Container; | |||||
import org.apache.fop.area.inline.ForeignObject; | import org.apache.fop.area.inline.ForeignObject; | ||||
import org.apache.fop.area.inline.Image; | import org.apache.fop.area.inline.Image; | ||||
import org.apache.fop.area.inline.InlineArea; | import org.apache.fop.area.inline.InlineArea; | ||||
makers.put("space", new SpaceMaker()); | makers.put("space", new SpaceMaker()); | ||||
makers.put("leader", new LeaderMaker()); | makers.put("leader", new LeaderMaker()); | ||||
makers.put("viewport", new InlineViewportMaker()); | makers.put("viewport", new InlineViewportMaker()); | ||||
makers.put("container", new ContainerMaker()); | |||||
makers.put("image", new ImageMaker()); | makers.put("image", new ImageMaker()); | ||||
makers.put("foreignObject", new ForeignObjectMaker()); | makers.put("foreignObject", new ForeignObjectMaker()); | ||||
makers.put("bookmarkTree", new BookmarkTreeMaker()); | makers.put("bookmarkTree", new BookmarkTreeMaker()); | ||||
} | } | ||||
} | } | ||||
private class ContainerMaker extends AbstractMaker { | |||||
public void startElement(Attributes attributes) { | |||||
Container container = new Container(); | |||||
transferForeignObjects(attributes, container); | |||||
InlineViewport parent = (InlineViewport) areaStack.peek(); | |||||
parent.setContent(container); | |||||
areaStack.push(container); | |||||
} | |||||
public void endElement() { | |||||
assertObjectOfClass(areaStack.pop(), Container.class); | |||||
} | |||||
} | |||||
private class InlineViewportMaker extends AbstractMaker { | private class InlineViewportMaker extends AbstractMaker { | ||||
public void startElement(Attributes attributes) { | public void startElement(Attributes attributes) { | ||||
} | } | ||||
private static final Object[] SUBSET_COMMON = new Object[] { | private static final Object[] SUBSET_COMMON = new Object[] { | ||||
Trait.PROD_ID}; | |||||
Trait.PROD_ID, Trait.LAYER}; | |||||
private static final Object[] SUBSET_LINK = new Object[] { | private static final Object[] SUBSET_LINK = new Object[] { | ||||
Trait.INTERNAL_LINK, Trait.EXTERNAL_LINK}; | Trait.INTERNAL_LINK, Trait.EXTERNAL_LINK}; | ||||
private static final Object[] SUBSET_COLOR = new Object[] { | private static final Object[] SUBSET_COLOR = new Object[] { |
@Override | @Override | ||||
public void addBlock(Block child) { | public void addBlock(Block child) { | ||||
addChildArea(child); | addChildArea(child); | ||||
this.setBPD(this.getBPD() + child.getBPD()); | |||||
setBPD(getBPD() + child.getAllocBPD()); | |||||
} | } | ||||
} | } |
/** shift direction trait */ | /** shift direction trait */ | ||||
public static final Integer SHIFT_DIRECTION = 42; | public static final Integer SHIFT_DIRECTION = 42; | ||||
/** For optional content groups. */ | |||||
public static final Integer LAYER = 43; | |||||
/** Maximum value used by trait keys */ | /** Maximum value used by trait keys */ | ||||
public static final int MAX_TRAIT_KEY = 42; | |||||
public static final int MAX_TRAIT_KEY = 43; | |||||
private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY + 1]; | private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY + 1]; | ||||
new TraitInfo("block-progression-direction", Direction.class)); | new TraitInfo("block-progression-direction", Direction.class)); | ||||
put(SHIFT_DIRECTION, | put(SHIFT_DIRECTION, | ||||
new TraitInfo("shift-direction", Direction.class)); | new TraitInfo("shift-direction", Direction.class)); | ||||
put(LAYER, new TraitInfo("layer", String.class)); | |||||
} | } | ||||
public Container() { | public Container() { | ||||
} | } | ||||
/** | |||||
* Add the block to this area. | |||||
* | |||||
* @param block the block area to add | |||||
*/ | |||||
public void addBlock(Block block) { | |||||
blocks.add(block); | |||||
@Override | |||||
public void addChildArea(Area child) { | |||||
if (!(child instanceof Block)) { | |||||
throw new IllegalArgumentException("Container only accepts block areas"); | |||||
} | |||||
blocks.add((Block) child); | |||||
} | } | ||||
/** | /** | ||||
* | * | ||||
* @return the list of block areas | * @return the list of block areas | ||||
*/ | */ | ||||
public List getBlocks() { | |||||
public List<Block> getBlocks() { | |||||
return blocks; | return blocks; | ||||
} | } | ||||
import org.apache.fop.render.print.PagesMode; | import org.apache.fop.render.print.PagesMode; | ||||
import org.apache.fop.render.print.PrintRenderer; | import org.apache.fop.render.print.PrintRenderer; | ||||
import org.apache.fop.render.xml.XMLRenderer; | import org.apache.fop.render.xml.XMLRenderer; | ||||
import org.apache.fop.util.CommandLineLogger; | |||||
/** | /** | ||||
* Options parses the commandline arguments | * Options parses the commandline arguments | ||||
* Construct a command line option object. | * Construct a command line option object. | ||||
*/ | */ | ||||
public CommandLineOptions() { | public CommandLineOptions() { | ||||
LogFactory logFactory = LogFactory.getFactory(); | |||||
// Enable the simple command line logging when no other logger is | |||||
// defined. | |||||
if (System.getProperty("org.apache.commons.logging.Log") == null) { | |||||
logFactory.setAttribute("org.apache.commons.logging.Log", | |||||
CommandLineLogger.class.getName()); | |||||
setLogLevel("info"); | |||||
} | |||||
log = LogFactory.getLog("FOP"); | log = LogFactory.getLog("FOP"); | ||||
} | } | ||||
//Factory config is set up, now we can create the user agent | //Factory config is set up, now we can create the user agent | ||||
foUserAgent = factory.newFOUserAgent(); | foUserAgent = factory.newFOUserAgent(); | ||||
foUserAgent.getRendererOptions().putAll(renderingOptions); | foUserAgent.getRendererOptions().putAll(renderingOptions); | ||||
if (targetResolution != 0) { | |||||
foUserAgent.setTargetResolution(targetResolution); | |||||
} | |||||
addXSLTParameter("fop-output-format", getOutputFormat()); | addXSLTParameter("fop-output-format", getOutputFormat()); | ||||
addXSLTParameter("fop-version", Version.getVersion()); | addXSLTParameter("fop-version", Version.getVersion()); | ||||
foUserAgent.setConserveMemoryPolicy(conserveMemoryPolicy); | foUserAgent.setConserveMemoryPolicy(conserveMemoryPolicy); | ||||
} else if (args[i].equals("-s")) { | } else if (args[i].equals("-s")) { | ||||
suppressLowLevelAreas = Boolean.TRUE; | suppressLowLevelAreas = Boolean.TRUE; | ||||
} else if (args[i].equals("-d")) { | } else if (args[i].equals("-d")) { | ||||
setLogOption("debug", "debug"); | |||||
// nop. Left there for backwards compatibility | |||||
} else if (args[i].equals("-r")) { | } else if (args[i].equals("-r")) { | ||||
strictValidation = false; | strictValidation = false; | ||||
} else if (args[i].equals("-conserve")) { | } else if (args[i].equals("-conserve")) { | ||||
} else if (args[i].equals("-dpi")) { | } else if (args[i].equals("-dpi")) { | ||||
i = i + parseResolution(args, i); | i = i + parseResolution(args, i); | ||||
} else if (args[i].equals("-q") || args[i].equals("--quiet")) { | } else if (args[i].equals("-q") || args[i].equals("--quiet")) { | ||||
setLogOption("quiet", "error"); | |||||
// nop. Left there for backwards compatibility | |||||
} else if (args[i].equals("-fo")) { | } else if (args[i].equals("-fo")) { | ||||
i = i + parseFOInputOption(args, i); | i = i + parseFOInputOption(args, i); | ||||
} else if (args[i].equals("-xsl")) { | } else if (args[i].equals("-xsl")) { | ||||
} | } | ||||
} | } | ||||
private void setLogOption(String option, String level) { | |||||
if (log instanceof CommandLineLogger | |||||
|| System.getProperty("org.apache.commons.logging.Log") == null) { | |||||
setLogLevel(level); | |||||
} else if (log != null) { | |||||
log.warn("The option " + option + " can only be used"); | |||||
log.warn("with FOP's command line logger,"); | |||||
log.warn("which is the default on the command line."); | |||||
log.warn("Configure other loggers using Java system properties."); | |||||
} | |||||
} | |||||
private void setLogLevel(String level) { | |||||
// Set the level for future loggers. | |||||
LogFactory.getFactory().setAttribute("level", level); | |||||
if (log instanceof CommandLineLogger) { | |||||
// Set the level for the logger created already. | |||||
((CommandLineLogger) log).setLogLevel(level); | |||||
} | |||||
} | |||||
private void setInputFormat(int format) throws FOPException { | private void setInputFormat(int format) throws FOPException { | ||||
if (inputmode == NOT_SET || inputmode == format) { | if (inputmode == NOT_SET || inputmode == format) { | ||||
inputmode = format; | inputmode = format; | ||||
fopFactoryBuilder.setComplexScriptFeatures(useComplexScriptFeatures); | fopFactoryBuilder.setComplexScriptFeatures(useComplexScriptFeatures); | ||||
} else { | } else { | ||||
try { | try { | ||||
fopFactoryBuilder = new FopConfParser(userConfigFile).getFopFactoryBuilder(); | |||||
FopConfParser fopConfParser = new FopConfParser(userConfigFile, baseURI); | |||||
fopFactoryBuilder = fopConfParser.getFopFactoryBuilder(); | |||||
} catch (SAXException e) { | } catch (SAXException e) { | ||||
throw new FOPException(e); | throw new FOPException(e); | ||||
} | } | ||||
+ "[-awt|-pdf|-mif|-rtf|-tiff|-png|-pcl|-ps|-txt|-at [mime]|-print] <outfile>\n" | + "[-awt|-pdf|-mif|-rtf|-tiff|-png|-pcl|-ps|-txt|-at [mime]|-print] <outfile>\n" | ||||
+ " [OPTIONS] \n" | + " [OPTIONS] \n" | ||||
+ " -version print FOP version and exit\n" | + " -version print FOP version and exit\n" | ||||
+ " -d debug mode \n" | |||||
+ " -x dump configuration settings \n" | + " -x dump configuration settings \n" | ||||
+ " -q quiet mode \n" | |||||
+ " -c cfg.xml use additional configuration file cfg.xml\n" | + " -c cfg.xml use additional configuration file cfg.xml\n" | ||||
+ " -l lang the language to use for user information \n" | + " -l lang the language to use for user information \n" | ||||
+ " -nocs disable complex script features\n" | + " -nocs disable complex script features\n" |
import java.util.Arrays; | import java.util.Arrays; | ||||
// CSOFF: WhitespaceAfterCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/* | /* |
import org.apache.fop.area.inline.InlineArea; | import org.apache.fop.area.inline.InlineArea; | ||||
import org.apache.fop.fo.pagination.PageSequence; | import org.apache.fop.fo.pagination.PageSequence; | ||||
// CSOFF: EmptyForIteratorPadCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
/** | /** | ||||
* <p>A utility class for performing bidirectional resolution processing.</p> | * <p>A utility class for performing bidirectional resolution processing.</p> | ||||
runsNew.addAll(ir.split()); | runsNew.addAll(ir.split()); | ||||
} | } | ||||
} | } | ||||
if (! runsNew.equals(runs)) { | |||||
if (!runsNew.equals(runs)) { | |||||
runs = runsNew; | runs = runsNew; | ||||
} | } | ||||
return runs; | return runs; | ||||
i = e - 1; | i = e - 1; | ||||
} | } | ||||
} | } | ||||
if (! runsNew.equals(runs)) { | |||||
if (!runsNew.equals(runs)) { | |||||
runs = runsNew; | runs = runsNew; | ||||
} | } | ||||
return runs; | return runs; | ||||
Vector rv = new Vector(); | Vector rv = new Vector(); | ||||
for (Iterator it = ranges.iterator(); it.hasNext(); ) { | for (Iterator it = ranges.iterator(); it.hasNext(); ) { | ||||
DelimitedTextRange r = (DelimitedTextRange) it.next(); | DelimitedTextRange r = (DelimitedTextRange) it.next(); | ||||
if (! r.isEmpty()) { | |||||
if (!r.isEmpty()) { | |||||
rv.add(r); | rv.add(r); | ||||
} | } | ||||
} | } |
import org.apache.fop.traits.WritingModeTraitsGetter; | import org.apache.fop.traits.WritingModeTraitsGetter; | ||||
import org.apache.fop.util.CharUtilities; | import org.apache.fop.util.CharUtilities; | ||||
// CSOFF: EmptyForIteratorPadCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* The <code>DelimitedTextRange</code> class implements the "delimited text range" as described | * The <code>DelimitedTextRange</code> class implements the "delimited text range" as described | ||||
TextInterval ti = (TextInterval) it.next(); | TextInterval ti = (TextInterval) it.next(); | ||||
intervalsNew.addAll(assignLevels(ti, levels)); | intervalsNew.addAll(assignLevels(ti, levels)); | ||||
} | } | ||||
if (! intervalsNew.equals(intervals)) { | |||||
if (!intervalsNew.equals(intervals)) { | |||||
intervals = intervalsNew; | intervals = intervalsNew; | ||||
} | } | ||||
} | } |
import org.apache.fop.area.inline.WordArea; | import org.apache.fop.area.inline.WordArea; | ||||
import org.apache.fop.util.CharUtilities; | import org.apache.fop.util.CharUtilities; | ||||
// CSOFF: EmptyForIteratorPadCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
/** | /** | ||||
* The <code>InlineRun</code> class is a utility class, the instances of which are used | * The <code>InlineRun</code> class is a utility class, the instances of which are used | ||||
* to capture a sequence of reordering levels associated with an inline area. | * to capture a sequence of reordering levels associated with an inline area. | ||||
if (inline instanceof WordArea) { | if (inline instanceof WordArea) { | ||||
WordArea w = (WordArea) inline; | WordArea w = (WordArea) inline; | ||||
// if not already reversed, then reverse now | // if not already reversed, then reverse now | ||||
if (! w.isReversed()) { | |||||
if (!w.isReversed()) { | |||||
if ((reversals & 1) != 0) { | if ((reversals & 1) != 0) { | ||||
w.reverse(mirror); | w.reverse(mirror); | ||||
} else if (mirror && maybeNeedsMirroring()) { | } else if (mirror && maybeNeedsMirroring()) { | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
} else if ((ir.levels == null) && (levels == null)) { | |||||
return true; | |||||
} else { | } else { | ||||
return false; | |||||
return (ir.levels == null) && (levels == null); | |||||
} | } | ||||
} else { | } else { | ||||
return false; | return false; |
import org.apache.fop.fo.flow.Leader; | import org.apache.fop.fo.flow.Leader; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
/** | /** | ||||
* <p>The <code>TextInterval</code> class is a utility class, the instances of which are used | * <p>The <code>TextInterval</code> class is a utility class, the instances of which are used | ||||
return false; | return false; | ||||
} else if (ti.getStart() != start) { | } else if (ti.getStart() != start) { | ||||
return false; | return false; | ||||
} else if (ti.getEnd() != end) { | |||||
return false; | |||||
} else { | } else { | ||||
return true; | |||||
return ti.getEnd() == end; | |||||
} | } | ||||
} else { | } else { | ||||
return false; | return false; |
import org.apache.fop.area.inline.TextArea; | import org.apache.fop.area.inline.TextArea; | ||||
import org.apache.fop.area.inline.UnresolvedPageNumber; | import org.apache.fop.area.inline.UnresolvedPageNumber; | ||||
// CSOFF: EmptyForIteratorPadCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
/** | /** | ||||
* <p>The <code>UnflattenProcessor</code> class is used to reconstruct (by unflattening) a line | * <p>The <code>UnflattenProcessor</code> class is used to reconstruct (by unflattening) a line | ||||
private boolean shouldFinishTextContainer(TextArea tc, InlineArea ia) { | private boolean shouldFinishTextContainer(TextArea tc, InlineArea ia) { | ||||
if ((tcOrig != null) && (tc != tcOrig)) { | if ((tcOrig != null) && (tc != tcOrig)) { | ||||
return true; | return true; | ||||
} else if ((iaLevelLast != -1) && (ia.getBidiLevel() != iaLevelLast)) { | |||||
return true; | |||||
} else { | } else { | ||||
return false; | |||||
return (iaLevelLast != -1) && (ia.getBidiLevel() != iaLevelLast); | |||||
} | } | ||||
} | } | ||||
private void finishTextContainer() { | private void finishTextContainer() { | ||||
private void finishTextContainer(TextArea tc, InlineArea ia) { | private void finishTextContainer(TextArea tc, InlineArea ia) { | ||||
if (tcNew != null) { | if (tcNew != null) { | ||||
updateIPD(tcNew); | updateIPD(tcNew); | ||||
if (! icNew.empty()) { | |||||
if (!icNew.empty()) { | |||||
icNew.peek().addChildArea(tcNew); | icNew.peek().addChildArea(tcNew); | ||||
} else { | } else { | ||||
ilNew.add(tcNew); | ilNew.add(tcNew); | ||||
} | } | ||||
private boolean shouldFinishInlineContainer(List<InlineParent> ich, TextArea tc, InlineArea ia) { | private boolean shouldFinishInlineContainer(List<InlineParent> ich, TextArea tc, InlineArea ia) { | ||||
if ((ich == null) || ich.isEmpty()) { | if ((ich == null) || ich.isEmpty()) { | ||||
return ! icOrig.empty(); | |||||
return !icOrig.empty(); | |||||
} else { | } else { | ||||
if (! icOrig.empty()) { | |||||
if (!icOrig.empty()) { | |||||
InlineParent ic = ich.get(0); | InlineParent ic = ich.get(0); | ||||
InlineParent ic0 = icOrig.peek(); | InlineParent ic0 = icOrig.peek(); | ||||
return (ic != ic0) && ! isInlineParentOf(ic, ic0); | |||||
return (ic != ic0) && !isInlineParentOf(ic, ic0); | |||||
} else { | } else { | ||||
return false; | return false; | ||||
} | } | ||||
finishInlineContainer(null, null, null); | finishInlineContainer(null, null, null); | ||||
} | } | ||||
private void finishInlineContainer(List<InlineParent> ich, TextArea tc, InlineArea ia) { | private void finishInlineContainer(List<InlineParent> ich, TextArea tc, InlineArea ia) { | ||||
if ((ich != null) && ! ich.isEmpty()) { // finish non-matching inner inline container(s) | |||||
if ((ich != null) && !ich.isEmpty()) { // finish non-matching inner inline container(s) | |||||
for (Iterator<InlineParent> it = ich.iterator(); it.hasNext(); ) { | for (Iterator<InlineParent> it = ich.iterator(); it.hasNext(); ) { | ||||
InlineParent ic = it.next(); | InlineParent ic = it.next(); | ||||
InlineParent ic0 = icOrig.empty() ? null : icOrig.peek(); | InlineParent ic0 = icOrig.empty() ? null : icOrig.peek(); | ||||
if (ic0 == null) { | if (ic0 == null) { | ||||
assert icNew.empty(); | assert icNew.empty(); | ||||
} else if (ic != ic0) { | } else if (ic != ic0) { | ||||
assert ! icNew.empty(); | |||||
assert !icNew.empty(); | |||||
InlineParent icO0 = icOrig.pop(); | InlineParent icO0 = icOrig.pop(); | ||||
InlineParent icN0 = icNew.pop(); | InlineParent icN0 = icNew.pop(); | ||||
assert icO0 != null; | assert icO0 != null; | ||||
} else { | } else { | ||||
icNew.peek().addChildArea(icN0); | icNew.peek().addChildArea(icN0); | ||||
} | } | ||||
if (! icOrig.empty() && (icOrig.peek() == ic)) { | |||||
if (!icOrig.empty() && (icOrig.peek() == ic)) { | |||||
break; | break; | ||||
} | } | ||||
} else { | } else { | ||||
} | } | ||||
} | } | ||||
} else { // finish all inline containers | } else { // finish all inline containers | ||||
while (! icNew.empty()) { | |||||
while (!icNew.empty()) { | |||||
InlineParent icO0 = icOrig.pop(); | InlineParent icO0 = icOrig.pop(); | ||||
InlineParent icN0 = icNew.pop(); | InlineParent icN0 = icNew.pop(); | ||||
assert icO0 != null; | assert icO0 != null; | ||||
finishInlineContainer(); | finishInlineContainer(); | ||||
} | } | ||||
private void update(List<InlineParent> ich, TextArea tc, InlineArea ia) { | private void update(List<InlineParent> ich, TextArea tc, InlineArea ia) { | ||||
if (! alreadyUnflattened(ia)) { | |||||
if ((ich != null) && ! ich.isEmpty()) { | |||||
if (!alreadyUnflattened(ia)) { | |||||
if ((ich != null) && !ich.isEmpty()) { | |||||
pushInlineContainers(ich); | pushInlineContainers(ich); | ||||
} | } | ||||
if (tc != null) { | if (tc != null) { | ||||
Area a = ia.getParentArea(); | Area a = ia.getParentArea(); | ||||
while (a != null) { | while (a != null) { | ||||
if (a instanceof InlineArea) { | if (a instanceof InlineArea) { | ||||
if ((a instanceof InlineParent) && ! (a instanceof TextArea)) { | |||||
if ((a instanceof InlineParent) && !(a instanceof TextArea)) { | |||||
ich.add((InlineParent) a); | ich.add((InlineParent) a); | ||||
} | } | ||||
a = ((InlineArea) a) .getParentArea(); | a = ((InlineArea) a) .getParentArea(); |
import org.apache.fop.traits.Direction; | import org.apache.fop.traits.Direction; | ||||
import org.apache.fop.util.CharUtilities; | import org.apache.fop.util.CharUtilities; | ||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: EmptyForIteratorPadCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: ParameterNumberCheck | |||||
/** | /** | ||||
* <p>The <code>UnicodeBidiAlgorithm</code> class implements functionality prescribed by | * <p>The <code>UnicodeBidiAlgorithm</code> class implements functionality prescribed by | ||||
case RLE: // start right-to-left embedding | case RLE: // start right-to-left embedding | ||||
case LRO: // start left-to-right override | case LRO: // start left-to-right override | ||||
case RLO: // start right-to-left override | case RLO: // start right-to-left override | ||||
{ | |||||
int en; /* new embedding level */ | |||||
if ((bc == RLE) || (bc == RLO)) { | |||||
en = ((ec & ~OVERRIDE) + 1) | 1; | |||||
} else { | |||||
en = ((ec & ~OVERRIDE) + 2) & ~1; | |||||
} | |||||
if (en < (MAX_LEVELS + 1)) { | |||||
es [ ei++ ] = ec; | |||||
if ((bc == LRO) || (bc == RLO)) { | |||||
ec = en | OVERRIDE; | |||||
} else { | |||||
ec = en & ~OVERRIDE; | |||||
} | |||||
int en; /* new embedding level */ | |||||
if ((bc == RLE) || (bc == RLO)) { | |||||
en = ((ec & ~OVERRIDE) + 1) | 1; | |||||
} else { | |||||
en = ((ec & ~OVERRIDE) + 2) & ~1; | |||||
} | |||||
if (en < (MAX_LEVELS + 1)) { | |||||
es [ ei++ ] = ec; | |||||
if ((bc == LRO) || (bc == RLO)) { | |||||
ec = en | OVERRIDE; | |||||
} else { | } else { | ||||
// max levels exceeded, so don't change level or override | |||||
ec = en & ~OVERRIDE; | |||||
} | } | ||||
el = ec; | |||||
break; | |||||
} else { | |||||
// max levels exceeded, so don't change level or override | |||||
} | } | ||||
el = ec; | |||||
break; | |||||
case PDF: // pop directional formatting | case PDF: // pop directional formatting | ||||
{ | |||||
el = ec; | |||||
if (ei > 0) { | |||||
ec = es [ --ei ]; | |||||
} else { | |||||
// ignore isolated PDF | |||||
} | |||||
break; | |||||
el = ec; | |||||
if (ei > 0) { | |||||
ec = es [ --ei ]; | |||||
} else { | |||||
// ignore isolated PDF | |||||
} | } | ||||
break; | |||||
case B: // paragraph separator | case B: // paragraph separator | ||||
{ | |||||
el = ec = defaultLevel; | |||||
ei = 0; | |||||
break; | |||||
} | |||||
el = ec = defaultLevel; | |||||
ei = 0; | |||||
break; | |||||
default: | default: | ||||
{ | |||||
el = ec; | |||||
break; | |||||
} | |||||
el = ec; | |||||
break; | |||||
} | } | ||||
switch (bc) { | switch (bc) { | ||||
case BN: | case BN: | ||||
private static boolean isRetainedFormatting(int[] ca, int s, int e) { | private static boolean isRetainedFormatting(int[] ca, int s, int e) { | ||||
for (int i = s; i < e; i++) { | for (int i = s; i < e; i++) { | ||||
if (! isRetainedFormatting(ca[i])) { | |||||
if (!isRetainedFormatting(ca[i])) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
chOut = chIn; | chOut = chIn; | ||||
} | } | ||||
if (! triggered && triggersBidi(chOut)) { | |||||
if (!triggered && triggersBidi(chOut)) { | |||||
triggered = true; | triggered = true; | ||||
} | } | ||||
if ((chOut & 0xFF0000) == 0) { | if ((chOut & 0xFF0000) == 0) { |
import java.util.List; | import java.util.List; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>Base class implementation of glyph class table.</p> | * <p>Base class implementation of glyph class table.</p> | ||||
} else { | } else { | ||||
for (Iterator it = entries.iterator(); it.hasNext();) { | for (Iterator it = entries.iterator(); it.hasNext();) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (! (o instanceof Integer)) { | |||||
if (!(o instanceof Integer)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
for (Iterator it = entries.iterator(); it.hasNext();) { | for (Iterator it = entries.iterator(); it.hasNext();) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (! (o instanceof MappingRange)) { | |||||
if (!(o instanceof MappingRange)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
for (Iterator it = entries.iterator(); it.hasNext();) { | for (Iterator it = entries.iterator(); it.hasNext();) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (! (o instanceof GlyphCoverageTable)) { | |||||
if (!(o instanceof GlyphCoverageTable)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
if (it.hasNext()) { | if (it.hasNext()) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (o instanceof Integer) { | if (o instanceof Integer) { | ||||
firstGlyph = ((Integer) o) . intValue(); | |||||
firstGlyph = ((Integer) o) .intValue(); | |||||
} else { | } else { | ||||
throw new AdvancedTypographicTableFormatException("illegal entry, first entry must be Integer denoting first glyph value, but is: " + o); | throw new AdvancedTypographicTableFormatException("illegal entry, first entry must be Integer denoting first glyph value, but is: " + o); | ||||
} | } | ||||
while (it.hasNext()) { | while (it.hasNext()) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (o instanceof Integer) { | if (o instanceof Integer) { | ||||
int gc = ((Integer) o) . intValue(); | |||||
int gc = ((Integer) o) .intValue(); | |||||
gca [ i++ ] = gc; | gca [ i++ ] = gc; | ||||
if (gc > gcMax) { | if (gc > gcMax) { | ||||
gcMax = gc; | gcMax = gc; |
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>.Base class implementation of glyph coverage table.</p> | * <p>.Base class implementation of glyph coverage table.</p> | ||||
} else { | } else { | ||||
for (Iterator it = entries.iterator(); it.hasNext();) { | for (Iterator it = entries.iterator(); it.hasNext();) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (! (o instanceof Integer)) { | |||||
if (!(o instanceof Integer)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
for (Iterator it = entries.iterator(); it.hasNext();) { | for (Iterator it = entries.iterator(); it.hasNext();) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (! (o instanceof MappingRange)) { | |||||
if (!(o instanceof MappingRange)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
for (Iterator it = entries.iterator(); it.hasNext();) { | for (Iterator it = entries.iterator(); it.hasNext();) { | ||||
Object o = it.next(); | Object o = it.next(); | ||||
if (o instanceof Integer) { | if (o instanceof Integer) { | ||||
int gid = ((Integer) o) . intValue(); | |||||
int gid = ((Integer) o) .intValue(); | |||||
if ((gid >= 0) && (gid < 65536)) { | if ((gid >= 0) && (gid < 65536)) { | ||||
if (gid > gidMax) { | if (gid > gidMax) { | ||||
map [ i++ ] = gidMax = gid; | map [ i++ ] = gidMax = gid; |
package org.apache.fop.complexscripts.fonts; | package org.apache.fop.complexscripts.fonts; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: InnerAssignmentCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphDefinitionSubtable</code> implements an abstract base of a glyph definition subtable, | * <p>The <code>GlyphDefinitionSubtable</code> implements an abstract base of a glyph definition subtable, |
import org.apache.fop.complexscripts.scripts.ScriptProcessor; | import org.apache.fop.complexscripts.scripts.ScriptProcessor; | ||||
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** |
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
int mi; | int mi; | ||||
if ((i = Arrays.binarySearch(sa, gid)) >= 0) { | if ((i = Arrays.binarySearch(sa, gid)) >= 0) { | ||||
mi = getMappedIndex(gid, sa [ i ], ma [ i ]); // matches start of (some) range | mi = getMappedIndex(gid, sa [ i ], ma [ i ]); // matches start of (some) range | ||||
} else if ((i = - (i + 1)) == 0) { | |||||
} else if ((i = -(i + 1)) == 0) { | |||||
mi = -1; // precedes first range | mi = -1; // precedes first range | ||||
} else if (gid > ea [ --i ]) { | } else if (gid > ea [ --i ]) { | ||||
mi = -1; // follows preceding (or last) range | mi = -1; // follows preceding (or last) range |
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: ParameterNumberCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphPositioningState</code> implements an state object used during glyph positioning | * <p>The <code>GlyphPositioningState</code> implements an state object used during glyph positioning |
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: ParameterNumberCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphPositioningSubtable</code> implements an abstract base of a glyph subtable, | * <p>The <code>GlyphPositioningSubtable</code> implements an abstract base of a glyph subtable, | ||||
boolean appliedOneShot = false; | boolean appliedOneShot = false; | ||||
while (ps.hasNext()) { | while (ps.hasNext()) { | ||||
boolean applied = false; | boolean applied = false; | ||||
if (! appliedOneShot && ps.maybeApplicable()) { | |||||
for (int i = 0, n = sta.length; ! applied && (i < n); i++) { | |||||
if (!appliedOneShot && ps.maybeApplicable()) { | |||||
for (int i = 0, n = sta.length; !applied && (i < n); i++) { | |||||
if (sequenceIndex < 0) { | if (sequenceIndex < 0) { | ||||
applied = ps.apply(sta [ i ]); | applied = ps.apply(sta [ i ]); | ||||
} else if (ps.getPosition() == (sequenceStart + sequenceIndex)) { | } else if (ps.getPosition() == (sequenceStart + sequenceIndex)) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (! applied || ! ps.didConsume()) { | |||||
if (!applied || !ps.didConsume()) { | |||||
ps.applyDefault(); | ps.applyDefault(); | ||||
} | } | ||||
ps.next(); | ps.next(); |
import org.apache.fop.complexscripts.util.GlyphTester; | import org.apache.fop.complexscripts.util.GlyphTester; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: ParameterNumberCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphPositioningTable</code> class is a glyph table that implements | * <p>The <code>GlyphPositioningTable</code> class is a glyph table that implements | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof Value[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof Value[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, single entry must be a Value[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, single entry must be a Value[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
Value[] va = (Value[]) o; | Value[] va = (Value[]) o; | ||||
int offsetLast = counts[0] + counts[1]; | int offsetLast = counts[0] + counts[1]; | ||||
// skip any ignored glyphs prior to first non-ignored glyph | // skip any ignored glyphs prior to first non-ignored glyph | ||||
for ( ; offset < offsetLast; ++offset) { | for ( ; offset < offsetLast; ++offset) { | ||||
if (! ps.isIgnoredGlyph(offset)) { | |||||
if (!ps.isIgnoredGlyph(offset)) { | |||||
break; | break; | ||||
} else { | } else { | ||||
ps.consume(1); | ps.consume(1); | ||||
} | } | ||||
// skip any ignored glyphs prior to second non-ignored glyph | // skip any ignored glyphs prior to second non-ignored glyph | ||||
for ( ; offset < offsetLast; ++offset) { | for ( ; offset < offsetLast; ++offset) { | ||||
if (! ps.isIgnoredGlyph(offset)) { | |||||
if (!ps.isIgnoredGlyph(offset)) { | |||||
break; | break; | ||||
} else { | } else { | ||||
ps.consume(1); | ps.consume(1); | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof PairValues[][])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof PairValues[][])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first (and only) entry must be a PairValues[][], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first (and only) entry must be a PairValues[][], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
pvm = (PairValues[][]) o; | pvm = (PairValues[][]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
cdt1 = (GlyphClassTable) o; | cdt1 = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) == null) || ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(1)) == null) || !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
cdt2 = (GlyphClassTable) o; | cdt2 = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(2)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(2)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
nc1 = ((Integer)(o)).intValue(); | nc1 = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(3)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(3)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
nc2 = ((Integer)(o)).intValue(); | nc2 = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(4)) == null) || ! (o instanceof PairValues[][])) { | |||||
if (((o = entries.get(4)) == null) || !(o instanceof PairValues[][])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be a PairValues[][], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be a PairValues[][], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
pvm = (PairValues[][]) o; | pvm = (PairValues[][]) o; | ||||
int enw = ps.getWidth(gi2); | int enw = ps.getWidth(gi2); | ||||
if ((exa != null) && (ena != null)) { | if ((exa != null) && (ena != null)) { | ||||
Value v = ena.getAlignmentAdjustment(exa); | Value v = ena.getAlignmentAdjustment(exa); | ||||
v.adjust(- enw, 0, 0, 0); | |||||
v.adjust(-enw, 0, 0, 0); | |||||
if (ps.adjust(v)) { | if (ps.adjust(v)) { | ||||
ps.setAdjusted(true); | ps.setAdjusted(true); | ||||
} | } | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof Anchor[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof Anchor[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first (and only) entry must be a Anchor[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first (and only) entry must be a Anchor[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else if ((((Anchor[]) o) . length % 2) != 0) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, Anchor[] array must have an even number of entries, but has: " + ((Anchor[]) o) . length); | |||||
} else if ((((Anchor[]) o) .length % 2) != 0) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, Anchor[] array must have an even number of entries, but has: " + ((Anchor[]) o) .length); | |||||
} else { | } else { | ||||
aa = (Anchor[]) o; | aa = (Anchor[]) o; | ||||
} | } | ||||
MarkAnchor ma = getMarkAnchor(ciMark, giMark); | MarkAnchor ma = getMarkAnchor(ciMark, giMark); | ||||
if (ma != null) { | if (ma != null) { | ||||
for (int i = 0, n = ps.getPosition(); i < n; i++) { | for (int i = 0, n = ps.getPosition(); i < n; i++) { | ||||
int gi = ps.getGlyph(- (i + 1)); | |||||
int gi = ps.getGlyph(-(i + 1)); | |||||
if (ps.isMark(gi)) { | if (ps.isMark(gi)) { | ||||
continue; | continue; | ||||
} else { | } else { | ||||
// start experimental fix for END OF AYAH in Lateef/Scheherazade | // start experimental fix for END OF AYAH in Lateef/Scheherazade | ||||
int[] aa = ps.getAdjustment(); | int[] aa = ps.getAdjustment(); | ||||
if (aa[2] == 0) { | if (aa[2] == 0) { | ||||
v.adjust(0, 0, - ps.getWidth(giMark), 0); | |||||
v.adjust(0, 0, -ps.getWidth(giMark), 0); | |||||
} | } | ||||
// end experimental fix for END OF AYAH in Lateef/Scheherazade | // end experimental fix for END OF AYAH in Lateef/Scheherazade | ||||
if (ps.adjust(v)) { | if (ps.adjust(v)) { | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 4 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 4 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphCoverageTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphCoverageTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphCoverageTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphCoverageTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
bct = (GlyphCoverageTable) o; | bct = (GlyphCoverageTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(1)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
nmc = ((Integer)(o)).intValue(); | nmc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(2)) == null) || ! (o instanceof MarkAnchor[])) { | |||||
if (((o = entries.get(2)) == null) || !(o instanceof MarkAnchor[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be a MarkAnchor[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be a MarkAnchor[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
maa = (MarkAnchor[]) o; | maa = (MarkAnchor[]) o; | ||||
} | } | ||||
if (((o = entries.get(3)) == null) || ! (o instanceof Anchor[][])) { | |||||
if (((o = entries.get(3)) == null) || !(o instanceof Anchor[][])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be a Anchor[][], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be a Anchor[][], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
bam = (Anchor[][]) o; | bam = (Anchor[][]) o; | ||||
int mxc = getMaxComponentCount(); | int mxc = getMaxComponentCount(); | ||||
if (ma != null) { | if (ma != null) { | ||||
for (int i = 0, n = ps.getPosition(); i < n; i++) { | for (int i = 0, n = ps.getPosition(); i < n; i++) { | ||||
int gi = ps.getGlyph(- (i + 1)); | |||||
int gi = ps.getGlyph(-(i + 1)); | |||||
if (ps.isMark(gi)) { | if (ps.isMark(gi)) { | ||||
continue; | continue; | ||||
} else { | } else { | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphCoverageTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphCoverageTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphCoverageTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphCoverageTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
lct = (GlyphCoverageTable) o; | lct = (GlyphCoverageTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(1)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
nmc = ((Integer)(o)).intValue(); | nmc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(2)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(2)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
mxc = ((Integer)(o)).intValue(); | mxc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(3)) == null) || ! (o instanceof MarkAnchor[])) { | |||||
if (((o = entries.get(3)) == null) || !(o instanceof MarkAnchor[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be a MarkAnchor[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be a MarkAnchor[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
maa = (MarkAnchor[]) o; | maa = (MarkAnchor[]) o; | ||||
} | } | ||||
if (((o = entries.get(4)) == null) || ! (o instanceof Anchor[][][])) { | |||||
if (((o = entries.get(4)) == null) || !(o instanceof Anchor[][][])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be a Anchor[][][], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be a Anchor[][][], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
lam = (Anchor[][][]) o; | lam = (Anchor[][][]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 4 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 4 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphCoverageTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphCoverageTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphCoverageTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphCoverageTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
mct2 = (GlyphCoverageTable) o; | mct2 = (GlyphCoverageTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(1)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
nmc = ((Integer)(o)).intValue(); | nmc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(2)) == null) || ! (o instanceof MarkAnchor[])) { | |||||
if (((o = entries.get(2)) == null) || !(o instanceof MarkAnchor[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be a MarkAnchor[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be a MarkAnchor[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
maa = (MarkAnchor[]) o; | maa = (MarkAnchor[]) o; | ||||
} | } | ||||
if (((o = entries.get(3)) == null) || ! (o instanceof Anchor[][])) { | |||||
if (((o = entries.get(3)) == null) || !(o instanceof Anchor[][])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be a Anchor[][], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be a Anchor[][], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
mam = (Anchor[][]) o; | mam = (Anchor[][]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 3 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 3 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
cdt = (GlyphClassTable) o; | cdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(1)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
ngc = ((Integer)(o)).intValue(); | ngc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(2)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(2)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
icdt = (GlyphClassTable) o; | icdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) != null) && ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(1)) != null) && !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an GlyphClassTable, but is: " + o.getClass()); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an GlyphClassTable, but is: " + o.getClass()); | ||||
} else { | } else { | ||||
bcdt = (GlyphClassTable) o; | bcdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(2)) != null) && ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(2)) != null) && !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an GlyphClassTable, but is: " + o.getClass()); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an GlyphClassTable, but is: " + o.getClass()); | ||||
} else { | } else { | ||||
lcdt = (GlyphClassTable) o; | lcdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(3)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(3)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
ngc = ((Integer)(o)).intValue(); | ngc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(4)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(4)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
boolean first = true; | boolean first = true; | ||||
sb.append("{ "); | sb.append("{ "); | ||||
if (xPlacement != 0) { | if (xPlacement != 0) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("xPlacement = " + xPlacement); | sb.append("xPlacement = " + xPlacement); | ||||
} | } | ||||
if (yPlacement != 0) { | if (yPlacement != 0) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("yPlacement = " + yPlacement); | sb.append("yPlacement = " + yPlacement); | ||||
} | } | ||||
if (xAdvance != 0) { | if (xAdvance != 0) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("xAdvance = " + xAdvance); | sb.append("xAdvance = " + xAdvance); | ||||
} | } | ||||
if (yAdvance != 0) { | if (yAdvance != 0) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("yAdvance = " + yAdvance); | sb.append("yAdvance = " + yAdvance); | ||||
} | } | ||||
if (xPlaDevice != null) { | if (xPlaDevice != null) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("xPlaDevice = " + xPlaDevice); | sb.append("xPlaDevice = " + xPlaDevice); | ||||
} | } | ||||
if (yPlaDevice != null) { | if (yPlaDevice != null) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("xPlaDevice = " + yPlaDevice); | sb.append("xPlaDevice = " + yPlaDevice); | ||||
} | } | ||||
if (xAdvDevice != null) { | if (xAdvDevice != null) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("xAdvDevice = " + xAdvDevice); | sb.append("xAdvDevice = " + xAdvDevice); | ||||
} | } | ||||
if (yAdvDevice != null) { | if (yAdvDevice != null) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
boolean first = true; | boolean first = true; | ||||
sb.append("{ "); | sb.append("{ "); | ||||
if (glyph != 0) { | if (glyph != 0) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("glyph = " + glyph); | sb.append("glyph = " + glyph); | ||||
} | } | ||||
if (value1 != null) { | if (value1 != null) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; | ||||
sb.append("value1 = " + value1); | sb.append("value1 = " + value1); | ||||
} | } | ||||
if (value2 != null) { | if (value2 != null) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(", "); | sb.append(", "); | ||||
} else { | } else { | ||||
first = false; | first = false; |
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphProcessingState</code> implements a common, base state object used during glyph substitution | * <p>The <code>GlyphProcessingState</code> implements a common, base state object used during glyph substitution | ||||
int start = index + offset; | int start = index + offset; | ||||
if (start < 0) { | if (start < 0) { | ||||
throw new IndexOutOfBoundsException("will attempt index at " + start); | throw new IndexOutOfBoundsException("will attempt index at " + start); | ||||
} else if (! reverseOrder && ((start + count) > indexLast)) { | |||||
} else if (!reverseOrder && ((start + count) > indexLast)) { | |||||
throw new IndexOutOfBoundsException("will attempt index at " + (start + count)); | throw new IndexOutOfBoundsException("will attempt index at " + (start + count)); | ||||
} else if (reverseOrder && ((start + 1) < count)) { | } else if (reverseOrder && ((start + 1) < count)) { | ||||
throw new IndexOutOfBoundsException("will attempt index at " + (start - count)); | throw new IndexOutOfBoundsException("will attempt index at " + (start - count)); | ||||
} else if (glyphs.length != count) { | } else if (glyphs.length != count) { | ||||
throw new IllegalArgumentException("glyphs array is non-null, but its length (" + glyphs.length + "), is not equal to count (" + count + ")"); | throw new IllegalArgumentException("glyphs array is non-null, but its length (" + glyphs.length + "), is not equal to count (" + count + ")"); | ||||
} | } | ||||
if (! reverseOrder) { | |||||
if (!reverseOrder) { | |||||
return getGlyphsForward(start, count, ignoreTester, glyphs, counts); | return getGlyphsForward(start, count, ignoreTester, glyphs, counts); | ||||
} else { | } else { | ||||
return getGlyphsReverse(start, count, ignoreTester, glyphs, counts); | return getGlyphsReverse(start, count, ignoreTester, glyphs, counts); | ||||
if (gi == 65535) { | if (gi == 65535) { | ||||
ignored++; | ignored++; | ||||
} else { | } else { | ||||
if ((ignoreTester == null) || ! ignoreTester.test(gi, getLookupFlags())) { | |||||
if ((ignoreTester == null) || !ignoreTester.test(gi, getLookupFlags())) { | |||||
glyphs [ counted++ ] = gi; | glyphs [ counted++ ] = gi; | ||||
} else { | } else { | ||||
ignored++; | ignored++; | ||||
if (gi == 65535) { | if (gi == 65535) { | ||||
ignored++; | ignored++; | ||||
} else { | } else { | ||||
if ((ignoreTester == null) || ! ignoreTester.test(gi, getLookupFlags())) { | |||||
if ((ignoreTester == null) || !ignoreTester.test(gi, getLookupFlags())) { | |||||
glyphs [ counted++ ] = gi; | glyphs [ counted++ ] = gi; | ||||
} else { | } else { | ||||
ignored++; | ignored++; | ||||
int start = index + offset; | int start = index + offset; | ||||
if ((start < 0) || (start > indexLast)) { | if ((start < 0) || (start > indexLast)) { | ||||
return new int[] { 0, 0 }; | return new int[] { 0, 0 }; | ||||
} else if (! reverseOrder) { | |||||
} else if (!reverseOrder) { | |||||
return getGlyphsAvailableForward(start, ignoreTester); | return getGlyphsAvailableForward(start, ignoreTester); | ||||
} else { | } else { | ||||
return getGlyphsAvailableReverse(start, ignoreTester); | return getGlyphsAvailableReverse(start, ignoreTester); | ||||
int start = index + offset; | int start = index + offset; | ||||
if (start < 0) { | if (start < 0) { | ||||
throw new IndexOutOfBoundsException("will attempt index at " + start); | throw new IndexOutOfBoundsException("will attempt index at " + start); | ||||
} else if (! reverseOrder && ((start + count) > indexLast)) { | |||||
} else if (!reverseOrder && ((start + count) > indexLast)) { | |||||
throw new IndexOutOfBoundsException("will attempt index at " + (start + count)); | throw new IndexOutOfBoundsException("will attempt index at " + (start + count)); | ||||
} else if (reverseOrder && ((start + 1) < count)) { | } else if (reverseOrder && ((start + 1) < count)) { | ||||
throw new IndexOutOfBoundsException("will attempt index at " + (start - count)); | throw new IndexOutOfBoundsException("will attempt index at " + (start - count)); | ||||
} else if (associations.length != count) { | } else if (associations.length != count) { | ||||
throw new IllegalArgumentException("associations array is non-null, but its length (" + associations.length + "), is not equal to count (" + count + ")"); | throw new IllegalArgumentException("associations array is non-null, but its length (" + associations.length + "), is not equal to count (" + count + ")"); | ||||
} | } | ||||
if (! reverseOrder) { | |||||
if (!reverseOrder) { | |||||
return getAssociationsForward(start, count, ignoreTester, associations, counts); | return getAssociationsForward(start, count, ignoreTester, associations, counts); | ||||
} else { | } else { | ||||
return getAssociationsReverse(start, count, ignoreTester, associations, counts); | return getAssociationsReverse(start, count, ignoreTester, associations, counts); | ||||
if (gi == 65535) { | if (gi == 65535) { | ||||
ignored++; | ignored++; | ||||
} else { | } else { | ||||
if ((ignoreTester == null) || ! ignoreTester.test(gi, getLookupFlags())) { | |||||
if ((ignoreTester == null) || !ignoreTester.test(gi, getLookupFlags())) { | |||||
if (k < count) { | if (k < count) { | ||||
associations [ k++ ] = getAssociation(i - index); | associations [ k++ ] = getAssociation(i - index); | ||||
counted++; | counted++; | ||||
if (gi == 65535) { | if (gi == 65535) { | ||||
ignored++; | ignored++; | ||||
} else { | } else { | ||||
if ((ignoreTester == null) || ! ignoreTester.test(gi, getLookupFlags())) { | |||||
if ((ignoreTester == null) || !ignoreTester.test(gi, getLookupFlags())) { | |||||
if (k < count) { | if (k < count) { | ||||
associations [ k++ ] = getAssociation(i - index); | associations [ k++ ] = getAssociation(i - index); | ||||
counted++; | counted++; | ||||
for (int i = 0, n = ngt; i < n; i++) { | for (int i = 0, n = ngt; i < n; i++) { | ||||
GlyphTester gt = gta [ i ]; | GlyphTester gt = gta [ i ]; | ||||
if (gt != null) { | if (gt != null) { | ||||
if (! gt.test(gi, flags)) { | |||||
if (!gt.test(gi, flags)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } |
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphSubstitutionState</code> implements an state object used during glyph substitution | * <p>The <code>GlyphSubstitutionState</code> implements an state object used during glyph substitution | ||||
* @param predication a predication value to add to association A if predications enabled | * @param predication a predication value to add to association A if predications enabled | ||||
*/ | */ | ||||
public void putGlyph(int glyph, GlyphSequence.CharAssociation a, Object predication) { | public void putGlyph(int glyph, GlyphSequence.CharAssociation a, Object predication) { | ||||
if (! ogb.hasRemaining()) { | |||||
if (!ogb.hasRemaining()) { | |||||
ogb = growBuffer(ogb); | ogb = growBuffer(ogb); | ||||
} | } | ||||
ogb.put(glyph); | ogb.put(glyph); |
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphSubstitutionSubtable</code> implements an abstract base of a glyph substitution subtable, | * <p>The <code>GlyphSubstitutionSubtable</code> implements an abstract base of a glyph substitution subtable, | ||||
boolean appliedOneShot = false; | boolean appliedOneShot = false; | ||||
while (ss.hasNext()) { | while (ss.hasNext()) { | ||||
boolean applied = false; | boolean applied = false; | ||||
if (! appliedOneShot && ss.maybeApplicable()) { | |||||
for (int i = 0, n = sta.length; ! applied && (i < n); i++) { | |||||
if (!appliedOneShot && ss.maybeApplicable()) { | |||||
for (int i = 0, n = sta.length; !applied && (i < n); i++) { | |||||
if (sequenceIndex < 0) { | if (sequenceIndex < 0) { | ||||
applied = ss.apply(sta [ i ]); | applied = ss.apply(sta [ i ]); | ||||
} else if (ss.getPosition() == (sequenceStart + sequenceIndex)) { | } else if (ss.getPosition() == (sequenceStart + sequenceIndex)) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (! applied || ! ss.didConsume()) { | |||||
if (!applied || !ss.didConsume()) { | |||||
ss.applyDefault(); | ss.applyDefault(); | ||||
} | } | ||||
ss.next(); | ss.next(); |
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
import org.apache.fop.complexscripts.util.GlyphTester; | import org.apache.fop.complexscripts.util.GlyphTester; | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>The <code>GlyphSubstitutionTable</code> class is a glyph table that implements | * <p>The <code>GlyphSubstitutionTable</code> class is a glyph table that implements | ||||
Object o = entries.get(0); | Object o = entries.get(0); | ||||
int delta = 0; | int delta = 0; | ||||
if (o instanceof Integer) { | if (o instanceof Integer) { | ||||
delta = ((Integer) o) . intValue(); | |||||
delta = ((Integer) o) .intValue(); | |||||
} else { | } else { | ||||
throw new AdvancedTypographicTableFormatException("illegal entries entry, must be Integer, but is: " + o); | throw new AdvancedTypographicTableFormatException("illegal entries entry, must be Integer, but is: " + o); | ||||
} | } | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof int[][])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof int[][])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an int[][], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an int[][], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
gsa = (int[][]) o; | gsa = (int[][]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 3 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 3 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
cdt = (GlyphClassTable) o; | cdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(1)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
ngc = ((Integer)(o)).intValue(); | ngc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(2)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(2)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 5 entries"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an GlyphClassTable, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
icdt = (GlyphClassTable) o; | icdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(1)) != null) && ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(1)) != null) && !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an GlyphClassTable, but is: " + o.getClass()); | throw new AdvancedTypographicTableFormatException("illegal entries, second entry must be an GlyphClassTable, but is: " + o.getClass()); | ||||
} else { | } else { | ||||
bcdt = (GlyphClassTable) o; | bcdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(2)) != null) && ! (o instanceof GlyphClassTable)) { | |||||
if (((o = entries.get(2)) != null) && !(o instanceof GlyphClassTable)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an GlyphClassTable, but is: " + o.getClass()); | throw new AdvancedTypographicTableFormatException("illegal entries, third entry must be an GlyphClassTable, but is: " + o.getClass()); | ||||
} else { | } else { | ||||
lcdt = (GlyphClassTable) o; | lcdt = (GlyphClassTable) o; | ||||
} | } | ||||
if (((o = entries.get(3)) == null) || ! (o instanceof Integer)) { | |||||
if (((o = entries.get(3)) == null) || !(o instanceof Integer)) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fourth entry must be an Integer, but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
ngc = ((Integer)(o)).intValue(); | ngc = ((Integer)(o)).intValue(); | ||||
} | } | ||||
if (((o = entries.get(4)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(4)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, fifth entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; | ||||
throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | throw new AdvancedTypographicTableFormatException("illegal entries, " + entries.size() + " entries present, but requires 1 entry"); | ||||
} else { | } else { | ||||
Object o; | Object o; | ||||
if (((o = entries.get(0)) == null) || ! (o instanceof RuleSet[])) { | |||||
if (((o = entries.get(0)) == null) || !(o instanceof RuleSet[])) { | |||||
throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | throw new AdvancedTypographicTableFormatException("illegal entries, first entry must be an RuleSet[], but is: " + ((o != null) ? o.getClass() : null)); | ||||
} else { | } else { | ||||
rsa = (RuleSet[]) o; | rsa = (RuleSet[]) o; |
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** |
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: EmptyForIteratorPadCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: ParameterNumberCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
/** | /** | ||||
* <p>Base class for all advanced typographic glyph tables.</p> | * <p>Base class for all advanced typographic glyph tables.</p> | ||||
* @param lookups map from lookup specs to lookup tables | * @param lookups map from lookup specs to lookup tables | ||||
*/ | */ | ||||
public GlyphTable(GlyphTable gdef, Map/*<LookupSpec,List<String>>*/ lookups) { | public GlyphTable(GlyphTable gdef, Map/*<LookupSpec,List<String>>*/ lookups) { | ||||
if ((gdef != null) && ! (gdef instanceof GlyphDefinitionTable)) { | |||||
if ((gdef != null) && !(gdef instanceof GlyphDefinitionTable)) { | |||||
throw new AdvancedTypographicTableFormatException("bad glyph definition table"); | throw new AdvancedTypographicTableFormatException("bad glyph definition table"); | ||||
} else if (lookups == null) { | } else if (lookups == null) { | ||||
throw new AdvancedTypographicTableFormatException("lookups must be non-null map"); | throw new AdvancedTypographicTableFormatException("lookups must be non-null map"); | ||||
* create resulting cached state. | * create resulting cached state. | ||||
*/ | */ | ||||
protected void freezeSubtables() { | protected void freezeSubtables() { | ||||
if (! frozen) { | |||||
if (!frozen) { | |||||
for (Iterator it = lookupTables.values().iterator(); it.hasNext(); ) { | for (Iterator it = lookupTables.values().iterator(); it.hasNext(); ) { | ||||
LookupTable lt = (LookupTable) it.next(); | LookupTable lt = (LookupTable) it.next(); | ||||
lt.freezeSubtables(lookupTables); | lt.freezeSubtables(lookupTables); | ||||
List/*<LookupSpec>*/ matches = new ArrayList/*<LookupSpec>*/(); | List/*<LookupSpec>*/ matches = new ArrayList/*<LookupSpec>*/(); | ||||
for (Iterator it = keys.iterator(); it.hasNext();) { | for (Iterator it = keys.iterator(); it.hasNext();) { | ||||
LookupSpec ls = (LookupSpec) it.next(); | LookupSpec ls = (LookupSpec) it.next(); | ||||
if (! "*".equals(script)) { | |||||
if (! ls.getScript().equals(script)) { | |||||
if (!"*".equals(script)) { | |||||
if (!ls.getScript().equals(script)) { | |||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
if (! "*".equals(language)) { | |||||
if (! ls.getLanguage().equals(language)) { | |||||
if (!"*".equals(language)) { | |||||
if (!ls.getLanguage().equals(language)) { | |||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
if (! "*".equals(feature)) { | |||||
if (! ls.getFeature().equals(feature)) { | |||||
if (!"*".equals(feature)) { | |||||
if (!ls.getFeature().equals(feature)) { | |||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
* @param permitWildcard if true the permit wildcard script, language, or feature | * @param permitWildcard if true the permit wildcard script, language, or feature | ||||
*/ | */ | ||||
LookupSpec(String script, String language, String feature, boolean permitEmpty, boolean permitWildcard) { | LookupSpec(String script, String language, String feature, boolean permitEmpty, boolean permitWildcard) { | ||||
if ((script == null) || (! permitEmpty && (script.length() == 0))) { | |||||
if ((script == null) || (!permitEmpty && (script.length() == 0))) { | |||||
throw new AdvancedTypographicTableFormatException("script must be non-empty string"); | throw new AdvancedTypographicTableFormatException("script must be non-empty string"); | ||||
} else if ((language == null) || (! permitEmpty && (language.length() == 0))) { | |||||
} else if ((language == null) || (!permitEmpty && (language.length() == 0))) { | |||||
throw new AdvancedTypographicTableFormatException("language must be non-empty string"); | throw new AdvancedTypographicTableFormatException("language must be non-empty string"); | ||||
} else if ((feature == null) || (! permitEmpty && (feature.length() == 0))) { | |||||
} else if ((feature == null) || (!permitEmpty && (feature.length() == 0))) { | |||||
throw new AdvancedTypographicTableFormatException("feature must be non-empty string"); | throw new AdvancedTypographicTableFormatException("feature must be non-empty string"); | ||||
} else if (! permitWildcard && script.equals("*")) { | |||||
} else if (!permitWildcard && script.equals("*")) { | |||||
throw new AdvancedTypographicTableFormatException("script must not be wildcard"); | throw new AdvancedTypographicTableFormatException("script must not be wildcard"); | ||||
} else if (! permitWildcard && language.equals("*")) { | |||||
} else if (!permitWildcard && language.equals("*")) { | |||||
throw new AdvancedTypographicTableFormatException("language must not be wildcard"); | throw new AdvancedTypographicTableFormatException("language must not be wildcard"); | ||||
} else if (! permitWildcard && feature.equals("*")) { | |||||
} else if (!permitWildcard && feature.equals("*")) { | |||||
throw new AdvancedTypographicTableFormatException("feature must not be wildcard"); | throw new AdvancedTypographicTableFormatException("feature must not be wildcard"); | ||||
} | } | ||||
this.script = script.trim(); | this.script = script.trim(); | ||||
public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
if (o instanceof LookupSpec) { | if (o instanceof LookupSpec) { | ||||
LookupSpec l = (LookupSpec) o; | LookupSpec l = (LookupSpec) o; | ||||
if (! l.script.equals(script)) { | |||||
if (!l.script.equals(script)) { | |||||
return false; | return false; | ||||
} else if (! l.language.equals(language)) { | |||||
return false; | |||||
} else if (! l.feature.equals(feature)) { | |||||
} else if (!l.language.equals(language)) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | |||||
return l.feature.equals(feature); | |||||
} | } | ||||
} else { | } else { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// append at end of list | // append at end of list | ||||
if (! added && (subtable != null)) { | |||||
if (!added && (subtable != null)) { | |||||
subtables.add(subtable); | subtables.add(subtable); | ||||
added = true; | added = true; | ||||
} | } | ||||
} | } | ||||
if (subtables.size() > 0) { | if (subtables.size() > 0) { | ||||
GlyphSubtable st = (GlyphSubtable) subtables.get(0); | GlyphSubtable st = (GlyphSubtable) subtables.get(0); | ||||
if (! st.isCompatible(subtable)) { | |||||
if (!st.isCompatible(subtable)) { | |||||
throw new AdvancedTypographicTableFormatException("subtable " + subtable + " is not compatible with subtable " + st); | throw new AdvancedTypographicTableFormatException("subtable " + subtable + " is not compatible with subtable " + st); | ||||
} | } | ||||
} | } | ||||
* @param lookupTables map from lookup table identifers, e.g. "lu4", to lookup tables | * @param lookupTables map from lookup table identifers, e.g. "lu4", to lookup tables | ||||
*/ | */ | ||||
public void freezeSubtables(Map/*<String,LookupTable>*/ lookupTables) { | public void freezeSubtables(Map/*<String,LookupTable>*/ lookupTables) { | ||||
if (! frozen) { | |||||
if (!frozen) { | |||||
GlyphSubtable[] sta = getSubtables(); | GlyphSubtable[] sta = getSubtables(); | ||||
resolveLookupReferences(sta, lookupTables); | resolveLookupReferences(sta, lookupTables); | ||||
this.subtablesArray = sta; | this.subtablesArray = sta; | ||||
Class c = r0.getClass(); | Class c = r0.getClass(); | ||||
for (int i = 1, n = rules.length; i < n; i++) { | for (int i = 1, n = rules.length; i < n; i++) { | ||||
Rule r = rules[i]; | Rule r = rules[i]; | ||||
if ((r != null) && ! c.isInstance(r)) { | |||||
if ((r != null) && !c.isInstance(r)) { | |||||
throw new AdvancedTypographicTableFormatException("rules[" + i + "] is not an instance of " + c.getName()); | throw new AdvancedTypographicTableFormatException("rules[" + i + "] is not an instance of " + c.getName()); | ||||
} | } | ||||
} | } |
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.fonts.truetype.FontFileReader; | import org.apache.fop.fonts.truetype.FontFileReader; | ||||
import org.apache.fop.fonts.truetype.TTFDirTabEntry; | |||||
import org.apache.fop.fonts.truetype.TTFFile; | |||||
import org.apache.fop.fonts.truetype.TTFTableName; | |||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
import org.apache.fop.fonts.truetype.OFDirTabEntry; | |||||
import org.apache.fop.fonts.truetype.OFTableName; | |||||
import org.apache.fop.fonts.truetype.OpenFont; | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
// logging state | // logging state | ||||
private static Log log = LogFactory.getLog(OTFAdvancedTypographicTableReader.class); | private static Log log = LogFactory.getLog(OTFAdvancedTypographicTableReader.class); | ||||
// instance state | // instance state | ||||
private TTFFile ttf; // parent font file reader | |||||
private OpenFont otf; // parent font file reader | |||||
private FontFileReader in; // input reader | private FontFileReader in; // input reader | ||||
private GlyphDefinitionTable gdef; // glyph definition table | private GlyphDefinitionTable gdef; // glyph definition table | ||||
private GlyphSubstitutionTable gsub; // glyph substitution table | private GlyphSubstitutionTable gsub; // glyph substitution table | ||||
* @param ttf parent font file reader (must be non-null) | * @param ttf parent font file reader (must be non-null) | ||||
* @param in font file reader (must be non-null) | * @param in font file reader (must be non-null) | ||||
*/ | */ | ||||
public OTFAdvancedTypographicTableReader(TTFFile ttf, FontFileReader in) { | |||||
assert ttf != null; | |||||
public OTFAdvancedTypographicTableReader(OpenFont otf, FontFileReader in) { | |||||
assert otf != null; | |||||
assert in != null; | assert in != null; | ||||
this.ttf = ttf; | |||||
this.otf = otf; | |||||
this.in = in; | this.in = in; | ||||
} | } | ||||
return gpos; | return gpos; | ||||
} | } | ||||
private void readLangSysTable(TTFTableName tableTag, long langSysTable, String langSysTag) throws IOException { | |||||
private void readLangSysTable(OFTableName tableTag, long langSysTable, String langSysTag) | |||||
throws IOException { | |||||
in.seekSet(langSysTable); | in.seekSet(langSysTable); | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + " lang sys table: " + langSysTag); | log.debug(tableTag + " lang sys table: " + langSysTag); | ||||
private static String defaultTag = "dflt"; | private static String defaultTag = "dflt"; | ||||
private void readScriptTable(TTFTableName tableTag, long scriptTable, String scriptTag) throws IOException { | |||||
private void readScriptTable(OFTableName tableTag, long scriptTable, String scriptTag) throws IOException { | |||||
in.seekSet(scriptTable); | in.seekSet(scriptTable); | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + " script table: " + scriptTag); | log.debug(tableTag + " script table: " + scriptTag); | ||||
seLanguages = null; | seLanguages = null; | ||||
} | } | ||||
private void readScriptList(TTFTableName tableTag, long scriptList) throws IOException { | |||||
private void readScriptList(OFTableName tableTag, long scriptList) throws IOException { | |||||
in.seekSet(scriptList); | in.seekSet(scriptList); | ||||
// read script record count | // read script record count | ||||
int ns = in.readTTFUShort(); | int ns = in.readTTFUShort(); | ||||
} | } | ||||
} | } | ||||
private void readFeatureTable(TTFTableName tableTag, long featureTable, String featureTag, int featureIndex) throws IOException { | |||||
private void readFeatureTable(OFTableName tableTag, long featureTable, String featureTag, int featureIndex) throws IOException { | |||||
in.seekSet(featureTable); | in.seekSet(featureTable); | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + " feature table: " + featureTag); | log.debug(tableTag + " feature table: " + featureTag); | ||||
seFeatures.put("f" + featureIndex, new Object[] { featureTag, lul }); | seFeatures.put("f" + featureIndex, new Object[] { featureTag, lul }); | ||||
} | } | ||||
private void readFeatureList(TTFTableName tableTag, long featureList) throws IOException { | |||||
private void readFeatureList(OFTableName tableTag, long featureList) throws IOException { | |||||
in.seekSet(featureList); | in.seekSet(featureList); | ||||
// read feature record count | // read feature record count | ||||
int nf = in.readTTFUShort(); | int nf = in.readTTFUShort(); | ||||
// XPlacement | // XPlacement | ||||
int xp; | int xp; | ||||
if ((valueFormat & GlyphPositioningTable.Value.X_PLACEMENT) != 0) { | if ((valueFormat & GlyphPositioningTable.Value.X_PLACEMENT) != 0) { | ||||
xp = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
xp = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
} else { | } else { | ||||
xp = 0; | xp = 0; | ||||
} | } | ||||
// YPlacement | // YPlacement | ||||
int yp; | int yp; | ||||
if ((valueFormat & GlyphPositioningTable.Value.Y_PLACEMENT) != 0) { | if ((valueFormat & GlyphPositioningTable.Value.Y_PLACEMENT) != 0) { | ||||
yp = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
yp = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
} else { | } else { | ||||
yp = 0; | yp = 0; | ||||
} | } | ||||
// XAdvance | // XAdvance | ||||
int xa; | int xa; | ||||
if ((valueFormat & GlyphPositioningTable.Value.X_ADVANCE) != 0) { | if ((valueFormat & GlyphPositioningTable.Value.X_ADVANCE) != 0) { | ||||
xa = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
xa = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
} else { | } else { | ||||
xa = 0; | xa = 0; | ||||
} | } | ||||
// YAdvance | // YAdvance | ||||
int ya; | int ya; | ||||
if ((valueFormat & GlyphPositioningTable.Value.Y_ADVANCE) != 0) { | if ((valueFormat & GlyphPositioningTable.Value.Y_ADVANCE) != 0) { | ||||
ya = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
ya = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
} else { | } else { | ||||
ya = 0; | ya = 0; | ||||
} | } | ||||
int af = in.readTTFUShort(); | int af = in.readTTFUShort(); | ||||
if (af == 1) { | if (af == 1) { | ||||
// read x coordinate | // read x coordinate | ||||
int x = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
int x = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
// read y coordinate | // read y coordinate | ||||
int y = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
int y = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
a = new GlyphPositioningTable.Anchor(x, y); | a = new GlyphPositioningTable.Anchor(x, y); | ||||
} else if (af == 2) { | } else if (af == 2) { | ||||
// read x coordinate | // read x coordinate | ||||
int x = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
int x = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
// read y coordinate | // read y coordinate | ||||
int y = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
int y = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
// read anchor point index | // read anchor point index | ||||
int ap = in.readTTFUShort(); | int ap = in.readTTFUShort(); | ||||
a = new GlyphPositioningTable.Anchor(x, y, ap); | a = new GlyphPositioningTable.Anchor(x, y, ap); | ||||
} else if (af == 3) { | } else if (af == 3) { | ||||
// read x coordinate | // read x coordinate | ||||
int x = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
int x = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
// read y coordinate | // read y coordinate | ||||
int y = ttf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
int y = otf.convertTTFUnit2PDFUnit(in.readTTFShort()); | |||||
// read x device table offset | // read x device table offset | ||||
int xdo = in.readTTFUShort(); | int xdo = in.readTTFUShort(); | ||||
// read y device table offset | // read y device table offset | ||||
resetATSubState(); | resetATSubState(); | ||||
} | } | ||||
private void readLookupTable(TTFTableName tableTag, int lookupSequence, long lookupTable) throws IOException { | |||||
boolean isGSUB = tableTag.equals(TTFTableName.GSUB); | |||||
boolean isGPOS = tableTag.equals(TTFTableName.GPOS); | |||||
private void readLookupTable(OFTableName tableTag, int lookupSequence, long lookupTable) throws IOException { | |||||
boolean isGSUB = tableTag.equals(OFTableName.GSUB); | |||||
boolean isGPOS = tableTag.equals(OFTableName.GPOS); | |||||
in.seekSet(lookupTable); | in.seekSet(lookupTable); | ||||
// read lookup type | // read lookup type | ||||
int lt = in.readTTFUShort(); | int lt = in.readTTFUShort(); | ||||
} | } | ||||
} | } | ||||
private void readLookupList(TTFTableName tableTag, long lookupList) throws IOException { | |||||
private void readLookupList(OFTableName tableTag, long lookupList) throws IOException { | |||||
in.seekSet(lookupList); | in.seekSet(lookupList); | ||||
// read lookup record count | // read lookup record count | ||||
int nl = in.readTTFUShort(); | int nl = in.readTTFUShort(); | ||||
* @param lookupList offset to lookup list from beginning of font file | * @param lookupList offset to lookup list from beginning of font file | ||||
* @throws IOException In case of a I/O problem | * @throws IOException In case of a I/O problem | ||||
*/ | */ | ||||
private void readCommonLayoutTables(TTFTableName tableTag, long scriptList, long featureList, long lookupList) throws IOException { | |||||
private void readCommonLayoutTables(OFTableName tableTag, long scriptList, long featureList, long lookupList) throws IOException { | |||||
if (scriptList > 0) { | if (scriptList > 0) { | ||||
readScriptList(tableTag, scriptList); | readScriptList(tableTag, scriptList); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private void readGDEFClassDefTable(TTFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
private void readGDEFClassDefTable(OFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
initATSubState(); | initATSubState(); | ||||
in.seekSet(subtableOffset); | in.seekSet(subtableOffset); | ||||
// subtable is a bare class definition table | // subtable is a bare class definition table | ||||
resetATSubState(); | resetATSubState(); | ||||
} | } | ||||
private void readGDEFAttachmentTable(TTFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
private void readGDEFAttachmentTable(OFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
initATSubState(); | initATSubState(); | ||||
in.seekSet(subtableOffset); | in.seekSet(subtableOffset); | ||||
// read coverage offset | // read coverage offset | ||||
resetATSubState(); | resetATSubState(); | ||||
} | } | ||||
private void readGDEFLigatureCaretTable(TTFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
private void readGDEFLigatureCaretTable(OFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
initATSubState(); | initATSubState(); | ||||
in.seekSet(subtableOffset); | in.seekSet(subtableOffset); | ||||
// read coverage offset | // read coverage offset | ||||
resetATSubState(); | resetATSubState(); | ||||
} | } | ||||
private void readGDEFMarkAttachmentTable(TTFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
private void readGDEFMarkAttachmentTable(OFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
initATSubState(); | initATSubState(); | ||||
in.seekSet(subtableOffset); | in.seekSet(subtableOffset); | ||||
// subtable is a bare class definition table | // subtable is a bare class definition table | ||||
resetATSubState(); | resetATSubState(); | ||||
} | } | ||||
private void readGDEFMarkGlyphsTableFormat1(TTFTableName tableTag, int lookupSequence, long subtableOffset, int subtableFormat) throws IOException { | |||||
private void readGDEFMarkGlyphsTableFormat1(OFTableName tableTag, int lookupSequence, long subtableOffset, int subtableFormat) throws IOException { | |||||
initATSubState(); | initATSubState(); | ||||
in.seekSet(subtableOffset); | in.seekSet(subtableOffset); | ||||
// skip over format (already known) | // skip over format (already known) | ||||
resetATSubState(); | resetATSubState(); | ||||
} | } | ||||
private void readGDEFMarkGlyphsTable(TTFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
private void readGDEFMarkGlyphsTable(OFTableName tableTag, int lookupSequence, long subtableOffset) throws IOException { | |||||
in.seekSet(subtableOffset); | in.seekSet(subtableOffset); | ||||
// read mark set subtable format | // read mark set subtable format | ||||
int sf = in.readTTFUShort(); | int sf = in.readTTFUShort(); | ||||
* @throws IOException In case of a I/O problem | * @throws IOException In case of a I/O problem | ||||
*/ | */ | ||||
private void readGDEF() throws IOException { | private void readGDEF() throws IOException { | ||||
TTFTableName tableTag = TTFTableName.GDEF; | |||||
OFTableName tableTag = OFTableName.GDEF; | |||||
// Initialize temporary state | // Initialize temporary state | ||||
initATState(); | initATState(); | ||||
// Read glyph definition (GDEF) table | // Read glyph definition (GDEF) table | ||||
TTFDirTabEntry dirTab = ttf.getDirectoryEntry(tableTag); | |||||
OFDirTabEntry dirTab = otf.getDirectoryEntry(tableTag); | |||||
if (gdef != null) { | if (gdef != null) { | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + ": ignoring duplicate table"); | log.debug(tableTag + ": ignoring duplicate table"); | ||||
} | } | ||||
} else if (dirTab != null) { | } else if (dirTab != null) { | ||||
ttf.seekTab(in, tableTag, 0); | |||||
otf.seekTab(in, tableTag, 0); | |||||
long version = in.readTTFULong(); | long version = in.readTTFULong(); | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + " version: " + (version / 65536) + "." + (version % 65536)); | log.debug(tableTag + " version: " + (version / 65536) + "." + (version % 65536)); | ||||
* @throws IOException In case of a I/O problem | * @throws IOException In case of a I/O problem | ||||
*/ | */ | ||||
private void readGSUB() throws IOException { | private void readGSUB() throws IOException { | ||||
TTFTableName tableTag = TTFTableName.GSUB; | |||||
OFTableName tableTag = OFTableName.GSUB; | |||||
// Initialize temporary state | // Initialize temporary state | ||||
initATState(); | initATState(); | ||||
// Read glyph substitution (GSUB) table | // Read glyph substitution (GSUB) table | ||||
TTFDirTabEntry dirTab = ttf.getDirectoryEntry(tableTag); | |||||
OFDirTabEntry dirTab = otf.getDirectoryEntry(tableTag); | |||||
if (gpos != null) { | if (gpos != null) { | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + ": ignoring duplicate table"); | log.debug(tableTag + ": ignoring duplicate table"); | ||||
} | } | ||||
} else if (dirTab != null) { | } else if (dirTab != null) { | ||||
ttf.seekTab(in, tableTag, 0); | |||||
otf.seekTab(in, tableTag, 0); | |||||
int version = in.readTTFLong(); | int version = in.readTTFLong(); | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + " version: " + (version / 65536) + "." + (version % 65536)); | log.debug(tableTag + " version: " + (version / 65536) + "." + (version % 65536)); | ||||
* @throws IOException In case of a I/O problem | * @throws IOException In case of a I/O problem | ||||
*/ | */ | ||||
private void readGPOS() throws IOException { | private void readGPOS() throws IOException { | ||||
TTFTableName tableTag = TTFTableName.GPOS; | |||||
OFTableName tableTag = OFTableName.GPOS; | |||||
// Initialize temporary state | // Initialize temporary state | ||||
initATState(); | initATState(); | ||||
// Read glyph positioning (GPOS) table | // Read glyph positioning (GPOS) table | ||||
TTFDirTabEntry dirTab = ttf.getDirectoryEntry(tableTag); | |||||
OFDirTabEntry dirTab = otf.getDirectoryEntry(tableTag); | |||||
if (gpos != null) { | if (gpos != null) { | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + ": ignoring duplicate table"); | log.debug(tableTag + ": ignoring duplicate table"); | ||||
} | } | ||||
} else if (dirTab != null) { | } else if (dirTab != null) { | ||||
ttf.seekTab(in, tableTag, 0); | |||||
otf.seekTab(in, tableTag, 0); | |||||
int version = in.readTTFLong(); | int version = in.readTTFLong(); | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug(tableTag + " version: " + (version / 65536) + "." + (version % 65536)); | log.debug(tableTag + " version: " + (version / 65536) + "." + (version % 65536)); | ||||
} else { | } else { | ||||
boolean first = true; | boolean first = true; | ||||
for (int i = 0; i < ia.length; i++) { | for (int i = 0; i < ia.length; i++) { | ||||
if (! first) { | |||||
if (!first) { | |||||
sb.append(' '); | sb.append(' '); | ||||
} else { | } else { | ||||
first = false; | first = false; |
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
} else { | } else { | ||||
int s = a.getStart(); | int s = a.getStart(); | ||||
int e = a.getEnd(); | int e = a.getEnd(); | ||||
if (! hasFinalPrecedingContext(ca, nc, s, e)) { | |||||
if (!hasFinalPrecedingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else if (forcesFinalThisContext(ca, nc, s, e)) { | } else if (forcesFinalThisContext(ca, nc, s, e)) { | ||||
return true; | return true; | ||||
} else if (! hasFinalFollowingContext(ca, nc, s, e)) { | |||||
} else if (!hasFinalFollowingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | return true; | ||||
} else { | } else { | ||||
int s = a.getStart(); | int s = a.getStart(); | ||||
int e = a.getEnd(); | int e = a.getEnd(); | ||||
if (! hasInitialPrecedingContext(ca, nc, s, e)) { | |||||
if (!hasInitialPrecedingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else if (! hasInitialFollowingContext(ca, nc, s, e)) { | |||||
} else if (!hasInitialFollowingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | return true; | ||||
} else { | } else { | ||||
int s = a.getStart(); | int s = a.getStart(); | ||||
int e = a.getEnd(); | int e = a.getEnd(); | ||||
if (! hasLigaturePrecedingContext(ca, nc, s, e)) { | |||||
if (!hasLigaturePrecedingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else if (! hasLigatureFollowingContext(ca, nc, s, e)) { | |||||
} else if (!hasLigatureFollowingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | return true; | ||||
} else { | } else { | ||||
int s = a.getStart(); | int s = a.getStart(); | ||||
int e = a.getEnd(); | int e = a.getEnd(); | ||||
if (! hasMedialPrecedingContext(ca, nc, s, e)) { | |||||
if (!hasMedialPrecedingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else if (! hasMedialThisContext(ca, nc, s, e)) { | |||||
} else if (!hasMedialThisContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else if (! hasMedialFollowingContext(ca, nc, s, e)) { | |||||
} else if (!hasMedialFollowingContext(ca, nc, s, e)) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | return true; |
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: WhitespaceAfter | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
} | } | ||||
private static boolean containsHalfConsonant(GlyphSequence gs, int k) { | private static boolean containsHalfConsonant(GlyphSequence gs, int k) { | ||||
Boolean half = (Boolean) gs.getAssociation(k) . getPredication("half"); | |||||
Boolean half = (Boolean) gs.getAssociation(k) .getPredication("half"); | |||||
return (half != null) ? half.booleanValue() : false; | return (half != null) ? half.booleanValue() : false; | ||||
} | } | ||||
// first candidate target is after first non-half consonant | // first candidate target is after first non-half consonant | ||||
for (int i = 0; i < ng; i++) { | for (int i = 0; i < ng; i++) { | ||||
if ((i != source) && containsConsonant(gs, i)) { | if ((i != source) && containsConsonant(gs, i)) { | ||||
if (! containsHalfConsonant(gs, i)) { | |||||
if (!containsHalfConsonant(gs, i)) { | |||||
c1 = i + 1; | c1 = i + 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// second candidate target is after last non-prebase matra after first candidate or before first syllable or vedic mark | // second candidate target is after last non-prebase matra after first candidate or before first syllable or vedic mark | ||||
for (int i = (c1 >= 0) ? c1 : 0; i < ng; i++) { | for (int i = (c1 >= 0) ? c1 : 0; i < ng; i++) { | ||||
if (containsMatra(gs, i) && ! containsPreBaseMatra(gs, i)) { | |||||
if (containsMatra(gs, i) && !containsPreBaseMatra(gs, i)) { | |||||
c2 = i + 1; | c2 = i + 1; | ||||
} else if (containsOtherMark(gs, i)) { | } else if (containsOtherMark(gs, i)) { | ||||
c2 = i; | c2 = i; | ||||
} | } | ||||
private static boolean containsReph(GlyphSequence gs, int k) { | private static boolean containsReph(GlyphSequence gs, int k) { | ||||
Boolean rphf = (Boolean) gs.getAssociation(k) . getPredication("rphf"); | |||||
Boolean rphf = (Boolean) gs.getAssociation(k) .getPredication("rphf"); | |||||
return (rphf != null) ? rphf.booleanValue() : false; | return (rphf != null) ? rphf.booleanValue() : false; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static boolean isC(int c) { | static boolean isC(int c) { | ||||
return isType(c,C_C); | |||||
return isType(c, C_C); | |||||
} | } | ||||
static boolean isR(int c) { | static boolean isR(int c) { | ||||
return isType(c,C_C) && hasR(c); | |||||
return isType(c, C_C) && hasR(c); | |||||
} | } | ||||
static boolean isV(int c) { | static boolean isV(int c) { | ||||
return isType(c,C_V); | |||||
return isType(c, C_V); | |||||
} | } | ||||
static boolean isN(int c) { | static boolean isN(int c) { | ||||
return c == 0x093C; | return c == 0x093C; | ||||
return c == 0x094D; | return c == 0x094D; | ||||
} | } | ||||
static boolean isM(int c) { | static boolean isM(int c) { | ||||
return isType(c,C_M); | |||||
return isType(c, C_M); | |||||
} | } | ||||
static boolean isPreM(int c) { | static boolean isPreM(int c) { | ||||
return isType(c,C_M) && hasFlag(c,C_PRE); | |||||
return isType(c, C_M) && hasFlag(c, C_PRE); | |||||
} | } | ||||
static boolean isX(int c) { | static boolean isX(int c) { | ||||
switch (typeOf(c)) { | switch (typeOf(c)) { | ||||
} | } | ||||
} | } | ||||
static boolean hasR(int c) { | static boolean hasR(int c) { | ||||
return hasFlag(c,C_R); | |||||
return hasFlag(c, C_R); | |||||
} | } | ||||
static boolean hasN(int c) { | static boolean hasN(int c) { | ||||
return hasFlag(c,C_N); | |||||
return hasFlag(c, C_N); | |||||
} | } | ||||
} | } |
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: WhitespaceAfter | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
} | } | ||||
private static boolean containsHalfConsonant(GlyphSequence gs, int k) { | private static boolean containsHalfConsonant(GlyphSequence gs, int k) { | ||||
Boolean half = (Boolean) gs.getAssociation(k) . getPredication("half"); | |||||
Boolean half = (Boolean) gs.getAssociation(k) .getPredication("half"); | |||||
return (half != null) ? half.booleanValue() : false; | return (half != null) ? half.booleanValue() : false; | ||||
} | } | ||||
// first candidate target is after first non-half consonant | // first candidate target is after first non-half consonant | ||||
for (int i = 0; i < ng; i++) { | for (int i = 0; i < ng; i++) { | ||||
if ((i != source) && containsConsonant(gs, i)) { | if ((i != source) && containsConsonant(gs, i)) { | ||||
if (! containsHalfConsonant(gs, i)) { | |||||
if (!containsHalfConsonant(gs, i)) { | |||||
c1 = i + 1; | c1 = i + 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// second candidate target is after last non-prebase matra after first candidate or before first syllable or vedic mark | // second candidate target is after last non-prebase matra after first candidate or before first syllable or vedic mark | ||||
for (int i = (c1 >= 0) ? c1 : 0; i < ng; i++) { | for (int i = (c1 >= 0) ? c1 : 0; i < ng; i++) { | ||||
if (containsMatra(gs, i) && ! containsPreBaseMatra(gs, i)) { | |||||
if (containsMatra(gs, i) && !containsPreBaseMatra(gs, i)) { | |||||
c2 = i + 1; | c2 = i + 1; | ||||
} else if (containsOtherMark(gs, i)) { | } else if (containsOtherMark(gs, i)) { | ||||
c2 = i; | c2 = i; | ||||
} | } | ||||
private static boolean containsReph(GlyphSequence gs, int k) { | private static boolean containsReph(GlyphSequence gs, int k) { | ||||
Boolean rphf = (Boolean) gs.getAssociation(k) . getPredication("rphf"); | |||||
Boolean rphf = (Boolean) gs.getAssociation(k) .getPredication("rphf"); | |||||
return (rphf != null) ? rphf.booleanValue() : false; | return (rphf != null) ? rphf.booleanValue() : false; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static boolean isC(int c) { | static boolean isC(int c) { | ||||
return isType(c,C_C); | |||||
return isType(c, C_C); | |||||
} | } | ||||
static boolean isR(int c) { | static boolean isR(int c) { | ||||
return isType(c,C_C) && hasR(c); | |||||
return isType(c, C_C) && hasR(c); | |||||
} | } | ||||
static boolean isV(int c) { | static boolean isV(int c) { | ||||
return isType(c,C_V); | |||||
return isType(c, C_V); | |||||
} | } | ||||
static boolean isN(int c) { | static boolean isN(int c) { | ||||
return c == 0x0ABC; | return c == 0x0ABC; | ||||
return c == 0x0ACD; | return c == 0x0ACD; | ||||
} | } | ||||
static boolean isM(int c) { | static boolean isM(int c) { | ||||
return isType(c,C_M); | |||||
return isType(c, C_M); | |||||
} | } | ||||
static boolean isPreM(int c) { | static boolean isPreM(int c) { | ||||
return isType(c,C_M) && hasFlag(c,C_PRE); | |||||
return isType(c, C_M) && hasFlag(c, C_PRE); | |||||
} | } | ||||
static boolean isX(int c) { | static boolean isX(int c) { | ||||
switch (typeOf(c)) { | switch (typeOf(c)) { | ||||
} | } | ||||
} | } | ||||
static boolean hasR(int c) { | static boolean hasR(int c) { | ||||
return hasFlag(c,C_R); | |||||
return hasFlag(c, C_R); | |||||
} | } | ||||
static boolean hasN(int c) { | static boolean hasN(int c) { | ||||
return hasFlag(c,C_N); | |||||
return hasFlag(c, C_N); | |||||
} | } | ||||
} | } |
import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; | import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; | ||||
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: WhitespaceAfter | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
} | } | ||||
private static boolean containsHalfConsonant(GlyphSequence gs, int k) { | private static boolean containsHalfConsonant(GlyphSequence gs, int k) { | ||||
Boolean half = (Boolean) gs.getAssociation(k) . getPredication("half"); | |||||
Boolean half = (Boolean) gs.getAssociation(k) .getPredication("half"); | |||||
return (half != null) ? half.booleanValue() : false; | return (half != null) ? half.booleanValue() : false; | ||||
} | } | ||||
// first candidate target is after first non-half consonant | // first candidate target is after first non-half consonant | ||||
for (int i = 0; i < ng; i++) { | for (int i = 0; i < ng; i++) { | ||||
if ((i != source) && containsConsonant(gs, i)) { | if ((i != source) && containsConsonant(gs, i)) { | ||||
if (! containsHalfConsonant(gs, i)) { | |||||
if (!containsHalfConsonant(gs, i)) { | |||||
c1 = i + 1; | c1 = i + 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// second candidate target is after last non-prebase matra after first candidate or before first syllable or vedic mark | // second candidate target is after last non-prebase matra after first candidate or before first syllable or vedic mark | ||||
for (int i = (c1 >= 0) ? c1 : 0; i < ng; i++) { | for (int i = (c1 >= 0) ? c1 : 0; i < ng; i++) { | ||||
if (containsMatra(gs, i) && ! containsPreBaseMatra(gs, i)) { | |||||
if (containsMatra(gs, i) && !containsPreBaseMatra(gs, i)) { | |||||
c2 = i + 1; | c2 = i + 1; | ||||
} else if (containsOtherMark(gs, i)) { | } else if (containsOtherMark(gs, i)) { | ||||
c2 = i; | c2 = i; | ||||
} | } | ||||
private static boolean containsReph(GlyphSequence gs, int k) { | private static boolean containsReph(GlyphSequence gs, int k) { | ||||
Boolean rphf = (Boolean) gs.getAssociation(k) . getPredication("rphf"); | |||||
Boolean rphf = (Boolean) gs.getAssociation(k) .getPredication("rphf"); | |||||
return (rphf != null) ? rphf.booleanValue() : false; | return (rphf != null) ? rphf.booleanValue() : false; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static boolean isC(int c) { | static boolean isC(int c) { | ||||
return isType(c,C_C); | |||||
return isType(c, C_C); | |||||
} | } | ||||
static boolean isR(int c) { | static boolean isR(int c) { | ||||
return isType(c,C_C) && hasR(c); | |||||
return isType(c, C_C) && hasR(c); | |||||
} | } | ||||
static boolean isV(int c) { | static boolean isV(int c) { | ||||
return isType(c,C_V); | |||||
return isType(c, C_V); | |||||
} | } | ||||
static boolean isN(int c) { | static boolean isN(int c) { | ||||
return c == 0x0A3C; | return c == 0x0A3C; | ||||
return c == 0x0A4D; | return c == 0x0A4D; | ||||
} | } | ||||
static boolean isM(int c) { | static boolean isM(int c) { | ||||
return isType(c,C_M); | |||||
return isType(c, C_M); | |||||
} | } | ||||
static boolean isPreM(int c) { | static boolean isPreM(int c) { | ||||
return isType(c,C_M) && hasFlag(c,C_PRE); | |||||
return isType(c, C_M) && hasFlag(c, C_PRE); | |||||
} | } | ||||
static boolean isX(int c) { | static boolean isX(int c) { | ||||
switch (typeOf(c)) { | switch (typeOf(c)) { | ||||
} | } | ||||
} | } | ||||
static boolean hasR(int c) { | static boolean hasR(int c) { | ||||
return hasFlag(c,C_R); | |||||
return hasFlag(c, C_R); | |||||
} | } | ||||
static boolean hasN(int c) { | static boolean hasN(int c) { | ||||
return hasFlag(c,C_N); | |||||
return hasFlag(c, C_N); | |||||
} | } | ||||
@Override | @Override |
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
// CSOFF: EmptyForIteratorPadCheck | |||||
// CSOFF: WhitespaceAfterCheck | |||||
// CSOFF: ParameterNumberCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
} | } | ||||
private GlyphSequence[] syllabize(GlyphSequence gs, String script, String language) { | private GlyphSequence[] syllabize(GlyphSequence gs, String script, String language) { | ||||
return Syllabizer.getSyllabizer(script, language, getSyllabizerClass()) . syllabize(gs); | |||||
return Syllabizer.getSyllabizer(script, language, getSyllabizerClass()) .syllabize(gs); | |||||
} | } | ||||
private GlyphSequence unsyllabize(GlyphSequence gs, GlyphSequence[] sa) { | private GlyphSequence unsyllabize(GlyphSequence gs, GlyphSequence[] sa) { | ||||
public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
if (o instanceof Syllabizer) { | if (o instanceof Syllabizer) { | ||||
Syllabizer s = (Syllabizer) o; | Syllabizer s = (Syllabizer) o; | ||||
if (! s.script.equals(script)) { | |||||
return false; | |||||
} else if (! s.language.equals(language)) { | |||||
if (!s.script.equals(script)) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | |||||
return s.language.equals(language); | |||||
} | } | ||||
} else { | } else { | ||||
return false; | return false; | ||||
} | } | ||||
return d; | return d; | ||||
} | } | ||||
private static Map<String,Syllabizer> syllabizers = new HashMap<String,Syllabizer>(); | |||||
private static Map<String, Syllabizer> syllabizers = new HashMap<String, Syllabizer>(); | |||||
static Syllabizer getSyllabizer(String script, String language, Class<? extends Syllabizer> syllabizerClass) { | static Syllabizer getSyllabizer(String script, String language, Class<? extends Syllabizer> syllabizerClass) { | ||||
String sid = makeSyllabizerId(script, language); | String sid = makeSyllabizerId(script, language); | ||||
Syllabizer s = syllabizers.get(sid); | Syllabizer s = syllabizers.get(sid); |
import org.apache.fop.complexscripts.util.GlyphSequence; | import org.apache.fop.complexscripts.util.GlyphSequence; | ||||
import org.apache.fop.complexscripts.util.ScriptContextTester; | import org.apache.fop.complexscripts.util.ScriptContextTester; | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: ParameterNumberCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
/** | /** | ||||
* <p>Abstract script processor base class for which an implementation of the substitution and positioning methods | * <p>Abstract script processor base class for which an implementation of the substitution and positioning methods | ||||
public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
if (o instanceof AssembledLookupsKey) { | if (o instanceof AssembledLookupsKey) { | ||||
AssembledLookupsKey k = (AssembledLookupsKey) o; | AssembledLookupsKey k = (AssembledLookupsKey) o; | ||||
if (! table.equals(k.table)) { | |||||
if (!table.equals(k.table)) { | |||||
return false; | return false; | ||||
} else if (! Arrays.equals(features, k.features)) { | |||||
return false; | |||||
} else if (! lookups.equals(k.lookups)) { | |||||
} else if (!Arrays.equals(features, k.features)) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | |||||
return lookups.equals(k.lookups); | |||||
} | } | ||||
} else { | } else { | ||||
return false; | return false; |
import org.apache.fop.util.CharUtilities; | import org.apache.fop.util.CharUtilities; | ||||
// CSOFF: AvoidNestedBlocksCheck | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | |||||
// CSOFF: SimplifyBooleanReturnCheck | |||||
// CSOFF: WhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>Script related utilities.</p> | * <p>Script related utilities.</p> | ||||
* | * | ||||
*/ | */ | ||||
public final class CharScript { | public final class CharScript { | ||||
// CSOFF: LineLength | |||||
// | // | ||||
// The following script codes are based on ISO 15924. Codes less than 1000 are | // The following script codes are based on ISO 15924. Codes less than 1000 are | ||||
// official assignments from 15924; those equal to or greater than 1000 are FOP | // official assignments from 15924; those equal to or greater than 1000 are FOP | ||||
case SCRIPT_UNCODED: | case SCRIPT_UNCODED: | ||||
break; | break; | ||||
default: | default: | ||||
{ | |||||
Integer v = (Integer) e.getValue(); | |||||
assert v != null; | |||||
int c = v.intValue(); | |||||
if (c > cMax) { | |||||
cMax = c; | |||||
sMax = s; | |||||
} | |||||
break; | |||||
Integer v = (Integer) e.getValue(); | |||||
assert v != null; | |||||
int c = v.intValue(); | |||||
if (c > cMax) { | |||||
cMax = c; | |||||
sMax = s; | |||||
} | } | ||||
break; | |||||
} | } | ||||
} | } | ||||
if (sMax < 0) { | if (sMax < 0) { | ||||
* @return a script tag | * @return a script tag | ||||
*/ | */ | ||||
public static String scriptTagFromCode(int code) { | public static String scriptTagFromCode(int code) { | ||||
Map<Integer,String> m = getScriptTagsMap(); | |||||
Map<Integer, String> m = getScriptTagsMap(); | |||||
if (m != null) { | if (m != null) { | ||||
String tag; | String tag; | ||||
if ((tag = m.get(Integer.valueOf(code))) != null) { | if ((tag = m.get(Integer.valueOf(code))) != null) { | ||||
* @return a script code | * @return a script code | ||||
*/ | */ | ||||
public static int scriptCodeFromTag(String tag) { | public static int scriptCodeFromTag(String tag) { | ||||
Map<String,Integer> m = getScriptCodeMap(); | |||||
Map<String, Integer> m = getScriptCodeMap(); | |||||
if (m != null) { | if (m != null) { | ||||
Integer c; | Integer c; | ||||
if ((c = m.get(tag)) != null) { | if ((c = m.get(tag)) != null) { | ||||
} | } | ||||
} | } | ||||
private static Map<Integer,String> scriptTagsMap = null; | |||||
private static Map<String,Integer> scriptCodeMap = null; | |||||
private static Map<Integer, String> scriptTagsMap = null; | |||||
private static Map<String, Integer> scriptCodeMap = null; | |||||
private static void putScriptTag(Map tm, Map cm, int code, String tag) { | private static void putScriptTag(Map tm, Map cm, int code, String tag) { | ||||
assert tag != null; | assert tag != null; | ||||
} | } | ||||
private static void makeScriptMaps() { | private static void makeScriptMaps() { | ||||
HashMap<Integer,String> tm = new HashMap<Integer,String>(); | |||||
HashMap<String,Integer> cm = new HashMap<String,Integer>(); | |||||
HashMap<Integer, String> tm = new HashMap<Integer, String>(); | |||||
HashMap<String, Integer> cm = new HashMap<String, Integer>(); | |||||
putScriptTag(tm, cm, SCRIPT_HEBREW, "hebr"); | putScriptTag(tm, cm, SCRIPT_HEBREW, "hebr"); | ||||
putScriptTag(tm, cm, SCRIPT_MONGOLIAN, "mong"); | putScriptTag(tm, cm, SCRIPT_MONGOLIAN, "mong"); | ||||
putScriptTag(tm, cm, SCRIPT_ARABIC, "arab"); | putScriptTag(tm, cm, SCRIPT_ARABIC, "arab"); | ||||
scriptCodeMap = cm; | scriptCodeMap = cm; | ||||
} | } | ||||
private static Map<Integer,String> getScriptTagsMap() { | |||||
private static Map<Integer, String> getScriptTagsMap() { | |||||
if (scriptTagsMap == null) { | if (scriptTagsMap == null) { | ||||
makeScriptMaps(); | makeScriptMaps(); | ||||
} | } | ||||
return scriptTagsMap; | return scriptTagsMap; | ||||
} | } | ||||
private static Map<String,Integer> getScriptCodeMap() { | |||||
private static Map<String, Integer> getScriptCodeMap() { | |||||
if (scriptCodeMap == null) { | if (scriptCodeMap == null) { | ||||
makeScriptMaps(); | makeScriptMaps(); | ||||
} | } |
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: WhitespaceAfterCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
/** | /** | ||||
* <p>A GlyphSequence encapsulates a sequence of character codes, a sequence of glyph codes, | * <p>A GlyphSequence encapsulates a sequence of character codes, a sequence of glyph codes, | ||||
private final int offset; | private final int offset; | ||||
private final int count; | private final int count; | ||||
private final int[] subIntervals; | private final int[] subIntervals; | ||||
private Map<String,Object> predications; | |||||
private Map<String, Object> predications; | |||||
// class state | // class state | ||||
private static volatile Map<String,PredicationMerger> predicationMergers; | |||||
private static volatile Map<String, PredicationMerger> predicationMergers; | |||||
interface PredicationMerger { | interface PredicationMerger { | ||||
Object merge(String key, Object v1, Object v2); | Object merge(String key, Object v1, Object v2); | ||||
public boolean contained(int offset, int count) { | public boolean contained(int offset, int count) { | ||||
int s = offset; | int s = offset; | ||||
int e = offset + count; | int e = offset + count; | ||||
if (! isDisjoint()) { | |||||
if (!isDisjoint()) { | |||||
int s0 = getStart(); | int s0 = getStart(); | ||||
int e0 = getEnd(); | int e0 = getEnd(); | ||||
return (s0 >= s) && (e0 <= e); | return (s0 >= s) && (e0 <= e); | ||||
*/ | */ | ||||
public void setPredication(String key, Object value) { | public void setPredication(String key, Object value) { | ||||
if (predications == null) { | if (predications == null) { | ||||
predications = new HashMap<String,Object>(); | |||||
predications = new HashMap<String, Object>(); | |||||
} | } | ||||
if (predications != null) { | if (predications != null) { | ||||
predications.put(key, value); | predications.put(key, value); | ||||
*/ | */ | ||||
public void mergePredication(String key, Object value) { | public void mergePredication(String key, Object value) { | ||||
if (predications == null) { | if (predications == null) { | ||||
predications = new HashMap<String,Object>(); | |||||
predications = new HashMap<String, Object>(); | |||||
} | } | ||||
if (predications != null) { | if (predications != null) { | ||||
if (predications.containsKey(key)) { | if (predications.containsKey(key)) { | ||||
*/ | */ | ||||
public void mergePredications(CharAssociation ca) { | public void mergePredications(CharAssociation ca) { | ||||
if (ca.predications != null) { | if (ca.predications != null) { | ||||
for (Map.Entry<String,Object> e : ca.predications.entrySet()) { | |||||
for (Map.Entry<String, Object> e : ca.predications.entrySet()) { | |||||
mergePredication(e.getKey(), e.getValue()); | mergePredication(e.getKey(), e.getValue()); | ||||
} | } | ||||
} | } | ||||
try { | try { | ||||
CharAssociation ca = (CharAssociation) super.clone(); | CharAssociation ca = (CharAssociation) super.clone(); | ||||
if (predications != null) { | if (predications != null) { | ||||
ca.predications = new HashMap<String,Object>(predications); | |||||
ca.predications = new HashMap<String, Object>(predications); | |||||
} | } | ||||
return ca; | return ca; | ||||
} catch (CloneNotSupportedException e) { | } catch (CloneNotSupportedException e) { | ||||
*/ | */ | ||||
public static void setPredicationMerger(String key, PredicationMerger pm) { | public static void setPredicationMerger(String key, PredicationMerger pm) { | ||||
if (predicationMergers == null) { | if (predicationMergers == null) { | ||||
predicationMergers = new HashMap<String,PredicationMerger>(); | |||||
predicationMergers = new HashMap<String, PredicationMerger>(); | |||||
} | } | ||||
if (predicationMergers != null) { | if (predicationMergers != null) { | ||||
predicationMergers.put(key, pm); | predicationMergers.put(key, pm); |
import java.util.List; | import java.util.List; | ||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: NoWhitespaceAfterCheck | |||||
// CSOFF: AvoidNestedBlocksCheck | |||||
/** | /** | ||||
* <p>Implementation of Number to String Conversion algorithm specified by | * <p>Implementation of Number to String Conversion algorithm specified by | ||||
separators.add(token.toArray(new Integer [ token.size() ])); | separators.add(token.toArray(new Integer [ token.size() ])); | ||||
} | } | ||||
} | } | ||||
if (! separators.isEmpty()) { | |||||
if (!separators.isEmpty()) { | |||||
this.prefix = separators.remove(0); | this.prefix = separators.remove(0); | ||||
} | } | ||||
if (! separators.isEmpty()) { | |||||
if (!separators.isEmpty()) { | |||||
this.suffix = separators.remove(separators.size() - 1); | this.suffix = separators.remove(separators.size() - 1); | ||||
} | } | ||||
this.separators = separators.toArray(new Integer [ separators.size() ] []); | this.separators = separators.toArray(new Integer [ separators.size() ] []); | ||||
int s = token[0].intValue(); | int s = token[0].intValue(); | ||||
switch (s) { | switch (s) { | ||||
case (int) '1': | case (int) '1': | ||||
{ | |||||
fn = formatNumberAsDecimal(number, (int) '1', 1); | |||||
break; | |||||
} | |||||
fn = formatNumberAsDecimal(number, (int) '1', 1); | |||||
break; | |||||
case (int) 'W': | case (int) 'W': | ||||
case (int) 'w': | case (int) 'w': | ||||
{ | |||||
fn = formatNumberAsWord(number, (s == (int) 'W') ? Character.UPPERCASE_LETTER : Character.LOWERCASE_LETTER); | |||||
break; | |||||
} | |||||
fn = formatNumberAsWord(number, (s == (int) 'W') ? Character.UPPERCASE_LETTER : Character.LOWERCASE_LETTER); | |||||
break; | |||||
case (int) 'A': // handled as numeric sequence | case (int) 'A': // handled as numeric sequence | ||||
case (int) 'a': // handled as numeric sequence | case (int) 'a': // handled as numeric sequence | ||||
case (int) 'I': // handled as numeric special | case (int) 'I': // handled as numeric special | ||||
case (int) 'i': // handled as numeric special | case (int) 'i': // handled as numeric special | ||||
default: | default: | ||||
{ | |||||
if (isStartOfDecimalSequence(s)) { | |||||
fn = formatNumberAsDecimal(number, s, 1); | |||||
} else if (isStartOfAlphabeticSequence(s)) { | |||||
fn = formatNumberAsSequence(number, s, getSequenceBase(s), null); | |||||
} else if (isStartOfNumericSpecial(s)) { | |||||
fn = formatNumberAsSpecial(number, s); | |||||
} else { | |||||
fn = null; | |||||
} | |||||
break; | |||||
if (isStartOfDecimalSequence(s)) { | |||||
fn = formatNumberAsDecimal(number, s, 1); | |||||
} else if (isStartOfAlphabeticSequence(s)) { | |||||
fn = formatNumberAsSequence(number, s, getSequenceBase(s), null); | |||||
} else if (isStartOfNumericSpecial(s)) { | |||||
fn = formatNumberAsSpecial(number, s); | |||||
} else { | |||||
fn = null; | |||||
} | } | ||||
break; | |||||
} | } | ||||
} else if ((token.length == 2) && (token[0] == (int) 'W') && (token[1] == (int) 'w')) { | } else if ((token.length == 2) && (token[0] == (int) 'W') && (token[1] == (int) 'w')) { | ||||
fn = formatNumberAsWord(number, Character.TITLECASE_LETTER); | fn = formatNumberAsWord(number, Character.TITLECASE_LETTER); |
import org.apache.fop.util.CharUtilities; | import org.apache.fop.util.CharUtilities; | ||||
// CSOFF: InnerAssignmentCheck | |||||
/** | /** | ||||
* <p>UTF32 related utilities.</p> | * <p>UTF32 related utilities.</p> |
/** Scope for table header */ | /** Scope for table header */ | ||||
int PR_X_HEADER_COLUMN = 290; | int PR_X_HEADER_COLUMN = 290; | ||||
/** For specifying PDF optional content group (layer) binding. */ | |||||
int PR_X_LAYER = 291; | |||||
/** Number of property constants defined */ | /** Number of property constants defined */ | ||||
int PROPERTY_COUNT = 290; | |||||
int PROPERTY_COUNT = 291; | |||||
// compound property constants | // compound property constants | ||||
m.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO")); | m.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO")); | ||||
m.setDefault("auto"); | m.setDefault("auto"); | ||||
addPropertyMaker("z-index", m); | addPropertyMaker("z-index", m); | ||||
// fox:layer | |||||
m = new StringProperty.Maker(PR_X_LAYER); | |||||
m.setInherited(false); | |||||
m.setDefault(""); | |||||
addPropertyMaker("fox:layer", m); | |||||
} | } | ||||
private void createShorthandProperties() { | private void createShorthandProperties() { |
private int bidiLevel = -1; | private int bidiLevel = -1; | ||||
// The value of properties relevant for all fo objects | // The value of properties relevant for all fo objects | ||||
private String id = null; | |||||
private String id; | |||||
private String layer; | |||||
// End of property values | // End of property values | ||||
/** | /** | ||||
String attributeName = attList.getQName(i); | String attributeName = attList.getQName(i); | ||||
String attributeValue = attList.getValue(i); | String attributeValue = attList.getValue(i); | ||||
Property prop = propertyList.getPropertyForAttribute(attList, attributeName, attributeValue); | Property prop = propertyList.getPropertyForAttribute(attList, attributeName, attributeValue); | ||||
if (prop.equals(value)) { | |||||
if (prop != null && prop.equals(value)) { | |||||
return attributeName; | return attributeName; | ||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
public void bind(PropertyList pList) throws FOPException { | public void bind(PropertyList pList) throws FOPException { | ||||
id = pList.get(PR_ID).getString(); | id = pList.get(PR_ID).getString(); | ||||
layer = pList.get(PR_X_LAYER).getString(); | |||||
} | } | ||||
/** | /** | ||||
return (id != null && id.length() > 0); | return (id != null && id.length() > 0); | ||||
} | } | ||||
/** @return the "layer" property. */ | |||||
public String getLayer() { | |||||
return layer; | |||||
} | |||||
/** @return whether this object has an layer set */ | |||||
public boolean hasLayer() { | |||||
return (layer != null && layer.length() > 0); | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public String getNamespaceURI() { | public String getNamespaceURI() { | ||||
return FOElementMapping.URI; | return FOElementMapping.URI; | ||||
if (bidiLevel >= 0) { | if (bidiLevel >= 0) { | ||||
if ((this.bidiLevel < 0) || (bidiLevel < this.bidiLevel)) { | if ((this.bidiLevel < 0) || (bidiLevel < this.bidiLevel)) { | ||||
this.bidiLevel = bidiLevel; | this.bidiLevel = bidiLevel; | ||||
if (parent != null) { | |||||
if ((parent != null) && !isBidiPropagationBoundary()) { | |||||
FObj foParent = (FObj) parent; | FObj foParent = (FObj) parent; | ||||
int parentBidiLevel = foParent.getBidiLevel(); | int parentBidiLevel = foParent.getBidiLevel(); | ||||
if ((parentBidiLevel < 0) || (bidiLevel < parentBidiLevel)) { | if ((parentBidiLevel < 0) || (bidiLevel < parentBidiLevel)) { | ||||
return level; | return level; | ||||
} | } | ||||
} | } | ||||
if (isBidiInheritanceBoundary()) { | |||||
break; | |||||
} | |||||
} | } | ||||
return -1; | return -1; | ||||
} | } | ||||
protected boolean isBidiBoundary(boolean propagate) { | |||||
return false; | |||||
} | |||||
private boolean isBidiInheritanceBoundary() { | |||||
return isBidiBoundary(false); | |||||
} | |||||
private boolean isBidiPropagationBoundary() { | |||||
return isBidiBoundary(true); | |||||
} | |||||
/** | /** | ||||
* Add a new extension attachment to this FObj. | * Add a new extension attachment to this FObj. | ||||
* (see org.apache.fop.fo.FONode for details) | * (see org.apache.fop.fo.FONode for details) |
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public Property getOptionalArgDefault(int index, PropertyInfo pi) throws PropertyException { | public Property getOptionalArgDefault(int index, PropertyInfo pi) throws PropertyException { | ||||
if (index >= getOptionalArgsCount()) { | if (index >= getOptionalArgsCount()) { | ||||
PropertyException e = new PropertyException(new IndexOutOfBoundsException("illegal optional argument index")); | |||||
PropertyException e = new PropertyException( | |||||
new IndexOutOfBoundsException("illegal optional argument index")); | |||||
e.setPropertyInfo(pi); | e.setPropertyInfo(pi); | ||||
throw e; | throw e; | ||||
} else { | } else { |
} | } | ||||
int numArgs = args.size(); | int numArgs = args.size(); | ||||
if (numArgs < numReq) { | if (numArgs < numReq) { | ||||
throw new PropertyException("Expected " + numReq + " required arguments, but only " + numArgs + " specified"); | |||||
throw new PropertyException("Expected " + numReq + " required arguments, but only " | |||||
+ numArgs + " specified"); | |||||
} else { | } else { | ||||
for (int i = 0; i < numOpt; i++) { | for (int i = 0; i < numOpt; i++) { | ||||
if (args.size() < (numReq + i + 1)) { | if (args.size() < (numReq + i + 1)) { |
PROPERTY_ATTRIBUTES.add("border-before-end-radius"); | PROPERTY_ATTRIBUTES.add("border-before-end-radius"); | ||||
PROPERTY_ATTRIBUTES.add("border-after-start-radius"); | PROPERTY_ATTRIBUTES.add("border-after-start-radius"); | ||||
PROPERTY_ATTRIBUTES.add("border-after-end-radius"); | PROPERTY_ATTRIBUTES.add("border-after-end-radius"); | ||||
//Optional content groups (layers) | |||||
PROPERTY_ATTRIBUTES.add("layer"); | |||||
} | } | ||||
/** | /** |
referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); | referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); | ||||
span = pList.get(PR_SPAN).getEnum(); | span = pList.get(PR_SPAN).getEnum(); | ||||
writingModeTraits = new WritingModeTraits( | writingModeTraits = new WritingModeTraits( | ||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum())); | |||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum()), | |||||
pList.getExplicit(PR_WRITING_MODE) != null); | |||||
disableColumnBalancing = pList.get(PR_X_DISABLE_COLUMN_BALANCING).getEnum(); | disableColumnBalancing = pList.get(PR_X_DISABLE_COLUMN_BALANCING).getEnum(); | ||||
} | } | ||||
return writingModeTraits.getWritingMode(); | return writingModeTraits.getWritingMode(); | ||||
} | } | ||||
/** | |||||
* Obtain writing mode explicit indicator. | |||||
* @return the writing mode explicit indicator | |||||
*/ | |||||
public boolean getExplicitWritingMode() { | |||||
return writingModeTraits.getExplicitWritingMode(); | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public String getLocalName() { | public String getLocalName() { | ||||
return "block-container"; | return "block-container"; | ||||
public int getNameId() { | public int getNameId() { | ||||
return FO_BLOCK_CONTAINER; | return FO_BLOCK_CONTAINER; | ||||
} | } | ||||
} | |||||
@Override | |||||
protected boolean isBidiBoundary(boolean propagate) { | |||||
return getExplicitWritingMode(); | |||||
} | |||||
} |
import org.apache.fop.traits.WritingMode; | import org.apache.fop.traits.WritingMode; | ||||
import org.apache.fop.traits.WritingModeTraits; | import org.apache.fop.traits.WritingModeTraits; | ||||
/** | |||||
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_inline-container"> | |||||
* <code>fo:inline-container</code></a> object. | |||||
*/ | |||||
public class InlineContainer extends FObj { | public class InlineContainer extends FObj { | ||||
// The value of FO traits (refined properties) that apply to fo:inline-container. | |||||
private Length alignmentAdjust; | |||||
private int alignmentBaseline; | |||||
private Length baselineShift; | |||||
private LengthRangeProperty inlineProgressionDimension; | |||||
private LengthRangeProperty blockProgressionDimension; | private LengthRangeProperty blockProgressionDimension; | ||||
private int overflow; | |||||
private CommonBorderPaddingBackground commonBorderPaddingBackground; | private CommonBorderPaddingBackground commonBorderPaddingBackground; | ||||
private CommonMarginInline commonMarginInline; | private CommonMarginInline commonMarginInline; | ||||
private int clip; | |||||
private int dominantBaseline; | |||||
private LengthRangeProperty inlineProgressionDimension; | |||||
private Numeric referenceOrientation; | |||||
private int displayAlign; | |||||
private KeepProperty keepTogether; | private KeepProperty keepTogether; | ||||
private KeepProperty keepWithNext; | |||||
private KeepProperty keepWithPrevious; | |||||
private SpaceProperty lineHeight; | private SpaceProperty lineHeight; | ||||
private int overflow; | |||||
private Numeric referenceOrientation; | |||||
private Length alignmentAdjust; | |||||
private int alignmentBaseline; | |||||
private Length baselineShift; | |||||
private int dominantBaseline; | |||||
private WritingModeTraits writingModeTraits; | private WritingModeTraits writingModeTraits; | ||||
// Unused but valid items, commented out for performance: | |||||
// private CommonRelativePosition commonRelativePosition; | |||||
// private int displayAlign; | |||||
// private Length height; | |||||
// private KeepProperty keepWithNext; | |||||
// private KeepProperty keepWithPrevious; | |||||
// private Length width; | |||||
// End of FO trait values | |||||
/** used for FO validation */ | /** used for FO validation */ | ||||
private boolean blockItemFound = false; | |||||
private boolean blockItemFound; | |||||
/** | /** | ||||
* Base constructor | |||||
* Creates a new instance. | |||||
* | * | ||||
* @param parent {@link FONode} that is the parent of this object | |||||
* @param parent the parent of this inline-container | |||||
*/ | */ | ||||
public InlineContainer(FONode parent) { | public InlineContainer(FONode parent) { | ||||
super(parent); | super(parent); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public void bind(PropertyList pList) throws FOPException { | public void bind(PropertyList pList) throws FOPException { | ||||
super.bind(pList); | super.bind(pList); | ||||
alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); | alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); | ||||
blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); | blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); | ||||
commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); | commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); | ||||
commonMarginInline = pList.getMarginInlineProps(); | commonMarginInline = pList.getMarginInlineProps(); | ||||
clip = pList.get(PR_CLIP).getEnum(); | |||||
displayAlign = pList.get(PR_DISPLAY_ALIGN).getEnum(); | |||||
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); | dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); | ||||
inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange(); | inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange(); | ||||
keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); | keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep(); | ||||
keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); | |||||
keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep(); | |||||
lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); | lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); | ||||
overflow = pList.get(PR_OVERFLOW).getEnum(); | overflow = pList.get(PR_OVERFLOW).getEnum(); | ||||
referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); | referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); | ||||
writingModeTraits = new WritingModeTraits( | writingModeTraits = new WritingModeTraits( | ||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum())); | |||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum()), | |||||
pList.getExplicit(PR_WRITING_MODE) != null); | |||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
* <br>XSL Content Model: marker* (%block;)+ | * <br>XSL Content Model: marker* (%block;)+ | ||||
*/ | */ | ||||
@Override | |||||
protected void validateChildNode(Locator loc, String nsURI, String localName) | protected void validateChildNode(Locator loc, String nsURI, String localName) | ||||
throws ValidationException { | throws ValidationException { | ||||
if (FO_URI.equals(nsURI)) { | if (FO_URI.equals(nsURI)) { | ||||
if (localName.equals("marker")) { | if (localName.equals("marker")) { | ||||
if (blockItemFound) { | if (blockItemFound) { | ||||
nodesOutOfOrderError(loc, "fo:marker", "(%block;)"); | |||||
nodesOutOfOrderError(loc, "fo:marker", "(%block;)+"); | |||||
} | } | ||||
} else if (!isBlockItem(nsURI, localName)) { | } else if (!isBlockItem(nsURI, localName)) { | ||||
invalidChildError(loc, nsURI, localName); | invalidChildError(loc, nsURI, localName); | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public void endOfNode() throws FOPException { | public void endOfNode() throws FOPException { | ||||
if (!blockItemFound) { | if (!blockItemFound) { | ||||
missingChildElementError("marker* (%block;)+"); | missingChildElementError("marker* (%block;)+"); | ||||
} | } | ||||
} | } | ||||
/** @return the "alignment-adjust" FO trait */ | |||||
public Length getAlignmentAdjust() { | |||||
return alignmentAdjust; | |||||
/** {@inheritDoc} */ | |||||
public String getLocalName() { | |||||
return "inline-container"; | |||||
} | } | ||||
/** @return the "alignment-baseline" FO trait */ | |||||
public int getAlignmentBaseline() { | |||||
return alignmentBaseline; | |||||
/** | |||||
* {@inheritDoc} | |||||
* @return {@link org.apache.fop.fo.Constants#FO_INLINE_CONTAINER} | |||||
*/ | |||||
public int getNameId() { | |||||
return FO_INLINE_CONTAINER; | |||||
} | } | ||||
/** @return the "baseline-shift" FO trait */ | |||||
public Length getBaselineShift() { | |||||
return baselineShift; | |||||
public LengthRangeProperty getInlineProgressionDimension() { | |||||
return inlineProgressionDimension; | |||||
} | } | ||||
/** @return the "block-progression-dimension" FO trait */ | |||||
public LengthRangeProperty getBlockProgressionDimension() { | public LengthRangeProperty getBlockProgressionDimension() { | ||||
return blockProgressionDimension; | return blockProgressionDimension; | ||||
} | } | ||||
/** @return the "clip" FO trait */ | |||||
public int getClip() { | |||||
return clip; | |||||
public int getOverflow() { | |||||
return overflow; | |||||
} | } | ||||
/**@return Returns the {@link CommonBorderPaddingBackground} */ | |||||
public CommonBorderPaddingBackground getCommonBorderPaddingBackground() { | public CommonBorderPaddingBackground getCommonBorderPaddingBackground() { | ||||
return this.commonBorderPaddingBackground; | return this.commonBorderPaddingBackground; | ||||
} | } | ||||
/** @return Returns the {@link CommonMarginInline} */ | |||||
public CommonMarginInline getCommonMarginInline() { | public CommonMarginInline getCommonMarginInline() { | ||||
return this.commonMarginInline; | return this.commonMarginInline; | ||||
} | } | ||||
/** @return the "dominant-baseline" FO trait */ | |||||
public int getDominantBaseline() { | |||||
return dominantBaseline; | |||||
public int getReferenceOrientation() { | |||||
return referenceOrientation.getValue(); | |||||
} | |||||
public int getDisplayAlign() { | |||||
return this.displayAlign; | |||||
} | |||||
public KeepProperty getKeepWithPrevious() { | |||||
return keepWithPrevious; | |||||
} | } | ||||
/** @return the "keep-together" FO trait */ | |||||
public KeepProperty getKeepTogether() { | public KeepProperty getKeepTogether() { | ||||
return keepTogether; | return keepTogether; | ||||
} | } | ||||
/** @return the "inline-progression-dimension" FO trait */ | |||||
public LengthRangeProperty getInlineProgressionDimension() { | |||||
return inlineProgressionDimension; | |||||
public KeepProperty getKeepWithNext() { | |||||
return keepWithNext; | |||||
} | } | ||||
/** @return the "line-height" FO trait */ | |||||
public SpaceProperty getLineHeight() { | public SpaceProperty getLineHeight() { | ||||
return lineHeight; | return lineHeight; | ||||
} | } | ||||
/** @return the "overflow" FO trait */ | |||||
public int getOverflow() { | |||||
return overflow; | |||||
public Length getAlignmentAdjust() { | |||||
return alignmentAdjust; | |||||
} | } | ||||
/** @return the "reference-orientation" FO trait */ | |||||
public int getReferenceOrientation() { | |||||
return referenceOrientation.getValue(); | |||||
public int getAlignmentBaseline() { | |||||
return alignmentBaseline; | |||||
} | |||||
public Length getBaselineShift() { | |||||
return baselineShift; | |||||
} | |||||
public int getDominantBaseline() { | |||||
return dominantBaseline; | |||||
} | |||||
public WritingMode getWritingMode() { | |||||
return writingModeTraits.getWritingMode(); | |||||
} | } | ||||
/** | /** | ||||
* Obtain inline progression direction. | |||||
* @return the inline progression direction | |||||
* Obtain writing mode explicit indicator. | |||||
* @return the writing mode explicit indicator | |||||
*/ | */ | ||||
public boolean getExplicitWritingMode() { | |||||
return writingModeTraits.getExplicitWritingMode(); | |||||
} | |||||
public Direction getInlineProgressionDirection() { | public Direction getInlineProgressionDirection() { | ||||
return writingModeTraits.getInlineProgressionDirection(); | return writingModeTraits.getInlineProgressionDirection(); | ||||
} | } | ||||
/** | |||||
* Obtain block progression direction. | |||||
* @return the block progression direction | |||||
*/ | |||||
public Direction getBlockProgressionDirection() { | public Direction getBlockProgressionDirection() { | ||||
return writingModeTraits.getBlockProgressionDirection(); | return writingModeTraits.getBlockProgressionDirection(); | ||||
} | } | ||||
/** | |||||
* Obtain column progression direction. | |||||
* @return the column progression direction | |||||
*/ | |||||
public Direction getColumnProgressionDirection() { | public Direction getColumnProgressionDirection() { | ||||
return writingModeTraits.getColumnProgressionDirection(); | return writingModeTraits.getColumnProgressionDirection(); | ||||
} | } | ||||
/** | |||||
* Obtain row progression direction. | |||||
* @return the row progression direction | |||||
*/ | |||||
public Direction getRowProgressionDirection() { | public Direction getRowProgressionDirection() { | ||||
return writingModeTraits.getRowProgressionDirection(); | return writingModeTraits.getRowProgressionDirection(); | ||||
} | } | ||||
/** | |||||
* Obtain (baseline) shift direction. | |||||
* @return the (baseline) shift direction | |||||
*/ | |||||
public Direction getShiftDirection() { | public Direction getShiftDirection() { | ||||
return writingModeTraits.getShiftDirection(); | return writingModeTraits.getShiftDirection(); | ||||
} | } | ||||
/** | |||||
* Obtain writing mode. | |||||
* @return the writing mode | |||||
*/ | |||||
public WritingMode getWritingMode() { | |||||
return writingModeTraits.getWritingMode(); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public String getLocalName() { | |||||
return "inline-container"; | |||||
@Override | |||||
public boolean isDelimitedTextRangeBoundary(int boundary) { | |||||
return false; | |||||
} | } | ||||
/** | |||||
* {@inheritDoc} | |||||
* @return {@link org.apache.fop.fo.Constants#FO_INLINE_CONTAINER} | |||||
*/ | |||||
public int getNameId() { | |||||
return FO_INLINE_CONTAINER; | |||||
@Override | |||||
public boolean generatesReferenceAreas() { | |||||
return true; | |||||
} | } | ||||
@Override | @Override | ||||
public boolean isDelimitedTextRangeBoundary(int boundary) { | |||||
return false; | |||||
protected boolean isBidiBoundary(boolean propagate) { | |||||
return getExplicitWritingMode(); | |||||
} | } | ||||
} | } |
tableOmitFooterAtBreak = pList.get(PR_TABLE_OMIT_FOOTER_AT_BREAK).getEnum(); | tableOmitFooterAtBreak = pList.get(PR_TABLE_OMIT_FOOTER_AT_BREAK).getEnum(); | ||||
tableOmitHeaderAtBreak = pList.get(PR_TABLE_OMIT_HEADER_AT_BREAK).getEnum(); | tableOmitHeaderAtBreak = pList.get(PR_TABLE_OMIT_HEADER_AT_BREAK).getEnum(); | ||||
writingModeTraits = new WritingModeTraits( | writingModeTraits = new WritingModeTraits( | ||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum())); | |||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum()), | |||||
pList.getExplicit(PR_WRITING_MODE) != null); | |||||
//Bind extension properties | //Bind extension properties | ||||
widowContentLimit = pList.get(PR_X_WIDOW_CONTENT_LIMIT).getLength(); | widowContentLimit = pList.get(PR_X_WIDOW_CONTENT_LIMIT).getLength(); | ||||
return writingModeTraits.getWritingMode(); | return writingModeTraits.getWritingMode(); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
public boolean getExplicitWritingMode() { | |||||
return writingModeTraits.getExplicitWritingMode(); | |||||
} | |||||
/** @return the "fox:widow-content-limit" extension FO trait */ | /** @return the "fox:widow-content-limit" extension FO trait */ | ||||
public Length getWidowContentLimit() { | public Length getWidowContentLimit() { | ||||
return widowContentLimit; | return widowContentLimit; | ||||
return ranges; | return ranges; | ||||
} | } | ||||
@Override | |||||
protected boolean isBidiBoundary(boolean propagate) { | |||||
return getExplicitWritingMode(); | |||||
} | |||||
} | } |
masterReference = pList.get(PR_MASTER_REFERENCE).getString(); | masterReference = pList.get(PR_MASTER_REFERENCE).getString(); | ||||
referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); | referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); | ||||
writingModeTraits = new WritingModeTraits( | writingModeTraits = new WritingModeTraits( | ||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum())); | |||||
WritingMode.valueOf(pList.get(PR_WRITING_MODE).getEnum()), | |||||
pList.getExplicit(PR_WRITING_MODE) != null); | |||||
if (masterReference == null || masterReference.equals("")) { | if (masterReference == null || masterReference.equals("")) { | ||||
missingPropertyError("master-reference"); | missingPropertyError("master-reference"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | |||||
* {@inheritDoc} | |||||
*/ | |||||
public boolean getExplicitWritingMode() { | |||||
if (writingModeTraits != null) { | |||||
return writingModeTraits.getExplicitWritingMode(); | |||||
} else { | |||||
return false; | |||||
} | |||||
} | |||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | ||||
return ranges; | return ranges; | ||||
} | } | ||||
@Override | |||||
protected boolean isBidiBoundary(boolean propagate) { | |||||
return true; | |||||
} | |||||
/** | /** | ||||
* Releases a page-sequence's children after the page-sequence has been fully processed. | * Releases a page-sequence's children after the page-sequence has been fully processed. | ||||
*/ | */ |
PropertyList propertyList) | PropertyList propertyList) | ||||
throws PropertyException { | throws PropertyException { | ||||
Property prop = null; | Property prop = null; | ||||
String vProperty = ""; | |||||
// Try each of the stored values in turn | // Try each of the stored values in turn | ||||
Iterator iprop = property.getList().iterator(); | Iterator iprop = property.getList().iterator(); | ||||
while (iprop.hasNext() && prop == null) { | while (iprop.hasNext() && prop == null) { | ||||
Property p = (Property)iprop.next(); | Property p = (Property)iprop.next(); | ||||
if (p.getNCname() != null) { | |||||
vProperty += p.getNCname() + " "; | |||||
} | |||||
prop = maker.convertShorthandProperty(propertyList, p, null); | prop = maker.convertShorthandProperty(propertyList, p, null); | ||||
propertyList.validatePropertyValue(p.getNCname(), prop, property); | |||||
} | } | ||||
propertyList.validatePropertyValue(vProperty.trim(), prop, property); | |||||
return prop; | return prop; | ||||
} | } | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.apps.io.InternalResourceResolver; | import org.apache.fop.apps.io.InternalResourceResolver; | ||||
import org.apache.fop.fonts.truetype.TTFFontLoader; | |||||
import org.apache.fop.fonts.truetype.OFFontLoader; | |||||
import org.apache.fop.fonts.type1.Type1FontLoader; | import org.apache.fop.fonts.type1.Type1FontLoader; | ||||
/** | /** | ||||
} | } | ||||
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resourceResolver); | loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resourceResolver); | ||||
} else { | } else { | ||||
loader = new TTFFontLoader(fontFileURI, subFontName, embedded, embeddingMode, | |||||
loader = new OFFontLoader(fontFileURI, subFontName, embedded, embeddingMode, | |||||
encodingMode, useKerning, useAdvanced, resourceResolver); | encodingMode, useKerning, useAdvanced, resourceResolver); | ||||
} | } | ||||
return loader.getFont(); | return loader.getFont(); |
private final Configuration cfg; | private final Configuration cfg; | ||||
private final URI defaultBaseUri; | |||||
private final URI baseURI; | |||||
private final URI fallbackURI; | |||||
private final ResourceResolver resourceResolver; | private final ResourceResolver resourceResolver; | ||||
/** | /** | ||||
* Main constructor | * Main constructor | ||||
* @param cfg the font manager configuration object | * @param cfg the font manager configuration object | ||||
* @param defaultBaseUri the default URI base to use for URI resolution | |||||
* @param baseURI the URI against which to resolve relative URIs | |||||
* @param fallbackURI the URI to use as a fallback if font-base is unspecified | |||||
* @param resourceResolver the resource resolver | * @param resourceResolver the resource resolver | ||||
*/ | */ | ||||
public FontManagerConfigurator(Configuration cfg, URI defaultBaseUri, | |||||
public FontManagerConfigurator(Configuration cfg, URI baseURI, URI fallbackURI, | |||||
ResourceResolver resourceResolver) { | ResourceResolver resourceResolver) { | ||||
this.cfg = cfg; | this.cfg = cfg; | ||||
this.defaultBaseUri = defaultBaseUri; | |||||
this.baseURI = baseURI; | |||||
this.fallbackURI = fallbackURI; | |||||
this.resourceResolver = resourceResolver; | this.resourceResolver = resourceResolver; | ||||
} | } | ||||
URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base") | URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base") | ||||
.getValue(null)); | .getValue(null)); | ||||
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( | fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( | ||||
defaultBaseUri.resolve(fontBase), resourceResolver)); | |||||
baseURI.resolve(fontBase), resourceResolver)); | |||||
} catch (URISyntaxException use) { | } catch (URISyntaxException use) { | ||||
LogUtil.handleException(log, use, true); | LogUtil.handleException(log, use, true); | ||||
} | } | ||||
} else { | } else { | ||||
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( | fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( | ||||
defaultBaseUri, resourceResolver)); | |||||
fallbackURI, resourceResolver)); | |||||
} | } | ||||
// caching (fonts) | // caching (fonts) | ||||
if (cfg.getChild("use-cache", false) != null) { | if (cfg.getChild("use-cache", false) != null) { |
*/ | */ | ||||
public class FontTriplet implements Comparable<FontTriplet>, Serializable { | public class FontTriplet implements Comparable<FontTriplet>, Serializable { | ||||
public static final FontTriplet DEFAULT_FONT_TRIPLET = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); | |||||
public static final FontTriplet DEFAULT_FONT_TRIPLET | |||||
= new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); | |||||
/** serial version UID */ | /** serial version UID */ | ||||
private static final long serialVersionUID = 1168991106658033508L; | private static final long serialVersionUID = 1168991106658033508L; |
import java.nio.CharBuffer; | import java.nio.CharBuffer; | ||||
import java.nio.IntBuffer; | import java.nio.IntBuffer; | ||||
import java.util.BitSet; | import java.util.BitSet; | ||||
import java.util.LinkedHashMap; | |||||
import java.util.Map; | import java.util.Map; | ||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
/** Contains the character bounding boxes for all characters in the font */ | /** Contains the character bounding boxes for all characters in the font */ | ||||
protected Rectangle[] boundingBoxes; | protected Rectangle[] boundingBoxes; | ||||
private boolean isOTFFile = false; | |||||
// since for most users the most likely glyphs are in the first cmap segments we store their mapping. | |||||
private static final int NUM_MOST_LIKELY_GLYPHS = 256; | |||||
private int[] mostLikelyGlyphs = new int[NUM_MOST_LIKELY_GLYPHS]; | |||||
//A map to store each used glyph from the CID set against the glyph name. | |||||
private LinkedHashMap<Integer, String> usedGlyphNames = new LinkedHashMap<Integer, String>(); | |||||
/** | /** | ||||
* Default constructor | * Default constructor | ||||
*/ | */ | ||||
return cidType; | return cidType; | ||||
} | } | ||||
public void setIsOTFFile(boolean isOTFFile) { | |||||
this.isOTFFile = isOTFFile; | |||||
} | |||||
public boolean isOTFFile() { | |||||
return this.isOTFFile; | |||||
} | |||||
/** | /** | ||||
* Sets the CIDType. | * Sets the CIDType. | ||||
* @param cidType The cidType to set | * @param cidType The cidType to set | ||||
return this.cidSet; | return this.cidSet; | ||||
} | } | ||||
public void mapUsedGlyphName(int gid, String value) { | |||||
usedGlyphNames.put(gid, value); | |||||
} | |||||
public LinkedHashMap<Integer, String> getUsedGlyphNames() { | |||||
return usedGlyphNames; | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public String getEncodingName() { | public String getEncodingName() { | ||||
* @return the glyph index (or 0 if the glyph is not available) | * @return the glyph index (or 0 if the glyph is not available) | ||||
*/ | */ | ||||
// [TBD] - needs optimization, i.e., change from linear search to binary search | // [TBD] - needs optimization, i.e., change from linear search to binary search | ||||
private int findGlyphIndex(int c) { | |||||
public int findGlyphIndex(int c) { | |||||
int idx = c; | int idx = c; | ||||
int retIdx = SingleByteEncoding.NOT_FOUND_CODE_POINT; | int retIdx = SingleByteEncoding.NOT_FOUND_CODE_POINT; | ||||
// for most users the most likely glyphs are in the first cmap segments (meaning the one with | |||||
// the lowest unicode start values) | |||||
if (idx < NUM_MOST_LIKELY_GLYPHS && mostLikelyGlyphs[idx] != 0) { | |||||
return mostLikelyGlyphs[idx]; | |||||
} | |||||
for (int i = 0; (i < cmap.length) && retIdx == 0; i++) { | for (int i = 0; (i < cmap.length) && retIdx == 0; i++) { | ||||
if (cmap[i].getUnicodeStart() <= idx | if (cmap[i].getUnicodeStart() <= idx | ||||
&& cmap[i].getUnicodeEnd() >= idx) { | && cmap[i].getUnicodeEnd() >= idx) { | ||||
retIdx = cmap[i].getGlyphStartIndex() | retIdx = cmap[i].getGlyphStartIndex() | ||||
+ idx | + idx | ||||
- cmap[i].getUnicodeStart(); | - cmap[i].getUnicodeStart(); | ||||
if (idx < NUM_MOST_LIKELY_GLYPHS) { | |||||
mostLikelyGlyphs[idx] = retIdx; | |||||
} | |||||
} | } | ||||
} | } | ||||
return retIdx; | return retIdx; | ||||
return findCharacterFromGlyphIndex(gi, true); | return findCharacterFromGlyphIndex(gi, true); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public char mapChar(char c) { | |||||
notifyMapOperation(); | |||||
int glyphIndex = findGlyphIndex(c); | |||||
if (glyphIndex == SingleByteEncoding.NOT_FOUND_CODE_POINT) { | |||||
warnMissingGlyph(c); | |||||
glyphIndex = findGlyphIndex(Typeface.NOT_FOUND); | |||||
} | |||||
if (isEmbeddable()) { | |||||
glyphIndex = cidSet.mapChar(glyphIndex, c); | |||||
} | |||||
return (char) glyphIndex; | |||||
} | |||||
protected BitSet getGlyphIndices() { | protected BitSet getGlyphIndices() { | ||||
BitSet bitset = new BitSet(); | BitSet bitset = new BitSet(); | ||||
bitset.set(0); | bitset.set(0); | ||||
return chars; | return chars; | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public char mapChar(char c) { | |||||
notifyMapOperation(); | |||||
int glyphIndex = findGlyphIndex(c); | |||||
if (glyphIndex == SingleByteEncoding.NOT_FOUND_CODE_POINT) { | |||||
warnMissingGlyph(c); | |||||
if (!isOTFFile) { | |||||
glyphIndex = findGlyphIndex(Typeface.NOT_FOUND); | |||||
} | |||||
} | |||||
if (isEmbeddable()) { | |||||
glyphIndex = cidSet.mapChar(glyphIndex, c); | |||||
} | |||||
return (char) glyphIndex; | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public boolean hasChar(char c) { | public boolean hasChar(char c) { |
import org.apache.xmlgraphics.fonts.Glyphs; | import org.apache.xmlgraphics.fonts.Glyphs; | ||||
import org.apache.fop.apps.io.InternalResourceResolver; | import org.apache.fop.apps.io.InternalResourceResolver; | ||||
import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; | |||||
import org.apache.fop.fonts.truetype.OpenFont.PostScriptVersion; | |||||
/** | /** | ||||
* Generic SingleByte font | * Generic SingleByte font |
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.util.CommandLineLogger; | |||||
/** | /** | ||||
* Abstract base class for the PFM and TTF Reader command-line applications. | * Abstract base class for the PFM and TTF Reader command-line applications. | ||||
*/ | */ | ||||
protected static void setLogLevel(String level) { | protected static void setLogLevel(String level) { | ||||
// Set the evel for future loggers. | // Set the evel for future loggers. | ||||
LogFactory.getFactory().setAttribute("level", level); | LogFactory.getFactory().setAttribute("level", level); | ||||
if (log instanceof CommandLineLogger) { | |||||
// Set the level for the logger creates already. | |||||
((CommandLineLogger) log).setLogLevel(level); | |||||
} | |||||
} | } | ||||
/** | /** |
import org.w3c.dom.Document; | import org.w3c.dom.Document; | ||||
import org.w3c.dom.Element; | import org.w3c.dom.Element; | ||||
import org.apache.commons.logging.LogFactory; | |||||
import org.apache.fop.Version; | import org.apache.fop.Version; | ||||
import org.apache.fop.fonts.type1.PFMFile; | import org.apache.fop.fonts.type1.PFMFile; | ||||
import org.apache.fop.util.CommandLineLogger; | |||||
/** | /** | ||||
* A tool which reads PFM files from Adobe Type 1 fonts and creates | * A tool which reads PFM files from Adobe Type 1 fonts and creates | ||||
Map options = new java.util.HashMap(); | Map options = new java.util.HashMap(); | ||||
String[] arguments = parseArguments(options, args); | String[] arguments = parseArguments(options, args); | ||||
// Enable the simple command line logging when no other logger is | |||||
// defined. | |||||
LogFactory logFactory = LogFactory.getFactory(); | |||||
if (System.getProperty("org.apache.commons.logging.Log") == null) { | |||||
logFactory.setAttribute("org.apache.commons.logging.Log", | |||||
CommandLineLogger.class.getName()); | |||||
} | |||||
determineLogLevel(options); | determineLogLevel(options); | ||||
PFMReader app = new PFMReader(); | PFMReader app = new PFMReader(); |
import org.xml.sax.Attributes; | import org.xml.sax.Attributes; | ||||
import org.xml.sax.SAXException; | import org.xml.sax.SAXException; | ||||
import org.apache.commons.logging.LogFactory; | |||||
import org.apache.fop.Version; | import org.apache.fop.Version; | ||||
import org.apache.fop.fonts.CMapSegment; | import org.apache.fop.fonts.CMapSegment; | ||||
import org.apache.fop.fonts.FontUtil; | import org.apache.fop.fonts.FontUtil; | ||||
import org.apache.fop.fonts.truetype.FontFileReader; | import org.apache.fop.fonts.truetype.FontFileReader; | ||||
import org.apache.fop.fonts.truetype.OFFontLoader; | |||||
import org.apache.fop.fonts.truetype.TTFFile; | import org.apache.fop.fonts.truetype.TTFFile; | ||||
import org.apache.fop.util.CommandLineLogger; | |||||
// CSOFF: InnerAssignmentCheck | |||||
// CSOFF: LineLengthCheck | // CSOFF: LineLengthCheck | ||||
/** | /** | ||||
Map options = new java.util.HashMap(); | Map options = new java.util.HashMap(); | ||||
String[] arguments = parseArguments(options, args); | String[] arguments = parseArguments(options, args); | ||||
// Enable the simple command line logging when no other logger is | |||||
// defined. | |||||
LogFactory logFactory = LogFactory.getFactory(); | |||||
if (System.getProperty("org.apache.commons.logging.Log") == null) { | |||||
logFactory.setAttribute("org.apache.commons.logging.Log", | |||||
CommandLineLogger.class.getName()); | |||||
} | |||||
determineLogLevel(options); | determineLogLevel(options); | ||||
TTFReader app = new TTFReader(); | TTFReader app = new TTFReader(); | ||||
InputStream stream = new FileInputStream(fileName); | InputStream stream = new FileInputStream(fileName); | ||||
try { | try { | ||||
FontFileReader reader = new FontFileReader(stream); | FontFileReader reader = new FontFileReader(stream); | ||||
boolean supported = ttfFile.readFont(reader, fontName); | |||||
String header = OFFontLoader.readHeader(reader); | |||||
boolean supported = ttfFile.readFont(reader, header, fontName); | |||||
if (!supported) { | if (!supported) { | ||||
return null; | return null; | ||||
} | } |
import org.apache.fop.fonts.FontUtil; | import org.apache.fop.fonts.FontUtil; | ||||
import org.apache.fop.fonts.MultiByteFont; | import org.apache.fop.fonts.MultiByteFont; | ||||
import org.apache.fop.fonts.truetype.FontFileReader; | import org.apache.fop.fonts.truetype.FontFileReader; | ||||
import org.apache.fop.fonts.truetype.OFFontLoader; | |||||
import org.apache.fop.fonts.truetype.TTFFile; | import org.apache.fop.fonts.truetype.TTFFile; | ||||
import org.apache.fop.fonts.truetype.TTFFontLoader; | |||||
/** | /** | ||||
* Attempts to determine correct FontInfo | * Attempts to determine correct FontInfo | ||||
log.debug("Loading " + fontName); | log.debug("Loading " + fontName); | ||||
} | } | ||||
try { | try { | ||||
TTFFontLoader ttfLoader = new TTFFontLoader(fontURI, fontName, true, | |||||
OFFontLoader ttfLoader = new OFFontLoader(fontURI, fontName, true, | |||||
EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced, | EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced, | ||||
resourceResolver); | resourceResolver); | ||||
customFont = ttfLoader.getFont(); | customFont = ttfLoader.getFont(); |
/* | |||||
* 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.fonts.cff; | |||||
import java.io.IOException; | |||||
import java.util.ArrayList; | |||||
import java.util.LinkedHashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import org.apache.fontbox.cff.CFFDataInput; | |||||
import org.apache.fontbox.cff.CFFOperator; | |||||
import org.apache.fop.fonts.truetype.FontFileReader; | |||||
import org.apache.fop.fonts.truetype.OTFFile; | |||||
/** | |||||
* A class to read the CFF data from an OTF CFF font file. | |||||
*/ | |||||
public class CFFDataReader { | |||||
private CFFDataInput cffData; | |||||
private byte[] header; | |||||
private CFFIndexData nameIndex; | |||||
private CFFIndexData topDICTIndex; | |||||
private CFFIndexData stringIndex; | |||||
private CFFIndexData charStringIndex; | |||||
private CFFIndexData globalIndexSubr; | |||||
private CFFIndexData localIndexSubr; | |||||
private CustomEncoding encoding; | |||||
private FDSelect fdSelect; | |||||
private List<FontDict> fdFonts; | |||||
private static final int DOUBLE_BYTE_OPERATOR = 12; | |||||
private static final int NUM_STANDARD_STRINGS = 391; | |||||
/** Commonly used parsed dictionaries */ | |||||
private LinkedHashMap<String, DICTEntry> topDict; | |||||
public CFFDataReader() { | |||||
} | |||||
/** | |||||
* Constructor for the CFF data reader which accepts the CFF byte data | |||||
* as an argument. | |||||
* @param cffDataArray A byte array which holds the CFF data | |||||
*/ | |||||
public CFFDataReader(byte[] cffDataArray) throws IOException { | |||||
cffData = new CFFDataInput(cffDataArray); | |||||
readCFFData(); | |||||
} | |||||
/** | |||||
* Constructor for the CFF data reader which accepts a FontFileReader object | |||||
* which points to the original font file as an argument. | |||||
* @param fontFile The font file as represented by a FontFileReader object | |||||
*/ | |||||
public CFFDataReader(FontFileReader fontFile) throws IOException { | |||||
cffData = new CFFDataInput(OTFFile.getCFFData(fontFile)); | |||||
readCFFData(); | |||||
} | |||||
private void readCFFData() throws IOException { | |||||
header = readHeader(); | |||||
nameIndex = readIndex(); | |||||
topDICTIndex = readIndex(); | |||||
topDict = parseDictData(topDICTIndex.getData()); | |||||
stringIndex = readIndex(); | |||||
globalIndexSubr = readIndex(); | |||||
charStringIndex = readCharStringIndex(); | |||||
encoding = readEncoding(); | |||||
fdSelect = readFDSelect(); | |||||
localIndexSubr = readLocalIndexSubrs(); | |||||
fdFonts = parseCIDData(); | |||||
} | |||||
public Map<String, DICTEntry> getPrivateDict(DICTEntry privateEntry) throws IOException { | |||||
return parseDictData(getPrivateDictBytes(privateEntry)); | |||||
} | |||||
public byte[] getPrivateDictBytes(DICTEntry privateEntry) throws IOException { | |||||
int privateLength = privateEntry.getOperands().get(0).intValue(); | |||||
int privateOffset = privateEntry.getOperands().get(1).intValue(); | |||||
return getCFFOffsetBytes(privateOffset, privateLength); | |||||
} | |||||
/** | |||||
* Retrieves a number of bytes from the CFF data stream | |||||
* @param offset The offset of the bytes to retrieve | |||||
* @param length The number of bytes to retrieve | |||||
* @return Returns a byte array of requested bytes | |||||
* @throws IOException Throws an IO Exception if an error occurs | |||||
*/ | |||||
private byte[] getCFFOffsetBytes(int offset, int length) throws IOException { | |||||
cffData.setPosition(offset); | |||||
return cffData.readBytes(length); | |||||
} | |||||
/** | |||||
* Parses the dictionary data and returns a map of objects for each entry | |||||
* @param dictData The data for the dictionary data | |||||
* @return Returns a map of type DICTEntry identified by the operand name | |||||
* @throws IOException Throws an IO Exception if an error occurs | |||||
*/ | |||||
public LinkedHashMap<String, DICTEntry> parseDictData(byte[] dictData) throws IOException { | |||||
LinkedHashMap<String, DICTEntry> dictEntries = new LinkedHashMap<String, DICTEntry>(); | |||||
List<Number> operands = new ArrayList<Number>(); | |||||
List<Integer> operandLengths = new ArrayList<Integer>(); | |||||
int lastOperandLength = 0; | |||||
for (int i = 0; i < dictData.length; i++) { | |||||
int readByte = dictData[i] & 0xFF; | |||||
if (readByte < 28) { | |||||
int[] operator = new int[(readByte == DOUBLE_BYTE_OPERATOR) ? 2 : 1]; | |||||
if (readByte == DOUBLE_BYTE_OPERATOR) { | |||||
operator[0] = dictData[i]; | |||||
operator[1] = dictData[i + 1]; | |||||
i++; | |||||
} else { | |||||
operator[0] = dictData[i]; | |||||
} | |||||
String operatorName = ""; | |||||
CFFOperator tempOp = null; | |||||
if (operator.length > 1) { | |||||
tempOp = CFFOperator.getOperator(new CFFOperator.Key(operator[0], operator[1])); | |||||
} else { | |||||
tempOp = CFFOperator.getOperator(new CFFOperator.Key(operator[0])); | |||||
} | |||||
if (tempOp != null) { | |||||
operatorName = tempOp.getName(); | |||||
} | |||||
DICTEntry newEntry = new DICTEntry(); | |||||
newEntry.setOperator(operator); | |||||
newEntry.setOperands(new ArrayList<Number>(operands)); | |||||
newEntry.setOperatorName(operatorName); | |||||
newEntry.setOffset(i - lastOperandLength); | |||||
newEntry.setOperandLength(lastOperandLength); | |||||
newEntry.setOperandLengths(new ArrayList<Integer>(operandLengths)); | |||||
byte[] byteData = new byte[lastOperandLength + operator.length]; | |||||
System.arraycopy(dictData, i - operator.length - (lastOperandLength - 1), | |||||
byteData, 0, operator.length + lastOperandLength); | |||||
newEntry.setByteData(byteData); | |||||
dictEntries.put(operatorName, newEntry); | |||||
operands.clear(); | |||||
operandLengths.clear(); | |||||
lastOperandLength = 0; | |||||
} else { | |||||
if (readByte >= 32 && readByte <= 246) { | |||||
operands.add(readByte - 139); | |||||
lastOperandLength += 1; | |||||
operandLengths.add(1); | |||||
} else if (readByte >= 247 && readByte <= 250) { | |||||
operands.add((readByte - 247) * 256 + (dictData[i + 1] & 0xFF) + 108); | |||||
lastOperandLength += 2; | |||||
operandLengths.add(2); | |||||
i++; | |||||
} else if (readByte >= 251 && readByte <= 254) { | |||||
operands.add(-(readByte - 251) * 256 - (dictData[i + 1] & 0xFF) - 108); | |||||
lastOperandLength += 2; | |||||
operandLengths.add(2); | |||||
i++; | |||||
} else if (readByte == 28) { | |||||
operands.add((dictData[i + 1] & 0xFF) << 8 | (dictData[i + 2] & 0xFF)); | |||||
lastOperandLength += 3; | |||||
operandLengths.add(3); | |||||
i += 2; | |||||
} else if (readByte == 29) { | |||||
operands.add((dictData[i + 1] & 0xFF) << 24 | (dictData[i + 2] & 0xFF) << 16 | |||||
| (dictData[i + 3] & 0xFF) << 8 | (dictData[i + 4] & 0xFF)); | |||||
lastOperandLength += 5; | |||||
operandLengths.add(5); | |||||
i += 4; | |||||
} else if (readByte == 30) { | |||||
boolean terminatorFound = false; | |||||
StringBuilder realNumber = new StringBuilder(); | |||||
int byteCount = 1; | |||||
do { | |||||
byte nibblesByte = dictData[++i]; | |||||
byteCount++; | |||||
terminatorFound = readNibble(realNumber, (nibblesByte >> 4) & 0x0F); | |||||
if (!terminatorFound) { | |||||
terminatorFound = readNibble(realNumber, nibblesByte & 0x0F); | |||||
} | |||||
} while (!terminatorFound); | |||||
operands.add(Double.valueOf(realNumber.toString())); | |||||
lastOperandLength += byteCount; | |||||
operandLengths.add(byteCount); | |||||
} | |||||
} | |||||
} | |||||
return dictEntries; | |||||
} | |||||
private boolean readNibble(StringBuilder realNumber, int nibble) { | |||||
if (nibble <= 0x9) { | |||||
realNumber.append(nibble); | |||||
} else { | |||||
switch (nibble) { | |||||
case 0xa: realNumber.append("."); break; | |||||
case 0xb: realNumber.append("E"); break; | |||||
case 0xc: realNumber.append("E-"); break; | |||||
case 0xd: break; | |||||
case 0xe: realNumber.append("-"); break; | |||||
case 0xf: return true; | |||||
default: throw new AssertionError("Unexpected nibble value"); | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* A class containing data for a dictionary entry | |||||
*/ | |||||
public static class DICTEntry { | |||||
private int[] operator; | |||||
private List<Number> operands; | |||||
private List<Integer> operandLengths; | |||||
private String operatorName; | |||||
private int offset; | |||||
private int operandLength; | |||||
private byte[] data = new byte[0]; | |||||
public void setOperator(int[] operator) { | |||||
this.operator = operator; | |||||
} | |||||
public int[] getOperator() { | |||||
return this.operator; | |||||
} | |||||
public void setOperands(List<Number> operands) { | |||||
this.operands = operands; | |||||
} | |||||
public List<Number> getOperands() { | |||||
return this.operands; | |||||
} | |||||
public void setOperatorName(String operatorName) { | |||||
this.operatorName = operatorName; | |||||
} | |||||
public String getOperatorName() { | |||||
return this.operatorName; | |||||
} | |||||
public void setOffset(int offset) { | |||||
this.offset = offset; | |||||
} | |||||
public int getOffset() { | |||||
return this.offset; | |||||
} | |||||
public void setOperandLength(int operandLength) { | |||||
this.operandLength = operandLength; | |||||
} | |||||
public int getOperandLength() { | |||||
return this.operandLength; | |||||
} | |||||
public void setByteData(byte[] data) { | |||||
this.data = data.clone(); | |||||
} | |||||
public byte[] getByteData() { | |||||
return data.clone(); | |||||
} | |||||
public void setOperandLengths(List<Integer> operandLengths) { | |||||
this.operandLengths = operandLengths; | |||||
} | |||||
public List<Integer> getOperandLengths() { | |||||
return operandLengths; | |||||
} | |||||
} | |||||
private byte[] readHeader() throws IOException { | |||||
//Read known header | |||||
byte[] fixedHeader = cffData.readBytes(4); | |||||
int hdrSize = (fixedHeader[2] & 0xFF); | |||||
byte[] extra = cffData.readBytes(hdrSize - 4); | |||||
byte[] header = new byte[hdrSize]; | |||||
for (int i = 0; i < fixedHeader.length; i++) { | |||||
header[i] = fixedHeader[i]; | |||||
} | |||||
for (int i = 4; i < extra.length; i++) { | |||||
header[i] = extra[i - 4]; | |||||
} | |||||
return header; | |||||
} | |||||
/** | |||||
* Reads a CFF index object are the specified offset position | |||||
* @param offset The position of the index object to read | |||||
* @return Returns an object representing the index | |||||
* @throws IOException Throws an IO Exception if an error occurs | |||||
*/ | |||||
public CFFIndexData readIndex(int offset) throws IOException { | |||||
cffData.setPosition(offset); | |||||
return readIndex(); | |||||
} | |||||
private CFFIndexData readIndex() throws IOException { | |||||
return readIndex(cffData); | |||||
} | |||||
/** | |||||
* Reads an index from the current position of the CFFDataInput object | |||||
* @param input The object holding the CFF byte data | |||||
* @return Returns an object representing the index | |||||
* @throws IOException Throws an IO Exception if an error occurs | |||||
*/ | |||||
public CFFIndexData readIndex(CFFDataInput input) throws IOException { | |||||
CFFIndexData nameIndex = new CFFIndexData(); | |||||
if (input != null) { | |||||
int origPos = input.getPosition(); | |||||
nameIndex.parseIndexHeader(input); | |||||
int tableSize = input.getPosition() - origPos; | |||||
nameIndex.setByteData(input.getPosition() - tableSize, tableSize); | |||||
} | |||||
return nameIndex; | |||||
} | |||||
/** | |||||
* Retrieves the SID for the given GID object | |||||
* @param charsetOffset The offset of the charset data | |||||
* @param GID The GID for which to retrieve the SID | |||||
* @return Returns the SID as an integer | |||||
*/ | |||||
public int getSIDFromGID(int charsetOffset, int gid) throws IOException { | |||||
if (gid == 0) { | |||||
return 0; | |||||
} | |||||
cffData.setPosition(charsetOffset); | |||||
int charsetFormat = cffData.readCard8(); | |||||
switch (charsetFormat) { | |||||
case 0: //Adjust for .notdef character | |||||
cffData.setPosition(cffData.getPosition() + (--gid * 2)); | |||||
return cffData.readSID(); | |||||
case 1: return getSIDFromGIDFormat(gid, 1); | |||||
case 2: return getSIDFromGIDFormat(gid, 2); | |||||
default: return 0; | |||||
} | |||||
} | |||||
private int getSIDFromGIDFormat(int gid, int format) throws IOException { | |||||
int glyphCount = 0; | |||||
while (true) { | |||||
int oldGlyphCount = glyphCount; | |||||
int start = cffData.readSID(); | |||||
glyphCount += ((format == 1) ? cffData.readCard8() : cffData.readCard16()) + 1; | |||||
if (gid <= glyphCount) { | |||||
return start + (gid - oldGlyphCount) - 1; | |||||
} | |||||
} | |||||
} | |||||
public byte[] getHeader() { | |||||
return header.clone(); | |||||
} | |||||
public CFFIndexData getNameIndex() { | |||||
return nameIndex; | |||||
} | |||||
public CFFIndexData getTopDictIndex() { | |||||
return topDICTIndex; | |||||
} | |||||
public LinkedHashMap<String, DICTEntry> getTopDictEntries() { | |||||
return topDict; | |||||
} | |||||
public CFFIndexData getStringIndex() { | |||||
return stringIndex; | |||||
} | |||||
public CFFIndexData getGlobalIndexSubr() { | |||||
return globalIndexSubr; | |||||
} | |||||
public CFFIndexData getLocalIndexSubr() { | |||||
return localIndexSubr; | |||||
} | |||||
public CFFIndexData getCharStringIndex() { | |||||
return charStringIndex; | |||||
} | |||||
public CFFDataInput getCFFData() { | |||||
return cffData; | |||||
} | |||||
public CustomEncoding getEncoding() { | |||||
return encoding; | |||||
} | |||||
public FDSelect getFDSelect() { | |||||
return fdSelect; | |||||
} | |||||
public List<FontDict> getFDFonts() { | |||||
return fdFonts; | |||||
} | |||||
public CFFDataInput getLocalSubrsForGlyph(int glyph) throws IOException { | |||||
//Subsets are currently written using a Format0 FDSelect | |||||
FDSelect fontDictionary = getFDSelect(); | |||||
if (fontDictionary instanceof Format0FDSelect) { | |||||
Format0FDSelect fdSelect = (Format0FDSelect)fontDictionary; | |||||
int found = fdSelect.getFDIndexes()[glyph]; | |||||
FontDict font = getFDFonts().get(found); | |||||
byte[] localSubrData = font.getLocalSubrData().getByteData(); | |||||
if (localSubrData != null) { | |||||
return new CFFDataInput(localSubrData); | |||||
} else { | |||||
return null; | |||||
} | |||||
} else if (fontDictionary instanceof Format3FDSelect) { | |||||
Format3FDSelect fdSelect = (Format3FDSelect)fontDictionary; | |||||
int index = 0; | |||||
for (int first : fdSelect.getRanges().keySet()) { | |||||
if (first > glyph) { | |||||
break; | |||||
} | |||||
index++; | |||||
} | |||||
FontDict font = getFDFonts().get(index); | |||||
byte[] localSubrsData = font.getLocalSubrData().getByteData(); | |||||
if (localSubrsData != null) { | |||||
return new CFFDataInput(localSubrsData); | |||||
} else { | |||||
return null; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/** | |||||
* Parses the char string index from the CFF byte data | |||||
* @param offset The offset to the char string index | |||||
* @return Returns the char string index object | |||||
* @throws IOException Throws an IO Exception if an error occurs | |||||
*/ | |||||
public CFFIndexData readCharStringIndex() throws IOException { | |||||
int offset = topDict.get("CharStrings").getOperands().get(0).intValue(); | |||||
cffData.setPosition(offset); | |||||
return readIndex(); | |||||
} | |||||
private CustomEncoding readEncoding() throws IOException { | |||||
CustomEncoding foundEncoding = null; | |||||
if (topDict.get("Encoding") != null) { | |||||
int offset = topDict.get("Encoding").getOperands().get(0).intValue(); | |||||
if (offset != 0 && offset != 1) { | |||||
//No need to set the offset as we are reading the data sequentially. | |||||
int format = cffData.readCard8(); | |||||
int numEntries = cffData.readCard8(); | |||||
switch (format) { | |||||
case 0: | |||||
foundEncoding = readFormat0Encoding(format, numEntries); | |||||
break; | |||||
case 1: | |||||
foundEncoding = readFormat1Encoding(format, numEntries); | |||||
break; | |||||
default: break; | |||||
} | |||||
} | |||||
} | |||||
return foundEncoding; | |||||
} | |||||
private Format0Encoding readFormat0Encoding(int format, int numEntries) | |||||
throws IOException { | |||||
Format0Encoding newEncoding = new Format0Encoding(); | |||||
newEncoding.setFormat(format); | |||||
newEncoding.setNumEntries(numEntries); | |||||
int[] codes = new int[numEntries]; | |||||
for (int i = 0; i < numEntries; i++) { | |||||
codes[i] = cffData.readCard8(); | |||||
} | |||||
newEncoding.setCodes(codes); | |||||
return newEncoding; | |||||
} | |||||
private Format1Encoding readFormat1Encoding(int format, int numEntries) | |||||
throws IOException { | |||||
Format1Encoding newEncoding = new Format1Encoding(); | |||||
newEncoding.setFormat(format); | |||||
newEncoding.setNumEntries(numEntries); | |||||
LinkedHashMap<Integer, Integer> ranges = new LinkedHashMap<Integer, Integer>(); | |||||
for (int i = 0; i < numEntries; i++) { | |||||
int first = cffData.readCard8(); | |||||
int left = cffData.readCard8(); | |||||
ranges.put(first, left); | |||||
} | |||||
newEncoding.setRanges(ranges); | |||||
return newEncoding; | |||||
} | |||||
private FDSelect readFDSelect() throws IOException { | |||||
FDSelect fdSelect = null; | |||||
DICTEntry fdSelectEntry = topDict.get("FDSelect"); | |||||
if (fdSelectEntry != null) { | |||||
int fdOffset = fdSelectEntry.getOperands().get(0).intValue(); | |||||
cffData.setPosition(fdOffset); | |||||
int format = cffData.readCard8(); | |||||
switch (format) { | |||||
case 0: | |||||
fdSelect = readFormat0FDSelect(); | |||||
break; | |||||
case 3: | |||||
fdSelect = readFormat3FDSelect(); | |||||
break; | |||||
default: | |||||
} | |||||
} | |||||
return fdSelect; | |||||
} | |||||
private Format0FDSelect readFormat0FDSelect() throws IOException { | |||||
Format0FDSelect newFDs = new Format0FDSelect(); | |||||
newFDs.setFormat(0); | |||||
int glyphCount = charStringIndex.getNumObjects(); | |||||
int[] fds = new int[glyphCount]; | |||||
for (int i = 0; i < glyphCount; i++) { | |||||
fds[i] = cffData.readCard8(); | |||||
} | |||||
newFDs.setFDIndexes(fds); | |||||
return newFDs; | |||||
} | |||||
private Format3FDSelect readFormat3FDSelect() throws IOException { | |||||
Format3FDSelect newFDs = new Format3FDSelect(); | |||||
newFDs.setFormat(3); | |||||
int rangeCount = cffData.readCard16(); | |||||
newFDs.setRangeCount(rangeCount); | |||||
LinkedHashMap<Integer, Integer> ranges = new LinkedHashMap<Integer, Integer>(); | |||||
for (int i = 0; i < rangeCount; i++) { | |||||
int first = cffData.readCard16(); | |||||
int fd = cffData.readCard8(); | |||||
ranges.put(first, fd); | |||||
} | |||||
newFDs.setRanges(ranges); | |||||
newFDs.setSentinelGID(cffData.readCard16()); | |||||
return newFDs; | |||||
} | |||||
private List<FontDict> parseCIDData() throws IOException { | |||||
ArrayList<FontDict> fdFonts = new ArrayList<FontDict>(); | |||||
if (topDict.get("ROS") != null) { | |||||
DICTEntry fdArray = topDict.get("FDArray"); | |||||
if (fdArray != null) { | |||||
int fdIndex = fdArray.getOperands().get(0).intValue(); | |||||
CFFIndexData fontDicts = readIndex(fdIndex); | |||||
for (int i = 0; i < fontDicts.getNumObjects(); i++) { | |||||
FontDict newFontDict = new FontDict(); | |||||
byte[] fdData = fontDicts.getValue(i); | |||||
LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData); | |||||
newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i)); | |||||
DICTEntry fontFDEntry = fdEntries.get("FontName"); | |||||
newFontDict.setFontName(getString(fontFDEntry.getOperands().get(0).intValue())); | |||||
DICTEntry privateFDEntry = fdEntries.get("Private"); | |||||
if (privateFDEntry != null) { | |||||
newFontDict = setFDData(privateFDEntry, newFontDict); | |||||
} | |||||
fdFonts.add(newFontDict); | |||||
} | |||||
} | |||||
} | |||||
return fdFonts; | |||||
} | |||||
private FontDict setFDData(DICTEntry privateFDEntry, FontDict newFontDict) throws IOException { | |||||
int privateFDLength = privateFDEntry.getOperands().get(0).intValue(); | |||||
int privateFDOffset = privateFDEntry.getOperands().get(1).intValue(); | |||||
cffData.setPosition(privateFDOffset); | |||||
byte[] privateDict = cffData.readBytes(privateFDLength); | |||||
newFontDict.setPrivateDictData(privateFDOffset, privateFDLength); | |||||
LinkedHashMap<String, DICTEntry> privateEntries = parseDictData(privateDict); | |||||
DICTEntry subroutines = privateEntries.get("Subrs"); | |||||
if (subroutines != null) { | |||||
CFFIndexData localSubrs = readIndex(privateFDOffset | |||||
+ subroutines.getOperands().get(0).intValue()); | |||||
newFontDict.setLocalSubrData(localSubrs); | |||||
} else { | |||||
newFontDict.setLocalSubrData(new CFFIndexData()); | |||||
} | |||||
return newFontDict; | |||||
} | |||||
private String getString(int sid) throws IOException { | |||||
return new String(stringIndex.getValue(sid - NUM_STANDARD_STRINGS)); | |||||
} | |||||
private CFFIndexData readLocalIndexSubrs() throws IOException { | |||||
CFFIndexData localSubrs = null; | |||||
DICTEntry privateEntry = topDict.get("Private"); | |||||
if (privateEntry != null) { | |||||
int length = privateEntry.getOperands().get(0).intValue(); | |||||
int offset = privateEntry.getOperands().get(1).intValue(); | |||||
cffData.setPosition(offset); | |||||
byte[] privateData = cffData.readBytes(length); | |||||
LinkedHashMap<String, DICTEntry> privateDict = parseDictData(privateData); | |||||
DICTEntry localSubrsEntry = privateDict.get("Subrs"); | |||||
if (localSubrsEntry != null) { | |||||
int localOffset = offset + localSubrsEntry.getOperands().get(0).intValue(); | |||||
cffData.setPosition(localOffset); | |||||
localSubrs = readIndex(); | |||||
} | |||||
} | |||||
return localSubrs; | |||||
} | |||||
/** | |||||
* Parent class which provides the ability to retrieve byte data from | |||||
* a sub-table. | |||||
*/ | |||||
public class CFFSubTable { | |||||
private DataLocation dataLocation = new DataLocation(); | |||||
public void setByteData(int position, int length) { | |||||
dataLocation = new DataLocation(position, length); | |||||
} | |||||
public byte[] getByteData() throws IOException { | |||||
int oldPos = cffData.getPosition(); | |||||
try { | |||||
cffData.setPosition(dataLocation.getDataPosition()); | |||||
return cffData.readBytes(dataLocation.getDataLength()); | |||||
} finally { | |||||
cffData.setPosition(oldPos); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* An object used to hold index data from the CFF data | |||||
*/ | |||||
public class CFFIndexData extends CFFSubTable { | |||||
private int numObjects; | |||||
private int offSize; | |||||
private int[] offsets = new int[0]; | |||||
private DataLocation dataLocation = new DataLocation(); | |||||
public void setNumObjects(int numObjects) { | |||||
this.numObjects = numObjects; | |||||
} | |||||
public int getNumObjects() { | |||||
return this.numObjects; | |||||
} | |||||
public void setOffSize(int offSize) { | |||||
this.offSize = offSize; | |||||
} | |||||
public int getOffSize() { | |||||
return this.offSize; | |||||
} | |||||
public void setOffsets(int[] offsets) { | |||||
this.offsets = offsets.clone(); | |||||
} | |||||
public int[] getOffsets() { | |||||
return offsets.clone(); | |||||
} | |||||
public void setData(int position, int length) { | |||||
dataLocation = new DataLocation(position, length); | |||||
} | |||||
public byte[] getData() throws IOException { | |||||
int origPos = cffData.getPosition(); | |||||
try { | |||||
cffData.setPosition(dataLocation.getDataPosition()); | |||||
return cffData.readBytes(dataLocation.getDataLength()); | |||||
} finally { | |||||
cffData.setPosition(origPos); | |||||
} | |||||
} | |||||
/** | |||||
* Parses index data from an index object found within the CFF byte data | |||||
* @param cffData A byte array containing the CFF data | |||||
* @throws IOException Throws an IO Exception if an error occurs | |||||
*/ | |||||
public void parseIndexHeader(CFFDataInput cffData) throws IOException { | |||||
setNumObjects(cffData.readCard16()); | |||||
setOffSize(cffData.readOffSize()); | |||||
int[] offsets = new int[getNumObjects() + 1]; | |||||
byte[] bytes; | |||||
//Fills the offsets array | |||||
for (int i = 0; i <= getNumObjects(); i++) { | |||||
switch (getOffSize()) { | |||||
case 1: | |||||
offsets[i] = cffData.readCard8(); | |||||
break; | |||||
case 2: | |||||
offsets[i] = cffData.readCard16(); | |||||
break; | |||||
case 3: | |||||
bytes = cffData.readBytes(3); | |||||
offsets[i] = ((bytes[0] & 0xFF) << 16) + ((bytes[1] & 0xFF) << 8) + (bytes[2] & 0xFF); | |||||
break; | |||||
case 4: | |||||
bytes = cffData.readBytes(4); | |||||
offsets[i] = ((bytes[0] & 0xFF) << 24) + ((bytes[1] & 0xFF) << 16) | |||||
+ ((bytes[2] & 0xFF) << 8) + (bytes[3] & 0xFF); | |||||
break; | |||||
default: continue; | |||||
} | |||||
} | |||||
setOffsets(offsets); | |||||
int position = cffData.getPosition(); | |||||
int dataSize = offsets[offsets.length - 1] - offsets[0]; | |||||
cffData.setPosition(cffData.getPosition() + dataSize); | |||||
setData(position, dataSize); | |||||
} | |||||
/** | |||||
* Retrieves data from the index data | |||||
* @param index The index position of the data to retrieve | |||||
* @return Returns the byte data for the given index | |||||
* @throws IOException Throws an IO Exception if an error occurs | |||||
*/ | |||||
public byte[] getValue(int index) throws IOException { | |||||
int oldPos = cffData.getPosition(); | |||||
try { | |||||
cffData.setPosition(dataLocation.getDataPosition() + (offsets[index] - 1)); | |||||
return cffData.readBytes(offsets[index + 1] - offsets[index]); | |||||
} finally { | |||||
cffData.setPosition(oldPos); | |||||
} | |||||
} | |||||
public int getValuePosition(int index) { | |||||
return dataLocation.getDataPosition() + (offsets[index] - 1); | |||||
} | |||||
public int getValueLength(int index) { | |||||
return offsets[index + 1] - offsets[index]; | |||||
} | |||||
} | |||||
public abstract class CustomEncoding { | |||||
private int format; | |||||
private int numEntries; | |||||
public void setFormat(int format) { | |||||
this.format = format; | |||||
} | |||||
public int getFormat() { | |||||
return format; | |||||
} | |||||
public void setNumEntries(int numEntries) { | |||||
this.numEntries = numEntries; | |||||
} | |||||
public int getNumEntries() { | |||||
return numEntries; | |||||
} | |||||
} | |||||
public class Format0Encoding extends CustomEncoding { | |||||
private int[] codes = new int[0]; | |||||
public void setCodes(int[] codes) { | |||||
this.codes = codes.clone(); | |||||
} | |||||
public int[] getCodes() { | |||||
return codes.clone(); | |||||
} | |||||
} | |||||
public class Format1Encoding extends CustomEncoding { | |||||
private LinkedHashMap<Integer, Integer> ranges; | |||||
public void setRanges(LinkedHashMap<Integer, Integer> ranges) { | |||||
this.ranges = ranges; | |||||
} | |||||
public LinkedHashMap<Integer, Integer> getRanges() { | |||||
return ranges; | |||||
} | |||||
} | |||||
public class FDSelect { | |||||
private int format; | |||||
public void setFormat(int format) { | |||||
this.format = format; | |||||
} | |||||
public int getFormat() { | |||||
return format; | |||||
} | |||||
} | |||||
public class Format0FDSelect extends FDSelect { | |||||
private int[] fds = new int[0]; | |||||
public void setFDIndexes(int[] fds) { | |||||
this.fds = fds.clone(); | |||||
} | |||||
public int[] getFDIndexes() { | |||||
return fds.clone(); | |||||
} | |||||
} | |||||
public class Format3FDSelect extends FDSelect { | |||||
private int rangeCount; | |||||
private LinkedHashMap<Integer, Integer> ranges; | |||||
private int sentinelGID; | |||||
public void setRangeCount(int rangeCount) { | |||||
this.rangeCount = rangeCount; | |||||
} | |||||
public int getRangeCount() { | |||||
return rangeCount; | |||||
} | |||||
public void setRanges(LinkedHashMap<Integer, Integer> ranges) { | |||||
this.ranges = ranges; | |||||
} | |||||
public LinkedHashMap<Integer, Integer> getRanges() { | |||||
return ranges; | |||||
} | |||||
public void setSentinelGID(int sentinelGID) { | |||||
this.sentinelGID = sentinelGID; | |||||
} | |||||
public int getSentinelGID() { | |||||
return sentinelGID; | |||||
} | |||||
} | |||||
public class FontDict extends CFFSubTable { | |||||
private String fontName; | |||||
private DataLocation dataLocation = new DataLocation(); | |||||
private CFFIndexData localSubrData; | |||||
public void setFontName(String groupName) { | |||||
this.fontName = groupName; | |||||
} | |||||
public String getFontName() { | |||||
return fontName; | |||||
} | |||||
public void setPrivateDictData(int position, int length) { | |||||
dataLocation = new DataLocation(position, length); | |||||
} | |||||
public byte[] getPrivateDictData() throws IOException { | |||||
int origPos = cffData.getPosition(); | |||||
try { | |||||
cffData.setPosition(dataLocation.getDataPosition()); | |||||
return cffData.readBytes(dataLocation.getDataLength()); | |||||
} finally { | |||||
cffData.setPosition(origPos); | |||||
} | |||||
} | |||||
public void setLocalSubrData(CFFIndexData localSubrData) { | |||||
this.localSubrData = localSubrData; | |||||
} | |||||
public CFFIndexData getLocalSubrData() { | |||||
return localSubrData; | |||||
} | |||||
} | |||||
private static class DataLocation { | |||||
private int dataPosition; | |||||
private int dataLength; | |||||
public DataLocation() { | |||||
dataPosition = 0; | |||||
dataLength = 0; | |||||
} | |||||
public DataLocation(int position, int length) { | |||||
this.dataPosition = position; | |||||
this.dataLength = length; | |||||
} | |||||
public int getDataPosition() { | |||||
return dataPosition; | |||||
} | |||||
public int getDataLength() { | |||||
return dataLength; | |||||
} | |||||
} | |||||
} |
*/ | */ | ||||
public class GlyfTable { | public class GlyfTable { | ||||
private final TTFMtxEntry[] mtxTab; | |||||
private final OFMtxEntry[] mtxTab; | |||||
private final long tableOffset; | private final long tableOffset; | ||||
/** All the glyphs that are composed, but do not appear in the subset. */ | /** All the glyphs that are composed, but do not appear in the subset. */ | ||||
private Set<Integer> composedGlyphs = new TreeSet<Integer>(); | private Set<Integer> composedGlyphs = new TreeSet<Integer>(); | ||||
GlyfTable(FontFileReader in, TTFMtxEntry[] metrics, TTFDirTabEntry dirTableEntry, | |||||
GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry, | |||||
Map<Integer, Integer> glyphs) throws IOException { | Map<Integer, Integer> glyphs) throws IOException { | ||||
mtxTab = metrics; | mtxTab = metrics; | ||||
tableOffset = dirTableEntry.getOffset(); | tableOffset = dirTableEntry.getOffset(); |
/** | /** | ||||
* This class represents an entry to a TrueType font's Dir Tab. | * This class represents an entry to a TrueType font's Dir Tab. | ||||
*/ | */ | ||||
public class TTFDirTabEntry { | |||||
public class OFDirTabEntry { | |||||
private byte[] tag = new byte[4]; | private byte[] tag = new byte[4]; | ||||
private int checksum; | private int checksum; | ||||
private long offset; | private long offset; | ||||
private long length; | private long length; | ||||
public TTFDirTabEntry() { | |||||
public OFDirTabEntry() { | |||||
} | } | ||||
public TTFDirTabEntry(long offset, long length) { | |||||
public OFDirTabEntry(long offset, long length) { | |||||
this.offset = offset; | this.offset = offset; | ||||
this.length = length; | this.length = length; | ||||
} | } |
import org.apache.fop.fonts.MultiByteFont; | import org.apache.fop.fonts.MultiByteFont; | ||||
import org.apache.fop.fonts.NamedCharacter; | import org.apache.fop.fonts.NamedCharacter; | ||||
import org.apache.fop.fonts.SingleByteFont; | import org.apache.fop.fonts.SingleByteFont; | ||||
import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; | |||||
import org.apache.fop.fonts.truetype.OpenFont.PostScriptVersion; | |||||
import org.apache.fop.util.HexEncoder; | import org.apache.fop.util.HexEncoder; | ||||
/** | /** | ||||
* Loads a TrueType font into memory directly from the original font file. | * Loads a TrueType font into memory directly from the original font file. | ||||
*/ | */ | ||||
public class TTFFontLoader extends FontLoader { | |||||
public class OFFontLoader extends FontLoader { | |||||
private MultiByteFont multiFont; | private MultiByteFont multiFont; | ||||
private SingleByteFont singleFont; | private SingleByteFont singleFont; | ||||
* @param fontFileURI the URI representing the font file | * @param fontFileURI the URI representing the font file | ||||
* @param resourceResolver the resource resolver for font URI resolution | * @param resourceResolver the resource resolver for font URI resolution | ||||
*/ | */ | ||||
public TTFFontLoader(URI fontFileURI, InternalResourceResolver resourceResolver) { | |||||
public OFFontLoader(URI fontFileURI, InternalResourceResolver resourceResolver) { | |||||
this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resourceResolver); | this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resourceResolver); | ||||
} | } | ||||
* @param useAdvanced true to enable loading advanced info if available, false to disable | * @param useAdvanced true to enable loading advanced info if available, false to disable | ||||
* @param resolver the FontResolver for font URI resolution | * @param resolver the FontResolver for font URI resolution | ||||
*/ | */ | ||||
public TTFFontLoader(URI fontFileURI, String subFontName, boolean embedded, | |||||
public OFFontLoader(URI fontFileURI, String subFontName, boolean embedded, | |||||
EmbeddingMode embeddingMode, EncodingMode encodingMode, boolean useKerning, | EmbeddingMode embeddingMode, EncodingMode encodingMode, boolean useKerning, | ||||
boolean useAdvanced, InternalResourceResolver resolver) { | boolean useAdvanced, InternalResourceResolver resolver) { | ||||
super(fontFileURI, embedded, useKerning, useAdvanced, resolver); | super(fontFileURI, embedded, useKerning, useAdvanced, resolver); | ||||
private void read(String ttcFontName) throws IOException { | private void read(String ttcFontName) throws IOException { | ||||
InputStream in = resourceResolver.getResource(this.fontFileURI); | InputStream in = resourceResolver.getResource(this.fontFileURI); | ||||
try { | try { | ||||
TTFFile ttf = new TTFFile(useKerning, useAdvanced); | |||||
FontFileReader reader = new FontFileReader(in); | FontFileReader reader = new FontFileReader(in); | ||||
boolean supported = ttf.readFont(reader, ttcFontName); | |||||
String header = readHeader(reader); | |||||
boolean isCFF = header.equals("OTTO"); | |||||
OpenFont otf = (isCFF) ? new OTFFile() : new TTFFile(useKerning, useAdvanced); | |||||
boolean supported = otf.readFont(reader, header, ttcFontName); | |||||
if (!supported) { | if (!supported) { | ||||
throw new IOException("TrueType font is not supported: " + fontFileURI); | |||||
throw new IOException("The font does not have a Unicode cmap table: " + fontFileURI); | |||||
} | } | ||||
buildFont(ttf, ttcFontName); | |||||
buildFont(otf, ttcFontName); | |||||
loaded = true; | loaded = true; | ||||
} finally { | } finally { | ||||
IOUtils.closeQuietly(in); | IOUtils.closeQuietly(in); | ||||
} | } | ||||
} | } | ||||
private void buildFont(TTFFile ttf, String ttcFontName) { | |||||
if (ttf.isCFF()) { | |||||
throw new UnsupportedOperationException( | |||||
"OpenType fonts with CFF data are not supported, yet"); | |||||
public static String readHeader(FontFileReader fontFile) throws IOException { | |||||
if (fontFile != null) { | |||||
fontFile.seekSet(0); | |||||
return fontFile.readTTFString(4); // TTF_FIXED_SIZE (4 bytes) | |||||
} | } | ||||
return null; | |||||
} | |||||
private void buildFont(OpenFont otf, String ttcFontName) { | |||||
boolean isCid = this.embedded; | boolean isCid = this.embedded; | ||||
if (this.encodingMode == EncodingMode.SINGLE_BYTE) { | if (this.encodingMode == EncodingMode.SINGLE_BYTE) { | ||||
isCid = false; | isCid = false; | ||||
if (isCid) { | if (isCid) { | ||||
multiFont = new MultiByteFont(resourceResolver, embeddingMode); | multiFont = new MultiByteFont(resourceResolver, embeddingMode); | ||||
multiFont.setIsOTFFile(otf instanceof OTFFile); | |||||
returnFont = multiFont; | returnFont = multiFont; | ||||
multiFont.setTTCName(ttcFontName); | multiFont.setTTCName(ttcFontName); | ||||
} else { | } else { | ||||
returnFont = singleFont; | returnFont = singleFont; | ||||
} | } | ||||
returnFont.setFontName(ttf.getPostScriptName()); | |||||
returnFont.setFullName(ttf.getFullName()); | |||||
returnFont.setFamilyNames(ttf.getFamilyNames()); | |||||
returnFont.setFontSubFamilyName(ttf.getSubFamilyName()); | |||||
returnFont.setCapHeight(ttf.getCapHeight()); | |||||
returnFont.setXHeight(ttf.getXHeight()); | |||||
returnFont.setAscender(ttf.getLowerCaseAscent()); | |||||
returnFont.setDescender(ttf.getLowerCaseDescent()); | |||||
returnFont.setFontBBox(ttf.getFontBBox()); | |||||
returnFont.setUnderlinePosition(ttf.getUnderlinePosition() - ttf.getUnderlineThickness() / 2); | |||||
returnFont.setUnderlineThickness(ttf.getUnderlineThickness()); | |||||
returnFont.setStrikeoutPosition(ttf.getStrikeoutPosition() - ttf.getStrikeoutThickness() / 2); | |||||
returnFont.setStrikeoutThickness(ttf.getStrikeoutThickness()); | |||||
returnFont.setFlags(ttf.getFlags()); | |||||
returnFont.setStemV(Integer.parseInt(ttf.getStemV())); //not used for TTF | |||||
returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle())); | |||||
returnFont.setFontName(otf.getPostScriptName()); | |||||
returnFont.setFullName(otf.getFullName()); | |||||
returnFont.setFamilyNames(otf.getFamilyNames()); | |||||
returnFont.setFontSubFamilyName(otf.getSubFamilyName()); | |||||
returnFont.setCapHeight(otf.getCapHeight()); | |||||
returnFont.setXHeight(otf.getXHeight()); | |||||
returnFont.setAscender(otf.getLowerCaseAscent()); | |||||
returnFont.setDescender(otf.getLowerCaseDescent()); | |||||
returnFont.setFontBBox(otf.getFontBBox()); | |||||
returnFont.setUnderlinePosition(otf.getUnderlinePosition() - otf.getUnderlineThickness() / 2); | |||||
returnFont.setUnderlineThickness(otf.getUnderlineThickness()); | |||||
returnFont.setStrikeoutPosition(otf.getStrikeoutPosition() - otf.getStrikeoutThickness() / 2); | |||||
returnFont.setStrikeoutThickness(otf.getStrikeoutThickness()); | |||||
returnFont.setFlags(otf.getFlags()); | |||||
returnFont.setStemV(Integer.parseInt(otf.getStemV())); //not used for TTF | |||||
returnFont.setItalicAngle(Integer.parseInt(otf.getItalicAngle())); | |||||
returnFont.setMissingWidth(0); | returnFont.setMissingWidth(0); | ||||
returnFont.setWeight(ttf.getWeightClass()); | |||||
returnFont.setWeight(otf.getWeightClass()); | |||||
returnFont.setEmbeddingMode(this.embeddingMode); | returnFont.setEmbeddingMode(this.embeddingMode); | ||||
if (isCid) { | if (isCid) { | ||||
multiFont.setCIDType(CIDFontType.CIDTYPE2); | |||||
multiFont.setWidthArray(ttf.getWidths()); | |||||
multiFont.setBBoxArray(ttf.getBoundingBoxes()); | |||||
if (otf instanceof OTFFile) { | |||||
multiFont.setCIDType(CIDFontType.CIDTYPE0); | |||||
} else { | |||||
multiFont.setCIDType(CIDFontType.CIDTYPE2); | |||||
} | |||||
multiFont.setWidthArray(otf.getWidths()); | |||||
multiFont.setBBoxArray(otf.getBoundingBoxes()); | |||||
} else { | } else { | ||||
singleFont.setFontType(FontType.TRUETYPE); | singleFont.setFontType(FontType.TRUETYPE); | ||||
singleFont.setEncoding(ttf.getCharSetName()); | |||||
returnFont.setFirstChar(ttf.getFirstChar()); | |||||
returnFont.setLastChar(ttf.getLastChar()); | |||||
singleFont.setTrueTypePostScriptVersion(ttf.getPostScriptVersion()); | |||||
copyGlyphMetricsSingleByte(ttf); | |||||
singleFont.setEncoding(otf.getCharSetName()); | |||||
returnFont.setFirstChar(otf.getFirstChar()); | |||||
returnFont.setLastChar(otf.getLastChar()); | |||||
singleFont.setTrueTypePostScriptVersion(otf.getPostScriptVersion()); | |||||
copyGlyphMetricsSingleByte(otf); | |||||
} | } | ||||
returnFont.setCMap(getCMap(ttf)); | |||||
returnFont.setCMap(getCMap(otf)); | |||||
if (useKerning) { | |||||
copyKerning(ttf, isCid); | |||||
if (otf.getKerning() != null && useKerning) { | |||||
copyKerning(otf, isCid); | |||||
} | } | ||||
if (useAdvanced) { | if (useAdvanced) { | ||||
copyAdvanced(ttf); | |||||
copyAdvanced(otf); | |||||
} | } | ||||
if (this.embedded) { | if (this.embedded) { | ||||
if (ttf.isEmbeddable()) { | |||||
if (otf.isEmbeddable()) { | |||||
returnFont.setEmbedURI(this.fontFileURI); | returnFont.setEmbedURI(this.fontFileURI); | ||||
} else { | } else { | ||||
String msg = "The font " + this.fontFileURI + " is not embeddable due to a" | String msg = "The font " + this.fontFileURI + " is not embeddable due to a" | ||||
} | } | ||||
} | } | ||||
private CMapSegment[] getCMap(TTFFile ttf) { | |||||
CMapSegment[] array = new CMapSegment[ttf.getCMaps().size()]; | |||||
return ttf.getCMaps().toArray(array); | |||||
private CMapSegment[] getCMap(OpenFont otf) { | |||||
CMapSegment[] array = new CMapSegment[otf.getCMaps().size()]; | |||||
return otf.getCMaps().toArray(array); | |||||
} | } | ||||
private void copyGlyphMetricsSingleByte(TTFFile ttf) { | |||||
int[] wx = ttf.getWidths(); | |||||
Rectangle[] bboxes = ttf.getBoundingBoxes(); | |||||
private void copyGlyphMetricsSingleByte(OpenFont otf) { | |||||
int[] wx = otf.getWidths(); | |||||
Rectangle[] bboxes = otf.getBoundingBoxes(); | |||||
for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) { | for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) { | ||||
singleFont.setWidth(i, ttf.getCharWidth(i)); | |||||
int[] bbox = ttf.getBBox(i); | |||||
singleFont.setWidth(i, otf.getCharWidth(i)); | |||||
int[] bbox = otf.getBBox(i); | |||||
singleFont.setBoundingBox(i, | singleFont.setBoundingBox(i, | ||||
new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1])); | new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1])); | ||||
} | } | ||||
for (CMapSegment segment : ttf.getCMaps()) { | |||||
for (CMapSegment segment : otf.getCMaps()) { | |||||
if (segment.getUnicodeStart() < 0xFFFE) { | if (segment.getUnicodeStart() < 0xFFFE) { | ||||
for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) { | for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) { | ||||
int codePoint = singleFont.getEncoding().mapChar(u); | int codePoint = singleFont.getEncoding().mapChar(u); | ||||
if (codePoint <= 0) { | if (codePoint <= 0) { | ||||
int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart(); | int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart(); | ||||
String glyphName = ttf.getGlyphName(glyphIndex); | |||||
if (glyphName.length() == 0 && ttf.getPostScriptVersion() != PostScriptVersion.V2) { | |||||
String glyphName = otf.getGlyphName(glyphIndex); | |||||
if (glyphName.length() == 0 && otf.getPostScriptVersion() != PostScriptVersion.V2) { | |||||
glyphName = "u" + HexEncoder.encode(u); | glyphName = "u" + HexEncoder.encode(u); | ||||
} | } | ||||
if (glyphName.length() > 0) { | if (glyphName.length() > 0) { | ||||
/** | /** | ||||
* Copy kerning information. | * Copy kerning information. | ||||
*/ | */ | ||||
private void copyKerning(TTFFile ttf, boolean isCid) { | |||||
private void copyKerning(OpenFont otf, boolean isCid) { | |||||
// Get kerning | // Get kerning | ||||
Set<Integer> kerningSet; | Set<Integer> kerningSet; | ||||
if (isCid) { | if (isCid) { | ||||
kerningSet = ttf.getKerning().keySet(); | |||||
kerningSet = otf.getKerning().keySet(); | |||||
} else { | } else { | ||||
kerningSet = ttf.getAnsiKerning().keySet(); | |||||
kerningSet = otf.getAnsiKerning().keySet(); | |||||
} | } | ||||
for (Integer kpx1 : kerningSet) { | for (Integer kpx1 : kerningSet) { | ||||
Map<Integer, Integer> h2; | Map<Integer, Integer> h2; | ||||
if (isCid) { | if (isCid) { | ||||
h2 = ttf.getKerning().get(kpx1); | |||||
h2 = otf.getKerning().get(kpx1); | |||||
} else { | } else { | ||||
h2 = ttf.getAnsiKerning().get(kpx1); | |||||
h2 = otf.getAnsiKerning().get(kpx1); | |||||
} | } | ||||
returnFont.putKerningEntry(kpx1, h2); | returnFont.putKerningEntry(kpx1, h2); | ||||
} | } | ||||
/** | /** | ||||
* Copy advanced typographic information. | * Copy advanced typographic information. | ||||
*/ | */ | ||||
private void copyAdvanced(TTFFile ttf) { | |||||
private void copyAdvanced(OpenFont otf) { | |||||
if (returnFont instanceof MultiByteFont) { | if (returnFont instanceof MultiByteFont) { | ||||
MultiByteFont mbf = (MultiByteFont) returnFont; | MultiByteFont mbf = (MultiByteFont) returnFont; | ||||
mbf.setGDEF(ttf.getGDEF()); | |||||
mbf.setGSUB(ttf.getGSUB()); | |||||
mbf.setGPOS(ttf.getGPOS()); | |||||
mbf.setGDEF(otf.getGDEF()); | |||||
mbf.setGSUB(otf.getGSUB()); | |||||
mbf.setGPOS(otf.getGPOS()); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* This class represents a TrueType Mtx Entry. | * This class represents a TrueType Mtx Entry. | ||||
*/ | */ | ||||
class TTFMtxEntry { | |||||
class OFMtxEntry { | |||||
private int wx; | private int wx; | ||||
private int lsb; | private int lsb; |
* Represents table names as found in a TrueType font's Table Directory. | * Represents table names as found in a TrueType font's Table Directory. | ||||
* TrueType fonts may have custom tables so we cannot use an enum. | * TrueType fonts may have custom tables so we cannot use an enum. | ||||
*/ | */ | ||||
public final class TTFTableName { | |||||
public final class OFTableName { | |||||
/** The first table in a TrueType font file containing metadata about other tables. */ | /** The first table in a TrueType font file containing metadata about other tables. */ | ||||
public static final TTFTableName TABLE_DIRECTORY = new TTFTableName("tableDirectory"); | |||||
public static final OFTableName TABLE_DIRECTORY = new OFTableName("tableDirectory"); | |||||
/** Baseline data */ | |||||
public static final OFTableName BASE = new OFTableName("BASE"); | |||||
/** CFF data/ */ | |||||
public static final OFTableName CFF = new OFTableName("CFF "); | |||||
/** Embedded bitmap data. */ | /** Embedded bitmap data. */ | ||||
public static final TTFTableName EBDT = new TTFTableName("EBDT"); | |||||
public static final OFTableName EBDT = new OFTableName("EBDT"); | |||||
/** Embedded bitmap location data. */ | /** Embedded bitmap location data. */ | ||||
public static final TTFTableName EBLC = new TTFTableName("EBLC"); | |||||
public static final OFTableName EBLC = new OFTableName("EBLC"); | |||||
/** Embedded bitmap scaling data. */ | /** Embedded bitmap scaling data. */ | ||||
public static final TTFTableName EBSC = new TTFTableName("EBSC"); | |||||
public static final OFTableName EBSC = new OFTableName("EBSC"); | |||||
/** A FontForge specific table. */ | /** A FontForge specific table. */ | ||||
public static final TTFTableName FFTM = new TTFTableName("FFTM"); | |||||
public static final OFTableName FFTM = new OFTableName("FFTM"); | |||||
/** Divides glyphs into various classes that make using the GPOS/GSUB tables easier. */ | /** Divides glyphs into various classes that make using the GPOS/GSUB tables easier. */ | ||||
public static final TTFTableName GDEF = new TTFTableName("GDEF"); | |||||
public static final OFTableName GDEF = new OFTableName("GDEF"); | |||||
/** Provides kerning information, mark-to-base, etc. for opentype fonts. */ | /** Provides kerning information, mark-to-base, etc. for opentype fonts. */ | ||||
public static final TTFTableName GPOS = new TTFTableName("GPOS"); | |||||
public static final OFTableName GPOS = new OFTableName("GPOS"); | |||||
/** Provides ligature information, swash, etc. for opentype fonts. */ | /** Provides ligature information, swash, etc. for opentype fonts. */ | ||||
public static final TTFTableName GSUB = new TTFTableName("GSUB"); | |||||
public static final OFTableName GSUB = new OFTableName("GSUB"); | |||||
/** Linear threshold table. */ | /** Linear threshold table. */ | ||||
public static final TTFTableName LTSH = new TTFTableName("LTSH"); | |||||
public static final OFTableName LTSH = new OFTableName("LTSH"); | |||||
/** OS/2 and Windows specific metrics. */ | /** OS/2 and Windows specific metrics. */ | ||||
public static final TTFTableName OS2 = new TTFTableName("OS/2"); | |||||
public static final OFTableName OS2 = new OFTableName("OS/2"); | |||||
/** PCL 5 data. */ | /** PCL 5 data. */ | ||||
public static final TTFTableName PCLT = new TTFTableName("PCLT"); | |||||
public static final OFTableName PCLT = new OFTableName("PCLT"); | |||||
/** Vertical Device Metrics table. */ | /** Vertical Device Metrics table. */ | ||||
public static final TTFTableName VDMX = new TTFTableName("VDMX"); | |||||
public static final OFTableName VDMX = new OFTableName("VDMX"); | |||||
/** Character to glyph mapping. */ | /** Character to glyph mapping. */ | ||||
public static final TTFTableName CMAP = new TTFTableName("cmap"); | |||||
public static final OFTableName CMAP = new OFTableName("cmap"); | |||||
/** Control Value Table. */ | /** Control Value Table. */ | ||||
public static final TTFTableName CVT = new TTFTableName("cvt "); | |||||
public static final OFTableName CVT = new OFTableName("cvt "); | |||||
/** Font program. */ | /** Font program. */ | ||||
public static final TTFTableName FPGM = new TTFTableName("fpgm"); | |||||
public static final OFTableName FPGM = new OFTableName("fpgm"); | |||||
/** Grid-fitting and scan conversion procedure (grayscale). */ | /** Grid-fitting and scan conversion procedure (grayscale). */ | ||||
public static final TTFTableName GASP = new TTFTableName("gasp"); | |||||
public static final OFTableName GASP = new OFTableName("gasp"); | |||||
/** Glyph data. */ | /** Glyph data. */ | ||||
public static final TTFTableName GLYF = new TTFTableName("glyf"); | |||||
public static final OFTableName GLYF = new OFTableName("glyf"); | |||||
/** Horizontal device metrics. */ | /** Horizontal device metrics. */ | ||||
public static final TTFTableName HDMX = new TTFTableName("hdmx"); | |||||
public static final OFTableName HDMX = new OFTableName("hdmx"); | |||||
/** Font header. */ | /** Font header. */ | ||||
public static final TTFTableName HEAD = new TTFTableName("head"); | |||||
public static final OFTableName HEAD = new OFTableName("head"); | |||||
/** Horizontal header. */ | /** Horizontal header. */ | ||||
public static final TTFTableName HHEA = new TTFTableName("hhea"); | |||||
public static final OFTableName HHEA = new OFTableName("hhea"); | |||||
/** Horizontal metrics. */ | /** Horizontal metrics. */ | ||||
public static final TTFTableName HMTX = new TTFTableName("hmtx"); | |||||
public static final OFTableName HMTX = new OFTableName("hmtx"); | |||||
/** Kerning. */ | /** Kerning. */ | ||||
public static final TTFTableName KERN = new TTFTableName("kern"); | |||||
public static final OFTableName KERN = new OFTableName("kern"); | |||||
/** Index to location. */ | /** Index to location. */ | ||||
public static final TTFTableName LOCA = new TTFTableName("loca"); | |||||
public static final OFTableName LOCA = new OFTableName("loca"); | |||||
/** Maximum profile. */ | /** Maximum profile. */ | ||||
public static final TTFTableName MAXP = new TTFTableName("maxp"); | |||||
public static final OFTableName MAXP = new OFTableName("maxp"); | |||||
/** Naming table. */ | /** Naming table. */ | ||||
public static final TTFTableName NAME = new TTFTableName("name"); | |||||
public static final OFTableName NAME = new OFTableName("name"); | |||||
/** PostScript information. */ | /** PostScript information. */ | ||||
public static final TTFTableName POST = new TTFTableName("post"); | |||||
public static final OFTableName POST = new OFTableName("post"); | |||||
/** CVT Program. */ | /** CVT Program. */ | ||||
public static final TTFTableName PREP = new TTFTableName("prep"); | |||||
public static final OFTableName PREP = new OFTableName("prep"); | |||||
/** Vertical Metrics header. */ | /** Vertical Metrics header. */ | ||||
public static final TTFTableName VHEA = new TTFTableName("vhea"); | |||||
public static final OFTableName VHEA = new OFTableName("vhea"); | |||||
/** Vertical Metrics. */ | /** Vertical Metrics. */ | ||||
public static final TTFTableName VMTX = new TTFTableName("vmtx"); | |||||
public static final OFTableName VMTX = new OFTableName("vmtx"); | |||||
private final String name; | private final String name; | ||||
private TTFTableName(String name) { | |||||
private OFTableName(String name) { | |||||
this.name = name; | this.name = name; | ||||
} | } | ||||
* @param tableName table name as in the Table Directory | * @param tableName table name as in the Table Directory | ||||
* @return TTFTableName | * @return TTFTableName | ||||
*/ | */ | ||||
public static TTFTableName getValue(String tableName) { | |||||
public static OFTableName getValue(String tableName) { | |||||
if (tableName != null) { | if (tableName != null) { | ||||
return new TTFTableName(tableName); | |||||
return new OFTableName(tableName); | |||||
} | } | ||||
throw new IllegalArgumentException("A TrueType font table name must not be null"); | throw new IllegalArgumentException("A TrueType font table name must not be null"); | ||||
} | } | ||||
if (o == this) { | if (o == this) { | ||||
return true; | return true; | ||||
} | } | ||||
if (!(o instanceof TTFTableName)) { | |||||
if (!(o instanceof OFTableName)) { | |||||
return false; | return false; | ||||
} | } | ||||
TTFTableName to = (TTFTableName) o; | |||||
OFTableName to = (OFTableName) o; | |||||
return this.name.equals(to.getName()); | return this.name.equals(to.getName()); | ||||
} | } | ||||
/* | |||||
* 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.fonts.truetype; | |||||
import java.io.IOException; | |||||
import org.apache.fontbox.cff.CFFDataInput; | |||||
import org.apache.fontbox.cff.CFFFont; | |||||
import org.apache.fontbox.cff.CFFFont.Mapping; | |||||
import org.apache.fontbox.cff.CFFParser; | |||||
public class OTFFile extends OpenFont { | |||||
protected CFFFont fileFont; | |||||
public OTFFile() throws IOException { | |||||
checkForFontbox(); | |||||
} | |||||
private void checkForFontbox() throws IOException { | |||||
try { | |||||
Class.forName("org.apache.fontbox.cff.CFFFont"); | |||||
} catch (ClassNotFoundException ex) { | |||||
throw new IOException("The Fontbox jar was not found in the classpath. This is " | |||||
+ "required for OTF CFF ssupport."); | |||||
} | |||||
} | |||||
@Override | |||||
protected void updateBBoxAndOffset() throws IOException { | |||||
UnicodeMapping[] mappings = unicodeMappings.toArray(new UnicodeMapping[0]); | |||||
for (int i = 0; i < mappings.length; i++) { | |||||
int glyphIdx = mappings[i].getGlyphIndex(); | |||||
Mapping m = fileFont.getGIDMappings().get(glyphIdx); | |||||
int[] bbox = fileFont.getBoundingBox(m.getSID()); | |||||
String name = fileFont.getNameOfCharFromCode(m.getSID()); | |||||
mtxTab[glyphIdx].setBoundingBox(bbox); | |||||
mtxTab[glyphIdx].setName(name); | |||||
} | |||||
} | |||||
@Override | |||||
protected void initializeFont(FontFileReader in) throws IOException { | |||||
fontFile = in; | |||||
fontFile.seekSet(0); | |||||
CFFParser parser = new CFFParser(); | |||||
fileFont = parser.parse(in.getAllBytes()).get(0); | |||||
} | |||||
protected void readName() throws IOException { | |||||
Object familyName = fileFont.getProperty("FamilyName"); | |||||
if (familyName != null && !familyName.equals("")) { | |||||
familyNames.add(familyName.toString()); | |||||
fullName = familyName.toString(); | |||||
} else { | |||||
fullName = fileFont.getName(); | |||||
familyNames.add(fullName); | |||||
} | |||||
} | |||||
/** | |||||
* Reads the CFFData from a given font file | |||||
* @param fontFile The font file being read | |||||
* @return The byte data found in the CFF table | |||||
*/ | |||||
public static byte[] getCFFData(FontFileReader fontFile) throws IOException { | |||||
byte[] cff = new byte[0]; | |||||
CFFDataInput input = new CFFDataInput(fontFile.getAllBytes()); | |||||
input.readBytes(4); //OTTO | |||||
short numTables = input.readShort(); | |||||
input.readShort(); //searchRange | |||||
input.readShort(); //entrySelector | |||||
input.readShort(); //rangeShift | |||||
for (int q = 0; q < numTables; q++) { | |||||
String tagName = new String(input.readBytes(4)); | |||||
readLong(input); //Checksum | |||||
long offset = readLong(input); | |||||
long length = readLong(input); | |||||
if (tagName.equals("CFF ")) { | |||||
cff = new byte[(int)length]; | |||||
System.arraycopy(fontFile.getAllBytes(), (int)offset, cff, 0, cff.length); | |||||
break; | |||||
} | |||||
} | |||||
return cff; | |||||
} | |||||
private static long readLong(CFFDataInput input) throws IOException { | |||||
return (input.readCard16() << 16) | input.readCard16(); | |||||
} | |||||
} |
* Offsets in name table to be filled out by table. | * Offsets in name table to be filled out by table. | ||||
* The offsets are to the checkSum field | * The offsets are to the checkSum field | ||||
*/ | */ | ||||
private Map<TTFTableName, Integer> offsets = new HashMap<TTFTableName, Integer>(); | |||||
private Map<OFTableName, Integer> offsets = new HashMap<OFTableName, Integer>(); | |||||
private int checkSumAdjustmentOffset = 0; | private int checkSumAdjustmentOffset = 0; | ||||
private int locaOffset = 0; | private int locaOffset = 0; | ||||
} | } | ||||
/** The dir tab entries in the new subset font. */ | /** The dir tab entries in the new subset font. */ | ||||
private Map<TTFTableName, TTFDirTabEntry> newDirTabs | |||||
= new HashMap<TTFTableName, TTFDirTabEntry>(); | |||||
private Map<OFTableName, OFDirTabEntry> newDirTabs | |||||
= new HashMap<OFTableName, OFDirTabEntry>(); | |||||
private int determineTableCount() { | private int determineTableCount() { | ||||
int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp | int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp | ||||
writeUShort((numTables * 16) - searchRange); | writeUShort((numTables * 16) - searchRange); | ||||
realSize += 2; | realSize += 2; | ||||
// Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) | // Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) | ||||
writeTableName(TTFTableName.OS2); | |||||
writeTableName(OFTableName.OS2); | |||||
if (hasCvt()) { | if (hasCvt()) { | ||||
writeTableName(TTFTableName.CVT); | |||||
writeTableName(OFTableName.CVT); | |||||
} | } | ||||
if (hasFpgm()) { | if (hasFpgm()) { | ||||
writeTableName(TTFTableName.FPGM); | |||||
writeTableName(OFTableName.FPGM); | |||||
} | } | ||||
writeTableName(TTFTableName.GLYF); | |||||
writeTableName(TTFTableName.HEAD); | |||||
writeTableName(TTFTableName.HHEA); | |||||
writeTableName(TTFTableName.HMTX); | |||||
writeTableName(TTFTableName.LOCA); | |||||
writeTableName(TTFTableName.MAXP); | |||||
writeTableName(TTFTableName.NAME); | |||||
writeTableName(TTFTableName.POST); | |||||
writeTableName(OFTableName.GLYF); | |||||
writeTableName(OFTableName.HEAD); | |||||
writeTableName(OFTableName.HHEA); | |||||
writeTableName(OFTableName.HMTX); | |||||
writeTableName(OFTableName.LOCA); | |||||
writeTableName(OFTableName.MAXP); | |||||
writeTableName(OFTableName.NAME); | |||||
writeTableName(OFTableName.POST); | |||||
if (hasPrep()) { | if (hasPrep()) { | ||||
writeTableName(TTFTableName.PREP); | |||||
writeTableName(OFTableName.PREP); | |||||
} | } | ||||
newDirTabs.put(TTFTableName.TABLE_DIRECTORY, new TTFDirTabEntry(0, currentPos)); | |||||
newDirTabs.put(OFTableName.TABLE_DIRECTORY, new OFDirTabEntry(0, currentPos)); | |||||
} | } | ||||
private void writeTableName(TTFTableName tableName) { | |||||
private void writeTableName(OFTableName tableName) { | |||||
writeString(tableName.getName()); | writeString(tableName.getName()); | ||||
offsets.put(tableName, currentPos); | offsets.put(tableName, currentPos); | ||||
currentPos += 12; | currentPos += 12; | ||||
private boolean hasCvt() { | private boolean hasCvt() { | ||||
return dirTabs.containsKey(TTFTableName.CVT); | |||||
return dirTabs.containsKey(OFTableName.CVT); | |||||
} | } | ||||
private boolean hasFpgm() { | private boolean hasFpgm() { | ||||
return dirTabs.containsKey(TTFTableName.FPGM); | |||||
return dirTabs.containsKey(OFTableName.FPGM); | |||||
} | } | ||||
private boolean hasPrep() { | private boolean hasPrep() { | ||||
return dirTabs.containsKey(TTFTableName.PREP); | |||||
return dirTabs.containsKey(OFTableName.PREP); | |||||
} | } | ||||
/** | /** | ||||
private void createLoca(int size) throws IOException { | private void createLoca(int size) throws IOException { | ||||
pad4(); | pad4(); | ||||
locaOffset = currentPos; | locaOffset = currentPos; | ||||
int dirTableOffset = offsets.get(TTFTableName.LOCA); | |||||
int dirTableOffset = offsets.get(OFTableName.LOCA); | |||||
writeULong(dirTableOffset + 4, currentPos); | writeULong(dirTableOffset + 4, currentPos); | ||||
writeULong(dirTableOffset + 8, size * 4 + 4); | writeULong(dirTableOffset + 8, size * 4 + 4); | ||||
currentPos += size * 4 + 4; | currentPos += size * 4 + 4; | ||||
realSize += size * 4 + 4; | realSize += size * 4 + 4; | ||||
} | } | ||||
private boolean copyTable(FontFileReader in, TTFTableName tableName) throws IOException { | |||||
TTFDirTabEntry entry = dirTabs.get(tableName); | |||||
private boolean copyTable(FontFileReader in, OFTableName tableName) throws IOException { | |||||
OFDirTabEntry entry = dirTabs.get(tableName); | |||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, tableName, 0); | seekTab(in, tableName, 0); | ||||
* Copy the cvt table as is from original font to subset font | * Copy the cvt table as is from original font to subset font | ||||
*/ | */ | ||||
private boolean createCvt(FontFileReader in) throws IOException { | private boolean createCvt(FontFileReader in) throws IOException { | ||||
return copyTable(in, TTFTableName.CVT); | |||||
return copyTable(in, OFTableName.CVT); | |||||
} | } | ||||
/** | /** | ||||
* Copy the fpgm table as is from original font to subset font | * Copy the fpgm table as is from original font to subset font | ||||
*/ | */ | ||||
private boolean createFpgm(FontFileReader in) throws IOException { | private boolean createFpgm(FontFileReader in) throws IOException { | ||||
return copyTable(in, TTFTableName.FPGM); | |||||
return copyTable(in, OFTableName.FPGM); | |||||
} | } | ||||
/** | /** | ||||
* Copy the name table as is from the original. | * Copy the name table as is from the original. | ||||
*/ | */ | ||||
private boolean createName(FontFileReader in) throws IOException { | private boolean createName(FontFileReader in) throws IOException { | ||||
return copyTable(in, TTFTableName.NAME); | |||||
return copyTable(in, OFTableName.NAME); | |||||
} | } | ||||
/** | /** | ||||
* Copy the OS/2 table as is from the original. | * Copy the OS/2 table as is from the original. | ||||
*/ | */ | ||||
private boolean createOS2(FontFileReader in) throws IOException { | private boolean createOS2(FontFileReader in) throws IOException { | ||||
return copyTable(in, TTFTableName.OS2); | |||||
return copyTable(in, OFTableName.OS2); | |||||
} | } | ||||
/** | /** | ||||
* and set num glyphs to size | * and set num glyphs to size | ||||
*/ | */ | ||||
private void createMaxp(FontFileReader in, int size) throws IOException { | private void createMaxp(FontFileReader in, int size) throws IOException { | ||||
TTFTableName maxp = TTFTableName.MAXP; | |||||
TTFDirTabEntry entry = dirTabs.get(maxp); | |||||
OFTableName maxp = OFTableName.MAXP; | |||||
OFDirTabEntry entry = dirTabs.get(maxp); | |||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, maxp, 0); | seekTab(in, maxp, 0); | ||||
} | } | ||||
private void createPost(FontFileReader in) throws IOException { | private void createPost(FontFileReader in) throws IOException { | ||||
TTFTableName post = TTFTableName.POST; | |||||
TTFDirTabEntry entry = dirTabs.get(post); | |||||
OFTableName post = OFTableName.POST; | |||||
OFDirTabEntry entry = dirTabs.get(post); | |||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, post, 0); | seekTab(in, post, 0); | ||||
* Copy the prep table as is from original font to subset font | * Copy the prep table as is from original font to subset font | ||||
*/ | */ | ||||
private boolean createPrep(FontFileReader in) throws IOException { | private boolean createPrep(FontFileReader in) throws IOException { | ||||
return copyTable(in, TTFTableName.PREP); | |||||
return copyTable(in, OFTableName.PREP); | |||||
} | } | ||||
* and fill in size of hmtx table | * and fill in size of hmtx table | ||||
*/ | */ | ||||
private void createHhea(FontFileReader in, int size) throws IOException { | private void createHhea(FontFileReader in, int size) throws IOException { | ||||
TTFDirTabEntry entry = dirTabs.get(TTFTableName.HHEA); | |||||
OFDirTabEntry entry = dirTabs.get(OFTableName.HHEA); | |||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, TTFTableName.HHEA, 0); | |||||
seekTab(in, OFTableName.HHEA, 0); | |||||
System.arraycopy(in.getBytes((int) entry.getOffset(), (int) entry.getLength()), 0, | System.arraycopy(in.getBytes((int) entry.getOffset(), (int) entry.getLength()), 0, | ||||
output, currentPos, (int) entry.getLength()); | output, currentPos, (int) entry.getLength()); | ||||
writeUShort((int) entry.getLength() + currentPos - 2, size); | writeUShort((int) entry.getLength() + currentPos - 2, size); | ||||
updateCheckSum(currentPos, (int) entry.getLength(), TTFTableName.HHEA); | |||||
updateCheckSum(currentPos, (int) entry.getLength(), OFTableName.HHEA); | |||||
currentPos += (int) entry.getLength(); | currentPos += (int) entry.getLength(); | ||||
realSize += (int) entry.getLength(); | realSize += (int) entry.getLength(); | ||||
} else { | } else { | ||||
* in checkSumAdjustmentOffset | * in checkSumAdjustmentOffset | ||||
*/ | */ | ||||
private void createHead(FontFileReader in) throws IOException { | private void createHead(FontFileReader in) throws IOException { | ||||
TTFTableName head = TTFTableName.HEAD; | |||||
TTFDirTabEntry entry = dirTabs.get(head); | |||||
OFTableName head = OFTableName.HEAD; | |||||
OFDirTabEntry entry = dirTabs.get(head); | |||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, head, 0); | seekTab(in, head, 0); | ||||
*/ | */ | ||||
private void createGlyf(FontFileReader in, | private void createGlyf(FontFileReader in, | ||||
Map<Integer, Integer> glyphs) throws IOException { | Map<Integer, Integer> glyphs) throws IOException { | ||||
TTFTableName glyf = TTFTableName.GLYF; | |||||
TTFDirTabEntry entry = dirTabs.get(glyf); | |||||
OFTableName glyf = OFTableName.GLYF; | |||||
OFDirTabEntry entry = dirTabs.get(glyf); | |||||
int size = 0; | int size = 0; | ||||
int startPos = 0; | int startPos = 0; | ||||
int endOffset = 0; // Store this as the last loca | int endOffset = 0; // Store this as the last loca | ||||
writeULong(locaOffset + glyphs.size() * 4, endOffset); | writeULong(locaOffset + glyphs.size() * 4, endOffset); | ||||
int locaSize = glyphs.size() * 4 + 4; | int locaSize = glyphs.size() * 4 + 4; | ||||
int checksum = getCheckSum(output, locaOffset, locaSize); | int checksum = getCheckSum(output, locaOffset, locaSize); | ||||
writeULong(offsets.get(TTFTableName.LOCA), checksum); | |||||
writeULong(offsets.get(OFTableName.LOCA), checksum); | |||||
int padSize = (locaOffset + locaSize) % 4; | int padSize = (locaOffset + locaSize) % 4; | ||||
newDirTabs.put(TTFTableName.LOCA, | |||||
new TTFDirTabEntry(locaOffset, locaSize + padSize)); | |||||
newDirTabs.put(OFTableName.LOCA, | |||||
new OFDirTabEntry(locaOffset, locaSize + padSize)); | |||||
} else { | } else { | ||||
throw new IOException("Can't find glyf table"); | throw new IOException("Can't find glyf table"); | ||||
} | } | ||||
*/ | */ | ||||
private void createHmtx(FontFileReader in, | private void createHmtx(FontFileReader in, | ||||
Map<Integer, Integer> glyphs) throws IOException { | Map<Integer, Integer> glyphs) throws IOException { | ||||
TTFTableName hmtx = TTFTableName.HMTX; | |||||
TTFDirTabEntry entry = dirTabs.get(hmtx); | |||||
OFTableName hmtx = OFTableName.HMTX; | |||||
OFDirTabEntry entry = dirTabs.get(hmtx); | |||||
int longHorMetricSize = glyphs.size() * 2; | int longHorMetricSize = glyphs.size() * 2; | ||||
int leftSideBearingSize = glyphs.size() * 2; | int leftSideBearingSize = glyphs.size() * 2; | ||||
* new index as (Integer) value) | * new index as (Integer) value) | ||||
* @throws IOException in case of an I/O problem | * @throws IOException in case of an I/O problem | ||||
*/ | */ | ||||
public void readFont(FontFileReader in, String name, | |||||
public void readFont(FontFileReader in, String name, String header, | |||||
Map<Integer, Integer> glyphs) throws IOException { | Map<Integer, Integer> glyphs) throws IOException { | ||||
fontFile = in; | fontFile = in; | ||||
//Check if TrueType collection, and that the name exists in the collection | //Check if TrueType collection, and that the name exists in the collection | ||||
if (!checkTTC(name)) { | |||||
if (!checkTTC(header, name)) { | |||||
throw new IOException("Failed to read font"); | throw new IOException("Failed to read font"); | ||||
} | } | ||||
glyphOffsets[i + 1] - glyphOffsets[i]); | glyphOffsets[i + 1] - glyphOffsets[i]); | ||||
} | } | ||||
// Stream the last glyph | // Stream the last glyph | ||||
TTFDirTabEntry glyf = newDirTabs.get(TTFTableName.GLYF); | |||||
OFDirTabEntry glyf = newDirTabs.get(OFTableName.GLYF); | |||||
long lastGlyphLength = glyf.getLength() | long lastGlyphLength = glyf.getLength() | ||||
- (glyphOffsets[glyphOffsets.length - 1] - glyf.getOffset()); | - (glyphOffsets[glyphOffsets.length - 1] - glyf.getOffset()); | ||||
glyphOut.streamGlyph(output, glyphOffsets[glyphOffsets.length - 1], | glyphOut.streamGlyph(output, glyphOffsets[glyphOffsets.length - 1], | ||||
@Override | @Override | ||||
public void stream(TTFOutputStream ttfOut) throws IOException { | public void stream(TTFOutputStream ttfOut) throws IOException { | ||||
SortedSet<Map.Entry<TTFTableName, TTFDirTabEntry>> sortedDirTabs | |||||
SortedSet<Map.Entry<OFTableName, OFDirTabEntry>> sortedDirTabs | |||||
= sortDirTabMap(newDirTabs); | = sortDirTabMap(newDirTabs); | ||||
TTFTableOutputStream tableOut = ttfOut.getTableOutputStream(); | TTFTableOutputStream tableOut = ttfOut.getTableOutputStream(); | ||||
TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream(); | TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream(); | ||||
ttfOut.startFontStream(); | ttfOut.startFontStream(); | ||||
for (Map.Entry<TTFTableName, TTFDirTabEntry> entry : sortedDirTabs) { | |||||
if (entry.getKey().equals(TTFTableName.GLYF)) { | |||||
for (Map.Entry<OFTableName, OFDirTabEntry> entry : sortedDirTabs) { | |||||
if (entry.getKey().equals(OFTableName.GLYF)) { | |||||
handleGlyphSubset(glyphOut); | handleGlyphSubset(glyphOut); | ||||
} else { | } else { | ||||
tableOut.streamTable(output, (int) entry.getValue().getOffset(), | tableOut.streamTable(output, (int) entry.getValue().getOffset(), | ||||
private void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs) | private void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs) | ||||
throws IOException { | throws IOException { | ||||
TTFDirTabEntry glyfTableInfo = dirTabs.get(TTFTableName.GLYF); | |||||
OFDirTabEntry glyfTableInfo = dirTabs.get(OFTableName.GLYF); | |||||
if (glyfTableInfo == null) { | if (glyfTableInfo == null) { | ||||
throw new IOException("Glyf table could not be found"); | throw new IOException("Glyf table could not be found"); | ||||
} | } | ||||
} | } | ||||
private void updateCheckSum(int tableStart, int tableSize, TTFTableName tableName) { | |||||
private void updateCheckSum(int tableStart, int tableSize, OFTableName tableName) { | |||||
int checksum = getCheckSum(output, tableStart, tableSize); | int checksum = getCheckSum(output, tableStart, tableSize); | ||||
int offset = offsets.get(tableName); | int offset = offsets.get(tableName); | ||||
int padSize = getPadSize(tableStart + tableSize); | int padSize = getPadSize(tableStart + tableSize); | ||||
newDirTabs.put(tableName, new TTFDirTabEntry(tableStart, tableSize + padSize)); | |||||
newDirTabs.put(tableName, new OFDirTabEntry(tableStart, tableSize + padSize)); | |||||
writeULong(offset, checksum); | writeULong(offset, checksum); | ||||
writeULong(offset + 4, tableStart); | writeULong(offset + 4, tableStart); | ||||
writeULong(offset + 8, tableSize); | writeULong(offset + 8, tableSize); |
*/ | */ | ||||
public void addCharMetrics(AFMCharMetrics metrics) { | public void addCharMetrics(AFMCharMetrics metrics) { | ||||
String name = metrics.getCharName(); | String name = metrics.getCharName(); | ||||
if (metrics.getUnicodeSequence() == null) { | |||||
if (metrics.getUnicodeSequence() == null && name.equals(".notdef")) { | |||||
//Ignore as no Unicode assignment is possible | //Ignore as no Unicode assignment is possible | ||||
return; | return; | ||||
} | } |
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.xmlgraphics.fonts.Glyphs; | |||||
import org.apache.fop.fonts.NamedCharacter; | import org.apache.fop.fonts.NamedCharacter; | ||||
import org.apache.fop.fonts.type1.AFMParser.ValueHandler; | import org.apache.fop.fonts.type1.AFMParser.ValueHandler; | ||||
AFMCharMetrics chm = defaultHandler.parse(line, stack, afmFileName); | AFMCharMetrics chm = defaultHandler.parse(line, stack, afmFileName); | ||||
NamedCharacter namedChar = chm.getCharacter(); | NamedCharacter namedChar = chm.getCharacter(); | ||||
if (namedChar != null) { | if (namedChar != null) { | ||||
int codePoint = AdobeStandardEncoding.getAdobeCodePoint(namedChar.getName()); | |||||
if (chm.getCharCode() != codePoint) { | |||||
LOG.info(afmFileName + ": named character '" + namedChar.getName() + "'" | |||||
String charName = namedChar.getName(); | |||||
int codePoint = AdobeStandardEncoding.getAdobeCodePoint(charName); | |||||
if (chm.getCharCode() != codePoint && !Glyphs.NOTDEF.equals(charName)) { | |||||
LOG.info(afmFileName + ": named character '" + charName + "'" | |||||
+ " has an incorrect code point: " + chm.getCharCode() | + " has an incorrect code point: " + chm.getCharCode() | ||||
+ ". Changed to " + codePoint); | + ". Changed to " + codePoint); | ||||
chm.setCharCode(codePoint); | chm.setCharCode(codePoint); |
addUnencodedBasedOnAFM(afm); | addUnencodedBasedOnAFM(afm); | ||||
} | } | ||||
} else { | } else { | ||||
if (pfm.getCharSet() >= 0 && pfm.getCharSet() <= 2) { | |||||
if (pfm.getCharSet() == 2 && !pfm.getCharSetName().equals("Symbol")) { | |||||
int[] table = new int[256]; | |||||
String[] charNameMap = new String[256]; | |||||
int j = 0; | |||||
for (int i = pfm.getFirstChar(); i < pfm.getLastChar(); i++) { | |||||
if (j < table.length) { | |||||
table[j] = i; | |||||
table[j + 1] = i; | |||||
j += 2; | |||||
} | |||||
charNameMap[i] = String.format("x%03o", i); | |||||
} | |||||
CodePointMapping mapping = new CodePointMapping("custom", table, charNameMap); | |||||
singleFont.setEncoding(mapping); | |||||
} else if (pfm.getCharSet() >= 0 && pfm.getCharSet() <= 2) { | |||||
singleFont.setEncoding(pfm.getCharSetName() + "Encoding"); | singleFont.setEncoding(pfm.getCharSetName() + "Encoding"); | ||||
} else { | } else { | ||||
log.warn("The PFM reports an unsupported encoding (" | log.warn("The PFM reports an unsupported encoding (" | ||||
List<AFMCharMetrics> chars = afm.getCharMetrics(); | List<AFMCharMetrics> chars = afm.getCharMetrics(); | ||||
for (AFMCharMetrics charMetrics : chars) { | for (AFMCharMetrics charMetrics : chars) { | ||||
if (charMetrics.getCharCode() >= 0) { | if (charMetrics.getCharCode() >= 0) { | ||||
String u = charMetrics.getUnicodeSequence(); | |||||
if (u != null && u.length() == 1) { | |||||
mappingCount++; | |||||
} | |||||
mappingCount++; | |||||
} | } | ||||
} | } | ||||
// ...and now build the table. | // ...and now build the table. | ||||
String unicodes = charMetrics.getUnicodeSequence(); | String unicodes = charMetrics.getUnicodeSequence(); | ||||
if (unicodes == null) { | if (unicodes == null) { | ||||
log.info("No Unicode mapping for glyph: " + charMetrics); | log.info("No Unicode mapping for glyph: " + charMetrics); | ||||
table[idx] = charMetrics.getCharCode(); | |||||
idx++; | |||||
table[idx] = charMetrics.getCharCode(); | |||||
idx++; | |||||
} else if (unicodes.length() == 1) { | } else if (unicodes.length() == 1) { | ||||
table[idx] = charMetrics.getCharCode(); | table[idx] = charMetrics.getCharCode(); | ||||
idx++; | idx++; |
public AbstractBaseLayoutManager(FObj fo) { | public AbstractBaseLayoutManager(FObj fo) { | ||||
this.fobj = fo; | this.fobj = fo; | ||||
setGeneratesReferenceArea(fo.generatesReferenceAreas()); | setGeneratesReferenceArea(fo.generatesReferenceAreas()); | ||||
if (getGeneratesReferenceArea()) { | |||||
setGeneratesBlockArea(true); | |||||
} | |||||
} | } | ||||
// --------- Property Resolution related functions --------- // | // --------- Property Resolution related functions --------- // |
&& isFinished()); | && isFinished()); | ||||
} | } | ||||
public boolean hasLineAreaDescendant() { | |||||
if (childLMs == null || childLMs.isEmpty()) { | |||||
return false; | |||||
} else { | |||||
for (LayoutManager childLM : childLMs) { | |||||
if (childLM.hasLineAreaDescendant()) { | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
public int getBaselineOffset() { | |||||
if (childLMs != null) { | |||||
for (LayoutManager childLM : childLMs) { | |||||
if (childLM.hasLineAreaDescendant()) { | |||||
return childLM.getBaselineOffset(); | |||||
} | |||||
} | |||||
} | |||||
throw newNoLineAreaDescendantException(); | |||||
} | |||||
protected IllegalStateException newNoLineAreaDescendantException() { | |||||
return new IllegalStateException("getBaselineOffset called on an object that has no line-area descendant"); | |||||
} | |||||
/** | /** | ||||
* Transfers foreign attributes from the formatting object to the area. | * Transfers foreign attributes from the formatting object to the area. | ||||
* @param targetArea the area to set the attributes on | * @param targetArea the area to set the attributes on |
/** | /** | ||||
* Creates the child areas for the given layout manager. | * Creates the child areas for the given layout manager. | ||||
* @param bslm the BlockStackingLayoutManager instance for which "addAreas" is performed. | |||||
* @param parentLM the parent layout manager | |||||
* @param parentIter the position iterator | * @param parentIter the position iterator | ||||
* @param layoutContext the layout context | * @param layoutContext the layout context | ||||
*/ | */ | ||||
public static void addAreas(BlockStackingLayoutManager bslm, | |||||
public static void addAreas(AbstractLayoutManager parentLM, | |||||
PositionIterator parentIter, LayoutContext layoutContext) { | PositionIterator parentIter, LayoutContext layoutContext) { | ||||
LayoutManager childLM; | LayoutManager childLM; | ||||
LayoutContext lc = LayoutContext.offspringOf(layoutContext); | LayoutContext lc = LayoutContext.offspringOf(layoutContext); | ||||
Position firstPos = null; | Position firstPos = null; | ||||
Position lastPos = null; | Position lastPos = null; | ||||
if (bslm != null) { | |||||
bslm.addId(); | |||||
if (parentLM != null) { | |||||
parentLM.addId(); | |||||
} | } | ||||
// "unwrap" the NonLeafPositions stored in parentIter | // "unwrap" the NonLeafPositions stored in parentIter | ||||
//doesn't give us that info. | //doesn't give us that info. | ||||
} | } | ||||
if (bslm != null) { | |||||
bslm.registerMarkers( | |||||
if (parentLM != null) { | |||||
parentLM.registerMarkers( | |||||
true, | true, | ||||
bslm.isFirst(firstPos), | |||||
bslm.isLast(lastPos)); | |||||
parentLM.isFirst(firstPos), | |||||
parentLM.isLast(lastPos)); | |||||
} | } | ||||
PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | ||||
childLM.addAreas(childPosIter, lc); | childLM.addAreas(childPosIter, lc); | ||||
} | } | ||||
if (bslm != null) { | |||||
bslm.registerMarkers( | |||||
if (parentLM != null) { | |||||
parentLM.registerMarkers( | |||||
false, | false, | ||||
bslm.isFirst(firstPos), | |||||
bslm.isLast(lastPos)); | |||||
parentLM.isFirst(firstPos), | |||||
parentLM.isLast(lastPos)); | |||||
} | } | ||||
import org.apache.fop.datatypes.Length; | import org.apache.fop.datatypes.Length; | ||||
import org.apache.fop.fo.flow.BlockContainer; | import org.apache.fop.fo.flow.BlockContainer; | ||||
import org.apache.fop.fo.properties.CommonAbsolutePosition; | import org.apache.fop.fo.properties.CommonAbsolutePosition; | ||||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | |||||
import org.apache.fop.fo.properties.KeepProperty; | import org.apache.fop.fo.properties.KeepProperty; | ||||
import org.apache.fop.traits.MinOptMax; | import org.apache.fop.traits.MinOptMax; | ||||
import org.apache.fop.traits.SpaceVal; | import org.apache.fop.traits.SpaceVal; | ||||
/** | /** | ||||
* LayoutManager for a block-container FO. | * LayoutManager for a block-container FO. | ||||
*/ | */ | ||||
public class BlockContainerLayoutManager extends BlockStackingLayoutManager implements | |||||
ConditionalElementListener, BreakOpportunity { | |||||
public class BlockContainerLayoutManager extends SpacedBorderedPaddedBlockLayoutManager | |||||
implements BreakOpportunity { | |||||
/** | /** | ||||
* logging instance | * logging instance | ||||
private MinOptMax foBlockSpaceBefore; | private MinOptMax foBlockSpaceBefore; | ||||
private MinOptMax foBlockSpaceAfter; | private MinOptMax foBlockSpaceAfter; | ||||
private boolean discardBorderBefore; | |||||
private boolean discardBorderAfter; | |||||
private boolean discardPaddingBefore; | |||||
private boolean discardPaddingAfter; | |||||
private MinOptMax effSpaceBefore; | |||||
private MinOptMax effSpaceAfter; | |||||
private int horizontalOverflow; | private int horizontalOverflow; | ||||
private double contentRectOffsetX = 0; | private double contentRectOffsetX = 0; | ||||
private double contentRectOffsetY = 0; | private double contentRectOffsetY = 0; | ||||
*/ | */ | ||||
public BlockContainerLayoutManager(BlockContainer node) { | public BlockContainerLayoutManager(BlockContainer node) { | ||||
super(node); | super(node); | ||||
setGeneratesBlockArea(true); | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
.spaceAfter.getSpace().getOptimum(this).getLength().getValue(this); | .spaceAfter.getSpace().getOptimum(this).getLength().getValue(this); | ||||
} | } | ||||
@Override | |||||
protected CommonBorderPaddingBackground getCommonBorderPaddingBackground() { | |||||
return getBlockContainerFO().getCommonBorderPaddingBackground(); | |||||
} | |||||
private void resetSpaces() { | private void resetSpaces() { | ||||
this.discardBorderBefore = false; | this.discardBorderBefore = false; | ||||
this.discardBorderAfter = false; | this.discardBorderAfter = false; | ||||
transferForeignAttributes(viewportBlockArea); | transferForeignAttributes(viewportBlockArea); | ||||
TraitSetter.setProducerID(viewportBlockArea, getBlockContainerFO().getId()); | TraitSetter.setProducerID(viewportBlockArea, getBlockContainerFO().getId()); | ||||
TraitSetter.setLayer(viewportBlockArea, getBlockContainerFO().getLayer()); | |||||
TraitSetter.addBorders(viewportBlockArea, | TraitSetter.addBorders(viewportBlockArea, | ||||
getBlockContainerFO().getCommonBorderPaddingBackground(), | getBlockContainerFO().getCommonBorderPaddingBackground(), | ||||
discardBorderBefore, discardBorderAfter, false, false, this); | discardBorderBefore, discardBorderAfter, false, false, this); | ||||
return true; | return true; | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
public void notifySpace(RelSide side, MinOptMax effectiveLength) { | |||||
if (RelSide.BEFORE == side) { | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Space " + side + ", " | |||||
+ this.effSpaceBefore + "-> " + effectiveLength); | |||||
} | |||||
this.effSpaceBefore = effectiveLength; | |||||
} else { | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Space " + side + ", " | |||||
+ this.effSpaceAfter + "-> " + effectiveLength); | |||||
} | |||||
this.effSpaceAfter = effectiveLength; | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public void notifyBorder(RelSide side, MinOptMax effectiveLength) { | |||||
if (effectiveLength == null) { | |||||
if (RelSide.BEFORE == side) { | |||||
this.discardBorderBefore = true; | |||||
} else { | |||||
this.discardBorderAfter = true; | |||||
} | |||||
} | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Border " + side + " -> " + effectiveLength); | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public void notifyPadding(RelSide side, MinOptMax effectiveLength) { | |||||
if (effectiveLength == null) { | |||||
if (RelSide.BEFORE == side) { | |||||
this.discardPaddingBefore = true; | |||||
} else { | |||||
this.discardPaddingAfter = true; | |||||
} | |||||
} | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Padding " + side + " -> " + effectiveLength); | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public boolean handleOverflow(int milliPoints) { | public boolean handleOverflow(int milliPoints) { | ||||
if (milliPoints > this.horizontalOverflow) { | if (milliPoints > this.horizontalOverflow) { |
import org.apache.fop.area.LineArea; | import org.apache.fop.area.LineArea; | ||||
import org.apache.fop.datatypes.Length; | import org.apache.fop.datatypes.Length; | ||||
import org.apache.fop.fo.FONode; | import org.apache.fop.fo.FONode; | ||||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | |||||
import org.apache.fop.fo.properties.KeepProperty; | import org.apache.fop.fo.properties.KeepProperty; | ||||
import org.apache.fop.fonts.Font; | import org.apache.fop.fonts.Font; | ||||
import org.apache.fop.fonts.FontInfo; | import org.apache.fop.fonts.FontInfo; | ||||
/** | /** | ||||
* LayoutManager for a block FO. | * LayoutManager for a block FO. | ||||
*/ | */ | ||||
public class BlockLayoutManager extends BlockStackingLayoutManager implements ConditionalElementListener, | |||||
BreakOpportunity { | |||||
public class BlockLayoutManager extends SpacedBorderedPaddedBlockLayoutManager | |||||
implements BreakOpportunity { | |||||
/** logging instance */ | /** logging instance */ | ||||
private static Log log = LogFactory.getLog(BlockLayoutManager.class); | private static Log log = LogFactory.getLog(BlockLayoutManager.class); | ||||
private int follow = 2000; | private int follow = 2000; | ||||
//private int middleShift = 0; | //private int middleShift = 0; | ||||
private boolean discardBorderBefore; | |||||
private boolean discardBorderAfter; | |||||
private boolean discardPaddingBefore; | |||||
private boolean discardPaddingAfter; | |||||
private MinOptMax effSpaceBefore; | |||||
private MinOptMax effSpaceAfter; | |||||
/** | /** | ||||
* Creates a new BlockLayoutManager. | * Creates a new BlockLayoutManager. | ||||
* @param inBlock the block FO object to create the layout manager for. | * @param inBlock the block FO object to create the layout manager for. | ||||
.getOptimum(this).getLength().getValue(this); | .getOptimum(this).getLength().getValue(this); | ||||
} | } | ||||
@Override | |||||
protected CommonBorderPaddingBackground getCommonBorderPaddingBackground() { | |||||
return getBlockFO().getCommonBorderPaddingBackground(); | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public List getNextKnuthElements(LayoutContext context, int alignment) { | public List getNextKnuthElements(LayoutContext context, int alignment) { | ||||
curBlockArea.setIPD(super.getContentAreaIPD()); | curBlockArea.setIPD(super.getContentAreaIPD()); | ||||
curBlockArea.setBidiLevel(getBlockFO().getBidiLevel()); | |||||
curBlockArea.setBidiLevel(getBlockFO().getBidiLevelRecursive()); | |||||
TraitSetter.addBreaks(curBlockArea, | TraitSetter.addBreaks(curBlockArea, | ||||
getBlockFO().getBreakBefore(), getBlockFO().getBreakAfter()); | getBlockFO().getBreakBefore(), getBlockFO().getBreakAfter()); | ||||
getBlockFO().getCommonBorderPaddingBackground(), | getBlockFO().getCommonBorderPaddingBackground(), | ||||
startIndent, endIndent, | startIndent, endIndent, | ||||
this); | this); | ||||
TraitSetter.setLayer(curBlockArea, getBlockFO().getLayer()); | |||||
curBlockArea.setLocale(getBlockFO().getCommonHyphenation().getLocale()); | curBlockArea.setLocale(getBlockFO().getCommonHyphenation().getLocale()); | ||||
curBlockArea.setLocation(FONode.getLocatorString(getBlockFO().getLocator())); | curBlockArea.setLocation(FONode.getLocatorString(getBlockFO().getLocator())); | ||||
return true; | return true; | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
public void notifySpace(RelSide side, MinOptMax effectiveLength) { | |||||
if (RelSide.BEFORE == side) { | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Space " + side + ", " | |||||
+ this.effSpaceBefore + "-> " + effectiveLength); | |||||
} | |||||
this.effSpaceBefore = effectiveLength; | |||||
} else { | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Space " + side + ", " | |||||
+ this.effSpaceAfter + "-> " + effectiveLength); | |||||
} | |||||
this.effSpaceAfter = effectiveLength; | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public void notifyBorder(RelSide side, MinOptMax effectiveLength) { | |||||
if (effectiveLength == null) { | |||||
if (RelSide.BEFORE == side) { | |||||
this.discardBorderBefore = true; | |||||
} else { | |||||
this.discardBorderAfter = true; | |||||
} | |||||
} | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Border " + side + " -> " + effectiveLength); | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public void notifyPadding(RelSide side, MinOptMax effectiveLength) { | |||||
if (effectiveLength == null) { | |||||
if (RelSide.BEFORE == side) { | |||||
this.discardPaddingBefore = true; | |||||
} else { | |||||
this.discardPaddingAfter = true; | |||||
} | |||||
} | |||||
if (log.isDebugEnabled()) { | |||||
log.debug(this + ": Padding " + side + " -> " + effectiveLength); | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public boolean isRestartable() { | public boolean isRestartable() { |
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | ||||
import org.apache.fop.fo.properties.KeepProperty; | import org.apache.fop.fo.properties.KeepProperty; | ||||
import org.apache.fop.fo.properties.SpaceProperty; | import org.apache.fop.fo.properties.SpaceProperty; | ||||
import org.apache.fop.layoutmgr.inline.InlineContainerLayoutManager; | |||||
import org.apache.fop.layoutmgr.inline.InlineLayoutManager; | import org.apache.fop.layoutmgr.inline.InlineLayoutManager; | ||||
import org.apache.fop.traits.MinOptMax; | import org.apache.fop.traits.MinOptMax; | ||||
import org.apache.fop.util.ListUtil; | import org.apache.fop.util.ListUtil; | ||||
public boolean handleOverflow(int milliPoints) { | public boolean handleOverflow(int milliPoints) { | ||||
if (getParent() instanceof BlockStackingLayoutManager) { | if (getParent() instanceof BlockStackingLayoutManager) { | ||||
return ((BlockStackingLayoutManager) getParent()).handleOverflow(milliPoints); | return ((BlockStackingLayoutManager) getParent()).handleOverflow(milliPoints); | ||||
} else if (getParent() instanceof InlineContainerLayoutManager) { | |||||
return ((InlineContainerLayoutManager) getParent()).handleOverflow(milliPoints); | |||||
} | } | ||||
return false; | return false; | ||||
} | } |
pv.setPage(pageArea); | pv.setPage(pageArea); | ||||
RegionViewport rv = new RegionViewport(referenceRect); | RegionViewport rv = new RegionViewport(referenceRect); | ||||
rv.setIPD(referenceRect.width); | |||||
rv.setBPD(referenceRect.height); | |||||
if (pageSeq.getReferenceOrientation() % 180 == 0) { | |||||
rv.setIPD(referenceRect.width); | |||||
rv.setBPD(referenceRect.height); | |||||
} else { | |||||
rv.setIPD(referenceRect.height); | |||||
rv.setBPD(referenceRect.width); | |||||
} | |||||
rv.setClip(true); | rv.setClip(true); | ||||
BodyRegion body = new BodyRegion(Constants.FO_REGION_BODY, | BodyRegion body = new BodyRegion(Constants.FO_REGION_BODY, |
*/ | */ | ||||
public FlowLayoutManager(PageSequenceLayoutManager pslm, Flow node) { | public FlowLayoutManager(PageSequenceLayoutManager pslm, Flow node) { | ||||
super(node); | super(node); | ||||
setGeneratesBlockArea(true); | |||||
setParent(pslm); | setParent(pslm); | ||||
} | } | ||||
*/ | */ | ||||
List getChangedKnuthElements(List oldList, int alignment); | List getChangedKnuthElements(List oldList, int alignment); | ||||
/** | |||||
* Whether the FO handled by this layout manager has a descendant (including itself) | |||||
* that will generate a line-area. | |||||
* | |||||
* @return {@code true} if a descendant line-area will be generated, {@code false} otherwise | |||||
*/ | |||||
boolean hasLineAreaDescendant(); | |||||
/** | |||||
* Returns the position of the dominant-baseline of this FO's first descendant | |||||
* line-area. <p>The behavior of this method is undefined if this FO has no descendant | |||||
* line-area, and an exception may be thrown. See {@link #hasLineAreaDescendant()}</p> | |||||
* | |||||
* @return this FO's space-before plus the distance from the before-edge of its | |||||
* allocation-rectangle to the dominant-baseline of the first line-area descendant | |||||
* @see #hasLineAreaDescendant() | |||||
*/ | |||||
int getBaselineOffset(); | |||||
/** | /** | ||||
* Returns the IPD of the content area | * Returns the IPD of the content area | ||||
* @return the IPD of the content area | * @return the IPD of the content area |
import org.apache.fop.layoutmgr.inline.ContentLayoutManager; | import org.apache.fop.layoutmgr.inline.ContentLayoutManager; | ||||
import org.apache.fop.layoutmgr.inline.ExternalGraphicLayoutManager; | import org.apache.fop.layoutmgr.inline.ExternalGraphicLayoutManager; | ||||
import org.apache.fop.layoutmgr.inline.FootnoteLayoutManager; | import org.apache.fop.layoutmgr.inline.FootnoteLayoutManager; | ||||
import org.apache.fop.layoutmgr.inline.ICLayoutManager; | |||||
import org.apache.fop.layoutmgr.inline.InlineContainerLayoutManager; | |||||
import org.apache.fop.layoutmgr.inline.InlineLayoutManager; | import org.apache.fop.layoutmgr.inline.InlineLayoutManager; | ||||
import org.apache.fop.layoutmgr.inline.InstreamForeignObjectLM; | import org.apache.fop.layoutmgr.inline.InstreamForeignObjectLM; | ||||
import org.apache.fop.layoutmgr.inline.LeaderLayoutManager; | import org.apache.fop.layoutmgr.inline.LeaderLayoutManager; | ||||
/** a layout manager maker */ | /** a layout manager maker */ | ||||
public static class InlineLayoutManagerMaker extends Maker { | public static class InlineLayoutManagerMaker extends Maker { | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void make(FONode node, List lms) { | |||||
lms.add(new InlineLayoutManager((InlineLevel) node)); | |||||
} | |||||
public void make(FONode node, List lms) { | |||||
lms.add(new InlineLayoutManager((InlineLevel) node)); | |||||
} | |||||
} | } | ||||
/** a layout manager maker */ | /** a layout manager maker */ | ||||
public static class InlineContainerLayoutManagerMaker extends Maker { | public static class InlineContainerLayoutManagerMaker extends Maker { | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void make(FONode node, List lms) { | public void make(FONode node, List lms) { | ||||
ArrayList childList = new ArrayList(); | |||||
super.make(node, childList); | |||||
lms.add(new ICLayoutManager((InlineContainer) node, childList)); | |||||
lms.add(new InlineContainerLayoutManager((InlineContainer) node)); | |||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
protected class KnuthPageNode extends KnuthNode { | protected class KnuthPageNode extends KnuthNode { | ||||
/** Additional length due to footnotes. */ | |||||
/** Additional length due to already inserted footnotes. */ | |||||
public int insertedFootnotes; | |||||
/** Total length of the footnotes. */ | |||||
public int totalFootnotes; | public int totalFootnotes; | ||||
/** Index of the last inserted footnote. */ | /** Index of the last inserted footnote. */ | ||||
public KnuthPageNode(int position, | public KnuthPageNode(int position, | ||||
int line, int fitness, | int line, int fitness, | ||||
int totalWidth, int totalStretch, int totalShrink, | int totalWidth, int totalStretch, int totalShrink, | ||||
int totalFootnotes, int footnoteListIndex, int footnoteElementIndex, | |||||
int insertedFootnotes, int totalFootnotes, | |||||
int footnoteListIndex, int footnoteElementIndex, | |||||
double adjustRatio, int availableShrink, int availableStretch, | double adjustRatio, int availableShrink, int availableStretch, | ||||
int difference, double totalDemerits, KnuthNode previous) { | int difference, double totalDemerits, KnuthNode previous) { | ||||
super(position, line, fitness, | super(position, line, fitness, | ||||
adjustRatio, availableShrink, availableStretch, | adjustRatio, availableShrink, availableStretch, | ||||
difference, totalDemerits, previous); | difference, totalDemerits, previous); | ||||
this.totalFootnotes = totalFootnotes; | this.totalFootnotes = totalFootnotes; | ||||
this.insertedFootnotes = insertedFootnotes; | |||||
this.footnoteListIndex = footnoteListIndex; | this.footnoteListIndex = footnoteListIndex; | ||||
this.footnoteElementIndex = footnoteElementIndex; | this.footnoteElementIndex = footnoteElementIndex; | ||||
} | } | ||||
*/ | */ | ||||
protected class BestPageRecords extends BestRecords { | protected class BestPageRecords extends BestRecords { | ||||
private int[] bestFootnotesLength = new int[4]; | |||||
private int[] bestInsertedFootnotesLength = new int[4]; | |||||
private int[] bestTotalFootnotesLength = new int[4]; | |||||
private int[] bestFootnoteListIndex = new int[4]; | private int[] bestFootnoteListIndex = new int[4]; | ||||
private int[] bestFootnoteElementIndex = new int[4]; | private int[] bestFootnoteElementIndex = new int[4]; | ||||
super.addRecord(demerits, node, adjust, | super.addRecord(demerits, node, adjust, | ||||
availableShrink, availableStretch, | availableShrink, availableStretch, | ||||
difference, fitness); | difference, fitness); | ||||
bestFootnotesLength[fitness] = insertedFootnotesLength; | |||||
bestInsertedFootnotesLength[fitness] = insertedFootnotesLength; | |||||
bestTotalFootnotesLength[fitness] = totalFootnotesLength; | |||||
bestFootnoteListIndex[fitness] = footnoteListIndex; | bestFootnoteListIndex[fitness] = footnoteListIndex; | ||||
bestFootnoteElementIndex[fitness] = footnoteElementIndex; | bestFootnoteElementIndex[fitness] = footnoteElementIndex; | ||||
} | } | ||||
public int getFootnotesLength(int fitness) { | |||||
return bestFootnotesLength[fitness]; | |||||
public int getInsertedFootnotesLength(int fitness) { | |||||
return bestInsertedFootnotesLength[fitness]; | |||||
} | |||||
public int getTotalFootnotesLength(int fitness) { | |||||
return bestTotalFootnotesLength[fitness]; | |||||
} | } | ||||
public int getFootnoteListIndex(int fitness) { | public int getFootnoteListIndex(int fitness) { | ||||
int difference, double totalDemerits, KnuthNode previous) { | int difference, double totalDemerits, KnuthNode previous) { | ||||
return new KnuthPageNode(position, line, fitness, | return new KnuthPageNode(position, line, fitness, | ||||
totalWidth, totalStretch, totalShrink, | totalWidth, totalStretch, totalShrink, | ||||
insertedFootnotesLength, footnoteListIndex, footnoteElementIndex, | |||||
insertedFootnotesLength, totalFootnotesLength, | |||||
footnoteListIndex, footnoteElementIndex, | |||||
adjustRatio, availableShrink, availableStretch, | adjustRatio, availableShrink, availableStretch, | ||||
difference, totalDemerits, previous); | difference, totalDemerits, previous); | ||||
} | } | ||||
int totalWidth, int totalStretch, int totalShrink) { | int totalWidth, int totalStretch, int totalShrink) { | ||||
return new KnuthPageNode(position, line, fitness, | return new KnuthPageNode(position, line, fitness, | ||||
totalWidth, totalStretch, totalShrink, | totalWidth, totalStretch, totalShrink, | ||||
((BestPageRecords) best).getFootnotesLength(fitness), | |||||
((BestPageRecords) best).getInsertedFootnotesLength(fitness), | |||||
((BestPageRecords) best).getTotalFootnotesLength(fitness), | |||||
((BestPageRecords) best).getFootnoteListIndex(fitness), | ((BestPageRecords) best).getFootnoteListIndex(fitness), | ||||
((BestPageRecords) best).getFootnoteElementIndex(fitness), | ((BestPageRecords) best).getFootnoteElementIndex(fitness), | ||||
best.getAdjust(fitness), best.getAvailableShrink(fitness), | best.getAdjust(fitness), best.getAvailableShrink(fitness), | ||||
resetFootnotes(((KnuthBlockBox) resetElement).getElementLists()); | resetFootnotes(((KnuthBlockBox) resetElement).getElementLists()); | ||||
} | } | ||||
} | } | ||||
assert restartingNode instanceof KnuthPageNode; | |||||
KnuthPageNode restartingPageNode = (KnuthPageNode) restartingNode; | |||||
footnoteElementIndex = restartingPageNode.footnoteElementIndex; | |||||
footnoteListIndex = restartingPageNode.footnoteListIndex; | |||||
totalFootnotesLength = restartingPageNode.totalFootnotes; | |||||
insertedFootnotesLength = restartingPageNode.insertedFootnotes; | |||||
} | } | ||||
return returnValue; | return returnValue; | ||||
} | } | ||||
for (int i = 0; i < elementLists.size(); i++) { | for (int i = 0; i < elementLists.size(); i++) { | ||||
ListUtil.removeLast(footnotesList); | ListUtil.removeLast(footnotesList); | ||||
ListUtil.removeLast(lengthList); | ListUtil.removeLast(lengthList); | ||||
// update totalFootnotesLength | |||||
if (!lengthList.isEmpty()) { | |||||
totalFootnotesLength = ListUtil.getLast(lengthList); | |||||
} else { | |||||
totalFootnotesLength = 0; | |||||
} | |||||
} | } | ||||
// update footnotesPending; | // update footnotesPending; | ||||
if (footnotesList.size() == 0) { | if (footnotesList.size() == 0) { | ||||
} | } | ||||
if (footnotesPending) { | if (footnotesPending) { | ||||
// compute the total length of the footnotes not yet inserted | // compute the total length of the footnotes not yet inserted | ||||
int allFootnotes = totalFootnotesLength - pageNode.totalFootnotes; | |||||
int allFootnotes = totalFootnotesLength - pageNode.insertedFootnotes; | |||||
if (allFootnotes > 0) { | if (allFootnotes > 0) { | ||||
// this page contains some footnote citations | // this page contains some footnote citations | ||||
// add the footnote separator width | // add the footnote separator width | ||||
// there is enough space to insert all footnotes: | // there is enough space to insert all footnotes: | ||||
// add the whole allFootnotes length | // add the whole allFootnotes length | ||||
actualWidth += allFootnotes; | actualWidth += allFootnotes; | ||||
insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes; | |||||
insertedFootnotesLength = pageNode.insertedFootnotes + allFootnotes; | |||||
footnoteListIndex = footnotesList.size() - 1; | footnoteListIndex = footnotesList.size() - 1; | ||||
footnoteElementIndex | footnoteElementIndex | ||||
= getFootnoteList(footnoteListIndex).size() - 1; | = getFootnoteList(footnoteListIndex).size() - 1; | ||||
// this is the first feasible break; in this case it is allowed | // this is the first feasible break; in this case it is allowed | ||||
// to break and defer, if necessary, old and new footnotes | // to break and defer, if necessary, old and new footnotes | ||||
actualWidth += footnoteSplit; | actualWidth += footnoteSplit; | ||||
insertedFootnotesLength = pageNode.totalFootnotes + footnoteSplit; | |||||
insertedFootnotesLength = pageNode.insertedFootnotes + footnoteSplit; | |||||
// footnoteListIndex has been set in getFootnoteSplit() | // footnoteListIndex has been set in getFootnoteSplit() | ||||
// footnoteElementIndex has been set in getFootnoteSplit() | // footnoteElementIndex has been set in getFootnoteSplit() | ||||
} else { | } else { | ||||
// that cannot be broken: | // that cannot be broken: | ||||
// add the whole allFootnotes length, so this breakpoint will be discarded | // add the whole allFootnotes length, so this breakpoint will be discarded | ||||
actualWidth += allFootnotes; | actualWidth += allFootnotes; | ||||
insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes; | |||||
insertedFootnotesLength = pageNode.insertedFootnotes + allFootnotes; | |||||
footnoteListIndex = footnotesList.size() - 1; | footnoteListIndex = footnotesList.size() - 1; | ||||
footnoteElementIndex | footnoteElementIndex | ||||
= getFootnoteList(footnoteListIndex).size() - 1; | = getFootnoteList(footnoteListIndex).size() - 1; | ||||
private boolean canDeferOldFootnotes(KnuthPageNode node, int contentElementIndex) { | private boolean canDeferOldFootnotes(KnuthPageNode node, int contentElementIndex) { | ||||
return (noBreakBetween(node.position, contentElementIndex) | return (noBreakBetween(node.position, contentElementIndex) | ||||
&& deferredFootnotes(node.footnoteListIndex, | && deferredFootnotes(node.footnoteListIndex, | ||||
node.footnoteElementIndex, node.totalFootnotes)); | |||||
node.footnoteElementIndex, node.insertedFootnotes)); | |||||
} | } | ||||
/** | /** | ||||
boolean canDeferOldFootnotes) { | boolean canDeferOldFootnotes) { | ||||
return getFootnoteSplit(activeNode.footnoteListIndex, | return getFootnoteSplit(activeNode.footnoteListIndex, | ||||
activeNode.footnoteElementIndex, | activeNode.footnoteElementIndex, | ||||
activeNode.totalFootnotes, | |||||
activeNode.insertedFootnotes, | |||||
availableLength, canDeferOldFootnotes); | availableLength, canDeferOldFootnotes); | ||||
} | } | ||||
int prevIndex = -1; | int prevIndex = -1; | ||||
int index = -1; | int index = -1; | ||||
while (!(somethingAdded && splitLength > availableLength)) { | |||||
if (!somethingAdded) { | |||||
somethingAdded = true; | |||||
} else { | |||||
while (splitLength <= availableLength) { | |||||
if (somethingAdded) { | |||||
prevSplitLength = splitLength; | prevSplitLength = splitLength; | ||||
prevIndex = index; | prevIndex = index; | ||||
} | } | ||||
// element is a box | // element is a box | ||||
splitLength += element.getWidth(); | splitLength += element.getWidth(); | ||||
boxPreceding = true; | boxPreceding = true; | ||||
if (splitLength > prevSplitLength) { | |||||
// and it is non-empty | |||||
somethingAdded = true; | |||||
} | |||||
} else if (element.isGlue()) { | } else if (element.isGlue()) { | ||||
// element is a glue | // element is a glue | ||||
if (boxPreceding) { | if (boxPreceding) { | ||||
index = noteListIterator.previousIndex(); | index = noteListIterator.previousIndex(); | ||||
break; | break; | ||||
} | } | ||||
boxPreceding = false; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
// page here | // page here | ||||
// if prevSplitLength is > 0 we can insert some footnote content in this page | // if prevSplitLength is > 0 we can insert some footnote content in this page | ||||
// and insert the remaining in the following one | // and insert the remaining in the following one | ||||
//TODO: check this conditional, as the first one is always false...? | |||||
if (!somethingAdded) { | if (!somethingAdded) { | ||||
// there was not enough space to add a piece of the first new footnote | // there was not enough space to add a piece of the first new footnote | ||||
// this is not a good break | // this is not a good break | ||||
if (difference > 0) { | if (difference > 0) { | ||||
int maxAdjustment = totalStretch - activeNode.totalStretch; | int maxAdjustment = totalStretch - activeNode.totalStretch; | ||||
// add the footnote separator stretch if some footnote content will be added | // add the footnote separator stretch if some footnote content will be added | ||||
if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) { | |||||
if (((KnuthPageNode) activeNode).insertedFootnotes < totalFootnotesLength) { | |||||
maxAdjustment += footnoteSeparatorLength.getStretch(); | maxAdjustment += footnoteSeparatorLength.getStretch(); | ||||
} | } | ||||
if (maxAdjustment > 0) { | if (maxAdjustment > 0) { | ||||
} else if (difference < 0) { | } else if (difference < 0) { | ||||
int maxAdjustment = totalShrink - activeNode.totalShrink; | int maxAdjustment = totalShrink - activeNode.totalShrink; | ||||
// add the footnote separator shrink if some footnote content will be added | // add the footnote separator shrink if some footnote content will be added | ||||
if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) { | |||||
if (((KnuthPageNode) activeNode).insertedFootnotes < totalFootnotesLength) { | |||||
maxAdjustment += footnoteSeparatorLength.getShrink(); | maxAdjustment += footnoteSeparatorLength.getShrink(); | ||||
} | } | ||||
if (maxAdjustment > 0) { | if (maxAdjustment > 0) { | ||||
for (KnuthPageNode node = (KnuthPageNode) getNode(i); | for (KnuthPageNode node = (KnuthPageNode) getNode(i); | ||||
node != null; | node != null; | ||||
node = (KnuthPageNode) node.next) { | node = (KnuthPageNode) node.next) { | ||||
if (node.totalFootnotes < totalFootnotesLength) { | |||||
if (node.insertedFootnotes < totalFootnotesLength) { | |||||
// layout remaining footnote bodies | // layout remaining footnote bodies | ||||
createFootnotePages(node); | createFootnotePages(node); | ||||
} | } | ||||
private void createFootnotePages(KnuthPageNode lastNode) { | private void createFootnotePages(KnuthPageNode lastNode) { | ||||
insertedFootnotesLength = lastNode.totalFootnotes; | |||||
insertedFootnotesLength = lastNode.insertedFootnotes; | |||||
footnoteListIndex = lastNode.footnoteListIndex; | footnoteListIndex = lastNode.footnoteListIndex; | ||||
footnoteElementIndex = lastNode.footnoteElementIndex; | footnoteElementIndex = lastNode.footnoteElementIndex; | ||||
int availableBPD = getLineWidth(lastNode.line); | int availableBPD = getLineWidth(lastNode.line); | ||||
// cannot add any content: create a new node and start again | // cannot add any content: create a new node and start again | ||||
KnuthPageNode node = (KnuthPageNode) | KnuthPageNode node = (KnuthPageNode) | ||||
createNode(lastNode.position, prevNode.line + 1, 1, | createNode(lastNode.position, prevNode.line + 1, 1, | ||||
insertedFootnotesLength - prevNode.totalFootnotes, | |||||
insertedFootnotesLength - prevNode.insertedFootnotes, | |||||
0, 0, | 0, 0, | ||||
0, 0, 0, | 0, 0, 0, | ||||
0, 0, prevNode); | 0, 0, prevNode); | ||||
// create the last node | // create the last node | ||||
KnuthPageNode node = (KnuthPageNode) | KnuthPageNode node = (KnuthPageNode) | ||||
createNode(lastNode.position, prevNode.line + 1, 1, | createNode(lastNode.position, prevNode.line + 1, 1, | ||||
totalFootnotesLength - prevNode.totalFootnotes, 0, 0, | |||||
totalFootnotesLength - prevNode.insertedFootnotes, 0, 0, | |||||
0, 0, 0, | 0, 0, 0, | ||||
0, 0, prevNode); | 0, 0, prevNode); | ||||
addNode(node.line, node); | addNode(node.line, node); |
/* | |||||
* 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.layoutmgr; | |||||
import org.apache.commons.logging.Log; | |||||
import org.apache.commons.logging.LogFactory; | |||||
import org.apache.fop.fo.FObj; | |||||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | |||||
import org.apache.fop.traits.MinOptMax; | |||||
/** | |||||
* A block-stacking layout manager for an FO that supports spaces, border and padding. | |||||
*/ | |||||
public abstract class SpacedBorderedPaddedBlockLayoutManager extends BlockStackingLayoutManager | |||||
implements ConditionalElementListener { | |||||
private static final Log LOG = LogFactory.getLog(BlockLayoutManager.class); | |||||
protected MinOptMax effSpaceBefore; | |||||
protected MinOptMax effSpaceAfter; | |||||
protected boolean discardBorderBefore; | |||||
protected boolean discardBorderAfter; | |||||
protected boolean discardPaddingBefore; | |||||
protected boolean discardPaddingAfter; | |||||
public SpacedBorderedPaddedBlockLayoutManager(FObj node) { | |||||
super(node); | |||||
} | |||||
public void notifySpace(RelSide side, MinOptMax effectiveLength) { | |||||
if (RelSide.BEFORE == side) { | |||||
if (LOG.isDebugEnabled()) { | |||||
LOG.debug(this + ": Space " + side + ", " | |||||
+ this.effSpaceBefore + "-> " + effectiveLength); | |||||
} | |||||
this.effSpaceBefore = effectiveLength; | |||||
} else { | |||||
if (LOG.isDebugEnabled()) { | |||||
LOG.debug(this + ": Space " + side + ", " | |||||
+ this.effSpaceAfter + "-> " + effectiveLength); | |||||
} | |||||
this.effSpaceAfter = effectiveLength; | |||||
} | |||||
} | |||||
public void notifyBorder(RelSide side, MinOptMax effectiveLength) { | |||||
if (effectiveLength == null) { | |||||
if (RelSide.BEFORE == side) { | |||||
this.discardBorderBefore = true; | |||||
} else { | |||||
this.discardBorderAfter = true; | |||||
} | |||||
} | |||||
if (LOG.isDebugEnabled()) { | |||||
LOG.debug(this + ": Border " + side + " -> " + effectiveLength); | |||||
} | |||||
} | |||||
public void notifyPadding(RelSide side, MinOptMax effectiveLength) { | |||||
if (effectiveLength == null) { | |||||
if (RelSide.BEFORE == side) { | |||||
this.discardPaddingBefore = true; | |||||
} else { | |||||
this.discardPaddingAfter = true; | |||||
} | |||||
} | |||||
if (LOG.isDebugEnabled()) { | |||||
LOG.debug(this + ": Padding " + side + " -> " + effectiveLength); | |||||
} | |||||
} | |||||
@Override | |||||
public int getBaselineOffset() { | |||||
int baselineOffset = super.getBaselineOffset(); | |||||
if (effSpaceBefore != null) { | |||||
baselineOffset += effSpaceBefore.getOpt(); | |||||
} | |||||
if (!discardBorderBefore) { | |||||
baselineOffset += getCommonBorderPaddingBackground().getBorderBeforeWidth(false); | |||||
} | |||||
if (!discardPaddingBefore) { | |||||
baselineOffset += getCommonBorderPaddingBackground().getPaddingBefore(false, this); | |||||
} | |||||
return baselineOffset; | |||||
} | |||||
/** | |||||
* Returns the {@link CommonBorderPaddingBackground} instance from the FO handled by this layout manager. | |||||
*/ | |||||
protected abstract CommonBorderPaddingBackground getCommonBorderPaddingBackground(); | |||||
} |