Browse Source

Merged revisions 634215-638841 via svnmerge from

https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk

................
  r635508 | jeremias | 2008-03-10 11:06:37 +0100 (Mo, 10 Mrz 2008) | 4 lines
  
  Fixed NPE in BlockContainerLayoutManager when used as a child of an inline-level FO. Split IP and BP stack limits in LayoutContext (there's now a certain amount of redundancy with "refIPD" in LayoutContext which I didn't resolve).
  Areas are now generated for block-level FOs when used as children of inline-level FOs.
  ClassCastException in ListLayoutManager.mustKeepTogether() fixed (occured if used as child of an inline-level FO).
................
  r635686 | vhennebert | 2008-03-10 21:52:43 +0100 (Mo, 10 Mrz 2008) | 2 lines
  
  Bugfix: forced break ignored when the minimum height of a table-row isn't reached
................
  r635701 | jeremias | 2008-03-10 22:28:08 +0100 (Mo, 10 Mrz 2008) | 1 line
  
  Need to clean up after myself.
................
  r635741 | jeremias | 2008-03-10 23:39:38 +0100 (Mo, 10 Mrz 2008) | 1 line
  
  Bugfix for row/body/col background painting when padding is used in the table-cells.
................
  r635884 | vhennebert | 2008-03-11 12:02:27 +0100 (Di, 11 Mrz 2008) | 2 lines
  
  Fixed a copy-paste error (getPaddingStart instead of getPaddingEnd)
................
  r635961 | vhennebert | 2008-03-11 16:05:27 +0100 (Di, 11 Mrz 2008) | 2 lines
  
  Forgot to add the testcase for forced break vs explicit row height in revision 635686
................
  r635967 | vhennebert | 2008-03-11 16:13:51 +0100 (Di, 11 Mrz 2008) | 2 lines
  
  Updated the disabled-testcases.xml file: re-enabled testcases which could easily be updated, removed the other ones which anyway were superseded by more complete ones
................
  r636276 | vhennebert | 2008-03-12 11:51:09 +0100 (Mi, 12 Mrz 2008) | 2 lines
  
  Since compliance.ihtml is now the source file and it would cost too much to revert to an xml version, tidied the file a bit. No content change.
................
  r636293 | vhennebert | 2008-03-12 13:14:51 +0100 (Mi, 12 Mrz 2008) | 2 lines
  
  Updated the compliance page. Re-added the 0.94 column since there are some noteworthy changes between the 0.94 and 0.95 versions
................
  r636295 | vhennebert | 2008-03-12 13:19:15 +0100 (Mi, 12 Mrz 2008) | 3 lines
  
  Update of the documentation before the release.
  Added notes about improved checks and conformance in tables.
................
  r636405 | vhennebert | 2008-03-12 17:25:52 +0100 (Mi, 12 Mrz 2008) | 2 lines
  
  Initialized merge tracking via "svnmerge" from the 0.95 branch
................
  r636409 | vhennebert | 2008-03-12 17:36:29 +0100 (Mi, 12 Mrz 2008) | 8 lines
  
  Blocked revisions 636406 via svnmerge
  
  ........
    r636406 | vhennebert | 2008-03-12 16:28:00 +0000 (Wed, 12 Mar 2008) | 2 lines
    
    Set the version to 0.95beta
  ........
................
  r636471 | vhennebert | 2008-03-12 20:24:05 +0100 (Mi, 12 Mrz 2008) | 2 lines
  
  Removed no longer used borderAndPaddingBPD field
................
  r637057 | jeremias | 2008-03-14 12:15:24 +0100 (Fr, 14 Mrz 2008) | 2 lines
  
  Bugzilla #44412:
  Bugfix: When there was a forced break after a block with (conditional) borders the border-after wasn't painted.
................
  r637076 | vhennebert | 2008-03-14 13:22:44 +0100 (Fr, 14 Mrz 2008) | 2 lines
  
  Reverting changes of rev. 637057. I applied the changes to the 0.95 branch instead so that they make their way into the 0.95 release. I will merge them back to the Trunk via svnmerge
................
  r638396 | vhennebert | 2008-03-18 16:01:43 +0100 (Di, 18 Mrz 2008) | 53 lines
  
  Merged revisions 636400-636405,636407-638388 via svnmerge from 
  https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_95
  
  ........
    r636403 | vhennebert | 2008-03-12 16:24:48 +0000 (Wed, 12 Mar 2008) | 2 lines
    
    Updated copyright years
  ........
    r637075 | vhennebert | 2008-03-14 12:19:45 +0000 (Fri, 14 Mar 2008) | 4 lines
    
    Bugzilla #44412:
    Bugfix: When there was a forced break after a block with (conditional) borders the border-after wasn't painted.
    Changes made by Jeremias
  ........
    r637119 | jeremias | 2008-03-14 14:41:03 +0000 (Fri, 14 Mar 2008) | 2 lines
    
    Bugzilla #44412:
    Bugfix: The before border of a block is no longer swallowed if its first child issues a break-before.
  ........
    r637791 | jeremias | 2008-03-17 08:59:51 +0000 (Mon, 17 Mar 2008) | 3 lines
    
    Removed old image adapters.
    Removed support for Java 1.3 building as it didn't work anymore anyway.
    Added a check to require Java 1.4 for building.
  ........
    r637857 | jeremias | 2008-03-17 12:24:33 +0000 (Mon, 17 Mar 2008) | 3 lines
    
    Partially reverted revision 637791:
    Restored JAI as a required dependency for distribution builds (used for error diffusion dithering in the PCL Renderer). It is optional otherwise.
    Updated the licensing info and release notes to make the changes clear.
  ........
    r637993 | vhennebert | 2008-03-17 17:48:44 +0000 (Mon, 17 Mar 2008) | 3 lines
    
    Bugzilla #44621: when the after border of a cell, in the trailing case, is bigger than in the normal case, the generated sequence of Knuth elements was wrong, leading to content being swallowed
    This is a partial fix only: the content is no longer swallowed, but the penalty is wrong (shorter than it should be). This will lead to the table overflowing the region-body without warning.
  ........
    r638048 | vhennebert | 2008-03-17 20:00:36 +0000 (Mon, 17 Mar 2008) | 2 lines
    
    Changed the documentation to reflect the move to Java 1.4 as a minimum requirement
  ........
    r638308 | vhennebert | 2008-03-18 10:26:32 +0000 (Tue, 18 Mar 2008) | 2 lines
    
    Simplified the getNextKnuthElements method a little bit
  ........
    r638316 | vhennebert | 2008-03-18 11:06:59 +0000 (Tue, 18 Mar 2008) | 2 lines
    
    Removed the 'jdk1.4' suffix appended to the binary artifacts. There's no point in making the distinction anymore since there is only one binary now
  ........
    r638317 | vhennebert | 2008-03-18 11:08:29 +0000 (Tue, 18 Mar 2008) | 2 lines
    
    Updated the probable date of the release
  ........
................


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ProcessingFeedback@638943 13f79535-47bb-0310-9956-ffa450edef68
Temp_ProcessingFeedback
Jeremias Maerki 16 years ago
parent
commit
c7a8ce9bdf
100 changed files with 8350 additions and 12469 deletions
  1. 40
    0
      README
  2. 2
    2
      build.properties
  3. 15
    65
      build.xml
  4. 10
    2
      lib/README.txt
  5. 2
    2
      src/documentation/content/.htaccess
  6. 2
    2
      src/documentation/content/xdocs/0.95/compiling.xml
  7. 2
    10
      src/documentation/content/xdocs/0.95/fonts.xml
  8. 0
    4
      src/documentation/content/xdocs/0.95/known-issues.xml
  9. 0
    48
      src/documentation/content/xdocs/0.95/layoutengine/disabled-testcases.xml
  10. 1
    6
      src/documentation/content/xdocs/0.95/pdfencryption.xml
  11. 1
    1
      src/documentation/content/xdocs/0.95/running.xml
  12. 7161
    5260
      src/documentation/content/xdocs/compliance.ihtml
  13. 1
    1
      src/documentation/content/xdocs/dev/release.xml
  14. 4
    4
      src/documentation/content/xdocs/download.xml
  15. 4
    3
      src/documentation/content/xdocs/index.xml
  16. 2
    2
      src/documentation/content/xdocs/trunk/compiling.xml
  17. 2
    10
      src/documentation/content/xdocs/trunk/fonts.xml
  18. 2
    4
      src/documentation/content/xdocs/trunk/pdfencryption.xml
  19. 1
    1
      src/documentation/content/xdocs/trunk/running.xml
  20. 0
    31
      src/java-1.3/org/apache/fop/svg/GraphicsConfiguration.java
  21. 0
    237
      src/java-1.4/org/apache/fop/image/ImageIOImage.java
  22. 0
    161
      src/java-1.4/org/apache/fop/image/JpegImageIOImage.java
  23. 0
    10
      src/java/org/apache/fop/apps/FopFactory.java
  24. 6
    0
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  25. 0
    5
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  26. 0
    12
      src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java
  27. 0
    376
      src/java/org/apache/fop/image/AbstractFopImage.java
  28. 0
    220
      src/java/org/apache/fop/image/BmpImage.java
  29. 0
    122
      src/java/org/apache/fop/image/EPSImage.java
  30. 0
    51
      src/java/org/apache/fop/image/EmfImage.java
  31. 0
    207
      src/java/org/apache/fop/image/FopImage.java
  32. 0
    211
      src/java/org/apache/fop/image/FopImageConsumer.java
  33. 0
    218
      src/java/org/apache/fop/image/GifImage.java
  34. 0
    72
      src/java/org/apache/fop/image/ImageCache.java
  35. 0
    708
      src/java/org/apache/fop/image/ImageFactory.java
  36. 0
    64
      src/java/org/apache/fop/image/ImageLoader.java
  37. 0
    194
      src/java/org/apache/fop/image/JAIImage.java
  38. 0
    186
      src/java/org/apache/fop/image/JimiImage.java
  39. 0
    239
      src/java/org/apache/fop/image/JpegImage.java
  40. 0
    87
      src/java/org/apache/fop/image/PNGImage.java
  41. 0
    49
      src/java/org/apache/fop/image/RegisterableImageProvider.java
  42. 0
    207
      src/java/org/apache/fop/image/TIFFImage.java
  43. 0
    78
      src/java/org/apache/fop/image/XMLImage.java
  44. 0
    239
      src/java/org/apache/fop/image/XmlGraphicsCommonsImage.java
  45. 0
    134
      src/java/org/apache/fop/image/analyser/BMPReader.java
  46. 0
    162
      src/java/org/apache/fop/image/analyser/EMFReader.java
  47. 0
    253
      src/java/org/apache/fop/image/analyser/EPSReader.java
  48. 0
    104
      src/java/org/apache/fop/image/analyser/GIFReader.java
  49. 0
    56
      src/java/org/apache/fop/image/analyser/ImageReader.java
  50. 0
    108
      src/java/org/apache/fop/image/analyser/ImageReaderFactory.java
  51. 0
    264
      src/java/org/apache/fop/image/analyser/JPEGReader.java
  52. 0
    115
      src/java/org/apache/fop/image/analyser/PNGReader.java
  53. 0
    188
      src/java/org/apache/fop/image/analyser/SVGReader.java
  54. 0
    53
      src/java/org/apache/fop/image/analyser/SVGZReader.java
  55. 0
    117
      src/java/org/apache/fop/image/analyser/TIFFReader.java
  56. 0
    167
      src/java/org/apache/fop/image/analyser/XMLReader.java
  57. 0
    23
      src/java/org/apache/fop/image/analyser/package.html
  58. 1
    1
      src/java/org/apache/fop/image/package.html
  59. 2
    2
      src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
  60. 1
    1
      src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java
  61. 15
    23
      src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
  62. 2
    1
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  63. 16
    5
      src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
  64. 1
    1
      src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
  65. 77
    31
      src/java/org/apache/fop/layoutmgr/LayoutContext.java
  66. 5
    8
      src/java/org/apache/fop/layoutmgr/MinOptMaxUtil.java
  67. 1
    1
      src/java/org/apache/fop/layoutmgr/PageBreaker.java
  68. 4
    4
      src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
  69. 2
    1
      src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
  70. 5
    4
      src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
  71. 5
    8
      src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
  72. 12
    12
      src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
  73. 10
    10
      src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
  74. 22
    16
      src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
  75. 104
    37
      src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
  76. 106
    115
      src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java
  77. 14
    9
      src/java/org/apache/fop/layoutmgr/table/RowPainter.java
  78. 18
    28
      src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
  79. 2
    0
      src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
  80. 5
    0
      src/java/org/apache/fop/layoutmgr/table/TableHFPenaltyPosition.java
  81. 5
    0
      src/java/org/apache/fop/layoutmgr/table/TableHeaderFooterPosition.java
  82. 0
    73
      src/java/org/apache/fop/render/ps/PSImageUtils.java
  83. 0
    70
      src/java/org/apache/fop/render/rtf/SVGConverter.java
  84. 0
    0
      src/java/org/apache/fop/svg/GraphicsConfiguration.java
  85. 48
    8
      status.xml
  86. 5
    6
      test/java/org/apache/fop/URIResolutionTestCase.java
  87. 0
    48
      test/layoutengine/disabled-testcases.xml
  88. 112
    0
      test/layoutengine/standard-testcases/block-level_break-after_bug44412.xml
  89. 64
    0
      test/layoutengine/standard-testcases/block_break-before_bug44412.xml
  90. 104
    0
      test/layoutengine/standard-testcases/inline_block-level_nested_1.xml
  91. 0
    110
      test/layoutengine/standard-testcases/table-body_background-image.xml
  92. 0
    85
      test/layoutengine/standard-testcases/table-cell_block_keep-with-previous.xml
  93. 0
    101
      test/layoutengine/standard-testcases/table-header_background-image.xml
  94. 210
    40
      test/layoutengine/standard-testcases/table-row_keep-with-previous.xml
  95. 0
    254
      test/layoutengine/standard-testcases/table-row_keep-with-previous_2.xml
  96. 113
    0
      test/layoutengine/standard-testcases/table_backgrounds_2.xml
  97. 0
    130
      test/layoutengine/standard-testcases/table_border-collapse_collapse_1.xml
  98. 0
    70
      test/layoutengine/standard-testcases/table_border-collapse_collapse_2.xml
  99. 1
    1
      test/layoutengine/standard-testcases/table_border-collapse_separate_1.xml
  100. 0
    0
      test/layoutengine/standard-testcases/table_border_padding.xml

+ 40
- 0
README View File

@@ -90,6 +90,46 @@ http://xmlgraphics.apache.org/fop/stable/running.html
RELEASE NOTES
==============================================================================

Version 0.95beta
================

This is a pre-version of the third production grade release of the new FOP
codebase. It contains many bug fixes and new features. See below for details.

Compliance
----------

This release implements the XSL 1.0 and 1.1 recommendations to a high
degree of compliance. See the compliance page
http://xmlgraphics.apache.org/fop/compliance.html for a detailed
overview.

Known issues
------------

The known issues of this release are listed at
http://xmlgraphics.apache.org/fop/0.95/knownissues_overview.html.

Major Changes in Version 0.95
-----------------------------

* Add new fox:external-document extension element that allows to insert whole
documents into a page-sequence (JM)
* Add support for background on fo:table-column and fo:table-header/footer/body
elements (VH)
* Add support for conditional borders in tables (VH)
* Add support for scale-down-to-fit and scale-up-to-fit (JM)
* Fix various bugs and performance problems with external graphics by
introducing a new image loading framework (JM)

The long list of changes in this release is available at
http://xmlgraphics.apache.org/fop/0.95/changes_0.95.html.

The long list of changes in this and earlier releases is available at
http://xmlgraphics.apache.org/fop/changes.html.



Version 0.94
============


+ 2
- 2
build.properties View File

@@ -24,8 +24,8 @@
# javac.debug = on
# javac.optimize = off
# javac.deprecation = on
# javac.source = 1.3
# javac.target = 1.3
# javac.source = 1.4
# javac.target = 1.4
# javac.fork = on

## JUnit task switches

+ 15
- 65
build.xml View File

@@ -133,10 +133,6 @@ list of possible build targets.
</fileset>
</path>

<patternset id="exclude-jimi">
<exclude name="org/apache/fop/image/JimiImage.java" unless="jimi.present"/>
</patternset>

<patternset id="exclude-jai">
<exclude name="org/apache/fop/image/JAIImage.java" unless="jai.present"/>
<exclude name="org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java" unless="jai.present"/>
@@ -150,7 +146,7 @@ list of possible build targets.
<property name="name" value="fop"/>
<property name="NAME" value="FOP"/>
<property name="version" value="svn-trunk"/>
<property name="year" value="1999-2007"/>
<property name="year" value="1999-2008"/>

<property name="javac.debug" value="on"/>
<property name="javac.optimize" value="off"/>
@@ -216,7 +212,7 @@ list of possible build targets.
<!-- =================================================================== -->
<!-- Initialization target -->
<!-- =================================================================== -->
<target name="init" depends="init-avail, init-filters-jdk14, init-filters-jdk13">
<target name="init" depends="init-avail">
</target>

<target name="init-avail">
@@ -226,18 +222,6 @@ list of possible build targets.
<echo message="VM: ${java.vm.version}, ${java.vm.vendor}"/>
<echo message="JAVA_HOME: ${env.JAVA_HOME}"/>

<available property="jimi.present" classname="com.sun.jimi.core.Jimi"
classpathref="libs-build-classpath"/>
<condition property="jimi.message" value="Jimi Support PRESENT">
<equals arg1="${jimi.present}" arg2="true"/>
</condition>
<condition property="jimi.message" value="Jimi Support NOT Present">
<not>
<equals arg1="${jimi.present}" arg2="true"/>
</not>
</condition>
<echo message="${jimi.message}"/>

<available property="jai.present" classname="javax.media.jai.JAI"
classpathref="libs-build-classpath"/>
<condition property="jai.message" value="JAI Support PRESENT">
@@ -263,7 +247,8 @@ list of possible build targets.
<echo message="${jce.message}"/>

<available property="jdk14.present" classname="java.lang.CharSequence"/>

<fail message="${Name} requires at least Java 1.4!" unless="jdk14.present"/>
<available property="junit.present" classname="junit.framework.TestCase"
classpathref="libs-build-classpath"/>
<condition property="junit.message" value="JUnit Support PRESENT">
@@ -294,22 +279,6 @@ list of possible build targets.
</target>

<target name="init-filters-jdk13" depends="init-avail" unless="jdk14.present">
<echo message="Use GraphicsConfiguration adapter for JDK 1.3 or earlier."/>
<path id="graphics-configuration-adapter">
<pathelement location="src/java-1.3"/>
</path>
<property name="src.java.version.dir" value="${basedir}/src/java-1.3"/>
</target>

<target name="init-filters-jdk14" depends="init-avail" if="jdk14.present">
<echo message="Use GraphicsConfiguration adapter for JDK 1.4."/>
<path id="graphics-configuration-adapter">
<pathelement location="src/java-1.4"/>
</path>
<property name="src.java.version.dir" value="${basedir}/src/java-1.4"/>
</target>

<!-- =================================================================== -->
<!-- Help on usage -->
<!-- =================================================================== -->
@@ -403,12 +372,9 @@ list of possible build targets.
source="${javac.source}" target="${javac.target}">
<src path="${build.gensrc.dir}"/>
<src path="${src.java.dir}"/>
<src refid="graphics-configuration-adapter"/>
<patternset includes="**/*.java"/>
<!--patternset includes="org/apache/fop/svg/GraphicsConfiguration.java"/-->
<patternset refid="exclude-jce-dependencies"/>
<patternset refid="exclude-jai"/>
<patternset refid="exclude-jimi"/>
<classpath refid="libs-build-classpath"/>
</javac>

@@ -592,7 +558,6 @@ list of possible build targets.
<uptodate property="jar.sources.uptodate" targetfile="${build.dir}/fop-sources.jar">
<srcfiles dir="${build.gensrc.dir}"/>
<srcfiles dir="${src.java.dir}"/>
<srcfiles refid="graphics-configuration-adapter"/>
</uptodate>
</target>

@@ -1095,7 +1060,6 @@ NOTE:
<pathelement path="${src.java.dir}"/>
<pathelement path="${src.sandbox.dir}"/>
<pathelement path="${build.gensrc.dir}"/>
<path refid="graphics-configuration-adapter"/>
</sourcepath>
<tag name="todo" scope="all" description="To do:"/>
<group title="Control and Startup">
@@ -1269,37 +1233,24 @@ NOTE:
-->
<echo message="Make sure you have a proper Forrest installation (see http://forrest.apache.org/)"/>

<!--<antcall target="site"/>-->
<!-- You can provide a JDK 1.4 for a JDK 1.3 build by adding "javahome.jdk14" to build-local.properties -->
<condition property="javahome.jdk14.override" value="${javahome.jdk14}">
<isset property="javahome.jdk14"/>
</condition>
<echo message="java home: ${javahome.jdk14.override}"/>
<condition property="javahome.jdk14.override" value="${env.JAVA_HOME}">
<not>
<isset property="javahome.jdk14.override"/>
</not>
</condition>
<echo message="java home: ${javahome.jdk14.override}"/>
<condition property="forrest.call" value="forrest.bat" else="forrest">
<os family="windows"/>
</condition>
<exec executable="${forrest.call}">
<env key="JAVA_HOME" value="${javahome.jdk14.override}"/>
</exec>
<exec executable="${forrest.call}"/>
</target>
<!-- =================================================================== -->
<!-- Creates the distribution -->
<!-- =================================================================== -->
<target name="dist" depends="dist-src,dist-bin" description="Generates the distribution package"/>
<target name="dist" depends="dist-prereq,dist-src,dist-bin" description="Generates the distribution package"/>

<target name="dist-bin" depends="all,javadocs,docs">
<echo message="Building the binary distribution files (zip,tar)"/>
<fail message="A complete binary build requires Jimi" unless="jimi.present"/>
<target name="dist-prereq" depends="init">
<fail message="A complete binary build requires JAI" unless="jai.present"/>
<fail message="A complete binary build requires JCE" unless="jce.present"/>
</target>

<target name="dist-bin" depends="all,javadocs,docs">
<echo message="Building the binary distribution files (zip,tar)"/>
<mkdir dir="${dist.bin.result.dir}"/>
<copy todir="${dist.bin.result.dir}">
<fileset refid="dist.bin"/>
@@ -1315,10 +1266,9 @@ NOTE:
<copy todir="${dist.bin.result.dir}/build" file="build/fop.jar"/>
<chmod file="${dist.bin.result.dir}/fop" perm="ugo+rx"/>

<property name="bin.suffix" value="bin-jdk${java.specification.version}"/>
<zip zipfile="${name}-${version}-${bin.suffix}.zip" basedir="${dist.bin.dir}" includes="**"/>
<zip zipfile="${name}-${version}-bin.zip" basedir="${dist.bin.dir}" includes="**"/>
<tar longfile="gnu"
destfile="${name}-${version}-${bin.suffix}.tar">
destfile="${name}-${version}-bin.tar">
<tarfileset dir="${dist.bin.dir}" mode="755">
<include name="${name}-${version}/fop"/>
</tarfileset>
@@ -1327,8 +1277,8 @@ NOTE:
<exclude name="${name}-${version}/fop"/>
</tarfileset>
</tar>
<gzip zipfile="${name}-${version}-${bin.suffix}.tar.gz" src="${name}-${version}-${bin.suffix}.tar"/>
<delete file="${name}-${version}-${bin.suffix}.tar"/>
<gzip zipfile="${name}-${version}-bin.tar.gz" src="${name}-${version}-bin.tar"/>
<delete file="${name}-${version}-bin.tar"/>
</target>

<target name="dist-src" depends="all">

+ 10
- 2
lib/README.txt View File

@@ -142,8 +142,16 @@ Please make sure you've read the license of each package.
https://jai-imageio.dev.java.net/
BSD license
Note: Not the whole JAI is needed, only the ImageIO-compatible codecs
packaged as "Image I/O Tools". The name may be misleading.
Note: This is not the same as JAI! Only the ImageIO-compatible codecs
are packaged as "Image I/O Tools". The name may be misleading.

- JAI (Java Advanced Imaging API)

http://java.sun.com/products/java-media/jai
Java Research License and Java Distribution License (Check which one applies to you!)
Currently used for:
- Grayscale error diffusion dithering in the PCL Renderer

- JEuclid (MathML implementation, for the MathML extension)


+ 2
- 2
src/documentation/content/.htaccess View File

@@ -18,8 +18,8 @@ RedirectMatch Permanent ^/fop/upgrading(.*) http://xmlgraphics.apache.org/fop/0.

# redirect to versioned documentation
Redirect Temp /fop/stable http://xmlgraphics.apache.org/fop/0.94
Redirect Temp /fop/current http://xmlgraphics.apache.org/fop/0.94
Redirect Temp /fop/unstable http://xmlgraphics.apache.org/fop/trunk
Redirect Temp /fop/current http://xmlgraphics.apache.org/fop/0.95
Redirect Temp /fop/unstable http://xmlgraphics.apache.org/fop/0.95
Redirect Temp /fop/latest http://xmlgraphics.apache.org/fop/trunk
Redirect Temp /fop/maintenance http://xmlgraphics.apache.org/fop/0.93
Redirect Temp /fop/previous http://xmlgraphics.apache.org/fop/0.93

+ 2
- 2
src/documentation/content/xdocs/0.95/compiling.xml View File

@@ -41,7 +41,7 @@
<section id="env-jdk">
<title>JDK</title>
<p>
Building FOP requires a minimum Java Development Kit (JDK/SDK) of 1.3
Building FOP requires a minimum Java Development Kit (JDK/SDK) of 1.4
(A Java Runtime Environment is not sufficient).
</p>
</section>
@@ -59,7 +59,7 @@
<p>
The build script uses <a href="ext:ant">Apache Ant</a>, a popular
Java-based build tool, which usually requires that the environment variable JAVA_HOME point to
your local JDK root directory. This is true even if you use JDK 1.3 or above, which normally
your local JDK root directory. This is true even if you use JDK 1.4 or above, which normally
does not need this setting.
</p>
</section>

+ 2
- 10
src/documentation/content/xdocs/0.95/fonts.xml View File

@@ -231,20 +231,12 @@
<title>Type 1 Font Metrics</title>
<p>FOP includes PFMReader, which reads the PFM file that normally comes with a Type 1 font, and generates an appropriate font metrics file for it.
To use it, run the class org.apache.fop.fonts.apps.PFMReader:</p>
<p>Windows (on JDK 1.4 and later):</p>
<p>Windows:</p>
<source>java -cp build\fop.jar;lib\avalon-framework.jar;lib\commons-logging.jar;lib\commons-io.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>Windows (on JDK 1.3.x):</p>
<source>java -cp build\fop.jar;lib\avalon-framework.jar;lib\commons-logging.jar;lib\commons-io.jar;lib\xml-apis.jar;
lib\xercesImpl.jar;lib\xalan.jar;lib\serializer.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>Unix (on JDK 1.4 and later):</p>
<p>Unix:</p>
<source>java -cp build/fop.jar:lib/avalon-framework.jar:lib/commons-logging.jar:lib/commons-io.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>Unix (on JDK 1.3.1):</p>
<source>java -cp build/fop.jar:lib/avalon-framework.jar:lib/commons-logging.jar:lib/commons-io.jar:lib/xml-apis.jar:
lib/xercesImpl.jar:lib/xalan.jar:lib/serializer.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>PFMReader [options]:</p>
<ul>
<li><strong>-fn &lt;fontname&gt;</strong> By default, FOP uses the fontname from the

+ 0
- 4
src/documentation/content/xdocs/0.95/known-issues.xml View File

@@ -63,10 +63,6 @@
Not all FO elements can be referenced by their "id", most notably:
table-body, table-header, table-footer and table-row.
</known-issue>
<known-issue>
The backgrounds of table-body, table-header, table-footer and
table-column are not painted, yet.
</known-issue>
<known-issue>
Column balancing in multi-column documents may not work as expected
(<a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=36356">Bugzilla #36356</a>)

+ 0
- 48
src/documentation/content/xdocs/0.95/layoutengine/disabled-testcases.xml View File

@@ -232,54 +232,6 @@
<file>region-body_column-count_bug36356.xml</file>
<description>Column balancing doesn't work as expected.</description>
</testcase>
<testcase>
<name>No background-images on table-body</name>
<file>table-body_background-image.xml</file>
<description>The backgrounds of table-body, table-header,
table-footer and table-column are not painted, yet.</description>
</testcase>
<testcase>
<name>Collapsing Border Model NYI</name>
<file>table_border-collapse_collapse_1.xml</file>
<description>Border-collapse="collapse" is not yet
implemented.</description>
</testcase>
<testcase>
<name>Collapsing Border Model NYI</name>
<file>table_border-collapse_collapse_2.xml</file>
<description>Border-collapse="collapse" is not yet
implemented.</description>
</testcase>
<testcase>
<name>Problems with border and padding on tables</name>
<file>table_border_padding.xml</file>
<description>The element list seems to not be fully correct, yet, causing
the layout to look odd.</description>
</testcase>
<testcase>
<name>keep-with-previous doesn't work inside tables</name>
<file>table-cell_block_keep-with-previous.xml</file>
<description>Keep-with-previous doesn't work inside tables and
lists, yet.</description>
</testcase>
<testcase>
<name>Border and padding conditionality is NYI on table-cells</name>
<file>table-cell_border_padding_conditionality.xml</file>
<description>Border and padding conditionality are not supported
on table-cells, yet.</description>
</testcase>
<testcase>
<name>No background-images on table-header</name>
<file>table-header_background-image.xml</file>
<description>The backgrounds of table-body, table-header,
table-footer and table-column are not painted, yet.</description>
</testcase>
<testcase>
<name>keep-with-previous doesn't work on table-rows</name>
<file>table-row_keep-with-previous.xml</file>
<description>Keep-with-previous doesn't work inside tables and
lists, yet.</description>
</testcase>
<testcase>
<name>table-cell empty area with marker.xml</name>
<file>table-cell_empty_area_with_marker.xml</file>

+ 1
- 6
src/documentation/content/xdocs/0.95/pdfencryption.xml View File

@@ -203,16 +203,11 @@ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent);
install.
</p>
<ol>
<li>
Download the binary distribution for your JDK version. If you have JDK
1.3 or earlier you must also download a JCE from the same page.
</li>
<li>
Unpack the distribution. Add the jar file to your classpath. A
convenient way to use the jar on Linux is to simply drop it into the
FOP lib directory, it will be automatically picked up by
<code>fop.sh</code>. If you have JDK 1.3 or earlier don't forget to
install the JCE as well.
<code>fop.sh</code>.
</li>
<li>
Open the <code>java.security</code> file and add<br/>

+ 1
- 1
src/documentation/content/xdocs/0.95/running.xml View File

@@ -305,7 +305,7 @@ Fop [options] [-fo|-xml] infile [-xsl file] [-awt|-pdf|-mif|-rtf|-tiff|-png|-pcl
<ul>
<li>
Increase memory available to the JVM. See
<a href="http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/java.html">the -Xmx option</a>
<a href="http://java.sun.com/j2se/1.4/docs/tooldocs/solaris/java.html">the -Xmx option</a>
for more information.
<warning>
It is usually unwise to increase the memory allocated to the JVM beyond the amount of

+ 7161
- 5260
src/documentation/content/xdocs/compliance.ihtml
File diff suppressed because it is too large
View File


+ 1
- 1
src/documentation/content/xdocs/dev/release.xml View File

@@ -73,7 +73,7 @@ The purpose of documenting it here is to facilitate consistency, ensure that the
<code>fop-hyph.jar</code> to lib/ (e.g. from
<code>http://sourceforge.net/projects/offo</code></li>
<li>Alternatively, create a build-local.properties file that points to the above libs.</li>
<li>Run build[.sh] dist. Do this once using Sun JDK 1.3.1_15 or later and once with Sun JDK 1.4.2_08 or later. A Forrest installation is needed.</li>
<li>Run build[.sh] dist. Do this using Sun JDK 1.4.2_08 or later. A Forrest installation is needed.</li>
<li>Create signatures. Don't forget to upload your KEY:
<code>gpg -a -b --force-v3-sigs fop-0.94-src.tar.gz</code> etc.</li>
<li>Upload the dist and signature files to your web directory

+ 4
- 4
src/documentation/content/xdocs/download.xml View File

@@ -108,16 +108,16 @@
<tr>
<td>Repository URL</td>
<td>
<link href="http://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-0_95rc/">
<code>http://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-0_95rc/</code>
<link href="http://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-0_95beta/">
<code>http://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-0_95beta/</code>
</link>
</td>
</tr>
<tr>
<td>Web view</td>
<td>
<link href="http://svn.apache.org/viewvc/xmlgraphics/fop/tags/fop-0_95rc/">
<code>http://svn.apache.org/viewvc/xmlgraphics/fop/tags/fop-0_95rc/</code>
<link href="http://svn.apache.org/viewvc/xmlgraphics/fop/tags/fop-0_95beta/">
<code>http://svn.apache.org/viewvc/xmlgraphics/fop/tags/fop-0_95beta/</code>
</link>
</td>
</tr>

+ 4
- 3
src/documentation/content/xdocs/index.xml View File

@@ -29,14 +29,15 @@
<p>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java
application that reads a formatting object (FO) tree and renders the resulting
pages to a specified output. <link href="0.94/output.html">Output formats</link>
pages to a specified output. <link href="0.95/output.html">Output formats</link>
currently supported include PDF, PS, PCL, AFP, XML (area tree representation),
Print, AWT and PNG, and to a lesser extent, RTF and TXT. The primary output target is PDF.
</p>
<figure width="480" height="260" src="images/document.jpg" alt="Render Diagram" />
<p>
The latest stable version of FOP (<link href="0.94/">0.94</link>) is the second
stable release after a large redesign effort and implements a large subset of the
A beta release of the latest version of FOP (<link href="0.95/">0.95</link>) is now
available. After a short testing period it will become the third
stable release after the large redesign effort and will implement a large subset of the
<link href="http://www.w3.org/TR/xsl11/">XSL-FO Version 1.1 W3C
Recommendation</link>.
</p>

+ 2
- 2
src/documentation/content/xdocs/trunk/compiling.xml View File

@@ -41,7 +41,7 @@
<section id="env-jdk">
<title>JDK</title>
<p>
Building FOP requires a minimum Java Development Kit (JDK/SDK) of 1.3
Building FOP requires a minimum Java Development Kit (JDK/SDK) of 1.4
(A Java Runtime Environment is not sufficient).
</p>
</section>
@@ -59,7 +59,7 @@
<p>
The build script uses <a href="ext:ant">Apache Ant</a>, a popular
Java-based build tool, which usually requires that the environment variable JAVA_HOME point to
your local JDK root directory. This is true even if you use JDK 1.3 or above, which normally
your local JDK root directory. This is true even if you use JDK 1.4 or above, which normally
does not need this setting.
</p>
</section>

+ 2
- 10
src/documentation/content/xdocs/trunk/fonts.xml View File

@@ -231,20 +231,12 @@
<title>Type 1 Font Metrics</title>
<p>FOP includes PFMReader, which reads the PFM file that normally comes with a Type 1 font, and generates an appropriate font metrics file for it.
To use it, run the class org.apache.fop.fonts.apps.PFMReader:</p>
<p>Windows (on JDK 1.4 and later):</p>
<p>Windows:</p>
<source>java -cp build\fop.jar;lib\avalon-framework.jar;lib\commons-logging.jar;lib\commons-io.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>Windows (on JDK 1.3.x):</p>
<source>java -cp build\fop.jar;lib\avalon-framework.jar;lib\commons-logging.jar;lib\commons-io.jar;lib\xml-apis.jar;
lib\xercesImpl.jar;lib\xalan.jar;lib\serializer.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>Unix (on JDK 1.4 and later):</p>
<p>Unix:</p>
<source>java -cp build/fop.jar:lib/avalon-framework.jar:lib/commons-logging.jar:lib/commons-io.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>Unix (on JDK 1.3.1):</p>
<source>java -cp build/fop.jar:lib/avalon-framework.jar:lib/commons-logging.jar:lib/commons-io.jar:lib/xml-apis.jar:
lib/xercesImpl.jar:lib/xalan.jar:lib/serializer.jar
org.apache.fop.fonts.apps.PFMReader [options] pfm-file xml-file</source>
<p>PFMReader [options]:</p>
<ul>
<li><strong>-fn &lt;fontname&gt;</strong> By default, FOP uses the fontname from the

+ 2
- 4
src/documentation/content/xdocs/trunk/pdfencryption.xml View File

@@ -204,15 +204,13 @@ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent);
</p>
<ol>
<li>
Download the binary distribution for your JDK version. If you have JDK
1.3 or earlier you must also download a JCE from the same page.
Download the binary distribution for your JDK version.
</li>
<li>
Unpack the distribution. Add the jar file to your classpath. A
convenient way to use the jar on Linux is to simply drop it into the
FOP lib directory, it will be automatically picked up by
<code>fop.sh</code>. If you have JDK 1.3 or earlier don't forget to
install the JCE as well.
<code>fop.sh</code>.
</li>
<li>
Open the <code>java.security</code> file and add<br/>

+ 1
- 1
src/documentation/content/xdocs/trunk/running.xml View File

@@ -305,7 +305,7 @@ Fop [options] [-fo|-xml] infile [-xsl file] [-awt|-pdf|-mif|-rtf|-tiff|-png|-pcl
<ul>
<li>
Increase memory available to the JVM. See
<a href="http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/java.html">the -Xmx option</a>
<a href="http://java.sun.com/j2se/1.4/docs/tooldocs/solaris/java.html">the -Xmx option</a>
for more information.
<warning>
It is usually unwise to increase the memory allocated to the JVM beyond the amount of

+ 0
- 31
src/java-1.3/org/apache/fop/svg/GraphicsConfiguration.java View File

@@ -1,31 +0,0 @@
/*
* 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.svg;
/**
* Adapter to allow subclassing java.awt.GraphicsConfiguration without
* compilation errors.
* The version for JDK 1.3 is just empty.
*
*/
abstract public class GraphicsConfiguration extends java.awt.GraphicsConfiguration {


}

+ 0
- 237
src/java-1.4/org/apache/fop/image/ImageIOImage.java View File

@@ -1,237 +0,0 @@
/*
* 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.image;

// AWT
import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.BufferedImage;
import java.util.Iterator;

// ImageIO
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;

import org.apache.commons.io.IOUtils;
import org.apache.fop.util.UnitConv;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
* FopImage object using ImageIO.
* @see AbstractFopImage
* @see FopImage
*/
public class ImageIOImage extends AbstractFopImage {

private byte[] softMask = null;

/**
* Creates a new ImageIOImage.
* @param info the image info from the ImageReader
*/
public ImageIOImage(FopImage.ImageInfo info) {
super(info);
if ("image/png".equals(info.mimeType)
|| "image/tiff".equals(info.mimeType)) {
this.loaded = 0; //TODO The PNG and TIFF Readers cannot read the resolution, yet.
}
}

/**
* @see org.apache.fop.image.AbstractFopImage#loadDimensions()
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
return loadBitmap();
}
return true;
}
private Element getChild(Element el, String name) {
NodeList nodes = el.getElementsByTagName(name);
if (nodes.getLength() > 0) {
return (Element)nodes.item(0);
} else {
return null;
}
}
/** @see org.apache.fop.image.AbstractFopImage#loadBitmap() */
protected boolean loadBitmap() {
if (this.bitmaps != null) {
return true;
}
try {
inputStream.reset();
ImageInputStream imgStream = ImageIO.createImageInputStream(inputStream);
Iterator iter = ImageIO.getImageReaders(imgStream);
if (!iter.hasNext()) {
log.error("No ImageReader found.");
return false;
}
ImageReader reader = (ImageReader)iter.next();
ImageReadParam param = reader.getDefaultReadParam();
reader.setInput(imgStream, true, false);
BufferedImage imageData = reader.read(0, param);
//Read image resolution
IIOMetadata iiometa = reader.getImageMetadata(0);
if (iiometa != null && iiometa.isStandardMetadataFormatSupported()) {
Element metanode = (Element)iiometa.getAsTree("javax_imageio_1.0");
Element dim = getChild(metanode, "Dimension");
if (dim != null) {
Element child;
child = getChild(dim, "HorizontalPixelSize");
if (child != null) {
this.dpiHorizontal = UnitConv.IN2MM
/ Float.parseFloat(child.getAttribute("value"));
}
child = getChild(dim, "VerticalPixelSize");
if (child != null) {
this.dpiVertical = UnitConv.IN2MM
/ Float.parseFloat(child.getAttribute("value"));
}
}
}
imgStream.close();
reader.dispose();
this.height = imageData.getHeight();
this.width = imageData.getWidth();

ColorModel cm = imageData.getColorModel();
this.bitsPerPixel = cm.getComponentSize(0); //only use first, we assume all are equal
//this.colorSpace = cm.getColorSpace();
//We currently force the image to sRGB
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);

int[] tmpMap = imageData.getRGB(0, 0, this.width,
this.height, null, 0, this.width);

if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();
if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
//TODO Is there another case?
this.isTransparent = false;
}
} else {
// TRANSLUCENT
this.softMask = new byte[width * height];
imageData.getAlphaRaster().getDataElements(
0, 0, width, height, this.softMask);
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)]
= (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1]
= (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2]
= (byte)(b & 0xFF);
}
}

} catch (Exception ex) {
log.error("Error while loading image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}
return true;
}

/** @see org.apache.fop.image.AbstractFopImage#loadOriginalData() */
protected boolean loadOriginalData() {
if (inputStream == null && getBitmaps() != null) {
return false;
} else {
return loadDefaultOriginalData();
}
}
/** @see org.apache.fop.image.FopImage#hasSoftMask() */
public boolean hasSoftMask() {
if (this.bitmaps == null && this.raw == null) {
loadBitmap();
}

return (this.softMask != null);
}

/** @see org.apache.fop.image.FopImage#getSoftMask() */
public byte[] getSoftMask() {
if (this.bitmaps == null) {
loadBitmap();
}

return this.softMask;
}

}


+ 0
- 161
src/java-1.4/org/apache/fop/image/JpegImageIOImage.java View File

@@ -1,161 +0,0 @@
/*
* 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.image;

// AWT
import java.awt.Color;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.BufferedImage;

// ImageIO
import javax.imageio.ImageIO;

import org.apache.commons.io.IOUtils;

/**
* FopImage object using ImageIO.
* Special class to allow the use of JpegImage for those
* renderers which can embed Jpeg directly but for renderers
* which require the decoded data this class delivers it.
* @see AbstractFopImage
* @see JpegImage
*/
public class JpegImageIOImage extends JpegImage {

/**
* Creates a new JpegImageIOImage.
* @param info the image info from the ImageReader
*/
public JpegImageIOImage(FopImage.ImageInfo info) {
super(info);
}

/**
* @see org.apache.fop.image.AbstractFopImage#loadDimensions()
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
return loadBitmap();
}
return true;
}
/** @see org.apache.fop.image.AbstractFopImage#loadBitmap() */
protected boolean loadBitmap() {
try {
inputStream.reset();
BufferedImage imageData = ImageIO.read(inputStream);

this.height = imageData.getHeight();
this.width = imageData.getWidth();

ColorModel cm = imageData.getColorModel();
this.bitsPerPixel = cm.getComponentSize(0); //only use first, we assume all are equal
this.colorSpace = cm.getColorSpace();

int[] tmpMap = imageData.getRGB(0, 0, this.width,
this.height, null, 0, this.width);

if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();
if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
* // or use special API...
*/
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)]
= (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1]
= (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2]
= (byte)(b & 0xFF);
}
}

} catch (Exception ex) {
log.error("Error while loading image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}
return true;
}

}


+ 0
- 10
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -47,7 +47,6 @@ import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fonts.FontCache;
import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.layoutmgr.LayoutManagerMaker;
import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry;
@@ -83,9 +82,6 @@ public class FopFactory implements ImageContext {

private ColorSpaceCache colorSpaceCache = null;
/** Image factory for creating fop image objects */
private ImageFactory imageFactory;

/** Image manager for loading and caching image objects */
private ImageManager imageManager;

@@ -156,7 +152,6 @@ public class FopFactory implements ImageContext {
this.elementMappingRegistry = new ElementMappingRegistry(this);
this.foURIResolver = new FOURIResolver(validateUserConfigStrictly());
this.colorSpaceCache = new ColorSpaceCache(foURIResolver);
this.imageFactory = new ImageFactory();
this.imageManager = new ImageManager(this);
this.rendererFactory = new RendererFactory();
this.xmlHandlers = new XMLHandlerRegistry();
@@ -291,11 +286,6 @@ public class FopFactory implements ImageContext {
return this.contentHandlerFactoryRegistry;
}

/** @return the image factory */
public ImageFactory getImageFactory() {
return this.imageFactory;
}

/**
* Returns the image manager.
* @return the image manager

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

@@ -412,6 +412,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_HEIGHT);
addPropertyMaker("top", l);

// right
@@ -419,6 +420,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_WIDTH);
addPropertyMaker("right", l);

// bottom
@@ -426,6 +428,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_HEIGHT);
addPropertyMaker("bottom", l);

// left
@@ -433,6 +436,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_WIDTH);
addPropertyMaker("left", l);
}

@@ -1161,6 +1165,7 @@ public final class FOPropertyMapping implements Constants {
m = new LengthProperty.Maker(PR_START_INDENT);
m.setInherited(true);
m.setDefault("0pt");
m.setPercentBase(LengthBase.CONTAINING_REFAREA_WIDTH);
IndentPropertyMaker sCorr = new IndentPropertyMaker(m);
sCorr.setCorresponding(PR_MARGIN_LEFT, PR_MARGIN_RIGHT, PR_MARGIN_TOP);
sCorr.setUseParent(false);
@@ -1177,6 +1182,7 @@ public final class FOPropertyMapping implements Constants {
m = new LengthProperty.Maker(PR_END_INDENT);
m.setInherited(true);
m.setDefault("0pt");
m.setPercentBase(LengthBase.CONTAINING_REFAREA_WIDTH);
IndentPropertyMaker eCorr = new IndentPropertyMaker(m);
eCorr.setCorresponding(PR_MARGIN_RIGHT, PR_MARGIN_LEFT, PR_MARGIN_BOTTOM);
eCorr.setUseParent(false);

+ 0
- 5
src/java/org/apache/fop/fo/FOTreeBuilder.java View File

@@ -40,7 +40,6 @@ import org.apache.fop.events.LoggingEventListener;
import org.apache.fop.fo.ElementMapping.Maker;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.pagination.Root;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;
import org.apache.fop.util.ContentHandlerFactory.ObjectSource;
@@ -168,10 +167,6 @@ public class FOTreeBuilder extends DefaultHandler {
log.debug("Parsing of document complete");
}
foEventHandler.endDocument();
//Notify the image factory that this user agent has expired.
ImageFactory imageFactory = userAgent.getFactory().getImageFactory();
imageFactory.removeContext(this.userAgent);
}

/** {@inheritDoc} */

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

@@ -238,18 +238,6 @@ public class PrimaryGridUnit extends GridUnit {
return contentLength;
}

/** @return true if cell/row has an explicit BPD/height */
public boolean hasBPD() {
if (!getCell().getBlockProgressionDimension().getOptimum(null).isAuto()) {
return true;
}
if (getRow() != null
&& !getRow().getBlockProgressionDimension().getOptimum(null).isAuto()) {
return true;
}
return false;
}

/**
* Returns the grid units belonging to the same span as this one.
*

+ 0
- 376
src/java/org/apache/fop/image/AbstractFopImage.java View File

@@ -1,376 +0,0 @@
/*
* 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.image;

// Java
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.InputStream;
import java.awt.Color;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.datatypes.Length;

/**
* Base class to implement the FopImage interface.
*
* @see FopImage
*/
public abstract class AbstractFopImage implements FopImage {

/**
* logging instance
*/
protected static Log log = LogFactory.getLog(AbstractFopImage.class);

/**
* Keeps track of what has been loaded.
*/
protected int loaded = 0;

/**
* Image width (in pixel).
*/
protected int width = 0;

/**
* Image height (in pixel).
*/
protected int height = 0;
/** Horizontal bitmap resolution (in dpi) */
protected double dpiHorizontal = 72.0f;

/** Vertical bitmap resolution (in dpi) */
protected double dpiVertical = 72.0f;

/**
* Image input stream.
*/
protected InputStream inputStream = null;

/**
* ImageReader object (to obtain image header informations).
*/
protected FopImage.ImageInfo imageInfo = null;

/**
* Image color space (java.awt.color.ColorSpace).
*/
protected ColorSpace colorSpace = null;

/**
* Bits per pixel.
*/
protected int bitsPerPixel = 0;

/**
* Image data (pixels, uncompressed).
*/
protected byte[] bitmaps = null;

/**
* Image data (undecoded, compressed, for image formats that can be embedded without decoding.
*/
protected byte[] raw = null;

/**
* Image transparency.
*/
protected boolean isTransparent = false;

/**
* Transparent color (java.awt.Color).
*/
protected Color transparentColor = null;

/**
* Photoshop generated CMYK JPEGs are inverted.
*/
protected boolean invertImage = false;
/**
* Constructor.
* Construct a new FopImage object and initialize its default properties:
* <UL>
* <LI>image width
* <LI>image height
* </UL>
* The image data isn't kept in memory.
* @param info image information
*/
public AbstractFopImage(FopImage.ImageInfo info) {
this.inputStream = info.inputStream;
this.imageInfo = info;
if (this.imageInfo.width != -1) {
width = imageInfo.width;
height = imageInfo.height;
dpiHorizontal = imageInfo.dpiHorizontal;
dpiVertical = imageInfo.dpiVertical;
loaded = loaded | DIMENSIONS;
}
}

/**
* Get the mime type for this image.
*
* @return the mime type for the image
*/
public String getMimeType() {
return imageInfo.mimeType;
}

/** {@inheritDoc} */
public String getOriginalURI() {
return this.imageInfo.originalURI;
}
/**
* Load image data and initialize its properties.
*
* @param type the type of loading to do
* @return true if the loading was successful
*/
public synchronized boolean load(int type) {
if ((loaded & type) != 0) {
return true;
}
boolean success = true;
if (((type & DIMENSIONS) != 0) && ((loaded & DIMENSIONS) == 0)) {
success = success && loadDimensions();

if (!success) {
return false;
}
loaded = loaded | DIMENSIONS;
}
if (((type & BITMAP) != 0) && ((loaded & BITMAP) == 0)) {
success = success && loadBitmap();
if (success) {
loaded = loaded | BITMAP;
}
}
if (((type & ORIGINAL_DATA) != 0) && ((loaded & ORIGINAL_DATA) == 0)) {
success = success && loadOriginalData();
if (success) {
loaded = loaded | ORIGINAL_DATA;
}
}
return success;
}

/**
* Load the dimensions of the image.
* All implementations should override this to get and
* return the dimensions.
*
* @return true if the loading was successful
*/
protected boolean loadDimensions() {
return false;
}

/**
* Load a bitmap array of the image.
* If the renderer requires a bitmap image then the
* implementations should override this to load the bitmap.
*
* @return true if the loading was successful
*/
protected boolean loadBitmap() {
return false;
}

/**
* Load the original image data.
* In some cases the original data can be used by the renderer.
* This should load the data and any other associated information.
*
* @return true if the loading was successful
*/
protected boolean loadOriginalData() {
return false;
}

/**
* Load the original image data. This is generic code for use by any
* subclass that wants to use this from a loadOriginalData() implementation.
*
* @return true if the loading was successful
*/
protected boolean loadDefaultOriginalData() {
if (inputStream == null) {
throw new IllegalStateException("inputStream is already null or was never set");
}
try {
this.raw = IOUtils.toByteArray(inputStream);
} catch (java.io.IOException ex) {
log.error("Error while reading raw image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}
return true;
}
/**
* @return the image width (in pixels)
*/
public int getWidth() {
return this.width;
}
/**
* @return the image height (in pixels)
*/
public int getHeight() {
return this.height;
}

/** {@inheritDoc} */
public int getIntrinsicWidth() {
return (int)(getWidth() * 72000 / getHorizontalResolution());
}

/** {@inheritDoc} */
public int getIntrinsicHeight() {
return (int)(getHeight() * 72000 / getVerticalResolution());
}
/** {@inheritDoc} */
public Length getIntrinsicAlignmentAdjust() {
return this.imageInfo.alignmentAdjust;
}

/** {@inheritDoc} */
public double getHorizontalResolution() {
return this.dpiHorizontal;
}
/** {@inheritDoc} */
public double getVerticalResolution() {
return this.dpiVertical;
}
/**
* Return the image color space.
* @return the image color space (java.awt.color.ColorSpace)
*/
public ColorSpace getColorSpace() {
return this.colorSpace;
}

/**
* Get ICC profile for this image.
* @return the icc profile or null if not applicable
*/
public ICC_Profile getICCProfile() {
if (this.colorSpace != null && this.colorSpace instanceof ICC_ColorSpace) {
return ((ICC_ColorSpace)this.colorSpace).getProfile();
}
return null;
}

/**
* Return the number of bits per pixel.
* @return number of bits per pixel
*/
public int getBitsPerPixel() {
return this.bitsPerPixel;
}

/**
* Return the image transparency.
* @return true if the image is transparent
*/
public boolean isTransparent() {
return this.isTransparent;
}

/**
* Check if this image has a soft mask.
*
* @return true if the image also has a soft transparency mask
*/
public boolean hasSoftMask() {
return false;
}

/**
* Get the soft mask.
* The soft mask should have the same bitdepth as the image data.
*
* @return the data array of soft mask values
*/
public byte[] getSoftMask() {
return null;
}

/**
* Return the transparent color.
* @return the transparent color (java.awt.Color)
*/
public Color getTransparentColor() {
return this.transparentColor;
}

/** @return true for CMYK images generated by Adobe Photoshop */
public boolean isInverted() {
return this.invertImage;
}
/**
* Return the image data (pixels, uncompressed).
* @return the image data
*/
public byte[] getBitmaps() {
return this.bitmaps;
}

/**
* Return the image data size (number of bytes taken up by the uncompressed pixels).
* @return the image data size
*/
public int getBitmapsSize() {
return (bitmaps != null ? bitmaps.length : 0);
}

/**
* Return the original image data (compressed).
* @return the original image data
*/
public byte[] getRessourceBytes() {
return raw;
}

/**
* Return the original image data size (compressed).
* @return the original image data size
*/
public int getRessourceBytesSize() {
return (raw != null ? raw.length : 0);
}

}


+ 0
- 220
src/java/org/apache/fop/image/BmpImage.java View File

@@ -1,220 +0,0 @@
/*
* 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.image;

// Java
import java.io.IOException;
import java.awt.color.ColorSpace;

import org.apache.commons.io.IOUtils;

/**
* Bitmap image.
* This supports loading a bitmap image into bitmap data.
*
* @see AbstractFopImage
* @see FopImage
*/
public class BmpImage extends AbstractFopImage {
/**
* Create a bitmap image with the image data.
*
* @param imgInfo the image information
*/
public BmpImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the bitmap.
* This laods the bitmap data from the bitmap image.
*
* @return true if it was loaded successfully
*/
protected boolean loadBitmap() {
int wpos = 18;
int hpos = 22; // offset positioning for w and height in bmp files
int[] headermap = new int[54];
int filepos = 0;
byte[] palette = null;
try {
boolean eof = false;
while ((!eof) && (filepos < 54)) {
int input = inputStream.read();
if (input == -1) {
eof = true;
} else {
headermap[filepos++] = input;
}
}

if (headermap[28] == 4 || headermap[28] == 8) {
int palettesize = 1 << headermap[28];
palette = new byte[palettesize * 3];
int countr = 0;
while (!eof && countr < palettesize) {
int count2 = 2;
while (!eof && count2 >= -1) {
int input = inputStream.read();
if (input == -1) {
eof = true;
} else if (count2 >= 0) {
palette[countr * 3 + count2] = (byte)(input & 0xFF);
}
count2--;
filepos++;
}
countr++;
}
}
} catch (IOException ex) {
log.error("Error while loading image (Bmp): " + ex.getMessage(), ex);
IOUtils.closeQuietly(inputStream);
inputStream = null;
return false;
}
// gets h & w from headermap
this.width = headermap[wpos]
+ headermap[wpos + 1] * 256
+ headermap[wpos + 2] * 256 * 256
+ headermap[wpos + 3] * 256 * 256 * 256;
this.height = headermap[hpos]
+ headermap[hpos + 1] * 256
+ headermap[hpos + 2] * 256 * 256
+ headermap[hpos + 3] * 256 * 256 * 256;

int imagestart = headermap[10]
+ headermap[11] * 256
+ headermap[12] * 256 * 256
+ headermap[13] * 256 * 256 * 256;
this.bitsPerPixel = headermap[28];
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
int bytes = 0;
if (this.bitsPerPixel == 1) {
bytes = (this.width + 7) / 8;
} else if (this.bitsPerPixel == 24) {
bytes = this.width * 3;
} else if (this.bitsPerPixel == 4 || this.bitsPerPixel == 8) {
bytes = this.width / (8 / this.bitsPerPixel);
} else {
log.error("Image (" + ""
+ ") has " + this.bitsPerPixel
+ " which is not a supported BMP format.");
return false;
}
if ((bytes & 0x03) != 0) {
bytes |= 0x03;
bytes++;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];

int[] temp = new int[bytes * this.height];
try {
int input;
int count = 0;
inputStream.skip((long)(imagestart - filepos));
while ((input = inputStream.read()) != -1) {
if (count >= temp.length) {
log.warn("Data longer than expected while loading image");
break;
} else {
temp[count++] = input;
}
}
} catch (IOException ex) {
log.error("Error while loading image (Bmp): " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

for (int i = 0; i < this.height; i++) {
int x = 0;
int j = 0;
while (j < bytes) {
int p = temp[(this.height - i - 1) * bytes + j];

if (this.bitsPerPixel == 24 && x < this.width) {
int countr = 2;
do {
this.bitmaps[3 * (i * this.width + x) + countr]
= (byte)(temp[(this.height - i - 1) * bytes + j] & 0xFF);
j++;
} while (--countr >= 0)
;
x++;
} else if (this.bitsPerPixel == 1) {
for (int countr = 0;
countr < 8 && x < this.width; countr++) {
if ((p & 0x80) != 0) {
this.bitmaps[3 * (i * this.width + x)] = (byte) 0xFF;
this.bitmaps[3 * (i * this.width + x) + 1] = (byte) 0xFF;
this.bitmaps[3 * (i * this.width + x) + 2] = (byte) 0xFF;
} else {
this.bitmaps[3 * (i * this.width + x)] = (byte) 0;
this.bitmaps[3 * (i * this.width + x) + 1] = (byte) 0;
this.bitmaps[3 * (i * this.width + x) + 2] = (byte) 0;
}
p <<= 1;
x++;
}
j++;
} else if (this.bitsPerPixel == 4) {
for (int countr = 0;
countr < 2 && x < this.width; countr++) {
int pal = ((p & 0xF0) >> 4) * 3;
this.bitmaps[3 * (i * this.width + x)] = palette[pal];
this.bitmaps[3 * (i * this.width + x) + 1] = palette[pal + 1];
this.bitmaps[3 * (i * this.width + x) + 2] = palette[pal + 2];
p <<= 4;
x++;
}
j++;
} else if (this.bitsPerPixel == 8) {
if (x < this.width) {
p *= 3;
this.bitmaps[3 * (i * this.width + x)] = palette[p];
this.bitmaps[3 * (i * this.width + x) + 1] = palette[p + 1];
this.bitmaps[3 * (i * this.width + x) + 2] = palette[p + 2];
j++;
x++;
} else {
j = bytes;
}
} else {
j++;
}
}
}

// This seems really strange to me, but I noticed that
// JimiImage hardcodes bitsPerPixel to 8. If I do not
// do this Acrobat is unable to read the resultant PDF,
// so we will hardcode this...
this.bitsPerPixel = 8;

return true;
}

}


+ 0
- 122
src/java/org/apache/fop/image/EPSImage.java View File

@@ -1,122 +0,0 @@
/*
* 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.image;


/**
* EPS image handler.
* This handles the Encapulated PostScript images.
* It gets the dimensions and original data from the analyser.
*
* @see AbstractFopImage
* @see FopImage
*/
public class EPSImage extends AbstractFopImage {
private String docName;
private int[] bbox;

private EPSData epsData = null;

/**
* Create an EPS image with the image information.
*
* @param imgInfo the information containing the data and bounding box
*/
public EPSImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
init("");
if (imgInfo.data instanceof EPSData) {
epsData = (EPSData) imgInfo.data;
bbox = new int[4];
bbox[0] = (int) epsData.bbox[0];
bbox[1] = (int) epsData.bbox[1];
bbox[2] = (int) epsData.bbox[2];
bbox[3] = (int) epsData.bbox[3];

loaded = loaded | ORIGINAL_DATA;
}
}

/**
* Initialize docName and bounding box.
* @param name the document name
*/
private void init(String name) {
bbox = new int[4];
bbox[0] = 0;
bbox[1] = 0;
bbox[2] = 0;
bbox[3] = 0;

docName = name;
}

/**
* Return the name of the eps
* @return the name of the eps
*/
public String getDocName() {
return docName;
}

/**
* Return the bounding box
* @return an int array containing the bounding box
*/
public int[] getBBox() {
return bbox;
}

/**
* Get the eps image.
*
* @return the original eps image data
*/
public byte[] getEPSImage() {
if (epsData.epsFile == null) {
//log.error("ERROR LOADING EXTERNAL EPS");
}
return epsData.epsFile;
}

/**
* Data for EPS image.
*/
public static class EPSData {
public long[] bbox;
public boolean isAscii; // True if plain ascii eps file

// offsets if not ascii
public long psStart = 0;
public long psLength = 0;
public long wmfStart = 0;
public long wmfLength = 0;
public long tiffStart = 0;
public long tiffLength = 0;

/** raw eps file */
public byte[] rawEps;
/** eps part */
public byte[] epsFile;
public byte[] preview = null;
}

}

+ 0
- 51
src/java/org/apache/fop/image/EmfImage.java View File

@@ -1,51 +0,0 @@
/*
* 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.image;

/**
* Enhanced metafile image.
* This supports loading a EMF image.
*
* @see AbstractFopImage
* @see FopImage
*/
public class EmfImage extends AbstractFopImage {
/**
* Create a bitmap image with the image data.
*
* @param imgInfo the image information
*/
public EmfImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the original EMF data.
* This loads the original EMF data and reads the color space,
* and icc profile if any.
*
* @return true if loaded false for any error
*/
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
}


+ 0
- 207
src/java/org/apache/fop/image/FopImage.java View File

@@ -1,207 +0,0 @@
/*
* 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.image;

import java.io.InputStream;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.Color;

import org.apache.fop.datatypes.Length;

/**
* Fop image interface for loading images.
*/
public interface FopImage {
/**
* Flag for loading dimensions.
*/
int DIMENSIONS = 1;

/**
* Flag for loading original data.
*/
int ORIGINAL_DATA = 2;

/**
* Flag for loading bitmap data.
*/
int BITMAP = 4;

/**
* Get the mime type of this image.
* This is used so that when reading from the image it knows
* what type of image it is.
*
* @return the mime type string
*/
String getMimeType();

/** @return the original URI used to access this image. */
String getOriginalURI();
/**
* Load particular inforamtion for this image
* This must be called before attempting to get
* the information.
*
* @param type the type of loading required
* @return boolean true if the information could be loaded
*/
boolean load(int type);

/**
* Returns the image width.
* @return the width in pixels
*/
int getWidth();

/**
* Returns the image height.
* @return the height in pixels
*/
int getHeight();
/**
* @return the intrinsic image width (in millipoints)
*/
int getIntrinsicWidth();

/**
* @return the intrinsic image width (in millipoints)
*/
int getIntrinsicHeight();

/**
* @return the intrinsic alignment-adjust value or NULL if the image does
* not have one.
*/
Length getIntrinsicAlignmentAdjust();
/**
* @return the horizontal bitmap resolution (in dpi)
*/
double getHorizontalResolution();
/**
* @return the vertical bitmap resolution (in dpi)
*/
double getVerticalResolution();

/**
* Returns the color space of the image.
* @return the color space
*/
ColorSpace getColorSpace();

/**
* Returns the ICC profile.
* @return the ICC profile, null if none is available
*/
ICC_Profile getICCProfile();

/**
* Returns the number of bits per pixel for the image.
* @return the number of bits per pixel
*/
int getBitsPerPixel();

/**
* Indicates whether the image is transparent.
* @return True if it is transparent
*/
boolean isTransparent();

/**
* For transparent images. Returns the transparent color.
* @return the transparent color
*/
Color getTransparentColor();

/**
* Indicates whether the image has a Soft Mask (See section 7.5.4 in the
* PDF specs)
* @return True if a Soft Mask exists
*/
boolean hasSoftMask();

/**
* For images with a Soft Mask. Returns the Soft Mask as an array.
* @return the Soft Mask
*/
byte[] getSoftMask();

/** @return true for CMYK images generated by Adobe Photoshop */
boolean isInverted();
/**
* Returns the decoded and uncompressed image as a array of
* width * height * [colorspace-multiplicator] pixels.
* @return the bitmap
*/
byte[] getBitmaps();
/**
* Returns the size of the image.
* width * (bitsPerPixel / 8) * height, no ?
* @return the size
*/
int getBitmapsSize();

/**
* Returns the encoded/compressed image as an array of bytes.
* @return the raw image
*/
byte[] getRessourceBytes();

/**
* Returns the number of bytes of the raw image.
* @return the size in bytes
*/
int getRessourceBytesSize();

/**
* Image info class.
* Information loaded from analyser and passed to image object.
*/
public static class ImageInfo {
/** InputStream to load the image from */
public InputStream inputStream;
/** Original URI the image was accessed with */
public String originalURI;
/** image width (in pixels) */
public int width;
/** image height (in pixels) */
public int height;
/** horizontal bitmap resolution (in dpi) */
public double dpiHorizontal = 72.0f;
/** vertical bitmap resolution (in dpi) */
public double dpiVertical = 72.0f;
/** implementation-specific data object (ex. a SVG DOM for SVG images) */
public Object data;
/** MIME type of the image */
public String mimeType;
/** implementation-specific String (ex. the namespace for XML-based images) */
public String str;
/** intrinsic alignment-adjust or null if there is none */
public Length alignmentAdjust;
}

}


+ 0
- 211
src/java/org/apache/fop/image/FopImageConsumer.java View File

@@ -1,211 +0,0 @@
/*
* 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.image;

// Java
import java.util.Hashtable;
import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.awt.image.PixelGrabber;

/**
* ImageConsumer implementation for FopImage classes.
*/
public class FopImageConsumer implements ImageConsumer {
/** Image width in pixels */
protected int width = -1;
/** Image height in pixels */
protected int height = -1;
/** Image status */
protected Integer imageStatus = new Integer(-1);
/** hints */
protected int hints = 0;
/** Image properties */
protected Hashtable properties = null;
/** Color model */
protected ColorModel cm = null;
/** Image producer */
protected ImageProducer ip = null;

/**
* Main constructor
* @param iprod ImageProducer to use
*/
public FopImageConsumer(ImageProducer iprod) {
this.ip = iprod;
}

/**
* {@inheritDoc}
*/
public void imageComplete(int status) {
/*
* log.error("Status ");
* if (status == ImageConsumer.COMPLETESCANLINES) {
* log.error("CompleteScanLines");
* } else if (status == ImageConsumer.IMAGEABORTED) {
* log.error("ImageAborted");
* } else if (status == ImageConsumer.IMAGEERROR) {
* log.error("ImageError");
* } else if (status == ImageConsumer.RANDOMPIXELORDER) {
* log.error("RandomPixelOrder");
* } else if (status == ImageConsumer.SINGLEFRAME) {
* log.error("SingleFrame");
* } else if (status == ImageConsumer.SINGLEFRAMEDONE) {
* log.error("SingleFrameDone");
* } else if (status == ImageConsumer.SINGLEPASS) {
* log.error("SinglePass");
* } else if (status == ImageConsumer.STATICIMAGEDONE) {
* log.error("StaticImageDone");
* } else if (status == ImageConsumer.TOPDOWNLEFTRIGHT) {
* log.error("TopDownLeftRight");
* }
*/
synchronized (this.imageStatus) {
// Need to stop status if image done
if (imageStatus.intValue() != ImageConsumer.STATICIMAGEDONE
&& imageStatus.intValue() != ImageConsumer.SINGLEFRAMEDONE) {
this.imageStatus = new Integer(status);
}
}
}

/**
* {@inheritDoc}
*/
public void setColorModel(ColorModel model) {
// log.error("setColorModel: " + model);
this.cm = model;
}

/**
* {@inheritDoc}
*/
public void setDimensions(int width, int height) {
// log.error("setDimension: w=" + width + " h=" + height);
this.width = width;
this.height = height;
}

/**
* {@inheritDoc}
*/
public void setHints(int hintflags) {
// log.error("setHints: " + hintflags);
this.hints = hintflags;
}

/**
* {@inheritDoc}
*/
public void setProperties(Hashtable props) {
// log.error("setProperties: " + props);
this.properties = props;
}

/**
* {@inheritDoc}
*/
public void setPixels(int x, int y, int w, int h, ColorModel model,
byte[] pixels, int off, int scansize) {
}

/**
* {@inheritDoc}
*/
public void setPixels(int x, int y, int w, int h, ColorModel model,
int[] pixels, int off, int scansize) {
}

/**
* Indicates whether the image is ready.
* @return boolean True if the image is ready, false if it's still loading
* @throws Exception If an error happened while loading the image
*/
public boolean isImageReady() throws Exception {
/**@todo Use a better exception than Exception */
synchronized (this.imageStatus) {
if (this.imageStatus.intValue() == ImageConsumer.IMAGEABORTED) {
throw new Exception("Image aborted");
}
if (this.imageStatus.intValue() == ImageConsumer.IMAGEERROR) {
throw new Exception("Image error");
}

if (imageStatus.intValue() == ImageConsumer.STATICIMAGEDONE
|| imageStatus.intValue() == ImageConsumer.SINGLEFRAMEDONE) {
return true;
}

return false;
}
}

/**
* Returns the image width
* @return the width in pixels
*/
public int getWidth() {
return this.width;
}

/**
* Returns the image height
* @return the height in pixels
*/
public int getHeight() {
return this.height;
}

/**
* Returns the color model of the image
* @return the color model
*/
public ColorModel getColorModel() {
return this.cm;
}

/**
* Returns the bitmap as an array.
* @return the bitmap as an array.
* @throws Exception if an error occured while generating the array
*/
public int[] getImage() throws Exception {
int tmpMap[] = new int[this.width * this.height];
PixelGrabber pg = new PixelGrabber(this.ip, 0, 0, this.width,
this.height, tmpMap, 0, this.width);
pg.setDimensions(this.width, this.height);
pg.setColorModel(this.cm);
pg.setHints(this.hints);
pg.setProperties(this.properties);
try {
pg.grabPixels();
} catch (InterruptedException intex) {
/**@todo Use a better exception than Exception */
throw new Exception("Image grabbing interrupted : "
+ intex.getMessage());
}
return tmpMap;
}

}


+ 0
- 218
src/java/org/apache/fop/image/GifImage.java View File

@@ -1,218 +0,0 @@
/*
* 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.image;

// Java
import java.awt.image.ImageProducer;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.color.ColorSpace;
import java.awt.Color;
import java.io.InputStream;
import java.io.IOException;
import java.net.URLConnection;

import org.apache.commons.io.IOUtils;

/**
* FopImage object for GIF images, using Java native classes.
*
* @see AbstractFopImage
* @see FopImage
*/
public class GifImage extends AbstractFopImage {

/**
* Create a new gif image.
*
* @param imgInfo the image info for this gif image
*/
public GifImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the bitmap for this gif image.
* This loads the data and creates a bitmap byte array
* of the image data.
* To decode the image a dummy URLConnection is used that
* will do the conversion.
*
* @return True if the load process succeeded
*/
protected boolean loadBitmap() {
int[] tmpMap = null;
try {
URLConnection con = new DummyConnection(inputStream);

ImageProducer ip = (ImageProducer) con.getContent();
if (ip == null) {
return false;
}
FopImageConsumer consumer = new FopImageConsumer(ip);
ip.startProduction(consumer);

//Load the image into memory
while (!consumer.isImageReady()) {
Thread.sleep(500);
}

this.height = consumer.getHeight();
this.width = consumer.getWidth();

try {
tmpMap = consumer.getImage();
} catch (Exception ex) {
log.error("Image grabbing interrupted : "
+ ex.getMessage(), ex);
return false;
}

ColorModel cm = consumer.getColorModel();
this.bitsPerPixel = 8;
// this.bitsPerPixel = cm.getPixelSize();
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();

if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
IndexColorModel indexcm = (IndexColorModel) cm;
this.isTransparent = false;
byte[] alphas = new byte[indexcm.getMapSize()];
byte[] reds = new byte[indexcm.getMapSize()];
byte[] greens = new byte[indexcm.getMapSize()];
byte[] blues = new byte[indexcm.getMapSize()];
indexcm.getAlphas(alphas);
indexcm.getReds(reds);
indexcm.getGreens(greens);
indexcm.getBlues(blues);
for (int i = 0;
i < indexcm.getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
*/
// use special API...
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} catch (Exception ex) {
log.error("Error while loading image (Gif): " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF);
}
}
return true;
}

/** {@inheritDoc} */
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
/**
* A dummy url connection for a gif image in an input stream.
*/
protected static class DummyConnection extends URLConnection {
private InputStream inputStream;

DummyConnection(InputStream is) {
super(null);
inputStream = is;
}

/**
* {@inheritDoc}
*/
public InputStream getInputStream() throws IOException {
return inputStream;
}

/**
* {@inheritDoc}
*/
public void connect() throws IOException {
// do nothing
}

/**
* {@inheritDoc}
*/
public String getContentType() {
return "image/gif";
}

/**
* {@inheritDoc}
*/
public int getContentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return -1;
}
}

}
}


+ 0
- 72
src/java/org/apache/fop/image/ImageCache.java View File

@@ -1,72 +0,0 @@
/*
* 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.image;

// FOP
import org.apache.fop.apps.FOUserAgent;

/**
* Image cache holder.
* This interface is used for caching images.
*/
public interface ImageCache {
/**
* Get an image from the cache.
*
* @param url the url and key for the image
* @param context the user agent context
* @return the requested image
*/
FopImage getImage(String url, FOUserAgent context);

/**
* Release an image in the current context.
*
* @param url the url and key for the image
* @param context the user agent context
*/
void releaseImage(String url, FOUserAgent context);

/**
* Invalidate image.
* If during loading this image is found to be invalid
* it will be invalidated to prevent further attempts at
* loading the image.
*
* @param url the url and key for the image
* @param context the user agent context
*/
void invalidateImage(String url, FOUserAgent context);

/**
* Remove a context and handle all images in the context.
*
* @param context the user agent context
*/
void removeContext(FOUserAgent context);
/**
* Forces the cache to fully cleared.
*/
void clearAll();
}


+ 0
- 708
src/java/org/apache/fop/image/ImageFactory.java View File

@@ -1,708 +0,0 @@
/*
* 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.image;

// Java
import java.io.InputStream;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.image.analyser.ImageReaderFactory;
import org.apache.xmlgraphics.util.Service;

/**
* Create FopImage objects (with a configuration file - not yet implemented).
* @author Eric SCHAEFFER
*/
public final class ImageFactory {

/**
* logging instance
*/
protected static Log log = LogFactory.getLog(FopImage.class);
private HashMap imageMimeTypes = new HashMap();
private ImageCache cache = new ContextImageCache(true);

/**
* Main constructor for the ImageFactory.
*/
public ImageFactory() {
/* @todo The mappings set up below of image mime types to implementing
* classes should be made externally configurable
*/
ImageProvider jaiImage = new ImageProvider("JAIImage", "org.apache.fop.image.JAIImage");
ImageProvider jimiImage = new ImageProvider("JIMIImage", "org.apache.fop.image.JimiImage");
ImageProvider imageIoImage = new ImageProvider(
"ImageIOImage", "org.apache.fop.image.ImageIOImage");
ImageProvider gifImage = new ImageProvider("GIFImage", "org.apache.fop.image.GifImage");
ImageProvider jpegImage = new ImageProvider("JPEGImage", "org.apache.fop.image.JpegImage");
ImageProvider jpegImageIOImage = new ImageProvider(
"JPEGImage", "org.apache.fop.image.JpegImageIOImage");
ImageProvider bmpImage = new ImageProvider("BMPImage", "org.apache.fop.image.BmpImage");
ImageProvider epsImage = new ImageProvider("EPSImage", "org.apache.fop.image.EPSImage");
ImageProvider pngImage = new ImageProvider("PNGImage", "org.apache.fop.image.PNGImage");
ImageProvider tiffImage = new ImageProvider("TIFFImage", "org.apache.fop.image.TIFFImage");
ImageProvider xmlImage = new ImageProvider("XMLImage", "org.apache.fop.image.XMLImage");
ImageProvider emfImage = new ImageProvider("EMFImage", "org.apache.fop.image.EmfImage");
ImageMimeType imt = new ImageMimeType("image/gif");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(imageIoImage);
imt.addProvider(jaiImage);
imt.addProvider(jimiImage);
imt.addProvider(gifImage);

imt = new ImageMimeType("image/jpeg");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(jpegImageIOImage);
imt.addProvider(jpegImage);

imt = new ImageMimeType("image/bmp");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(bmpImage);

imt = new ImageMimeType("image/eps");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(epsImage);

imt = new ImageMimeType("image/png");
imageMimeTypes.put(imt.getMimeType(), imt);
//Image I/O is faster and more memory-efficient than own codec for PNG
imt.addProvider(imageIoImage);
imt.addProvider(pngImage);

imt = new ImageMimeType("image/tga");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(jaiImage);
imt.addProvider(imageIoImage);
imt.addProvider(jimiImage);

imt = new ImageMimeType("image/tiff");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(tiffImage); //Slower but supports CCITT embedding
imt.addProvider(imageIoImage); //Fast but doesn't support CCITT embedding
imt.addProvider(jaiImage); //Fast but doesn't support CCITT embedding

imt = new ImageMimeType("image/svg+xml");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(xmlImage);

imt = new ImageMimeType("text/xml");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(xmlImage);
imt = new ImageMimeType("image/emf");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(emfImage);

Iterator iter = Service.providers(RegisterableImageProvider.class, true);
while (iter.hasNext()) {
RegisterableImageProvider impl = (RegisterableImageProvider)iter.next();
imt = new ImageMimeType(impl.getSupportedMimeType());
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(new ImageProvider(impl.getName(), impl.getClassName()));
}
}

/**
* Get the url string from a wrapped url.
*
* @param href the input wrapped url
* @return the raw url
*/
public static String getURL(String href) {
return URISpecification.getURL(href);
}

/**
* Get the image from the cache or load.
* If this returns null then the image could not be loaded
* due to an error. Messages should be logged.
* Before calling this the getURL(url) must be used.
*
* @param url the url for the image
* @param context the user agent context
* @return the fop image instance
*/
public FopImage getImage(String url, FOUserAgent context) {
return cache.getImage(url, context);
}

/**
* Release an image from the cache.
* This can be used if the renderer has its own cache of
* the image.
* The image should then be put into the weak cache.
*
* @param url the url for the image
* @param context the user agent context
*/
public void releaseImage(String url, FOUserAgent context) {
cache.releaseImage(url, context);
}

/**
* Release the context and all images in the context.
*
* @param context the context to remove
*/
public void removeContext(FOUserAgent context) {
cache.removeContext(context);
}

/**
* Create an FopImage objects.
* @param href the url for the image
* @param ua the user agent context
* @return the fop image instance
*/
public FopImage loadImage(String href, FOUserAgent ua) {

Source source = ua.resolveURI(href);
if (source == null) {
return null;
}
// Got a valid source, obtain an InputStream from it
InputStream in = null;
if (source instanceof StreamSource) {
in = ((StreamSource)source).getInputStream();
}
if (in == null) {
try {
in = new java.net.URL(source.getSystemId()).openStream();
} catch (Exception ex) {
log.error("Unable to obtain stream from id '"
+ source.getSystemId() + "'");
}
}
if (in == null) {
return null;
}

//Make sure the InputStream is decorated with a BufferedInputStream
if (!(in instanceof java.io.BufferedInputStream)) {
in = new java.io.BufferedInputStream(in);
}

// Check image type
FopImage.ImageInfo imgInfo = null;
try {
imgInfo = ImageReaderFactory.make(source.getSystemId(), in, ua);
} catch (Exception e) {
log.error("Error while recovering image information ("
+ href + ") : " + e.getMessage(), e);
return null;
}
if (imgInfo == null) {
try {
in.close();
in = null;
} catch (Exception e) {
log.debug("Error closing the InputStream for the image", e);
}
log.error("No ImageReader for this type of image (" + href + ")");
return null;
}
// Associate mime-type to FopImage class
String imgMimeType = imgInfo.mimeType;
Class imageClass = getImageClass(imgMimeType);
if (imageClass == null) {
log.error("Unsupported image type (" + href + "): " + imgMimeType);
return null;
} else {
if (log.isDebugEnabled()) {
log.debug("Loading " + imgMimeType + " with " + imageClass.getName()
+ ": " + href);
}
}

// load the right image class
// return new <FopImage implementing class>
Object imageInstance = null;
try {
Class[] imageConstructorParameters = new Class[1];
imageConstructorParameters[0] = org.apache.fop.image.FopImage.ImageInfo.class;
Constructor imageConstructor = imageClass.getDeclaredConstructor(
imageConstructorParameters);
Object[] initArgs = new Object[1];
initArgs[0] = imgInfo;
imageInstance = imageConstructor.newInstance(initArgs);
} catch (java.lang.reflect.InvocationTargetException ex) {
Throwable t = ex.getTargetException();
String msg;
if (t != null) {
msg = t.getMessage();
} else {
msg = ex.getMessage();
}
log.error("Error creating FopImage object ("
+ href + "): " + msg, (t == null) ? ex : t);
return null;
} catch (InstantiationException ie) {
log.error("Error creating FopImage object ("
+ href + "): Could not instantiate " + imageClass.getName() + " instance");
return null;
} catch (Exception ex) {
log.error("Error creating FopImage object ("
+ href + "): " + ex.getMessage(), ex);
return null;
}
if (!(imageInstance instanceof org.apache.fop.image.FopImage)) {
log.error("Error creating FopImage object (" + href + "): " + "class "
+ imageClass.getName()
+ " doesn't implement org.apache.fop.image.FopImage interface");
return null;
}
return (FopImage) imageInstance;
}

private Class getImageClass(String imgMimeType) {
ImageMimeType imt = (ImageMimeType)imageMimeTypes.get(imgMimeType);
if (imt == null) {
return null;
}
return imt.getFirstImplementingClass();
}
/**
* Forces all the image caches to be cleared. This should normally only be used in
* testing environments. If you happen to think that you need to call this yourself
* in a production environment, please notify the development team so we can look
* into the issue. A call like this shouldn't be necessary anymore like it may have
* been with FOP 0.20.5.
*/
public void clearCaches() {
cache.clearAll();
}
}

/**
* Basic image cache.
* This keeps track of invalid images.
*/
class BasicImageCache implements ImageCache {

private Set invalid = Collections.synchronizedSet(new java.util.HashSet());
//private Map contextStore = Collections.synchronizedMap(new java.util.HashMap());

public FopImage getImage(String url, FOUserAgent context) {
if (invalid.contains(url)) {
return null;
}
//TODO Doesn't seem to be fully implemented. Do we need it at all? Not referenced.
return null;
}

public void releaseImage(String url, FOUserAgent context) {
// do nothing
}

public void invalidateImage(String url, FOUserAgent context) {
// cap size of invalid list
if (invalid.size() > 100) {
invalid.clear();
}
invalid.add(url);
}

public void removeContext(FOUserAgent context) {
// do nothing
}

/** {@inheritDoc} */
public void clearAll() {
invalid.clear();
}
}

/**
* This is the context image cache.
* This caches images on the basis of the given context.
* Common images in different contexts are currently not handled.
* There are two possiblities, each context handles its own images
* and renderers can cache information or images are shared and
* all information is retained.
* Once a context is removed then all images are placed into a
* weak hashmap so they may be garbage collected.
*/
class ContextImageCache implements ImageCache {

// if this cache is collective then images can be shared
// among contexts, this implies that the base directory
// is either the same or does not effect the images being
// loaded
private boolean collective;
private Map contextStore = Collections.synchronizedMap(new java.util.HashMap());
private Set invalid = null;
private Map refStore = null;
private ReferenceQueue refQueue = new ReferenceQueue();

public ContextImageCache(boolean col) {
collective = col;
if (collective) {
refStore = Collections.synchronizedMap(new java.util.HashMap());
invalid = Collections.synchronizedSet(new java.util.HashSet());
}
}

// sync around lookups and puts
// another sync around load for a particular image
public FopImage getImage(String url, FOUserAgent context) {
ImageLoader im = null;
// this protects the finding or creating of a new
// ImageLoader for multi threads
synchronized (this) {
if (collective && invalid.contains(url)) {
return null;
}
Context con = (Context) contextStore.get(context);
if (con == null) {
con = new Context(context, collective);
contextStore.put(context, con);
} else {
if (con.invalid(url)) {
return null;
}
im = con.getImage(url);
}
if (im == null && collective) {
Iterator i = contextStore.values().iterator();
while (i.hasNext()) {
Context c = (Context)i.next();
if (c != con) {
im = c.getImage(url);
if (im != null) {
break;
}
}
}
if (im == null) {
Reference ref = (Reference)refStore.get(url);
if (ref != null) {
im = (ImageLoader) ref.get();
if (im == null) {
//Remove key if its value has been garbage collected
refStore.remove(url);
}
}
}
}

if (im != null) {
con.putImage(url, im);
} else {
im = con.getImage(url, this);
}
}

// the ImageLoader is synchronized so images with the
// same url will not be loaded at the same time
if (im != null) {
return im.loadImage();
}
return null;
}

public void releaseImage(String url, FOUserAgent context) {
Context con = (Context) contextStore.get(context);
if (con != null) {
if (collective) {
ImageLoader im = con.getImage(url);
refStore.put(url, wrapInReference(im, url));
}
con.releaseImage(url);
}
}

public void invalidateImage(String url, FOUserAgent context) {
if (collective) {
// cap size of invalid list
if (invalid.size() > 100) {
invalid.clear();
}
invalid.add(url);
}
Context con = (Context) contextStore.get(context);
if (con != null) {
con.invalidateImage(url);
}
}

private Reference wrapInReference(Object obj, Object key) {
return new SoftReferenceWithKey(obj, key, refQueue);
}
private static class SoftReferenceWithKey extends SoftReference {
private Object key;
public SoftReferenceWithKey(Object referent, Object key, ReferenceQueue q) {
super(referent, q);
this.key = key;
}
}
public void removeContext(FOUserAgent context) {
Context con = (Context) contextStore.get(context);
if (con != null) {
if (collective) {
Map images = con.getImages();
Iterator iter = images.entrySet().iterator();
while (iter.hasNext()) {
Entry entry = (Entry)iter.next();
refStore.put(entry.getKey(),
wrapInReference(entry.getValue(), entry.getKey()));
}
}
contextStore.remove(context);
}
//House-keeping (remove cleared references)
checkReferenceQueue();
}
/**
* Checks the reference queue if any references have been cleared and removes them from the
* cache.
*/
private void checkReferenceQueue() {
SoftReferenceWithKey ref;
while ((ref = (SoftReferenceWithKey)refQueue.poll()) != null) {
refStore.remove(ref.key);
}
}

class Context {
private Map images = Collections.synchronizedMap(new java.util.HashMap());
private Set invalid = null;
private FOUserAgent userAgent;

public Context(FOUserAgent ua, boolean inv) {
userAgent = ua;
if (inv) {
invalid = Collections.synchronizedSet(new java.util.HashSet());
}
}

public ImageLoader getImage(String url, ImageCache c) {
if (images.containsKey(url)) {
return (ImageLoader) images.get(url);
}
ImageLoader loader = new ImageLoader(url, c, userAgent);
images.put(url, loader);
return loader;
}

public void putImage(String url, ImageLoader image) {
images.put(url, image);
}

public ImageLoader getImage(String url) {
return (ImageLoader) images.get(url);
}

public void releaseImage(String url) {
images.remove(url);
}

public Map getImages() {
return images;
}

public void invalidateImage(String url) {
invalid.add(url);
}

public boolean invalid(String url) {
return invalid.contains(url);
}

}

/** {@inheritDoc} */
public void clearAll() {
this.refStore.clear();
this.invalid.clear();
//The context-sensitive caches are not cleared so there are no negative side-effects
//in a multi-threaded environment. Not that it's a good idea to use this method at
//all except in testing environments. If such a calls is necessary in normal environments
//we need to check on memory leaks!
}

}

/**
* Encapsulates a class of type FopImage by holding its class name.
* This allows dynamic loading of the class at runtime.
*/
class ImageProvider {

private String name = null;

private String className = null;

private boolean checked = false;

private Class clazz = null;

/**
* Creates an ImageProvider with a given name and implementing class.
* The class name should refer to a class of type {@link FopImage}.
* However, this is not checked on construction.
* @param name The name of the provider
* @param className The full class name of the class implementing this provider
*/
public ImageProvider(String name, String className) {
setName(name);
setClassName(className);
}

/**
* Returns the provider name.
* @return The provider name
*/
public String getName() {
return name;
}

private void setName(String name) {
this.name = name;
}

/**
* Returns the implementing class name.
* @return The implementing class name
*/
public String getClassName() {
return className;
}

private void setClassName(String className) {
this.className = className;
}

/**
* Returns the implementing class as a {@link Class} object.
* @return The implementing class or null if it couldn't be loaded.
*/
public Class getImplementingClass() {
if (!checked) {
try {
clazz = Class.forName(getClassName());
} catch (ClassNotFoundException cnfe) {
//nop
} catch (LinkageError le) {
// This can happen if fop was build with support for a
// particular provider (e.g. a binary fop distribution)
// but the required support files (e.g. jai, jimi) are not
// available in the current runtime environment.
ImageFactory.log.debug("Image support provider " + getName()
+ " could not be loaded. If " + getName() + " should be"
+ " available please make sure all required external libraries"
+ " are on the classpath.");
}
checked = true;
}
return clazz;
}
}

/**
* Holds a mime type for a particular image format plus a list of
* {@link ImageProvider} objects which support the particular image format.
*/
class ImageMimeType {

private String mimeType = null;

private List providers = null;

/**
* Constructor for a particular mime type.
* @param mimeType The mime type
*/
public ImageMimeType(String mimeType) {
setMimeType(mimeType);
}

/**
* Returns the mime type.
* @return The mime type
*/
public String getMimeType() {
return mimeType;
}

private void setMimeType(String mimeType) {
this.mimeType = mimeType;
}

/**
* Returns the class from the first available provider.
* @return The first available class or null if none can be found
*/
public Class getFirstImplementingClass() {
if (providers == null) {
return null;
}
for (Iterator it = providers.iterator(); it.hasNext();) {
ImageProvider ip = (ImageProvider)it.next();
Class clazz = ip.getImplementingClass();
if (clazz != null) {
return clazz;
}
}
return null;
}

/**
* Adds a new provider.
* The provider is added to the end of the current provider list.
* @param The new provider to add
*/
public void addProvider(ImageProvider provider) {
if (providers == null) {
providers = new ArrayList(4); // Assume we only have a few providers
}
if (!providers.contains(provider)) {
providers.add(provider);
}
}
}

+ 0
- 64
src/java/org/apache/fop/image/ImageLoader.java View File

@@ -1,64 +0,0 @@
/*
* 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.image;

import org.apache.fop.apps.FOUserAgent;

/**
* Class to load images.
*/
class ImageLoader {
private String url;
private ImageCache cache;
private boolean valid = true;
private FOUserAgent userAgent;
private FopImage image = null;

/**
* Main constructor.
* @param url URL to the image
* @param cache Image cache
* @param ua User agent
*/
public ImageLoader(String url, ImageCache cache, FOUserAgent ua) {
this.url = url;
this.cache = cache;
this.userAgent = ua;
}

/**
* Loads the image.
* @return the loaded image
*/
public synchronized FopImage loadImage() {
if (!valid || image != null) {
return image;
}
ImageFactory imageFactory = userAgent.getFactory().getImageFactory();
image = imageFactory.loadImage(url, userAgent);
if (image == null) {
cache.invalidateImage(url, userAgent);
valid = false;
}
return image;
}

}

+ 0
- 194
src/java/org/apache/fop/image/JAIImage.java View File

@@ -1,194 +0,0 @@
/*
* 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.image;

// AWT
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.BufferedImage;
import java.awt.Color;

// JAI
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;

import org.apache.commons.io.IOUtils;
// Sun codec
import com.sun.media.jai.codec.FileCacheSeekableStream;

/**
* FopImage object using JAI.
*
* @see AbstractFopImage
* @see FopImage
*/
public class JAIImage extends AbstractFopImage {

/**
* Create a new JAI image.
*
* @param imgInfo the image info for this JAI image
*/
public JAIImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* {@inheritDoc}
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
loadImage();
}
return this.bitmaps != null;
}
/**
* {@inheritDoc}
*/
protected boolean loadBitmap() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* Loads the image from the inputstream
*/
protected void loadImage() {
com.sun.media.jai.codec.FileCacheSeekableStream seekableInput = null;
RenderedOp imageOp = null;
try {
seekableInput = new FileCacheSeekableStream(inputStream);
imageOp = JAI.create("stream", seekableInput);

this.height = imageOp.getHeight();
this.width = imageOp.getWidth();

ColorModel cm = imageOp.getColorModel();
//this.bitsPerPixel = 8;
this.bitsPerPixel = cm.getPixelSize();
// TODO: the getRGB() function converts the image into the RGB
// colorspace. However, here we assume the image colorspace is kept.
// It should be either one of them, but not both. Unfortunately
// there are other hacks for images in the CMYK colorspace (e.g. in
// the PDF output) that would need to be changed as well.
//this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
this.colorSpace = cm.getColorSpace();
BufferedImage imageData = imageOp.getAsBufferedImage();
int[] tmpMap = imageData.getRGB(0, 0, this.width,
this.height, null, 0, this.width);

if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();

if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
* // or use special API...
*/
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF);
}
}

} catch (Exception ex) {
log.error("Error while loading image (JAI): " + ex.getMessage(), ex);
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
if (imageOp != null) {
imageOp.dispose();
}
if (seekableInput != null) {
IOUtils.closeQuietly(seekableInput);
}
}
}

/** {@inheritDoc} */
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
}


+ 0
- 186
src/java/org/apache/fop/image/JimiImage.java View File

@@ -1,186 +0,0 @@
/*
* 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.image;

// Java
import java.awt.image.ImageProducer;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.color.ColorSpace;
import java.awt.Color;

import org.apache.commons.io.IOUtils;

// Jimi
import com.sun.jimi.core.Jimi;

/**
* FopImage object for several images types, using Jimi.
* See Jimi documentation for supported image types.
*
* @see AbstractFopImage
* @see FopImage
*/
public class JimiImage extends AbstractFopImage {

/**
* Create a new Jimi image.
*
* @param imgInfo the image info for this Jimi image
*/
public JimiImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* {@inheritDoc}
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* {@inheritDoc}
*/
protected boolean loadBitmap() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* Loads the image from the inputstream
*/
protected void loadImage() {
int[] tmpMap = null;
try {
ImageProducer ip = Jimi.getImageProducer(inputStream,
Jimi.SYNCHRONOUS | Jimi.IN_MEMORY);
FopImageConsumer consumer = new FopImageConsumer(ip);
ip.startProduction(consumer);

while (!consumer.isImageReady()) {
Thread.sleep(500);
}
this.height = consumer.getHeight();
this.width = consumer.getWidth();

try {
tmpMap = consumer.getImage();
} catch (Exception ex) {
log.error("Image grabbing interrupted", ex);
return;
}

ColorModel cm = consumer.getColorModel();
this.bitsPerPixel = 8;
// this.bitsPerPixel = cm.getPixelSize();
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();
if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
*/
// use special API...
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} catch (Throwable ex) {
log.error("Error while loading image (Jimi): " + ex.getMessage(), ex);
return;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}


// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF);
}
}
}

/** {@inheritDoc} */
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
}


+ 0
- 239
src/java/org/apache/fop/image/JpegImage.java View File

@@ -1,239 +0,0 @@
/*
* 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.image;

import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.fop.util.CMYKColorSpace;

/**
* FopImage object for JPEG images, Using Java native classes.
*
* @see AbstractFopImage
* @see FopImage
*/
public class JpegImage extends AbstractFopImage {
private ICC_Profile iccProfile = null;
private boolean foundICCProfile = false;
private boolean hasAPPEMarker = false;

/**
* Create a jpeg image with the info.
*
* @param imgInfo the image info for this jpeg
*/
public JpegImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the original jpeg data.
* This loads the original jpeg data and reads the color space,
* and icc profile if any.
*
* @return true if loaded false for any error
*/
protected boolean loadOriginalData() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayOutputStream iccStream = null;
int index = 0;
boolean cont = true;

try {
byte[] readBuf = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(readBuf)) != -1) {
baos.write(readBuf, 0, bytesRead);
}
} catch (java.io.IOException ex) {
log.error("Error while loading image (Jpeg): " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

this.raw = baos.toByteArray();
this.bitsPerPixel = 8;
this.isTransparent = false;

//Check for SOI (Start of image) marker (FFD8)
if (this.raw.length > (index + 2)
&& uByte(this.raw[index]) == 255 /*0xFF*/
&& uByte(this.raw[index + 1]) == 216 /*0xD8*/) {
index += 2;

while (index < this.raw.length && cont) {
//check to be sure this is the begining of a header
if (this.raw.length > (index + 2)
&& uByte(this.raw[index]) == 255 /*0xFF*/) {

//192 or 194 are the header bytes that contain
// the jpeg width height and color depth.
if (uByte(this.raw[index + 1]) == 192 /*0xC0*/
|| uByte(this.raw[index + 1]) == 194 /*0xC2*/) {

this.height = calcBytes(this.raw[index + 5],
this.raw[index + 6]);
this.width = calcBytes(this.raw[index + 7],
this.raw[index + 8]);

int numComponents = this.raw[index + 9];
if (numComponents == 1) {
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_GRAY);
} else if (numComponents == 3) {
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_LINEAR_RGB);
} else if (numComponents == 4) {
// howto create CMYK color space
/*
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_CIEXYZ);
*/
this.colorSpace = CMYKColorSpace.getInstance();
} else {
log.error("Unknown ColorSpace for image: "
+ "");
return false;
}

if (foundICCProfile) {
cont = false;
break;
}
index += calcBytes(this.raw[index + 2],
this.raw[index + 3]) + 2;

} else if (uByte(this.raw[index + 1]) == 226 /*0xE2*/
&& this.raw.length > (index + 60)) {
// Check if ICC profile
byte[] iccString = new byte[11];
System.arraycopy(this.raw, index + 4,
iccString, 0, 11);

if ("ICC_PROFILE".equals(new String(iccString))) {
int chunkSize = calcBytes(
this.raw[index + 2],
this.raw[index + 3]) + 2;

if (iccStream == null) {
iccStream = new ByteArrayOutputStream();
}
iccStream.write(this.raw,
index + 18, chunkSize - 18);

}

index += calcBytes(this.raw[index + 2],
this.raw[index + 3]) + 2;
// Check for Adobe APPE Marker
} else if ((uByte(this.raw[index]) == 0xff
&& uByte(this.raw[index + 1]) == 0xee
&& uByte(this.raw[index + 2]) == 0
&& uByte(this.raw[index + 3]) == 14
&& "Adobe".equals(new String(this.raw, index + 4, 5)))) {
// The reason for reading the APPE marker is that Adobe Photoshop
// generates CMYK JPEGs with inverted values. The correct thing
// to do would be to interpret the values in the marker, but for now
// only assume that if APPE marker is present and colorspace is CMYK,
// the image is inverted.
hasAPPEMarker = true;

index += calcBytes(this.raw[index + 2],
this.raw[index + 3]) + 2;
} else {
index += calcBytes(this.raw[index + 2],
this.raw[index + 3]) + 2;
}

} else {
cont = false;
}
}
} else {
log.error("Error while loading "
+ "JpegImage - Invalid JPEG Header.");
return false;
}
if (iccStream != null && iccStream.size() > 0) {
int padding = (8 - (iccStream.size() % 8)) % 8;
if (padding != 0) {
try {
iccStream.write(new byte[padding]);
} catch (Exception ex) {
log.error("Error while aligning ICC stream: " + ex.getMessage(), ex);
return false;
}
}
try {
iccProfile = ICC_Profile.getInstance(iccStream.toByteArray());
} catch (IllegalArgumentException iae) {
log.warn("An ICC profile is present but it is invalid ("
+ iae.getMessage() + "). The color profile will be ignored. ("
+ this.getOriginalURI() + ")");
}
if (iccProfile.getNumComponents() != this.colorSpace.getNumComponents()) {
log.warn("The number of components of the ICC profile ("
+ iccProfile.getNumComponents()
+ ") doesn't match the image ("
+ this.colorSpace.getNumComponents()
+ "). Ignoring the ICC color profile.");
this.iccProfile = null;
}
} else if (this.colorSpace == null) {
log.error("ColorSpace not specified for JPEG image");
return false;
}
if (hasAPPEMarker && this.colorSpace.getType() == ColorSpace.TYPE_CMYK) {
if (log.isDebugEnabled()) {
log.debug("JPEG has an Adobe APPE marker. Note: CMYK Image will be inverted. ("
+ this.getOriginalURI() + ")");
}
this.invertImage = true;
}
return true;
}

/**
* Get the ICC profile for this Jpeg image.
*
* @return the icc profile or null if not found
*/
public ICC_Profile getICCProfile() {
return iccProfile;
}

private int calcBytes(byte bOne, byte bTwo) {
return (uByte(bOne) * 256) + uByte(bTwo);
}

private int uByte(byte bIn) {
if (bIn < 0) {
return 256 + bIn;
} else {
return bIn;
}
}
}


+ 0
- 87
src/java/org/apache/fop/image/PNGImage.java View File

@@ -1,87 +0,0 @@
/*
* 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.image;

import java.io.IOException;

import org.apache.xmlgraphics.image.codec.png.PNGRed;
import org.apache.xmlgraphics.image.codec.png.PNGDecodeParam;
import org.apache.xmlgraphics.image.codec.util.SeekableStream;
import org.apache.xmlgraphics.image.rendered.CachableRed;
import org.apache.commons.io.IOUtils;

/**
* FopImage object using PNG
*
* @see AbstractFopImage
* @see FopImage
*/
public class PNGImage extends XmlGraphicsCommonsImage {

/**
* Constructs a new PNGImage instance.
* @param imgReader basic metadata for the image
*/
public PNGImage(FopImage.ImageInfo imgReader) {
super(imgReader);
this.loaded = 0; //TODO The PNGReader cannot read the resolution, yet.
}

/**
* {@inheritDoc}
*/
protected CachableRed decodeImage(SeekableStream stream) throws IOException {
PNGDecodeParam param = new PNGDecodeParam();
param.setPerformGammaCorrection(true);
param.setDisplayExponent(2.2f); // sRGB gamma
PNGRed red = new PNGRed(stream, param);
String unit = (String)red.getProperty("pixel_units");
if ("Meters".equals(unit)) {
this.dpiHorizontal = ((Integer)red.getProperty("x_pixels_per_unit")).intValue()
* 25.4f / 1000f;
this.dpiVertical = ((Integer)red.getProperty("y_pixels_per_unit")).intValue()
* 25.4f / 1000f;
}
return red;
}
/**
* Load the original PNG data.
* This loads the original PNG data as is into memory.
*
* @return true if loaded false for any error
*/
protected boolean loadOriginalData() {
try {
seekableInput.seek(0);
this.raw = IOUtils.toByteArray(seekableInput);
} catch (java.io.IOException ex) {
log.error("Error while loading raw image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

return true;
}
}

+ 0
- 49
src/java/org/apache/fop/image/RegisterableImageProvider.java View File

@@ -1,49 +0,0 @@
/*
* 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.image;

/**
* This interface is used to dynamically register FopImage implementations.
* <p>
* NOTE: Please don't rely on this interface too much. It is a temporary measure
* until the whole image package can be redesigned. The redesign will likely
* provide a different mechanism to dynamically register new implementations.
*/
public interface RegisterableImageProvider {

/**
* Returns the MIME type the implementation supports.
* @return the MIME type
*/
String getSupportedMimeType();
/**
* Returns the name of the implementation.
* @return the name
*/
String getName();
/**
* Returns the fully qualified class name for the implementing class.
* @return the class name
*/
String getClassName();

}

+ 0
- 207
src/java/org/apache/fop/image/TIFFImage.java View File

@@ -1,207 +0,0 @@
/*
* 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.image;

import java.awt.color.ColorSpace;
import java.io.IOException;

import org.apache.xmlgraphics.image.codec.util.SeekableStream;
import org.apache.xmlgraphics.image.codec.tiff.TIFFDirectory;
import org.apache.xmlgraphics.image.codec.tiff.TIFFField;
import org.apache.xmlgraphics.image.codec.tiff.TIFFImageDecoder;
import org.apache.xmlgraphics.image.rendered.CachableRed;
import org.apache.commons.io.IOUtils;

/**
* TIFF implementation using the Batik codecs.
*/
public class TIFFImage extends XmlGraphicsCommonsImage {

private int compression = 0;
private int stripCount = 0;
private long stripOffset = 0;
private long stripLength = 0;
private int fillOrder = 1;

/**
* Constructs a new BatikImage instance.
* @param imgReader basic metadata for the image
*/
public TIFFImage(FopImage.ImageInfo imgReader) {
super(imgReader);
}

/**
* The compression type set in the TIFF directory
* @return the TIFF compression type
*/
public int getCompression() {
return compression;
}

/**
* The number of strips in the image
* @return the number of strips in the image
*/
public int getStripCount() {
return stripCount;
}

/**
* {@inheritDoc}
* org.apache.xmlgraphics.image.codec.util.SeekableStream)
*/
protected CachableRed decodeImage(SeekableStream stream) throws IOException {
org.apache.xmlgraphics.image.codec.tiff.TIFFImage img
= new org.apache.xmlgraphics.image.codec.tiff.TIFFImage
(stream, null, 0);
TIFFDirectory dir = (TIFFDirectory)img.getProperty("tiff_directory");
TIFFField fld = dir.getField(TIFFImageDecoder.TIFF_RESOLUTION_UNIT);
int resUnit = fld.getAsInt(0);
fld = dir.getField(TIFFImageDecoder.TIFF_X_RESOLUTION);
double xRes = fld.getAsDouble(0);
fld = dir.getField(TIFFImageDecoder.TIFF_Y_RESOLUTION);
double yRes = fld.getAsDouble(0);
switch (resUnit) {
case 2: //inch
this.dpiHorizontal = xRes;
this.dpiVertical = yRes;
break;
case 3: //cm
this.dpiHorizontal = xRes * 2.54f;
this.dpiVertical = yRes * 2.54f;
break;
default:
//ignored
log.warn("Cannot determine bitmap resolution."
+ " Unimplemented resolution unit: " + resUnit);
}
fld = dir.getField(TIFFImageDecoder.TIFF_COMPRESSION);
if (fld != null) {
compression = fld.getAsInt(0);
}
fld = dir.getField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE);
if (fld != null) {
bitsPerPixel = fld.getAsInt(0);
}
fld = dir.getField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP);
if (fld == null) {
stripCount = 1;
} else {
stripCount = (int)(dir.getFieldAsLong(TIFFImageDecoder.TIFF_IMAGE_LENGTH)
/ fld.getAsLong(0));
}

fld = dir.getField(TIFFImageDecoder.TIFF_FILL_ORDER);
if (fld != null) {
fillOrder = fld.getAsInt(0);
}

stripOffset = dir.getField(TIFFImageDecoder.TIFF_STRIP_OFFSETS).getAsLong(0);
stripLength = dir.getField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS).getAsLong(0);
if (this.bitsPerPixel == 1) {
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
}
return img;
}

/**
* Load the original TIFF data.
* This loads only strip 1 of the original TIFF data.
*
* @return true if loaded false for any error
* {@inheritDoc}
*/
protected boolean loadOriginalData() {
if (loadDimensions()) {
byte[] readBuf = new byte[(int)stripLength];
int bytesRead;

try {
this.seekableInput.reset();
this.seekableInput.skip(stripOffset);
bytesRead = seekableInput.read(readBuf);
if (bytesRead != stripLength) {
log.error("Error while loading image: length mismatch on read");
return false;
}

// need to invert bytes if fill order = 2
if (fillOrder == 2) {
for (int i = 0; i < (int)stripLength; i++) {
readBuf[i] = flipTable[readBuf[i] & 0xff];
}
}
this.raw = readBuf;

return true;
} catch (IOException ioe) {
log.error("Error while loading image strip 1 (TIFF): ", ioe);
return false;
} finally {
IOUtils.closeQuietly(seekableInput);
IOUtils.closeQuietly(inputStream);
this.seekableInput = null;
this.inputStream = null;
this.cr = null;
}
}
return false;
}

// Table to be used when fillOrder = 2, for flipping bytes.
// Copied from XML Graphics Commons' TIFFFaxDecoder class
private static byte[] flipTable = {
0, -128, 64, -64, 32, -96, 96, -32,
16, -112, 80, -48, 48, -80, 112, -16,
8, -120, 72, -56, 40, -88, 104, -24,
24, -104, 88, -40, 56, -72, 120, -8,
4, -124, 68, -60, 36, -92, 100, -28,
20, -108, 84, -44, 52, -76, 116, -12,
12, -116, 76, -52, 44, -84, 108, -20,
28, -100, 92, -36, 60, -68, 124, -4,
2, -126, 66, -62, 34, -94, 98, -30,
18, -110, 82, -46, 50, -78, 114, -14,
10, -118, 74, -54, 42, -86, 106, -22,
26, -102, 90, -38, 58, -70, 122, -6,
6, -122, 70, -58, 38, -90, 102, -26,
22, -106, 86, -42, 54, -74, 118, -10,
14, -114, 78, -50, 46, -82, 110, -18,
30, -98, 94, -34, 62, -66, 126, -2,
1, -127, 65, -63, 33, -95, 97, -31,
17, -111, 81, -47, 49, -79, 113, -15,
9, -119, 73, -55, 41, -87, 105, -23,
25, -103, 89, -39, 57, -71, 121, -7,
5, -123, 69, -59, 37, -91, 101, -27,
21, -107, 85, -43, 53, -75, 117, -11,
13, -115, 77, -51, 45, -83, 109, -19,
29, -99, 93, -35, 61, -67, 125, -3,
3, -125, 67, -61, 35, -93, 99, -29,
19, -109, 83, -45, 51, -77, 115, -13,
11, -117, 75, -53, 43, -85, 107, -21,
27, -101, 91, -37, 59, -69, 123, -5,
7, -121, 71, -57, 39, -89, 103, -25,
23, -105, 87, -41, 55, -73, 119, -9,
15, -113, 79, -49, 47, -81, 111, -17,
31, -97, 95, -33, 63, -65, 127, -1,
};
// end
}

+ 0
- 78
src/java/org/apache/fop/image/XMLImage.java View File

@@ -1,78 +0,0 @@
/*
* 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.image;

// Java
import org.w3c.dom.Document;
import javax.xml.parsers.SAXParserFactory;

/**
* This is an implementation for XML-based images such as SVG.
*
* @see AbstractFopImage
* @see FopImage
*/
public class XMLImage extends AbstractFopImage {

private Document doc;
private String namespace = "";

/**
* @see org.apache.fop.image.AbstractFopImage#AbstractFopImage(FopImage.ImageInfo)
*/
public XMLImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
if (imgInfo.data instanceof Document) {
doc = (Document)imgInfo.data;
loaded = loaded | ORIGINAL_DATA;
}
namespace = imgInfo.str;
}

/**
* Returns the fully qualified classname of an XML parser for
* Batik classes that apparently need it (error messages, perhaps)
* @return an XML parser classname
*/
public static String getParserName() {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
return factory.newSAXParser().getXMLReader().getClass().getName();
} catch (Exception e) {
return null;
}
}

/**
* Returns the XML document as a DOM document.
* @return the DOM document
*/
public Document getDocument() {
return this.doc;
}

/**
* Returns the namespace of the XML document.
* @return the namespace
*/
public String getNameSpace() {
return this.namespace;
}
}

+ 0
- 239
src/java/org/apache/fop/image/XmlGraphicsCommonsImage.java View File

@@ -1,239 +0,0 @@
/*
* 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.image;

import java.awt.Color;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.BufferedImage;
import java.io.IOException;

import org.apache.xmlgraphics.image.GraphicsUtil;
import org.apache.xmlgraphics.image.codec.util.SeekableStream;
import org.apache.xmlgraphics.image.codec.util.MemoryCacheSeekableStream;
import org.apache.xmlgraphics.image.codec.util.FileCacheSeekableStream;
import org.apache.xmlgraphics.image.rendered.CachableRed;

import org.apache.commons.io.IOUtils;

/**
* Abstract FopImage implementation which uses the internal codecs from XML Graphics Commons.
*
* @see AbstractFopImage
* @see FopImage
*/
public abstract class XmlGraphicsCommonsImage extends AbstractFopImage {

private byte[] softMask = null;

/**
* The InputStream wrapped into a SeekableStream for decoding.
*/
protected SeekableStream seekableInput = null;

/**
* The Batik representation of the image
*/
protected CachableRed cr = null;
/**
* Constructs a new BatikImage instance.
* @param imgReader basic metadata for the image
*/
public XmlGraphicsCommonsImage(FopImage.ImageInfo imgReader) {
super(imgReader);
}

/**
* {@inheritDoc}
*/
protected boolean loadDimensions() {
if (seekableInput == null && inputStream != null) {
try {
seekableInput = new FileCacheSeekableStream(inputStream);
} catch (IOException ioe) {
seekableInput = new MemoryCacheSeekableStream(inputStream);
}
try {
this.bitsPerPixel = 8;
cr = decodeImage(seekableInput);
this.height = cr.getHeight();
this.width = cr.getWidth();
this.isTransparent = false;
this.softMask = null;
ColorModel cm = cr.getColorModel();

this.height = cr.getHeight();
this.width = cr.getWidth();
this.isTransparent = false;
this.softMask = null;

int transparencyType = cm.getTransparency();
if (cm instanceof IndexColorModel) {
if (transparencyType == Transparency.BITMASK) {
// Use 'transparent color'.
IndexColorModel icm = (IndexColorModel)cm;
int numColor = icm.getMapSize();
byte [] alpha = new byte[numColor];
icm.getAlphas(alpha);
for (int i = 0; i < numColor; i++) {
if ((alpha[i] & 0xFF) == 0) {
this.isTransparent = true;
int red = (icm.getRed (i)) & 0xFF;
int grn = (icm.getGreen(i)) & 0xFF;
int blu = (icm.getBlue (i)) & 0xFF;
this.transparentColor = new Color(red, grn, blu);
break;
}
}
}
} else {
cr = GraphicsUtil.convertTosRGB(cr);
}

// Get our current ColorModel
cm = cr.getColorModel();
if (this.colorSpace == null) {
this.colorSpace = cm.getColorSpace();
}
} catch (IOException ioe) {
log.error("Error while loading image (Batik): " + ioe.getMessage(), ioe);
IOUtils.closeQuietly(seekableInput);
IOUtils.closeQuietly(inputStream);
seekableInput = null;
inputStream = null;
return false;
}
}
return this.height != -1;
}

/**
* {@inheritDoc}
*/
protected boolean loadBitmap() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* {@inheritDoc}
*/
public boolean hasSoftMask() {
if (this.bitmaps == null && this.raw == null) {
loadImage();
}

return (this.softMask != null);
}

/**
* {@inheritDoc}
*/
public byte[] getSoftMask() {
if (this.bitmaps == null) {
loadImage();
}

return this.softMask;
}

/**
* Decodes the image from the stream.
* @param stream the stream to read the image from
* @return the decoded image
* @throws IOException in case an I/O problem occurs
*/
protected abstract CachableRed decodeImage(SeekableStream stream) throws IOException;
/**
* Loads the image from the InputStream.
*/
protected void loadImage() {
if (loadDimensions()) {
try {
if (cr == null) {
throw new IllegalStateException(
"Can't load the bitmaps data without the CachableRed instance");
}
// Get our current ColorModel
ColorModel cm = cr.getColorModel();

// It has an alpha channel so generate a soft mask.
if (!this.isTransparent && cm.hasAlpha()) {
this.softMask = new byte[this.width * this.height];
}

this.bitmaps = new byte[this.width * this.height * 3];

constructBitmaps(cr, this.bitmaps, this.softMask);
} catch (Exception ex) {
log.error("Error while loading image (Batik): " + ex.getMessage(), ex);
} finally {
// Make sure we clean up
IOUtils.closeQuietly(seekableInput);
IOUtils.closeQuietly(inputStream);
seekableInput = null;
inputStream = null;
cr = null;
}
}
}

private static void constructBitmaps(RenderedImage red, byte[] bitmaps, byte[] softMask) {
WritableRaster wr = (WritableRaster)red.getData();
ColorModel cm = red.getColorModel();
BufferedImage bi = new BufferedImage
(cm, wr.createWritableTranslatedChild(0, 0),
cm.isAlphaPremultiplied(), null);
int width = red.getWidth();
int height = red.getHeight();
int [] tmpMap = new int[width];
int idx = 0;
int sfIdx = 0;
for (int y = 0; y < height; y++) {
tmpMap = bi.getRGB(0, y, width, 1, tmpMap, 0, width);
if (softMask != null) {
for (int x = 0; x < width; x++) {
int pix = tmpMap[x];
softMask[sfIdx++] = (byte)(pix >>> 24);
bitmaps[idx++] = (byte)((pix >>> 16) & 0xFF);
bitmaps[idx++] = (byte)((pix >>> 8) & 0xFF);
bitmaps[idx++] = (byte)((pix) & 0xFF);
}
} else {
for (int x = 0; x < width; x++) {
int pix = tmpMap[x];
bitmaps[idx++] = (byte)((pix >> 16) & 0xFF);
bitmaps[idx++] = (byte)((pix >> 8) & 0xFF);
bitmaps[idx++] = (byte)((pix) & 0xFF);
}
}
}
}
}

+ 0
- 134
src/java/org/apache/fop/image/analyser/BMPReader.java View File

@@ -1,134 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for BMP image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class BMPReader implements ImageReader {

/** Length of the BMP header */
protected static final int BMP_SIG_LENGTH = 46;
/** offset to width */
private static final int WIDTH_OFFSET = 18;
/** offset to height */
private static final int HEIGHT_OFFSET = 22;
/** offset to horizontal res */
private static final int HRES_OFFSET = 38;
/** offset to vertical res */
private static final int VRES_OFFSET = 42;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = ((header[0] == (byte) 0x42)
&& (header[1] == (byte) 0x4d));
if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/bmp";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// little endian notation
int byte1 = header[WIDTH_OFFSET] & 0xff;
int byte2 = header[WIDTH_OFFSET + 1] & 0xff;
int byte3 = header[WIDTH_OFFSET + 2] & 0xff;
int byte4 = header[WIDTH_OFFSET + 3] & 0xff;
long l = (long) ((byte4 << 24) | (byte3 << 16)
| (byte2 << 8) | byte1);
info.width = (int) (l & 0xffffffff);

byte1 = header[HEIGHT_OFFSET] & 0xff;
byte2 = header[HEIGHT_OFFSET + 1] & 0xff;
byte3 = header[HEIGHT_OFFSET + 2] & 0xff;
byte4 = header[HEIGHT_OFFSET + 3] & 0xff;
l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
info.height = (int) (l & 0xffffffff);

byte1 = header[HRES_OFFSET] & 0xff;
byte2 = header[HRES_OFFSET + 1] & 0xff;
byte3 = header[HRES_OFFSET + 2] & 0xff;
byte4 = header[HRES_OFFSET + 3] & 0xff;
l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
if (l > 0) {
info.dpiHorizontal = l / 39.37d;
}

byte1 = header[VRES_OFFSET] & 0xff;
byte2 = header[VRES_OFFSET + 1] & 0xff;
byte3 = header[VRES_OFFSET + 2] & 0xff;
byte4 = header[VRES_OFFSET + 3] & 0xff;
l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
if (l > 0) {
info.dpiVertical = l / 39.37d;
}
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[BMP_SIG_LENGTH];
try {
imageStream.mark(BMP_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}

+ 0
- 162
src/java/org/apache/fop/image/analyser/EMFReader.java View File

@@ -1,162 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for EMF image type.
*
* @author Peter Herweg
*/
public class EMFReader implements ImageReader {

/** Length of the EMF header */
protected static final int EMF_SIG_LENGTH = 88;
/** offset to signature */
private static final int SIGNATURE_OFFSET = 40;
/** offset to width */
private static final int WIDTH_OFFSET = 32;
/** offset to height */
private static final int HEIGHT_OFFSET = 36;
/** offset to horizontal resolution in pixel */
private static final int HRES_PIXEL_OFFSET = 72;
/** offset to vertical resolution in pixel */
private static final int VRES_PIXEL_OFFSET = 76;
/** offset to horizontal resolution in mm */
private static final int HRES_MM_OFFSET = 80;
/** offset to vertical resolution in mm */
private static final int VRES_MM_OFFSET = 84;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported
= ( (header[SIGNATURE_OFFSET + 0] == (byte) 0x20)
&& (header[SIGNATURE_OFFSET + 1] == (byte) 0x45)
&& (header[SIGNATURE_OFFSET + 2] == (byte) 0x4D)
&& (header[SIGNATURE_OFFSET + 3] == (byte) 0x46) );
if (supported) {
FopImage.ImageInfo info = getDimension(header);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/emf";
}

private FopImage.ImageInfo getDimension(byte[] header) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
long value = 0;
int byte1;
int byte2;
int byte3;
int byte4;
// little endian notation

//resolution
byte1 = header[HRES_MM_OFFSET] & 0xff;
byte2 = header[HRES_MM_OFFSET + 1] & 0xff;
byte3 = header[HRES_MM_OFFSET + 2] & 0xff;
byte4 = header[HRES_MM_OFFSET + 3] & 0xff;
long hresMM = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
byte1 = header[VRES_MM_OFFSET] & 0xff;
byte2 = header[VRES_MM_OFFSET + 1] & 0xff;
byte3 = header[VRES_MM_OFFSET + 2] & 0xff;
byte4 = header[VRES_MM_OFFSET + 3] & 0xff;
long vresMM = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
byte1 = header[HRES_PIXEL_OFFSET] & 0xff;
byte2 = header[HRES_PIXEL_OFFSET + 1] & 0xff;
byte3 = header[HRES_PIXEL_OFFSET + 2] & 0xff;
byte4 = header[HRES_PIXEL_OFFSET + 3] & 0xff;
long hresPixel = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
byte1 = header[VRES_PIXEL_OFFSET] & 0xff;
byte2 = header[VRES_PIXEL_OFFSET + 1] & 0xff;
byte3 = header[VRES_PIXEL_OFFSET + 2] & 0xff;
byte4 = header[VRES_PIXEL_OFFSET + 3] & 0xff;
long vresPixel = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
info.dpiHorizontal = hresPixel / (hresMM / 25.4f);
info.dpiVertical = vresPixel / (vresMM / 25.4f);
//width
byte1 = header[WIDTH_OFFSET] & 0xff;
byte2 = header[WIDTH_OFFSET + 1] & 0xff;
byte3 = header[WIDTH_OFFSET + 2] & 0xff;
byte4 = header[WIDTH_OFFSET + 3] & 0xff;
value = (long) ((byte4 << 24) | (byte3 << 16)
| (byte2 << 8) | byte1);
value = Math.round(value / 100f / 25.4f * info.dpiHorizontal);
info.width = (int) (value & 0xffffffff);

//height
byte1 = header[HEIGHT_OFFSET] & 0xff;
byte2 = header[HEIGHT_OFFSET + 1] & 0xff;
byte3 = header[HEIGHT_OFFSET + 2] & 0xff;
byte4 = header[HEIGHT_OFFSET + 3] & 0xff;
value = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
value = Math.round(value / 100f / 25.4f * info.dpiVertical);
info.height = (int) (value & 0xffffffff);

return info;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[EMF_SIG_LENGTH];
try {
imageStream.mark(EMF_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}
}

+ 0
- 253
src/java/org/apache/fop/image/analyser/EPSReader.java View File

@@ -1,253 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

// FOP
import org.apache.commons.io.IOUtils;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.EPSImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for EPS document image type.
*
* @version $Id$
*/
public class EPSReader implements ImageReader {

private static final byte[] EPS_HEADER_ASCII = "%!PS".getBytes();
private static final byte[] BOUNDINGBOX = "%%BoundingBox: ".getBytes();
//private static final byte[] HIRESBOUNDINGBOX = "%%HiResBoundingBox: ".getBytes();
//TODO Implement HiResBoundingBox, ImageInfo probably needs some changes for that

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {

boolean isEPS = false;

bis.mark(32);
byte[] header = new byte[30];
bis.read(header, 0, 30);
bis.reset();

EPSImage.EPSData data = new EPSImage.EPSData();

// Check if binary header
if (getLong(header, 0) == 0xC6D3D0C5) {
data.isAscii = false;
isEPS = true;

data.psStart = getLong(header, 4);
data.psLength = getLong(header, 8);
data.wmfStart = getLong(header, 12);
data.wmfLength = getLong(header, 16);
data.tiffStart = getLong(header, 20);
data.tiffLength = getLong(header, 24);

} else {
// Check if plain ascii
byte[] epsh = "%!PS".getBytes();
if (EPS_HEADER_ASCII[0] == header[0]
&& EPS_HEADER_ASCII[1] == header[1]
&& EPS_HEADER_ASCII[2] == header[2]
&& EPS_HEADER_ASCII[3] == header[3]) {
data.isAscii = true;
isEPS = true;
}
}

if (isEPS) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.originalURI = uri;
info.mimeType = getMimeType();
info.data = data;
readEPSImage(bis, data);
data.bbox = readBBox(data);

if (data.bbox != null) {
info.width = (int) (data.bbox[2] - data.bbox[0]);
info.height = (int) (data.bbox[3] - data.bbox[1]);

// image data read
IOUtils.closeQuietly(bis);
info.inputStream = null;

return info;
} else {
// Ain't eps if no BoundingBox
isEPS = false;
}
}

return null;
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/eps";
}

private long getLong(byte[] buf, int idx) {
int b1 = buf[idx] & 0xff;
int b2 = buf[idx + 1] & 0xff;
int b3 = buf[idx + 2] & 0xff;
int b4 = buf[idx + 3] & 0xff;

return (long) ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
}

/**
* Read the eps file and extract eps part.
*
* @param bis The InputStream
* @param data EPSData object to write the results to
* @exception IOException If an I/O error occurs
*/
private void readEPSImage(InputStream bis, EPSImage.EPSData data)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] file;
byte[] readBuf = new byte[20480];
int bytesRead;
int index = 0;
boolean cont = true;

try {
while ((bytesRead = bis.read(readBuf)) != -1) {
baos.write(readBuf, 0, bytesRead);
}
} catch (java.io.IOException ex) {
throw new IOException("Error while loading EPS image: "
+ ex.getMessage());
}

file = baos.toByteArray();

if (data.isAscii) {
data.rawEps = null;
data.epsFile = new byte[file.length];
System.arraycopy(file, 0, data.epsFile, 0, data.epsFile.length);
} else {
data.rawEps = new byte[file.length];
data.epsFile = new byte[(int) data.psLength];
System.arraycopy(file, 0, data.rawEps, 0, data.rawEps.length);
System.arraycopy(data.rawEps, (int) data.psStart, data.epsFile, 0,
(int) data.psLength);
}
}

/**
* Get embedded TIFF preview or null.
*
* @param data The EPS payload
* @return The embedded preview
*/
public byte[] getPreview(EPSImage.EPSData data) {
if (data.preview == null) {
if (data.tiffLength > 0) {
data.preview = new byte[(int) data.tiffLength];
System.arraycopy(data.rawEps, (int) data.tiffStart, data.preview, 0,
(int) data.tiffLength);
}
}
return data.preview;
}

/**
* Extract bounding box from eps part.
*
* @param data The EPS payload
* @return An Array of four coordinates making up the bounding box
*/
private long[] readBBox(EPSImage.EPSData data) {
long[] mbbox = null;
int idx = 0;
boolean found = false;

while (!found && (data.epsFile.length > (idx + BOUNDINGBOX.length))) {
boolean sfound = true;
int i = idx;
for (i = idx; sfound && (i - idx) < BOUNDINGBOX.length; i++) {
if (BOUNDINGBOX[i - idx] != data.epsFile[i]) {
sfound = false;
}
}
if (sfound) {
found = true;
idx = i;
} else {
idx++;
}
}

if (!found) {
return mbbox;
}

mbbox = new long[4];
idx += readLongString(data, mbbox, 0, idx);
idx += readLongString(data, mbbox, 1, idx);
idx += readLongString(data, mbbox, 2, idx);
idx += readLongString(data, mbbox, 3, idx);

return mbbox;
}

private int readLongString(EPSImage.EPSData data, long[] mbbox, int i, int idx) {
while (idx < data.epsFile.length && (data.epsFile[idx] == 32)) {
idx++;
}

int nidx = idx;

// check also for ANSI46(".") to identify floating point values
while (nidx < data.epsFile.length
&& ((data.epsFile[nidx] >= 48 && data.epsFile[nidx] <= 57)
|| (data.epsFile[nidx] == 45)
|| (data.epsFile[nidx] == 46))) {
nidx++;
}

byte[] num = new byte[nidx - idx];
System.arraycopy(data.epsFile, idx, num, 0, nidx - idx);
String ns = new String(num);

//if( ns.indexOf(".") != -1 ) {
// do something like logging a warning
//}

// then parse the double and round off to the next math. Integer
mbbox[i] = (long) Math.ceil(Double.parseDouble(ns));

return (1 + nidx - idx);
}

}


+ 0
- 104
src/java/org/apache/fop/image/analyser/GIFReader.java View File

@@ -1,104 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for GIF image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class GIFReader implements ImageReader {

private static final int GIF_SIG_LENGTH = 10;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = ((header[0] == 'G')
&& (header[1] == 'I')
&& (header[2] == 'F')
&& (header[3] == '8')
&& (header[4] == '7' || header[4] == '9')
&& (header[5] == 'a'));
if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/gif";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// little endian notation
int byte1 = header[6] & 0xff;
int byte2 = header[7] & 0xff;
info.width = ((byte2 << 8) | byte1) & 0xffff;

byte1 = header[8] & 0xff;
byte2 = header[9] & 0xff;
info.height = ((byte2 << 8) | byte1) & 0xffff;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[GIF_SIG_LENGTH];
try {
imageStream.mark(GIF_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}


+ 0
- 56
src/java/org/apache/fop/image/analyser/ImageReader.java View File

@@ -1,56 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader objects read image headers to determine the image size.
*
* @author Pankaj Narula
* @version $Id$
*/
public interface ImageReader {

/**
* Verify image type. If the stream does not contain image data expected by
* the reader it must reset the stream to the start. This is so that the
* next reader can start reading from the start. The reader must not close
* the stream unless it can handle the image and it has read the
* information.
*
* @param bis Image buffered input stream
* @param uri URI to the image
* @param ua The user agent
* @return <code>true</code> if image type is the handled one
* @exception IOException if an I/O error occurs
*/
FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua)
throws IOException;

}


+ 0
- 108
src/java/org/apache/fop/image/analyser/ImageReaderFactory.java View File

@@ -1,108 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.image.FopImage;
import org.apache.xmlgraphics.util.Service;

/**
* Factory for ImageReader objects.
*
* @author Pankaj Narula
* @version $Id$
*/
public class ImageReaderFactory {

private static List formats = new java.util.ArrayList();

/** logger */
protected static Log log = LogFactory.getLog(ImageReaderFactory.class);

static {
registerFormat(new JPEGReader());
registerFormat(new BMPReader());
registerFormat(new GIFReader());
registerFormat(new PNGReader());
registerFormat(new TIFFReader());
registerFormat(new EPSReader());
registerFormat(new EMFReader());

//Dynamic registration of ImageReaders
Iterator iter = Service.providers(ImageReader.class, true);
while (iter.hasNext()) {
registerFormat((ImageReader)iter.next());
}
// the xml parser through batik closes the stream when finished
// so there is a workaround in the SVGReader
registerFormat(new SVGReader());
registerFormat(new SVGZReader());
registerFormat(new XMLReader());
}

/**
* Registers a new ImageReader.
*
* @param reader An ImageReader instance
*/
public static void registerFormat(ImageReader reader) {
formats.add(reader);
}

/**
* ImageReader maker.
*
* @param uri URI to the image
* @param in image input stream
* @param ua user agent
* @return An ImageInfo object describing the image
*/
public static FopImage.ImageInfo make(String uri, InputStream in,
FOUserAgent ua) {

ImageReader reader;
try {
for (int count = 0; count < formats.size(); count++) {
reader = (ImageReader) formats.get(count);
FopImage.ImageInfo info = reader.verifySignature(uri, in, ua);
if (info != null) {
return info;
}
}
log.warn("No ImageReader found for " + uri);
in.close();
} catch (IOException ex) {
log.error("Error while recovering Image Informations ("
+ uri + ")", ex);
}
return null;
}

}


+ 0
- 264
src/java/org/apache/fop/image/analyser/JPEGReader.java View File

@@ -1,264 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for JPEG image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class JPEGReader implements ImageReader {

/**
* Only SOFn and APPn markers are defined as SOFn is needed for the height and
* width search. APPn is also defined because if the JPEG contains thumbnails
* the dimensions of the thumnail would also be after the SOFn marker enclosed
* inside the APPn marker. And we don't want to confuse those dimensions with
* the image dimensions.
*/
private static final int MARK = 0xff; // Beginning of a Marker
private static final int NULL = 0x00; // Special case for 0xff00
private static final int SOF1 = 0xc0; // Baseline DCT
private static final int SOF2 = 0xc1; // Extended Sequential DCT
private static final int SOF3 = 0xc2; // Progrssive DCT only PDF 1.3
private static final int SOFA = 0xca; // Progressice DCT only PDF 1.3
private static final int APP0 = 0xe0; // Application marker, JFIF
private static final int APPF = 0xef; // Application marker
private static final int SOS = 0xda; // Start of Scan
private static final int SOI = 0xd8; // start of Image
private static final int JPG_SIG_LENGTH = 2;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(fis);
boolean supported = ((header[0] == (byte) 0xff)
&& (header[1] == (byte) 0xd8));
if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(fis, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = fis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/jpeg";
}

private byte[] getDefaultHeader(InputStream imageStream) throws IOException {
byte[] header = new byte[JPG_SIG_LENGTH];
try {
imageStream.mark(JPG_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

private void getDimension(InputStream imageStream,
FopImage.ImageInfo info)
throws IOException {
try {
int pos=0, avail = imageStream.available();
imageStream.mark(avail);
int marker = NULL;
long length, skipped;
outer:
while (true) {
do {
if (avail == 0) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
//Marker first byte (FF)
marker = imageStream.read();
pos++; avail--;
} while (marker != MARK);

do {
if (avail == 0) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
//Marker second byte
marker = imageStream.read();
pos++; avail--;
} while (marker == MARK);

switch (marker) {
case SOI:
break;
case NULL:
break;
case APP0:
if (avail < 14) {
imageStream.reset();
avail = 2 * pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
int reclen = this.read2bytes(imageStream);
pos += 2; avail -= 2;
this.skip(imageStream, 7);
pos += 7; avail -= 7;
int densityUnits = imageStream.read();
pos++; avail--;
int xdensity = this.read2bytes(imageStream);
pos += 2; avail -= 2;
int ydensity = this.read2bytes(imageStream);
pos += 2; avail -= 2;
if (densityUnits == 2) {
info.dpiHorizontal = xdensity * 28.3464567 / 72; //dpi
info.dpiVertical = ydensity * 28.3464567 / 72; //dpi
} else if (densityUnits == 1) {
info.dpiHorizontal = xdensity;
info.dpiVertical = ydensity;
} else {
// Use resolution specified in
// FOUserAgent.getFactory() (default 72dpi).
}
int restlen = reclen - 12;
if (avail < restlen) {
imageStream.reset();
avail = 2 * pos;
if (avail < pos + restlen + 10) {
avail = (int)(pos + restlen + 10);
}
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
skipped = this.skip(imageStream, restlen - 2);
pos += skipped; avail -= skipped;
if (skipped != restlen - 2) {
throw new IOException("Skipping Error");
}
break;
case SOF1:
case SOF2:
case SOF3: // SOF3 and SOFA are only supported by PDF 1.3
case SOFA:
while (avail < 7) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
this.skip(imageStream, 3);
pos+=3; avail-=3;
info.height = this.read2bytes(imageStream);
pos+=2; avail-=2;
info.width = this.read2bytes(imageStream);
pos+=2; avail-=2;
break outer;
default:
while (avail < 2) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
length = this.read2bytes(imageStream);
pos+=2; avail-=2;
if (avail < length) {
imageStream.reset();
avail = 2*pos;
if (avail < pos+length+10) {
avail = (int)(pos+length+10);
}
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
skipped = this.skip(imageStream, length - 2);
pos += skipped; avail -= skipped;
if (skipped != length - 2) {
throw new IOException("Skipping Error");
}
}
}
imageStream.reset();
} catch (IOException ioe) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ioe;
}
}

private int read2bytes(InputStream imageStream) throws IOException {
int byte1 = imageStream.read();
int byte2 = imageStream.read();
return (int) ((byte1 << 8) | byte2);
}

private long skip(InputStream imageStream, long n) throws IOException {
long discarded = 0;
while (discarded != n) {
imageStream.read();
discarded++;
}
return discarded; // scope for exception
}

}


+ 0
- 115
src/java/org/apache/fop/image/analyser/PNGReader.java View File

@@ -1,115 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for PNG image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class PNGReader implements ImageReader {

private static final int PNG_SIG_LENGTH = 24;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = ((header[0] == (byte) 0x89)
&& (header[1] == (byte) 0x50)
&& (header[2] == (byte) 0x4e)
&& (header[3] == (byte) 0x47)
&& (header[4] == (byte) 0x0d)
&& (header[5] == (byte) 0x0a)
&& (header[6] == (byte) 0x1a)
&& (header[7] == (byte) 0x0a));

if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/png";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// png is always big endian
int byte1 = header[16] & 0xff;
int byte2 = header[17] & 0xff;
int byte3 = header[18] & 0xff;
int byte4 = header[19] & 0xff;
long l = (long) ((byte1 << 24)
| (byte2 << 16)
| (byte3 << 8)
| (byte4));
info.width = (int) l;

byte1 = header[20] & 0xff;
byte2 = header[21] & 0xff;
byte3 = header[22] & 0xff;
byte4 = header[23] & 0xff;
l = (long) ((byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4);
info.height = (int) l;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[PNG_SIG_LENGTH];
try {
imageStream.mark(PNG_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}

+ 0
- 188
src/java/org/apache/fop/image/analyser/SVGReader.java View File

@@ -1,188 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;
import java.awt.geom.AffineTransform;

// XML
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;

// Batik
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.UnitProcessor;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

// FOP
import org.apache.fop.image.XMLImage;
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.svg.SVGUserAgent;
import org.apache.fop.util.UnclosableInputStream;

/**
* ImageReader object for SVG document image type.
*/
public class SVGReader implements ImageReader {

/** Logger instance */
protected static Log log = LogFactory.getLog(SVGReader.class);
/** SVG's MIME type */
public static final String SVG_MIME_TYPE = "image/svg+xml";

private boolean batik = true;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
FOUserAgent ua) throws IOException {
FopImage.ImageInfo info = loadImage(uri, fis, ua);
if (info != null) {
IOUtils.closeQuietly(fis);
}
return info;
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return SVG_MIME_TYPE;
}

/**
* This means the external svg document will be loaded twice. Possibly need
* a slightly different design for the image stuff.
*
* @param uri @todo Description of the Parameter
* @param fis @todo Description of the Parameter
* @param ua @todo Description of the Parameter
* @return @todo Description of the Return Value
*/
private FopImage.ImageInfo loadImage(String uri, InputStream bis,
FOUserAgent ua) {
if (batik) {
try {
Loader loader = new Loader();
return loader.getImage(uri, bis,
ua.getSourcePixelUnitToMillimeter());
} catch (NoClassDefFoundError e) {
batik = false;
log.warn("Batik not in class path", e);
return null;
}
}
return null;
}

/**
* This method is put in another class so that the classloader does not
* attempt to load batik related classes when constructing the SVGReader
* class.
*/
class Loader {
private FopImage.ImageInfo getImage(String uri, InputStream fis,
float pixelUnitToMM) {
// parse document and get the size attributes of the svg element

try {
fis = new UnclosableInputStream(fis);

FopImage.ImageInfo info = new FopImage.ImageInfo();

//Set the resolution to that of the FOUserAgent
info.dpiHorizontal = 25.4f / pixelUnitToMM;
info.dpiVertical = info.dpiHorizontal;
info.originalURI = uri;
info.mimeType = getMimeType();
info.str = SVGDOMImplementation.SVG_NAMESPACE_URI;

int length = fis.available();
fis.mark(length + 1);
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(
XMLImage.getParserName());
SVGDocument doc = (SVGDocument) factory.createSVGDocument(uri, fis);
info.data = doc;

Element e = doc.getRootElement();
String s;
SVGUserAgent userAg = new SVGUserAgent(pixelUnitToMM,
new AffineTransform());
BridgeContext ctx = new BridgeContext(userAg);
UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);

// 'width' attribute - default is 100%
s = e.getAttributeNS(null,
SVGOMDocument.SVG_WIDTH_ATTRIBUTE);
if (s.length() == 0) {
s = SVGOMDocument.SVG_SVG_WIDTH_DEFAULT_VALUE;
}
info.width = Math.round(UnitProcessor.svgHorizontalLengthToUserSpace(
s, SVGOMDocument.SVG_WIDTH_ATTRIBUTE, uctx));

// 'height' attribute - default is 100%
s = e.getAttributeNS(null,
SVGOMDocument.SVG_HEIGHT_ATTRIBUTE);
if (s.length() == 0) {
s = SVGOMDocument.SVG_SVG_HEIGHT_DEFAULT_VALUE;
}
info.height = Math.round(UnitProcessor.svgVerticalLengthToUserSpace(
s, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE, uctx));

return info;
} catch (NoClassDefFoundError ncdfe) {
try {
fis.reset();
} catch (IOException ioe) {
// we're more interested in the original exception
}
batik = false;
log.warn("Batik not in class path", ncdfe);
return null;
} catch (IOException e) {
// If the svg is invalid then it throws an IOException
// so there is no way of knowing if it is an svg document

log.debug("Error while trying to load stream as an SVG file: "
+ e.getMessage());
// assuming any exception means this document is not svg
// or could not be loaded for some reason
try {
fis.reset();
} catch (IOException ioe) {
// we're more interested in the original exception
}
return null;
}
}
}

}

+ 0
- 53
src/java/org/apache/fop/image/analyser/SVGZReader.java View File

@@ -1,53 +0,0 @@
/*
* 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.image.analyser;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.image.FopImage;

/**
* Implements a reader for gzipped XMLFiles.
*
* <p>
* The current implementation is limited to SVG files only.
*/
public class SVGZReader extends XMLReader {
/**
* Default constructor.
*/
public SVGZReader() {
}

/** {@inheritDoc} */
protected FopImage.ImageInfo loadImage(final String uri,
final InputStream bis, final FOUserAgent ua) {
try {
return new SVGReader().verifySignature(uri,
new GZIPInputStream(bis), ua);
} catch (final IOException e) {
// ignore
}
return null;
}
}

+ 0
- 117
src/java/org/apache/fop/image/analyser/TIFFReader.java View File

@@ -1,117 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for TIFF image type.
*
* @author Pankaj Narula, Michael Lee
* @version $Id$
*/
public class TIFFReader implements ImageReader {

private static final int TIFF_SIG_LENGTH = 8;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = false;

// first 2 bytes = II (little endian encoding)
if (header[0] == (byte) 0x49 && header[1] == (byte) 0x49) {

// look for '42' in byte 3 and '0' in byte 4
if (header[2] == 42 && header[3] == 0) {
supported = true;
}
}

// first 2 bytes == MM (big endian encoding)
if (header[0] == (byte) 0x4D && header[1] == (byte) 0x4D) {

// look for '42' in byte 4 and '0' in byte 3
if (header[2] == 0 && header[3] == 42) {
supported = true;
}
}

if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/tiff";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// currently not setting the width and height
// these are set again by the Jimi image reader.
// I suppose I'll do it one day to be complete. Or
// someone else will.
// Note: bytes 4,5,6,7 contain the byte offset in the stream of the first IFD block
info.width = -1;
info.height = -1;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[TIFF_SIG_LENGTH];
try {
imageStream.mark(TIFF_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}


+ 0
- 167
src/java/org/apache/fop/image/analyser/XMLReader.java View File

@@ -1,167 +0,0 @@
/*
* 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.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;
import java.util.Map;

// XML
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.util.UnclosableInputStream;
import org.apache.fop.apps.FOUserAgent;

// Commons-Logging
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/** ImageReader object for XML document image type. */
public class XMLReader implements ImageReader {

/**
* logging instance
*/
private Log log = LogFactory.getLog(XMLReader.class);

private static Map converters = new java.util.HashMap();

/**
* Registers a Converter implementation with XMLReader.
*
* @param ns The namespace to associate with this converter
* @param conv The actual Converter implementation
*/
public static void setConverter(String ns, Converter conv) {
converters.put(ns, conv);
}

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
FOUserAgent ua)
throws IOException {
FopImage.ImageInfo info = loadImage(uri, fis, ua);
if (info != null) {
info.originalURI = uri;
IOUtils.closeQuietly(fis);
}
return info;
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "text/xml";
}

/**
* Creates an ImageInfo object from an XML image read from a stream.
*
* (todo) This means the external svg document will be loaded twice. Possibly need
* a slightly different design for the image stuff.
*
* @param uri The URI to the image
* @param bis The InputStream
* @param ua The user agent
* @return An ImageInfo object describing the image
*/
protected FopImage.ImageInfo loadImage(String uri, InputStream bis,
FOUserAgent ua) {
return createDocument(bis, ua);
}

/**
* Creates an ImageInfo object from an XML image read from a stream.
*
* @param input The InputStream
* @param ua The user agent
* @return An ImageInfo object describing the image
*/
public FopImage.ImageInfo createDocument(final InputStream input, final FOUserAgent ua) {
Document doc = null;
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.mimeType = getMimeType();

try {
final InputStream is = new UnclosableInputStream(input);
int length = is.available();
is.mark(length);

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
doc = dbf.newDocumentBuilder().parse(is);
info.data = doc;

Element root = doc.getDocumentElement();
log.debug("XML image namespace: " + root.getAttribute("xmlns"));
String ns = root.getAttribute("xmlns");
info.str = ns;

Converter conv = (Converter) converters.get(ns);
if (conv != null) {
FopImage.ImageInfo i = conv.convert(doc);
if (i != null) {
info = i;
}
}
} catch (Exception e) {
log.debug("Error while constructing image from XML", e);
try {
input.reset();
} catch (IOException ioe) {
// throw the original exception, not this one
}
return null;
}
if (info != null) {
try {
input.close();
} catch (IOException io) {
// ignore
}
}
return info;
}

/**
* This interface is to be implemented for XML to image converters.
*/
public static interface Converter {

/**
* This method is called for a DOM document to be converted into an
* ImageInfo object.
*
* @param doc The DOM document to convert
* @return An ImageInfo object describing the image
*/
FopImage.ImageInfo convert(Document doc);
}

}


+ 0
- 23
src/java/org/apache/fop/image/analyser/package.html View File

@@ -1,23 +0,0 @@
<!--
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$ -->
<HTML>
<TITLE>org.apache.fop.image.analyser Package</TITLE>
<BODY>
<P>Image analyzers for determining the format of an image and to preload its intrinsic size.</P>
</BODY>
</HTML>

+ 1
- 1
src/java/org/apache/fop/image/package.html View File

@@ -18,6 +18,6 @@
<HTML>
<TITLE>org.apache.fop.image Package</TITLE>
<BODY>
<P>Contains image loading adapters for various image sources and the image cache.</P>
<P>Contains image loading adapters for various image sources.</P>
</BODY>
</HTML>

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

@@ -272,7 +272,7 @@ public abstract class AbstractBreaker {
*/
public void doLayout(int flowBPD, boolean autoHeight) {
LayoutContext childLC = createLayoutContext();
childLC.setStackLimit(new MinOptMax(flowBPD));
childLC.setStackLimitBP(new MinOptMax(flowBPD));

if (getCurrentDisplayAlign() == Constants.EN_X_FILL) {
//EN_X_FILL is non-standard (by LF)
@@ -495,7 +495,7 @@ public abstract class AbstractBreaker {
int averageLineLength = optimizeLineLength(effectiveList,
startElementIndex, endElementIndex);
if (averageLineLength != 0) {
childLC.setStackLimit(new MinOptMax(averageLineLength));
childLC.setStackLimitBP(new MinOptMax(averageLineLength));
}
}
/* *** *** non-standard extension *** *** */

+ 1
- 1
src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java View File

@@ -117,7 +117,7 @@ public class AreaAdditionUtil {
// set space after for each LM, in order to implement
// display-align = distribute
lc.setSpaceAfter(layoutContext.getSpaceAfter());
lc.setStackLimit(layoutContext.getStackLimit());
lc.setStackLimitsFrom(layoutContext);
childLM.addAreas(childPosIter, lc);
}

+ 15
- 23
src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java View File

@@ -37,7 +37,6 @@ import org.apache.fop.datatypes.FODimension;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.properties.CommonAbsolutePosition;
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;

@@ -200,7 +199,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
= (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
autoHeight = false;
//boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
int maxbpd = context.getStackLimit().opt;
int maxbpd = context.getStackLimitBP().opt;
int allocBPD;
if (height.getEnum() == EN_AUTO
|| (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
@@ -279,8 +278,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
LayoutContext childLC = new LayoutContext(0);
childLC.copyPendingMarksFrom(context);
// curLM is a ?
childLC.setStackLimit(MinOptMax.subtract(context
.getStackLimit(), stackLimit));
childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
childLC.setRefIPD(relDims.ipd);
childLC.setWritingMode(getBlockContainerFO().getWritingMode());

@@ -389,6 +387,9 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
}
addKnuthElementsForBorderPaddingAfter(returnList, true);
addKnuthElementsForSpaceAfter(returnList, alignment);

//All child content is processed. Only break-after can occur now, so...
context.clearPendingMarks();
addKnuthElementsForBreakAfter(returnList, context);

setFinished(true);
@@ -412,7 +413,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
if (isFixed()) {
availHeight = (int)getCurrentPV().getViewArea().getHeight();
} else {
availHeight = context.getStackLimit().opt;
availHeight = context.getStackLimitBP().opt;
}
allocBPD = availHeight;
allocBPD -= offset.y;
@@ -445,7 +446,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
}
}
} else {
int maxbpd = context.getStackLimit().opt;
int maxbpd = context.getStackLimitBP().opt;
allocBPD = maxbpd;
if (!switchedProgressionDirection) {
autoHeight = true;
@@ -635,7 +636,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager

while ((curLM = getChildLM()) != null) {
LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimit(context.getStackLimit());
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(context.getRefIPD());
childLC.setWritingMode(getBlockContainerFO().getWritingMode());
@@ -864,7 +865,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
// set last area flag
lc.setFlags(LayoutContext.LAST_AREA,
(layoutContext.isLastArea() && childLM == lastLM));
/*LF*/lc.setStackLimit(layoutContext.getStackLimit());
/*LF*/lc.setStackLimitBP(layoutContext.getStackLimitBP());
// Add the line areas to Area
childLM.addAreas(childPosIter, lc);
}
@@ -1002,30 +1003,21 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public boolean mustKeepTogether() {
//TODO Keeps will have to be more sophisticated sooner or later
return (!getBlockContainerFO().getKeepTogether().getWithinPage().isAuto()
|| !getBlockContainerFO().getKeepTogether().getWithinColumn().isAuto()
|| (getParent() instanceof BlockLevelLayoutManager
&& ((BlockLevelLayoutManager) getParent()).mustKeepTogether())
|| (getParent() instanceof InlineLayoutManager
&& ((InlineLayoutManager) getParent()).mustKeepTogether()));
return super.mustKeepTogether()
|| !getBlockContainerFO().getKeepTogether().getWithinPage().isAuto()
|| !getBlockContainerFO().getKeepTogether().getWithinColumn().isAuto();
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public boolean mustKeepWithPrevious() {
return !getBlockContainerFO().getKeepWithPrevious().getWithinPage().isAuto()
|| !getBlockContainerFO().getKeepWithPrevious().getWithinColumn().isAuto();
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public boolean mustKeepWithNext() {
return !getBlockContainerFO().getKeepWithNext().getWithinPage().isAuto()
|| !getBlockContainerFO().getKeepWithNext().getWithinColumn().isAuto();

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

@@ -25,6 +25,7 @@ import java.util.ListIterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.LineArea;
@@ -389,7 +390,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// set last area flag
lc.setFlags(LayoutContext.LAST_AREA,
(layoutContext.isLastArea() && childLM == lastLM));
lc.setStackLimit(layoutContext.getStackLimit());
lc.setStackLimitBP(layoutContext.getStackLimitBP());
// Add the line areas to Area
childLM.addAreas(childPosIter, lc);
}

+ 16
- 5
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -282,13 +282,14 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
if (curLM instanceof LineLayoutManager) {
// curLM is a LineLayoutManager
// set stackLimit for lines (stack limit is now i-p-direction, not b-p-direction!)
childLC.setStackLimit(new MinOptMax(getContentAreaIPD()));
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setStackLimitIP(new MinOptMax(getContentAreaIPD()));
childLC.setRefIPD(getContentAreaIPD());
} else {
// curLM is a ?
//childLC.setStackLimit(MinOptMax.subtract(context
// .getStackLimit(), stackSize));
childLC.setStackLimit(context.getStackLimit());
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(referenceIPD);
}

@@ -301,15 +302,22 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
if (returnedList != null
&& returnedList.size() == 1
&& ((ListElement) returnedList.getFirst()).isForcedBreak()) {
// a descendant of this block has break-before
contentList.addAll(returnedList);

if (curLM.isFinished() && !hasNextChildLM()) {
forcedBreakAfterLast = (BreakElement)contentList.removeLast();
// a descendant of this block has break-before
forcedBreakAfterLast = (BreakElement) returnedList.getFirst();
context.clearPendingMarks();
break;
}

if (contentList.size() == 0) {
// Empty fo:block, zero-length box makes sure the IDs and/or markers
// are registered and borders/padding are painted.
returnList.add(new KnuthBox(0, notifyPos(new Position(this)), false));
}
// a descendant of this block has break-before
contentList.addAll(returnedList);
/* extension: conversione di tutta la sequenza fin'ora ottenuta */
if (bpUnit > 0) {
storedList = contentList;
@@ -400,6 +408,9 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

addKnuthElementsForBorderPaddingAfter(returnList, true);
addKnuthElementsForSpaceAfter(returnList, alignment);
//All child content is processed. Only break-after can occur now, so...
context.clearPendingMarks();
if (forcedBreakAfterLast == null) {
addKnuthElementsForBreakAfter(returnList, context);
}

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

@@ -99,7 +99,7 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
//MinOptMax bpd = context.getStackLimit();

LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimit(context.getStackLimit());
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(context.getRefIPD());
childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());

+ 77
- 31
src/java/org/apache/fop/layoutmgr/LayoutContext.java View File

@@ -74,18 +74,29 @@ public class LayoutContext {
private int flags; // Contains some set of flags defined above
/**
* Total available stacking dimension for a "galley-level" layout
* manager (Line or Flow). It is passed by the parent LM. For LineLM,
* the block LM determines this based on indent properties.
* manager in block-progression-direction. It is passed by the
* parent LM.
* These LM <b>may</b> wish to pass this information down to lower
* level LM to allow them to optimize returned break possibilities.
*/
private MinOptMax stackLimit;
private MinOptMax stackLimitBP;
/**
* Total available stacking dimension for a "galley-level" layout
* manager in inline-progression-direction. It is passed by the
* parent LM. For LineLM, the block LM determines this based on
* indent properties.
* These LM <b>may</b> wish to pass this information down to lower
* level LM to allow them to optimize returned break possibilities.
*/
private MinOptMax stackLimitIP;

/** True if current element list is spanning in multi-column layout. */
private int nextSpan = Constants.NOT_SET;

/** inline-progression-dimension of nearest ancestor reference area */
private int refIPD;
//TODO After the split of stackLimit into stackLimitBP and stackLimitIP there's now some
//overlap with refIPD. Need to investigate how best to refactor that.

/** the writing mode established by the nearest ancestor reference area */
private int writingMode = Constants.EN_LR_TB;
@@ -145,7 +156,7 @@ public class LayoutContext {
this.flags = parentLC.flags;
this.refIPD = parentLC.refIPD;
this.writingMode = parentLC.writingMode;
this.stackLimit = null; // Don't reference parent MinOptMax!
setStackLimitsFrom(parentLC);
this.leadingSpace = parentLC.leadingSpace; //???
this.trailingSpace = parentLC.trailingSpace; //???
this.hyphContext = parentLC.hyphContext;
@@ -166,7 +177,8 @@ public class LayoutContext {
public LayoutContext(int flags) {
this.flags = flags;
this.refIPD = 0;
stackLimit = new MinOptMax(0);
stackLimitBP = new MinOptMax(0);
stackLimitIP = new MinOptMax(0);
leadingSpace = null;
trailingSpace = null;
}
@@ -273,12 +285,8 @@ public class LayoutContext {
* Clears all pending marks on the LayoutContext.
*/
public void clearPendingMarks() {
if (this.pendingBeforeMarks != null) {
this.pendingBeforeMarks.clear();
}
if (this.pendingAfterMarks != null) {
this.pendingAfterMarks.clear();
}
this.pendingBeforeMarks = null;
this.pendingAfterMarks = null;
}
/**
@@ -306,14 +314,47 @@ public class LayoutContext {
}
}
public void setStackLimit(MinOptMax limit) {
stackLimit = limit;
/**
* Sets the stack limit in block-progression-dimension.
* @param limit the stack limit
*/
public void setStackLimitBP(MinOptMax limit) {
stackLimitBP = limit;
}

public MinOptMax getStackLimit() {
return stackLimit;
/**
* Returns the stack limit in block-progression-dimension.
* @return the stack limit
*/
public MinOptMax getStackLimitBP() {
return stackLimitBP;
}

/**
* Sets the stack limit in inline-progression-dimension.
* @param limit the stack limit
*/
public void setStackLimitIP(MinOptMax limit) {
stackLimitIP = limit;
}

/**
* Returns the stack limit in inline-progression-dimension.
* @return the stack limit
*/
public MinOptMax getStackLimitIP() {
return stackLimitIP;
}

/**
* Sets (Copies) the stack limits in both directions from another layout context.
* @param context the layout context to taje the values from
*/
public void setStackLimitsFrom(LayoutContext context) {
setStackLimitBP(context.getStackLimitBP());
setStackLimitIP(context.getStackLimitIP());
}
/**
* Sets the inline-progression-dimension of the nearest ancestor reference area.
*/
@@ -536,22 +577,27 @@ public class LayoutContext {

/** {@inheritDoc} */
public String toString() {
return "Layout Context:" +
"\nStack Limit: \t" + (getStackLimit() == null ? "null" : getStackLimit().toString()) +
"\nTrailing Space: \t" + (getTrailingSpace() == null ? "null" : getTrailingSpace().toString()) +
"\nLeading Space: \t" + (getLeadingSpace() == null ? "null" : getLeadingSpace().toString()) +
"\nReference IPD: \t" + getRefIPD() +
"\nSpace Adjust: \t" + getSpaceAdjust() +
"\nIPD Adjust: \t" + getIPDAdjust() +
"\nResolve Leading Space: \t" + resolveLeadingSpace() +
"\nSuppress Leading Space: \t" + suppressLeadingSpace() +
"\nIs First Area: \t" + isFirstArea() +
"\nStarts New Area: \t" + startsNewArea() +
"\nIs Last Area: \t" + isLastArea() +
"\nTry Hyphenate: \t" + tryHyphenate() +
"\nKeeps: \t[" + (isKeepWithNextPending() ? "keep-with-next" : "") + "]["
+ (isKeepWithPreviousPending() ? "keep-with-previous" : "") + "] pending" +
"\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "]["
return "Layout Context:"
+ "\nStack Limit BPD: \t"
+ (getStackLimitBP() == null ? "null" : getStackLimitBP().toString())
+ "\nStack Limit IPD: \t"
+ (getStackLimitIP() == null ? "null" : getStackLimitIP().toString())
+ "\nTrailing Space: \t"
+ (getTrailingSpace() == null ? "null" : getTrailingSpace().toString())
+ "\nLeading Space: \t"
+ (getLeadingSpace() == null ? "null" : getLeadingSpace().toString())
+ "\nReference IPD: \t" + getRefIPD()
+ "\nSpace Adjust: \t" + getSpaceAdjust()
+ "\nIPD Adjust: \t" + getIPDAdjust()
+ "\nResolve Leading Space: \t" + resolveLeadingSpace()
+ "\nSuppress Leading Space: \t" + suppressLeadingSpace()
+ "\nIs First Area: \t" + isFirstArea()
+ "\nStarts New Area: \t" + startsNewArea()
+ "\nIs Last Area: \t" + isLastArea()
+ "\nTry Hyphenate: \t" + tryHyphenate()
+ "\nKeeps: \t[" + (isKeepWithNextPending() ? "keep-with-next" : "") + "]["
+ (isKeepWithPreviousPending() ? "keep-with-previous" : "") + "] pending"
+ "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "]["
+ (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]";
}


+ 5
- 8
src/java/org/apache/fop/layoutmgr/MinOptMaxUtil.java View File

@@ -68,19 +68,16 @@ public class MinOptMaxUtil {
}

/**
* Extend the minimum length to the given length.
* Extends the minimum length to the given length if necessary, and adjusts opt and
* max accordingly.
*
* @param mom the min/opt/max trait
* @param len the new minimum length
* @param optToLen if set adjusts the optimum length to be the smaller of the
* minimum length and the given length
*/
public static void extendMinimum(MinOptMax mom, int len, boolean optToLen) {
public static void extendMinimum(MinOptMax mom, int len) {
if (mom.min < len) {
mom.min = len;
mom.opt = Math.max(mom.min, mom.opt);
if (optToLen) {
mom.opt = Math.min(mom.min, len);
}
mom.max = Math.max(mom.opt, mom.max);
}
}
@@ -111,7 +108,7 @@ public class MinOptMaxUtil {
? 0 : prop.getMinimum(context).getLength().getValue(context)),
(prop.getOptimum(context).isAuto()
? 0 : prop.getOptimum(context).getLength().getValue(context)),
(prop.getMinimum(context).isAuto()
(prop.getMaximum(context).isAuto()
? Integer.MAX_VALUE
: prop.getMaximum(context).getLength().getValue(context)));
return mom;

+ 1
- 1
src/java/org/apache/fop/layoutmgr/PageBreaker.java View File

@@ -153,7 +153,7 @@ public class PageBreaker extends AbstractBreaker {
// element represents a line with footnote citations
bFootnotesPresent = true;
LayoutContext footnoteContext = new LayoutContext(context);
footnoteContext.setStackLimit(context.getStackLimit());
footnoteContext.setStackLimitBP(context.getStackLimitBP());
footnoteContext.setRefIPD(pslm.getCurrentPV()
.getRegionReference(Constants.FO_REGION_BODY).getIPD());
LinkedList footnoteBodyLMs = ((KnuthBlockBox) element).getFootnoteBodyLMs();

+ 4
- 4
src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java View File

@@ -95,7 +95,7 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
//TODO Empty this method?!?
// set layout dimensions
setContentAreaIPD(context.getRefIPD());
setContentAreaBPD(context.getStackLimit().opt);
setContentAreaBPD(context.getStackLimitBP().opt);

//TODO Copied from elsewhere. May be worthwhile to factor out the common parts.
// currently active LM
@@ -113,10 +113,10 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
}

// Set up a LayoutContext
MinOptMax bpd = context.getStackLimit();
MinOptMax bpd = context.getStackLimitBP();

LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimit(MinOptMax.subtract(bpd, stackSize));
childLC.setStackLimitBP(MinOptMax.subtract(bpd, stackSize));
childLC.setRefIPD(context.getRefIPD());

// get elements from curLM
@@ -331,7 +331,7 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {

while ((curLM = getChildLM()) != null) {
LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimit(context.getStackLimit());
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(context.getRefIPD());
childLC.setWritingMode(context.getWritingMode());


+ 2
- 1
src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java View File

@@ -28,6 +28,7 @@ import java.util.ListIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.LineArea;
@@ -113,7 +114,7 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
childLC.setLeadingSpace(new SpaceSpecifier(false));
childLC.setTrailingSpace(new SpaceSpecifier(false));
// set stackLimit for lines
childLC.setStackLimit(new MinOptMax(ipd));
childLC.setStackLimitIP(new MinOptMax(ipd));
childLC.setRefIPD(ipd);

int lineHeight = 14000;

+ 5
- 4
src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java View File

@@ -19,12 +19,13 @@

package org.apache.fop.layoutmgr.inline;

import java.util.ListIterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.area.Area;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineBlockParent;
@@ -47,12 +48,12 @@ import org.apache.fop.layoutmgr.InlineKnuthSequence;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.SpaceSpecifier;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;


+ 5
- 8
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java View File

@@ -583,9 +583,6 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// Get a break from currently active child LM
// Set up constraints for inline level managers

// IPD remaining in line
MinOptMax availIPD = context.getStackLimit();

clearPrevIPD();

//PHASE 1: Create Knuth elements
@@ -647,7 +644,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
InlineLevelLayoutManager curLM;
LinkedList returnedList = null;
iLineWidth = context.getStackLimit().opt;
iLineWidth = context.getStackLimitIP().opt;
// convert all the text in a sequence of paragraphs made
// of KnuthBox, KnuthGlue and KnuthPenalty objects
@@ -1690,7 +1687,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
*/
if (false && textAlignment == EN_JUSTIFY) {
// re-compute space adjust ratio
int updatedDifference = context.getStackLimit().opt
int updatedDifference = context.getStackLimitIP().opt
- lbp.lineWidth + lbp.difference;
double updatedRatio = 0.0;
if (updatedDifference > 0) {
@@ -1704,12 +1701,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
} else if (false && textAlignment == EN_CENTER) {
// re-compute indent
int updatedIndent = lbp.startIndent
+ (context.getStackLimit().opt - lbp.lineWidth) / 2;
+ (context.getStackLimitIP().opt - lbp.lineWidth) / 2;
lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
} else if (false && textAlignment == EN_END) {
// re-compute indent
int updatedIndent = lbp.startIndent
+ (context.getStackLimit().opt - lbp.lineWidth);
+ (context.getStackLimitIP().opt - lbp.lineWidth);
lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
}
@@ -1773,7 +1770,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// set last area flag
blocklc.setFlags(LayoutContext.LAST_AREA,
(context.isLastArea() && childLM == lastLM));
blocklc.setStackLimit(context.getStackLimit());
blocklc.setStackLimitsFrom(context);
// Add the line areas to Area
childLM.addAreas(childPosIter, blocklc);
blocklc.setLeadingSpace(blocklc.getTrailingSpace());

+ 12
- 12
src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java View File

@@ -19,29 +19,29 @@
package org.apache.fop.layoutmgr.list;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.RelSide;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
* LayoutManager for a list-block FO.
* A list block contains list items which are stacked within
@@ -200,7 +200,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
lc.setFlags(LayoutContext.FIRST_AREA, childLM == firstLM);
lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
lc.setStackLimit(layoutContext.getStackLimit());
lc.setStackLimitBP(layoutContext.getStackLimitBP());
childLM.addAreas(childPosIter, lc);
}

@@ -280,7 +280,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
/** {@inheritDoc} */
public boolean mustKeepTogether() {
//TODO Keeps will have to be more sophisticated sooner or later
return ((BlockLevelLayoutManager)getParent()).mustKeepTogether()
return super.mustKeepTogether()
|| !getListBlockFO().getKeepTogether().getWithinPage().isAuto()
|| !getListBlockFO().getKeepTogether().getWithinColumn().isAuto();
}

+ 10
- 10
src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java View File

@@ -19,24 +19,24 @@
package org.apache.fop.layoutmgr.list;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.AbstractListItemPart;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;

import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;

/**
* LayoutManager for a list-item-label or list-item-body FO.
@@ -162,7 +162,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager {
lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
// set the space adjustment ratio
lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
lc.setStackLimit(layoutContext.getStackLimit());
lc.setStackLimitBP(layoutContext.getStackLimitBP());
childLM.addAreas(childPosIter, lc);
}


+ 22
- 16
src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java View File

@@ -19,8 +19,16 @@

package org.apache.fop.layoutmgr.list;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
@@ -30,28 +38,21 @@ import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.KnuthPossPosIter;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.RelSide;
import org.apache.fop.layoutmgr.SpaceResolver;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.KnuthPossPosIter;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;

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

/**
* LayoutManager for a list-item FO.
* The list item contains a list item label and a list item body.
@@ -115,6 +116,11 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
return iBodyLastIndex;
}
/** {@inheritDoc} */
public boolean generatesAreas() {
return true;
}

/** {@inheritDoc} */
public String toString() {
StringBuffer sb = new StringBuffer("ListItemPosition:");
@@ -510,7 +516,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
// set the space adjustment ratio
lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
// TO DO: use the right stack limit for the label
lc.setStackLimit(layoutContext.getStackLimit());
lc.setStackLimitBP(layoutContext.getStackLimitBP());
label.addAreas(labelIter, lc);
}

@@ -531,7 +537,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
// set the space adjustment ratio
lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
// TO DO: use the right stack limit for the body
lc.setStackLimit(layoutContext.getStackLimit());
lc.setStackLimitBP(layoutContext.getStackLimitBP());
body.addAreas(bodyIter, lc);
}


+ 104
- 37
src/java/org/apache/fop/layoutmgr/table/ActiveCell.java View File

@@ -33,6 +33,8 @@ import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.MinOptMaxUtil;
import org.apache.fop.traits.MinOptMax;

/**
* A cell playing in the construction of steps for a row-group.
@@ -133,6 +135,49 @@ class ActiveCell {
}
}

// TODO to be removed along with the RowPainter#computeContentLength method
/** See {@link ActiveCell#handleExplicitHeight(MinOptMax, MinOptMax)}. */
private static class FillerPenalty extends KnuthPenalty {

private int contentLength;

FillerPenalty(KnuthPenalty p, int length) {
super(length, p.getP(), p.isFlagged(), p.getBreakClass(),
p.getPosition(), p.isAuxiliary());
contentLength = p.getW();
}

FillerPenalty(int length) {
super(length, 0, false, null, true);
contentLength = 0;
}
}

/** See {@link ActiveCell#handleExplicitHeight(MinOptMax, MinOptMax)}. */
private static class FillerBox extends KnuthBox {
FillerBox(int length) {
super(length, null, true);
}
}

/**
* Returns the actual length of the content represented by the given element. In the
* case where this element is used as a filler to match a row's fixed height, the
* value returned by the getW() method will be higher than the actual content.
*
* @param el an element
* @return the actual content length corresponding to the element
*/
static int getElementContentLength(KnuthElement el) {
if (el instanceof FillerPenalty) {
return ((FillerPenalty) el).contentLength;
} else if (el instanceof FillerBox) {
return 0;
} else {
return el.getW();
}
}

ActiveCell(PrimaryGridUnit pgu, EffRow row, int rowIndex, int previousRowsLength,
TableLayoutManager tableLM) {
this.pgu = pgu;
@@ -149,22 +194,10 @@ class ActiveCell {
+ pgu.getBeforeBorderWidth(0, ConditionalBorder.REST);
bpAfterNormal = paddingAfterNormal + pgu.getAfterBorderWidth(ConditionalBorder.NORMAL);
bpAfterTrailing = paddingAfterTrailing + pgu.getAfterBorderWidth(0, ConditionalBorder.REST);
boolean makeBoxForWholeRow = false;
if (row.getExplicitHeight().min > 0) {
boolean contentsSmaller = ElementListUtils.removeLegalBreaks(
pgu.getElements(), row.getExplicitHeight());
if (contentsSmaller) {
makeBoxForWholeRow = true;
}
}
if (makeBoxForWholeRow) {
elementList = new java.util.ArrayList(1);
int height = row.getHeight().opt;
height -= bpBeforeNormal + bpAfterNormal;
elementList.add(new KnuthBoxCellWithBPD(height));
} else {
elementList = pgu.getElements();
}
elementList = pgu.getElements();
handleExplicitHeight(
MinOptMaxUtil.toMinOptMax(pgu.getCell().getBlockProgressionDimension(), tableLM),
row.getExplicitHeight());
knuthIter = elementList.listIterator();
includedLength = -1; // Avoid troubles with cells having content of zero length
totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList);
@@ -181,6 +214,46 @@ class ActiveCell {
}
}

/**
* Modifies the cell's element list by putting filler elements, so that the cell's or
* row's explicit height is always reached.
*
* TODO this will work properly only for the first break. Then the limitation
* explained on http://wiki.apache.org/xmlgraphics-fop/TableLayout/KnownProblems
* occurs. The list of elements needs to be re-adjusted after each break.
*/
private void handleExplicitHeight(MinOptMax cellBPD, MinOptMax rowBPD) {
int minBPD = Math.max(cellBPD.min, rowBPD.min);
if (minBPD > 0) {
ListIterator iter = elementList.listIterator();
int cumulateLength = 0;
boolean prevIsBox = false;
while (iter.hasNext() && cumulateLength < minBPD) {
KnuthElement el = (KnuthElement) iter.next();
if (el.isBox()) {
prevIsBox = true;
cumulateLength += el.getW();
} else if (el.isGlue()) {
if (prevIsBox) {
elementList.add(iter.nextIndex() - 1,
new FillerPenalty(minBPD - cumulateLength));
}
prevIsBox = false;
cumulateLength += el.getW();
} else {
prevIsBox = false;
if (cumulateLength + el.getW() < minBPD) {
iter.set(new FillerPenalty((KnuthPenalty) el, minBPD - cumulateLength));
}
}
}
}
int optBPD = Math.max(minBPD, Math.max(cellBPD.opt, rowBPD.opt));
if (pgu.getContentLength() < optBPD) {
elementList.add(new FillerBox(optBPD - pgu.getContentLength()));
}
}

PrimaryGridUnit getPrimaryGridUnit() {
return pgu;
}
@@ -264,14 +337,22 @@ class ActiveCell {
}

/**
* Returns the last step for this cell.
* Returns the last step for this cell. This includes the normal border- and
* padding-before, the whole content, the normal padding-after, and the
* <em>trailing</em> after border. Indeed, if the normal border is taken instead,
* and appears to be smaller than the trailing one, the last step may be smaller than
* the current step (see TableStepper#considerRowLastStep). This will produce a wrong
* infinite penalty, plus the cell's content won't be taken into account since the
* final step will be smaller than the current one (see {@link #signalNextStep(int)}).
* This actually means that the content will be swallowed.
*
* @return the step including all of the cell's content plus the normal borders and paddings
* @return the length of last step
*/
int getLastStep() {
assert nextStep.end == elementList.size() - 1;
assert nextStep.contentLength == totalLength && nextStep.penaltyLength == 0;
int lastStep = bpBeforeNormal + totalLength + bpAfterNormal;
int lastStep = bpBeforeNormal + totalLength + paddingAfterNormal
+ pgu.getAfterBorderWidth(ConditionalBorder.LEADING_TRAILING);
log.debug(this + ": last step = " + lastStep);
return lastStep;
}
@@ -393,8 +474,12 @@ class ActiveCell {
*/
void endRow(int rowIndex) {
if (endsOnRow(rowIndex)) {
// Subtract the old value of bpAfterTrailing...
nextStep.totalLength -= bpAfterTrailing;
bpAfterTrailing = paddingAfterNormal
+ pgu.getAfterBorderWidth(ConditionalBorder.LEADING_TRAILING);
// ... and add the new one
nextStep.totalLength += bpAfterTrailing;
lastCellPart = true;
} else {
bpBeforeLeading = paddingBeforeLeading
@@ -444,13 +529,6 @@ class ActiveCell {
return new CellPart(pgu, nextStep.start, previousStep.end, lastCellPart,
0, 0, previousStep.penaltyLength,
bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterTrailing);
} else if (nextStep.start == 0 && nextStep.end == 0
&& elementList.size() == 1
&& elementList.get(0) instanceof KnuthBoxCellWithBPD) {
//Special case: Cell with fixed BPD
return new CellPart(pgu, 0, pgu.getElements().size() - 1, lastCellPart,
nextStep.condBeforeContentLength, length, nextStep.penaltyLength,
bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterTrailing);
} else {
return new CellPart(pgu, nextStep.start, nextStep.end, lastCellPart,
nextStep.condBeforeContentLength, length, nextStep.penaltyLength,
@@ -467,15 +545,4 @@ class ActiveCell {
public String toString() {
return "Cell " + (pgu.getRowIndex() + 1) + "." + (pgu.getColIndex() + 1);
}


/**
* Marker class denoting table cells fitting in just one box (no legal break inside).
*/
private static class KnuthBoxCellWithBPD extends KnuthBox {

public KnuthBoxCellWithBPD(int w) {
super(w, null, true);
}
}
}

+ 106
- 115
src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java View File

@@ -19,8 +19,8 @@

package org.apache.fop.layoutmgr.table;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -29,6 +29,7 @@ import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.table.EffRow;
import org.apache.fop.fo.flow.table.GridUnit;
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.LengthRangeProperty;
@@ -95,133 +96,123 @@ class RowGroupLayoutManager {
private void createElementsForRowGroup(LayoutContext context, int alignment,
int bodyType, LinkedList returnList) {
log.debug("Handling row group with " + rowGroup.length + " rows...");
EffRow row;
for (int rgi = 0; rgi < rowGroup.length; rgi++) {
row = rowGroup[rgi];
for (Iterator iter = row.getGridUnits().iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next();
if (gu.isPrimary()) {
PrimaryGridUnit primary = gu.getPrimary();
// TODO a new LM must be created for every new static-content
primary.createCellLM();
primary.getCellLM().setParent(tableLM);
//Calculate width of cell
int spanWidth = 0;
Iterator colIter = tableLM.getTable().getColumns().listIterator(
primary.getColIndex());
for (int i = 0, c = primary.getCell().getNumberColumnsSpanned(); i < c; i++) {
spanWidth += ((TableColumn) colIter.next()).getColumnWidth().getValue(
tableLM);
}
LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimitBP(context.getStackLimitBP()); //necessary?
childLC.setRefIPD(spanWidth);
//Get the element list for the cell contents
LinkedList elems = primary.getCellLM().getNextKnuthElements(
childLC, alignment);
ElementListObserver.observe(elems, "table-cell", primary.getCell().getId());
primary.setElements(elems);
}
}
}
computeRowHeights();
LinkedList elements = tableStepper.getCombinedKnuthElementsForRowGroup(context,
rowGroup, bodyType);
returnList.addAll(elements);
}

/**
* Calculate the heights of the rows in the row group, see CSS21, 17.5.3 Table height
* algorithms.
*
* TODO this method will need to be adapted once clarification has been made by the
* W3C regarding whether borders or border-separation must be included or not
*/
private void computeRowHeights() {
log.debug("rowGroup:");
MinOptMax[] rowHeights = new MinOptMax[rowGroup.length];
MinOptMax[] explicitRowHeights = new MinOptMax[rowGroup.length];
EffRow row;
List pgus = new java.util.ArrayList(); //holds a list of a row's primary grid units
for (int rgi = 0; rgi < rowGroup.length; rgi++) {
row = rowGroup[rgi];
rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
explicitRowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
pgus.clear();
TableRow tableRow = null;
// The row's minimum content height; 0 if the row's height is auto, otherwise
// the .minimum component of the explicitly specified value
int minRowBPD = 0;
// The BPD of the biggest cell in the row
int maxCellBPD = 0;
for (int j = 0; j < row.getGridUnits().size(); j++) {
GridUnit gu = row.getGridUnit(j);
if ((gu.isPrimary() || (gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()))
&& !gu.isEmpty()) {
// int maxCellBPD = 0;
MinOptMax explicitRowHeight;
TableRow tableRowFO = rowGroup[rgi].getTableRow();
if (tableRowFO == null) {
rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
explicitRowHeight = new MinOptMax(0, 0, Integer.MAX_VALUE);
} else {
LengthRangeProperty rowBPD = tableRowFO.getBlockProgressionDimension();
rowHeights[rgi] = MinOptMaxUtil.toMinOptMax(rowBPD, tableLM);
explicitRowHeight = MinOptMaxUtil.toMinOptMax(rowBPD, tableLM);
}
for (Iterator iter = row.getGridUnits().iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next();
if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) {
PrimaryGridUnit primary = gu.getPrimary();
if (gu.isPrimary()) {
// TODO a new LM must be created for every new static-content
primary.createCellLM();
primary.getCellLM().setParent(tableLM);
//Determine the table-row if any
if (tableRow == null && primary.getRow() != null) {
tableRow = primary.getRow();
//Check for bpd on row, see CSS21, 17.5.3 Table height algorithms
LengthRangeProperty rowBPD = tableRow.getBlockProgressionDimension();
if (!rowBPD.getMinimum(tableLM).isAuto()) {
minRowBPD = Math.max(minRowBPD,
rowBPD.getMinimum(tableLM).getLength().getValue(tableLM));
}
MinOptMaxUtil.restrict(explicitRowHeights[rgi], rowBPD, tableLM);
}

//Calculate width of cell
int spanWidth = 0;
for (int i = primary.getColIndex();
i < primary.getColIndex()
+ primary.getCell().getNumberColumnsSpanned();
i++) {
if (tableLM.getColumns().getColumn(i + 1) != null) {
spanWidth += tableLM.getColumns().getColumn(i + 1)
.getColumnWidth().getValue(tableLM);
}
}
LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimit(context.getStackLimit()); //necessary?
childLC.setRefIPD(spanWidth);
//Get the element list for the cell contents
LinkedList elems = primary.getCellLM().getNextKnuthElements(
childLC, alignment);
ElementListObserver.observe(elems, "table-cell", primary.getCell().getId());
primary.setElements(elems);
int effectiveCellBPD = 0;
LengthRangeProperty cellBPD = primary.getCell().getBlockProgressionDimension();
if (!cellBPD.getMinimum(tableLM).isAuto()) {
effectiveCellBPD = cellBPD.getMinimum(tableLM).getLength()
.getValue(tableLM);
}

//Calculate height of row, see CSS21, 17.5.3 Table height algorithms
if (gu.isLastGridUnitRowSpan()) {
// The effective cell's bpd, after taking into account bpd
// (possibly explicitly) set on the row or on the cell, and the
// cell's content length
int effectiveCellBPD = minRowBPD;
LengthRangeProperty cellBPD = primary.getCell()
.getBlockProgressionDimension();
if (!cellBPD.getMinimum(tableLM).isAuto()) {
effectiveCellBPD = Math.max(effectiveCellBPD,
cellBPD.getMinimum(tableLM).getLength().getValue(tableLM));
}
if (!cellBPD.getOptimum(tableLM).isAuto()) {
effectiveCellBPD = Math.max(effectiveCellBPD,
cellBPD.getOptimum(tableLM).getLength().getValue(tableLM));
}
if (gu.getRowSpanIndex() == 0) {
//TODO ATM only non-row-spanned cells are taken for this
MinOptMaxUtil.restrict(explicitRowHeights[rgi], cellBPD, tableLM);
}
effectiveCellBPD = Math.max(effectiveCellBPD,
primary.getContentLength());
int borderWidths = primary.getBeforeAfterBorderWidth();
int padding = 0;
maxCellBPD = Math.max(maxCellBPD, effectiveCellBPD);
CommonBorderPaddingBackground cbpb
= primary.getCell().getCommonBorderPaddingBackground();
padding += cbpb.getPaddingBefore(false, primary.getCellLM());
padding += cbpb.getPaddingAfter(false, primary.getCellLM());
int effRowHeight = effectiveCellBPD
+ padding + borderWidths;
for (int previous = 0; previous < gu.getRowSpanIndex(); previous++) {
effRowHeight -= rowHeights[rgi - previous - 1].opt;
}
if (effRowHeight > rowHeights[rgi].min) {
//This is the new height of the (grid) row
MinOptMaxUtil.extendMinimum(rowHeights[rgi], effRowHeight, false);
}
if (!cellBPD.getOptimum(tableLM).isAuto()) {
effectiveCellBPD = cellBPD.getOptimum(tableLM).getLength()
.getValue(tableLM);
}
if (gu.isPrimary()) {
pgus.add(primary);
if (gu.getRowSpanIndex() == 0) {
effectiveCellBPD = Math.max(effectiveCellBPD, explicitRowHeight.opt);
}
effectiveCellBPD = Math.max(effectiveCellBPD, primary.getContentLength());
int borderWidths = primary.getBeforeAfterBorderWidth();
int padding = 0;
CommonBorderPaddingBackground cbpb = primary.getCell()
.getCommonBorderPaddingBackground();
padding += cbpb.getPaddingBefore(false, primary.getCellLM());
padding += cbpb.getPaddingAfter(false, primary.getCellLM());
int effRowHeight = effectiveCellBPD + padding + borderWidths;
for (int prev = rgi - 1; prev >= rgi - gu.getRowSpanIndex(); prev--) {
effRowHeight -= rowHeights[prev].opt;
}
if (effRowHeight > rowHeights[rgi].min) {
// This is the new height of the (grid) row
MinOptMaxUtil.extendMinimum(rowHeights[rgi], effRowHeight);
}
}
}

row.setHeight(rowHeights[rgi]);
row.setExplicitHeight(explicitRowHeights[rgi]);
if (maxCellBPD > row.getExplicitHeight().max) {
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Factory.create(
tableRow.getUserAgent().getEventBroadcaster());
eventProducer.rowTooTall(this, row.getIndex() + 1,
maxCellBPD, row.getExplicitHeight().max, tableRow.getLocator());
}
}
if (log.isDebugEnabled()) {
log.debug("rowGroup:");
for (int i = 0; i < rowHeights.length; i++) {
log.debug(" height=" + rowHeights[i] + " explicit=" + explicitRowHeights[i]);
}
row.setExplicitHeight(explicitRowHeight);
// TODO re-enable and improve after clarification
//See http://markmail.org/message/h25ycwwu7qglr4k4
// if (maxCellBPD > row.getExplicitHeight().max) {
//old:
// log.warn(FONode.decorateWithContextInfo(
// "The contents of row " + (row.getIndex() + 1)
// + " are taller than they should be (there is a"
// + " block-progression-dimension or height constraint
// + " on the indicated row)."
// + " Due to its contents the row grows"
// + " to " + maxCellBPD + " millipoints, but the row shouldn't get"
// + " any taller than " + row.getExplicitHeight() + " millipoints.",
// row.getTableRow()));
//new (with events):
// BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Factory.create(
// tableRow.getUserAgent().getEventBroadcaster());
// eventProducer.rowTooTall(this, row.getIndex() + 1,
// maxCellBPD, row.getExplicitHeight().max, tableRow.getLocator());
// }
}
LinkedList elements = tableStepper.getCombinedKnuthElementsForRowGroup(context,
rowGroup, bodyType);
returnList.addAll(elements);
}
}

+ 14
- 9
src/java/org/apache/fop/layoutmgr/table/RowPainter.java View File

@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -298,18 +299,22 @@ class RowPainter {
// cell, in most cases)
return 0;
} else {
int actualStart = startIndex;
ListIterator iter = pgu.getElements().listIterator(startIndex);
// Skip from the content length calculation glues and penalties occurring at the
// beginning of the page
while (actualStart <= endIndex
&& !((KnuthElement) pgu.getElements().get(actualStart)).isBox()) {
actualStart++;
boolean nextIsBox = false;
while (iter.nextIndex() <= endIndex && !nextIsBox) {
nextIsBox = ((KnuthElement) iter.next()).isBox();
}
int len = ElementListUtils.calcContentLength(
pgu.getElements(), actualStart, endIndex);
KnuthElement el = (KnuthElement)pgu.getElements().get(endIndex);
if (el.isPenalty()) {
len += el.getW();
int len = 0;
if (((KnuthElement) iter.previous()).isBox()) {
while (iter.nextIndex() < endIndex) {
KnuthElement el = (KnuthElement) iter.next();
if (el.isBox() || el.isGlue()) {
len += el.getW();
}
}
len += ActiveCell.getElementContentLength((KnuthElement) iter.next());
}
return len;
}

+ 18
- 28
src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java View File

@@ -23,6 +23,7 @@ import java.util.LinkedList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.Trait;
@@ -75,7 +76,6 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
private int cellIPD;
private int totalHeight;
private int usedBPD;
private int borderAndPaddingBPD;
private boolean emptyCell = true;

/**
@@ -98,22 +98,6 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
return getTable().isSeparateBorderModel();
}

/** {@inheritDoc} */
public void initialize() {
borderAndPaddingBPD = 0;
borderAndPaddingBPD += getTableCell()
.getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
borderAndPaddingBPD += getTableCell()
.getCommonBorderPaddingBackground().getBorderAfterWidth(false);
if (!isSeparateBorderModel()) {
borderAndPaddingBPD /= 2;
}
borderAndPaddingBPD += getTableCell().getCommonBorderPaddingBackground()
.getPaddingBefore(false, this);
borderAndPaddingBPD += getTableCell().getCommonBorderPaddingBackground()
.getPaddingAfter(false, this);
}

/**
* @return the table owning this cell
*/
@@ -146,7 +130,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
* {@inheritDoc}
*/
public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
MinOptMax stackLimit = new MinOptMax(context.getStackLimit());
MinOptMax stackLimit = new MinOptMax(context.getStackLimitBP());

referenceIPD = context.getRefIPD();
cellIPD = referenceIPD;
@@ -161,8 +145,8 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
LayoutContext childLC = new LayoutContext(0);
// curLM is a ?
childLC.setStackLimit(MinOptMax.subtract(context
.getStackLimit(), stackLimit));
childLC.setStackLimitBP(MinOptMax.subtract(context
.getStackLimitBP(), stackLimit));
childLC.setRefIPD(cellIPD);

// get elements from curLM
@@ -353,11 +337,12 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager

CommonBorderPaddingBackground padding = primaryGridUnit.getCell()
.getCommonBorderPaddingBackground();
int cellBPD = totalHeight - borderBeforeWidth - borderAfterWidth;
int paddingRectBPD = totalHeight - borderBeforeWidth - borderAfterWidth;
int cellBPD = paddingRectBPD;
cellBPD -= padding.getPaddingBefore(borderBeforeWhich == ConditionalBorder.REST, this);
cellBPD -= padding.getPaddingAfter(borderAfterWhich == ConditionalBorder.REST, this);

addBackgroundAreas(painter, firstRowHeight, borderBeforeWidth, cellBPD);
addBackgroundAreas(painter, firstRowHeight, borderBeforeWidth, paddingRectBPD);

if (isSeparateBorderModel()) {
if (!emptyCell || getTableCell().showEmptyCells()) {
@@ -487,22 +472,23 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager

/** Adds background areas for the column, body and row, if any. */
private void addBackgroundAreas(RowPainter painter, int firstRowHeight, int borderBeforeWidth,
int cellBPD) {
int paddingRectBPD) {
TableColumn column = getTable().getColumn(primaryGridUnit.getColIndex());
if (column.getCommonBorderPaddingBackground().hasBackground()) {
Block colBackgroundArea = getBackgroundArea(cellBPD, borderBeforeWidth);
Block colBackgroundArea = getBackgroundArea(paddingRectBPD, borderBeforeWidth);
((TableLayoutManager) parentLM).registerColumnBackgroundArea(column, colBackgroundArea,
-startIndent);
}

TableBody body = primaryGridUnit.getTableBody();
if (body.getCommonBorderPaddingBackground().hasBackground()) {
painter.registerPartBackgroundArea(getBackgroundArea(cellBPD, borderBeforeWidth));
painter.registerPartBackgroundArea(
getBackgroundArea(paddingRectBPD, borderBeforeWidth));
}

TableRow row = primaryGridUnit.getRow();
if (row != null && row.getCommonBorderPaddingBackground().hasBackground()) {
Block rowBackgroundArea = getBackgroundArea(cellBPD, borderBeforeWidth);
Block rowBackgroundArea = getBackgroundArea(paddingRectBPD, borderBeforeWidth);
((TableLayoutManager) parentLM).addBackgroundArea(rowBackgroundArea);
TraitSetter.addBackground(rowBackgroundArea, row.getCommonBorderPaddingBackground(),
(TableLayoutManager) parentLM,
@@ -540,12 +526,16 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}

private Block getBackgroundArea(int bpd, int borderBeforeWidth) {
CommonBorderPaddingBackground padding = getTableCell().getCommonBorderPaddingBackground();
int paddingStart = padding.getPaddingStart(false, this);
int paddingEnd = padding.getPaddingEnd(false, this);
Block block = new Block();
TraitSetter.setProducerID(block, getTable().getId());
block.setPositioning(Block.ABSOLUTE);
block.setIPD(cellIPD);
block.setIPD(cellIPD + paddingStart + paddingEnd);
block.setBPD(bpd);
block.setXOffset(xoffset + startIndent);
block.setXOffset(xoffset + startIndent - paddingStart);
block.setYOffset(yoffset + borderBeforeWidth);
return block;
}

+ 2
- 0
src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java View File

@@ -106,10 +106,12 @@ class TableContentPosition extends Position {
}
}

/** {@inheritDoc} */
public boolean generatesAreas() {
return true;
}

/** {@inheritDoc} */
public String toString() {
StringBuffer sb = new StringBuffer("TableContentPosition:");
sb.append(getIndex());

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

@@ -43,6 +43,11 @@ class TableHFPenaltyPosition extends Position {
super(lm);
}

/** {@inheritDoc} */
public boolean generatesAreas() {
return true;
}

public String toString() {
StringBuffer sb = new StringBuffer("TableHFPenaltyPosition:");
sb.append(getIndex()).append("(");

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

@@ -48,6 +48,11 @@ class TableHeaderFooterPosition extends Position {
this.nestedElements = nestedElements;
}

/** {@inheritDoc} */
public boolean generatesAreas() {
return true;
}

public String toString() {
StringBuffer sb = new StringBuffer("Table");
sb.append(header ? "Header" : "Footer");

+ 0
- 73
src/java/org/apache/fop/render/ps/PSImageUtils.java View File

@@ -1,73 +0,0 @@
/*
* 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.render.ps;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.ps.PSGenerator;

import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;

/**
* Utility code for rendering images in PostScript.
*/
public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils {

/** logging instance */
protected static Log log = LogFactory.getLog(PSImageUtils.class);

/**
* Renders an EPS image to PostScript.
* @param img EPS image to render
* @param x x position
* @param y y position
* @param w width
* @param h height
* @param gen PS generator
* @deprecated Use {@link #renderEPS(java.io.InputStream, String, java.awt.geom.Rectangle2D,
* java.awt.geom.Rectangle2D, PSGenerator)} instead
*/
public static void renderEPS(EPSImage img,
float x, float y, float w, float h,
PSGenerator gen) {
try {
if (!img.load(FopImage.ORIGINAL_DATA)) {
gen.commentln("%EPS image could not be processed: " + img);
return;
}
int[] bbox = img.getBBox();
int bboxw = bbox[2] - bbox[0];
int bboxh = bbox[3] - bbox[1];
String name = img.getDocName();
if (name == null || name.length() == 0) {
name = img.getOriginalURI();
}
renderEPS(img.getEPSImage(), name,
x, y, w, h,
bbox[0], bbox[1], bboxw, bboxh, gen);

} catch (Exception e) {
log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
+ e.getMessage() + ")", e);
}
}

}

+ 0
- 70
src/java/org/apache/fop/render/rtf/SVGConverter.java View File

@@ -1,70 +0,0 @@
/*
* 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.render.rtf;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.image.XMLImage;

/**
* Helper class for converting SVG to bitmap images.
*/
public final class SVGConverter {

/** logger instance */
private static Log log = LogFactory.getLog(SVGConverter.class);

/**
* Constructor is private, because it's just a utility class.
*/
private SVGConverter() {
}
/**
* Converts a SVG image to a JPEG bitmap.
* @param image the SVG image
* @return a byte array containing the JPEG image
*/
public static byte[] convertToJPEG(XMLImage image) {
JPEGTranscoder transcoder = new JPEGTranscoder();
/* TODO Disabled to avoid side-effect due to the mixing of source and target resolutions
* This should be reenabled when it has been determined how exactly to handle this
transcoder.addTranscodingHint(ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER,
new Float(25.4f / 300)); //300dpi should be enough for now.
*/
transcoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(0.9f));
TranscoderInput input = new TranscoderInput(image.getDocument());
ByteArrayOutputStream baout = new ByteArrayOutputStream(16384);
TranscoderOutput output = new TranscoderOutput(baout);
try {
transcoder.transcode(input, output);
return baout.toByteArray();
} catch (TranscoderException e) {
log.error(e);
return null;
}
}
}

src/java-1.4/org/apache/fop/svg/GraphicsConfiguration.java → src/java/org/apache/fop/svg/GraphicsConfiguration.java View File


+ 48
- 8
status.xml View File

@@ -59,7 +59,7 @@
</action>
-->
<!--/release-->
<release version="0.95beta" date="8 March 2008">
<release version="0.95beta" date="22 March 2008">
<notes>
<section>
<title>Notes</title>
@@ -69,8 +69,8 @@
</p>
<ul>
<li>
Improvements and bugfixes for tables (keep and break support, border
conditionality etc.)
Many bugfixes in tables, plus some new features (full support for keeps and
breaks, border conditionality, background on columns and header/footer/body)
</li>
<li>
Improvements and bugfixes for font handling and font
@@ -86,14 +86,54 @@
FOP will, from now on, <strong>require at least Java 1.4</strong>.
</p>
<p>
The image libraries Jimi and JAI are no longer needed (and used). Instead we rely
completely on the Image I/O API that has been introduced with Java 1.4. If you still
need support for bitmap image formats that do not work out-of-the-box, we recommend
adding <link href="http://jai-imageio.dev.java.net/">JAI Image I/O Tools</link>
(an Image I/O compatible image codec package) to the classpath.
There have been a few changes in tables that make FOP both more strict and more
compliant to the Recommendation:
<ul>
<li>XSL-FO 1.1 explicitly states that a row-spanning fo:table-cell element is not
allowed to span further than its enclosing fo:table-header/footer/body element
(see bottom of <link href="http://www.w3.org/TR/xsl11/#fo_table">section
6.7.3</link>). From now on FOP will give a validation error if a document
contains such an erroneous cell.
</li>
<li>
<p>If an fo:table element contains explicit fo:table-column children, then those
elements set the total number of columns in the table. This means that a
validation error will now occur if a row contains more cells than available
columns. This change allows to improve performance, since the rendering of the
table may start as soon as the table-column elements have been parsed.</p>
<p>If more flexibility is needed, then the fo:table-column elements may be just
omitted. The final number of columns will then be set by the row that has the
most cells.</p>
</li>
</ul>
</p>
<p>
The image libraries Jimi and JAI are no longer needed (and used) for image loading.
Instead we rely completely on the Image I/O API that has been introduced with
Java 1.4. If you still need support for bitmap image formats that do not work
out-of-the-box, we recommend adding
<link href="http://jai-imageio.dev.java.net/">JAI Image I/O Tools</link>
(an Image I/O compatible image codec package) to the classpath. JAI is still required
for building the FOP distribution but it is optional for normal builds and at run-time.
</p>
</section>
</notes>
<action context="Layout" dev="JM" type="fix" fixes-bug="44412">
Bugfix: The before border of a block is no longer swallowed if its first child issues
a break-before.
</action>
<action context="Layout" dev="JM" type="fix" fixes-bug="44412">
Bugfix: When there was a forced break after a block with (conditional) borders the
border-after wasn't painted.
</action>
<action context="Layout" dev="VH" type="fix">
Bugfix: a forced break inside a cell was ignored when occurring before the minimum height
set on the enclosing row was set.
</action>
<action context="Layout" dev="JM" type="fix">
Fixed exceptions when lists, tables or block-container are children of an inline-level
FO.
</action>
<action context="Layout" dev="VH" type="add" importance="high">
Added support for background on fo:table-column and fo:table-header/footer/body elements.
</action>

+ 5
- 6
test/java/org/apache/fop/URIResolutionTestCase.java View File

@@ -36,17 +36,19 @@ import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.xml.XMLRenderer;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Document;

/**
* Tests URI resolution facilities.
@@ -85,9 +87,6 @@ public class URIResolutionTestCase extends AbstractFOPTestCase {
private void innerTestFO1(boolean withStream) throws Exception {
FOUserAgent ua = fopFactory.newFOUserAgent();

//Reset the image caches to force URI resolution!
ua.getFactory().getImageFactory().clearCaches();
File foFile = new File(getBaseDir(), "test/xml/uri-resolution1.fo");
MyURIResolver resolver = new MyURIResolver(withStream);

+ 0
- 48
test/layoutengine/disabled-testcases.xml View File

@@ -232,54 +232,6 @@
<file>region-body_column-count_bug36356.xml</file>
<description>Column balancing doesn't work as expected.</description>
</testcase>
<testcase>
<name>No background-images on table-body</name>
<file>table-body_background-image.xml</file>
<description>The backgrounds of table-body, table-header,
table-footer and table-column are not painted, yet.</description>
</testcase>
<testcase>
<name>Collapsing Border Model NYI</name>
<file>table_border-collapse_collapse_1.xml</file>
<description>Border-collapse="collapse" is not yet
implemented.</description>
</testcase>
<testcase>
<name>Collapsing Border Model NYI</name>
<file>table_border-collapse_collapse_2.xml</file>
<description>Border-collapse="collapse" is not yet
implemented.</description>
</testcase>
<testcase>
<name>Problems with border and padding on tables</name>
<file>table_border_padding.xml</file>
<description>The element list seems to not be fully correct, yet, causing
the layout to look odd.</description>
</testcase>
<testcase>
<name>keep-with-previous doesn't work inside tables</name>
<file>table-cell_block_keep-with-previous.xml</file>
<description>Keep-with-previous doesn't work inside tables and
lists, yet.</description>
</testcase>
<testcase>
<name>Border and padding conditionality is NYI on table-cells</name>
<file>table-cell_border_padding_conditionality.xml</file>
<description>Border and padding conditionality are not supported
on table-cells, yet.</description>
</testcase>
<testcase>
<name>No background-images on table-header</name>
<file>table-header_background-image.xml</file>
<description>The backgrounds of table-body, table-header,
table-footer and table-column are not painted, yet.</description>
</testcase>
<testcase>
<name>keep-with-previous doesn't work on table-rows</name>
<file>table-row_keep-with-previous.xml</file>
<description>Keep-with-previous doesn't work inside tables and
lists, yet.</description>
</testcase>
<testcase>
<name>table-cell empty area with marker.xml</name>
<file>table-cell_empty_area_with_marker.xml</file>

+ 112
- 0
test/layoutengine/standard-testcases/block-level_break-after_bug44412.xml View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks Bugzilla #44412 where the border-after of an fo:block wasn't painted in
case break-after is present.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page" page-height="5in" page-width="5in" margin="20pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body">
<fo:block>Before the block</fo:block>
<fo:block id="b1" border="4pt solid black" break-before="column" break-after="column">A block with
borders and break-before and break-after.</fo:block>
<fo:block>After the block</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body">
<fo:block-container id="bc1" border="4pt solid black" break-after="column">
<fo:block>A block-container with borders and break-after.</fo:block>
</fo:block-container>
<fo:block>After the block-container</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body">
<fo:list-block id="lb1" border="4pt solid black" break-after="column">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>&#x2022;</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block start-indent="body-start()">Blaaaaaah</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
<fo:block>After the list-block</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body">
<fo:list-block>
<fo:list-item id="li1" border="4pt solid black" break-after="column">
<fo:list-item-label end-indent="label-end()">
<fo:block>&#x2022;</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block start-indent="body-start()">Blaaaaaah</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
<fo:block>After the list-item</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%" id="tbl1" border="4pt solid black" break-after="column">
<fo:table-column column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>Blaaaaah</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>After the table</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="1" xpath="count(//block[@prod-id = 'b1'])"/>
<eval expected="4000 4000 4000 4000" xpath="//block[@prod-id = 'b1']/@bap"/>

<eval expected="2" xpath="count(//block[@prod-id = 'bc1'])"/> <!-- 2 because viewport/ref pair -->
<eval expected="4000 4000 4000 4000" xpath="//block[@prod-id = 'bc1'][1]/@bap"/>
<eval expected="1" xpath="count(//block[@prod-id = 'lb1'])"/>
<eval expected="4000 4000 4000 4000" xpath="//block[@prod-id = 'lb1']/@bap"/>
<eval expected="1" xpath="count(//block[@prod-id = 'li1'])"/>
<eval expected="4000 4000 4000 4000" xpath="//block[@prod-id = 'li1']/@bap"/>
<eval expected="1" xpath="count(//block[@prod-id = 'tbl1'])"/>
<eval expected="4000 4000 4000 4000" xpath="//block[@prod-id = 'tbl1']/block[1]/@bap"/>
</checks>
</testcase>

+ 64
- 0
test/layoutengine/standard-testcases/block_break-before_bug44412.xml View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks Bugzilla #44412 where a break-before on the first child of an otherwise
empty block is set. It is expected that the parent block creates two areas, the first with
only border-before on the first page and zero bpd.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page" page-height="5in" page-width="5in" margin="20pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body">
<fo:block>Before the block</fo:block>
<fo:block id="b1" border="4pt solid black">
<fo:block break-before="page">The break-before set on this block causes the parent
block to produce an empty block area with only a border before on the
first page.</fo:block>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="2" xpath="count(//block[@prod-id = 'b1'])"/>
<eval expected="4000 4000 4000 0" xpath="(//block[@prod-id = 'b1'])[1]/@bap"/>
<eval expected="4000 4000 0 4000" xpath="(//block[@prod-id = 'b1'])[2]/@bap"/>
<eval expected="0" xpath="(//block[@prod-id = 'b1'])[1]/@bpd"/>
<eval expected="43200" xpath="(//block[@prod-id = 'b1'])[2]/@bpd"/>
<element-list category="breaker" index="0">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="0" aux="true"/>
<penalty w="0" p="INF"/>
<glue w="4000"/> <!-- border-before -->
<box w="0"/> <!-- first block area of the "b1" block with zero bpd -->
<skip>3</skip>
</element-list>
</checks>
</testcase>

+ 104
- 0
test/layoutengine/standard-testcases/inline_block-level_nested_1.xml View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks fo:inline and nested block-level nodes.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="6in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal">
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:inline>before
<fo:list-block>
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>&#x2022;</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block id="list-item-body1">Inline list item one.</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
after</fo:inline>
</fo:block>
<fo:block space-before="0.5em">
<fo:inline>before
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="proportional-column-width(1)"
number-columns-repeated="2"/>"
<fo:table-body>
<fo:table-row>
<fo:table-cell id="table-cell1">
<fo:block>cell1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>cell2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
after</fo:inline>
</fo:block>
<fo:block space-before="0.5em">
<fo:inline>before
<fo:block-container>
<fo:block id="block-in-bc">block in block-container</fo:block>
</fo:block-container>
after</fo:inline>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<element-list category="breaker">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<glue w="6000" aux="true"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<glue w="6000" aux="true"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<skip>3</skip>
</element-list>
<true xpath="boolean(//block[@prod-id='list-item-body1'])"/>
<true xpath="boolean(//block[@prod-id='table-cell1'])"/>
<true xpath="boolean(//block[@prod-id='block-in-bc'])"/>
</checks>
</testcase>

+ 0
- 110
test/layoutengine/standard-testcases/table-body_background-image.xml View File

@@ -1,110 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks background image on a fo:table-body.
</p>
</info>
<variables>
<img>../../resources/images/bgimg300dpi.jpg</img>
</variables>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:table>
<fo:table-column column-number="1" />
<fo:table-column column-number="2" />
<fo:table-column column-number="3" />
<fo:table-header>
<fo:table-row>
<fo:table-cell>
<fo:block>Header Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Header Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Header Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body background-color="yellow" background-repeat="no-repeat" background-position-horizontal="center" background-position-vertical="center" background-image="##img">
<fo:table-row>
<fo:table-cell>
<fo:block>Row 1 Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 1 Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 1 Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>Row 2 Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 2 Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 2 Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>Row 3 Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 3 Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 3 Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>Row 4 Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 4 Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 4 Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>Table with centered background image on body</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<!-- backgrounds on table-body are not supported at the time this test
was written. Therefore no checks! -->
</checks>
</testcase>

+ 0
- 85
test/layoutengine/standard-testcases/table-cell_block_keep-with-previous.xml View File

@@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks keep-with-previous on content inside tables.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" white-space-collapse="true" widows="0" orphans="0">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="4.5 * 14.4pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal">
<fo:flow flow-name="xsl-region-body">
<fo:block>block1</fo:block>
<fo:table table-layout="fixed">
<fo:table-column/>
<fo:table-column/>
<fo:table-body>
<fo:table-row>
<fo:table-cell id="cell1">
<fo:block keep-with-previous.within-page="always">line1</fo:block>
<fo:block>line2</fo:block>
</fo:table-cell>
<fo:table-cell id="cell2">
<fo:block>line1</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell id="cell3">
<fo:block>line1</fo:block>
</fo:table-cell>
<fo:table-cell id="cell4">
<fo:block keep-with-previous.within-page="always">line1</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>block2</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<element-list category="table-cell" id="cell1">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
</element-list>
<element-list category="table-cell" id="cell2">
<box w="14400"/>
</element-list>
<element-list category="breaker" index="0">
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<skip>3</skip>
</element-list>
</checks>
</testcase>

+ 0
- 101
test/layoutengine/standard-testcases/table-header_background-image.xml View File

@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks background image on a fo:table-header and footer.
</p>
</info>
<variables>
<img>../../resources/images/bgimg300dpi.jpg</img>
</variables>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:table>
<fo:table-column column-number="1" />
<fo:table-column column-number="2" />
<fo:table-column column-number="3" />
<fo:table-header background-color="yellow" background-repeat="no-repeat" background-position-horizontal="center" background-position-vertical="center" background-image="##img">
<fo:table-row>
<fo:table-cell>
<fo:block>Header Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Header Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Header Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-footer background-color="yellow" background-repeat="no-repeat" background-position-horizontal="center" background-position-vertical="center" background-image="##img">
<fo:table-row>
<fo:table-cell>
<fo:block>Footer Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Footer Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Footer Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-footer>
<fo:table-body background-color="blue">
<fo:table-row height="4in" background-color="blue">
<fo:table-cell>
<fo:block>Row 1 Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 1 Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 1 Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row height="4in" background-color="blue">
<fo:table-cell>
<fo:block>Row 2 Col 1</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 2 Col 2</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Row 2 Col 3</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>Table with centered background image in header and footer</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<!-- backgrounds on table-header/footer are not supported at the time this test
was written. Therefore no checks! -->
</checks>
</testcase>

+ 210
- 40
test/layoutengine/standard-testcases/table-row_keep-with-previous.xml View File

@@ -19,66 +19,236 @@
<testcase>
<info>
<p>
This test checks keep-with-previous on table-rows.
This test checks that keep-with-previous works on table-row.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" white-space-collapse="true" widows="0" orphans="0">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="4.5 * 14.4pt">
<fo:region-body/>
<fo:simple-page-master master-name="page" page-height="3in" page-width="5in"
margin="0.5in">
<fo:region-body background-color="#F0F0F0"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal">

<!-- table 1 -->
<fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block space-after="1.5*14.4pt">block1</fo:block>
<fo:table table-layout="fixed" width="100%">
<fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/>
<fo:block space-after="106pt">1. Before the table</fo:block>
<fo:table width="100%" table-layout="fixed"
border-collapse="separate" border="4pt solid black">
<fo:table-column number-columns-repeated="2"
column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row keep-with-previous.within-page="always">
<fo:table-cell id="cell1">
<fo:block>line1</fo:block>
<fo:block>line2</fo:block>
<fo:table-row>
<fo:table-cell border="2pt solid blue">
<fo:block>Cell 1.1 Line 1</fo:block>
<fo:block>Cell 1.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid teal">
<fo:block>Cell 1.2 Line 1</fo:block>
<fo:block>Cell 1.2 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row keep-with-previous="always">
<fo:table-cell border="2pt solid green">
<fo:block>Cell 2.1 Line 1</fo:block>
<fo:block>Cell 2.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid olive">
<fo:block>Cell 3.1 Line 1</fo:block>
<fo:block>Cell 3.1 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>After the table</fo:block>
</fo:flow>
</fo:page-sequence>

<!-- table 2 -->
<fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block space-after="106pt">2. Before the table</fo:block>
<fo:table width="100%" table-layout="fixed"
border-collapse="separate" border="4pt solid black">
<fo:table-column number-columns-repeated="2"
column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="2pt solid blue">
<fo:block>Cell 1.1 Line 1</fo:block>
<fo:block>Cell 1.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid teal" number-rows-spanned="2">
<fo:block>Cell 1.2 Line 1</fo:block>
<fo:block>Cell 1.2 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell id="cell2">
<fo:block>line1</fo:block>
</fo:table-row>
<fo:table-row keep-with-previous="always">
<fo:table-cell border="2pt solid green">
<fo:block>Cell 2.1 Line 1</fo:block>
<fo:block>Cell 2.1 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row keep-with-previous.within-page="always">
<fo:table-cell id="cell3">
<fo:block>line1</fo:block>
</fo:table-body>
</fo:table>
<fo:block>After the table</fo:block>
</fo:flow>
</fo:page-sequence>

<!-- table 3 -->
<fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block space-after="124">3. Before the table</fo:block>
<fo:block>Before the table</fo:block>
<fo:table width="100%" table-layout="fixed"
border-collapse="collapse" border="4pt solid black">
<fo:table-column number-columns-repeated="2"
column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row keep-with-previous="always">
<fo:table-cell border="2pt solid blue" number-rows-spanned="2">
<fo:block>Cell 1.1 Line 1</fo:block>
<fo:block>Cell 1.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell id="cell4">
<fo:block>line1</fo:block>
<fo:table-cell border="2pt solid teal">
<fo:block>Cell 1.2 Line 1</fo:block>
<fo:block>Cell 1.2 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell border="2pt solid olive">
<fo:block>Cell 2.1 Line 1</fo:block>
<fo:block>Cell 2.1 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>block2</fo:block>
<fo:block>After the table</fo:block>
</fo:flow>
</fo:page-sequence>

</fo:root>
</fo>
<checks>
<element-list category="table-cell" id="cell1">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
</element-list>
<element-list category="table-cell" id="cell2">
<box w="14400"/>
</element-list>
<element-list category="breaker" index="0">
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<skip>3</skip>
</element-list>

<!-- table 1 -->
<eval expected="2" xpath="count(//pageSequence[1]/pageViewport)"/>
<!-- page 1 -->
<eval expected="2" xpath="count(//pageViewport[@nr=1]//flow/block)"/>
<eval expected="1. Before the table" xpath="//pageViewport[@nr=1]//flow/block[1]/lineArea"/>
<eval expected="12000" xpath="//pageViewport[@nr=1]//flow/block[2]/@bpd"/>
<eval expected="16000" xpath="//pageViewport[@nr=1]//flow/block[2]/@bpda"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=1]//flow/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=1]//flow/block[2]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@bpda"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=1]//flow/block[2]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 1" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/block/lineArea"/>
<!-- cell 1.2 -->
<eval expected="10000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@bpda"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=1]//flow/block[2]/block[2]/block)"/>
<eval expected="Cell 1.2 Line 1" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/block/lineArea"/>
<!-- page 2 -->
<eval expected="2" xpath="count(//pageViewport[@nr=2]//flow/block)"/>
<eval expected="After the table" xpath="//pageViewport[@nr=2]//flow/block[2]/lineArea"/>
<eval expected="36000" xpath="//pageViewport[@nr=2]//flow/block[1]/@bpd"/>
<eval expected="40000" xpath="//pageViewport[@nr=2]//flow/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=2]//flow/block[1]/@border-before"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=2]//flow/block[1]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@border-before"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block[1]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 2" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/block/lineArea"/>
<!-- cell 1.2 -->
<eval expected="10000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@border-before"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block[1]/block[2]/block)"/>
<eval expected="Cell 1.2 Line 2" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/block/lineArea"/>
<!-- cell 2.1 -->
<eval expected="20000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@bpd"/>
<eval expected="24000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@bpda"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@border-before"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@border-after"/>
<!-- cell 2.2 -->
<eval expected="20000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@bpd"/>
<eval expected="24000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@bpda"/>
<eval expected="(solid,#808000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@border-before"/>
<eval expected="(solid,#808000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@border-after"/>

<!-- table 2 -->
<eval expected="2" xpath="count(//pageSequence[2]/pageViewport)"/>
<!-- page 1 -->
<eval expected="2" xpath="count(//pageViewport[@nr=3]//flow/block)"/>
<eval expected="2. Before the table" xpath="//pageViewport[@nr=3]//flow/block[1]/lineArea"/>
<eval expected="12000" xpath="//pageViewport[@nr=3]//flow/block[2]/@bpd"/>
<eval expected="16000" xpath="//pageViewport[@nr=3]//flow/block[2]/@bpda"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=3]//flow/block[2]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@bpda"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=3]//flow/block[2]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 1" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/block/lineArea"/>
<!-- cell 1.2 -->
<eval expected="10000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@bpda"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=3]//flow/block[2]/block[2]/block)"/>
<eval expected="Cell 1.2 Line 1" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/block/lineArea"/>
<!-- page 2 -->
<eval expected="2" xpath="count(//pageViewport[@nr=4]//flow/block)"/>
<eval expected="After the table" xpath="//pageViewport[@nr=4]//flow/block[2]/lineArea"/>
<eval expected="36000" xpath="//pageViewport[@nr=4]//flow/block[1]/@bpd"/>
<eval expected="40000" xpath="//pageViewport[@nr=4]//flow/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=4]//flow/block[1]/@border-before"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=4]//flow/block[1]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@border-before"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=4]//flow/block[1]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 2" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/block/lineArea"/>
<!-- cell 2.1 -->
<eval expected="20000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@bpd"/>
<eval expected="24000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@bpda"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@border-before"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@border-after"/>
<!-- cell 1.2 -->
<eval expected="34000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@bpd"/>
<eval expected="36000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@border-before"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=4]//flow/block[1]/block[3]/block)"/>
<eval expected="Cell 1.2 Line 2" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/block/lineArea"/>

<!-- table 3 -->
<eval expected="2" xpath="count(//pageSequence[3]/pageViewport)"/>
<!-- page 1 -->
<eval expected="1" xpath="count(//pageViewport[@nr=5]//flow/block)"/>
<eval expected="3. Before the table" xpath="//pageViewport[@nr=5]//flow/block[1]/lineArea"/>
<!-- page 2 -->
<eval expected="3" xpath="count(//pageViewport[@nr=6]//flow/block)"/>
<eval expected="Before the table" xpath="//pageViewport[@nr=6]//flow/block[1]/lineArea"/>
<eval expected="46000" xpath="//pageViewport[@nr=6]//flow/block[2]/@bpd"/>
<eval expected="46000" xpath="//pageViewport[@nr=6]//flow/block[2]/@bpda"/>
<eval expected="After the table" xpath="//pageViewport[@nr=6]//flow/block[3]/lineArea"/>

</checks>
</testcase>

+ 0
- 254
test/layoutengine/standard-testcases/table-row_keep-with-previous_2.xml View File

@@ -1,254 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks that keep-with-previous works on table-row.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page" page-height="3in" page-width="5in"
margin="0.5in">
<fo:region-body background-color="#F0F0F0"/>
</fo:simple-page-master>
</fo:layout-master-set>

<!-- table 1 -->
<fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block space-after="106pt">1. Before the table</fo:block>
<fo:table width="100%" table-layout="fixed"
border-collapse="separate" border="4pt solid black">
<fo:table-column number-columns-repeated="2"
column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="2pt solid blue">
<fo:block>Cell 1.1 Line 1</fo:block>
<fo:block>Cell 1.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid teal">
<fo:block>Cell 1.2 Line 1</fo:block>
<fo:block>Cell 1.2 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row keep-with-previous="always">
<fo:table-cell border="2pt solid green">
<fo:block>Cell 2.1 Line 1</fo:block>
<fo:block>Cell 2.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid olive">
<fo:block>Cell 3.1 Line 1</fo:block>
<fo:block>Cell 3.1 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>After the table</fo:block>
</fo:flow>
</fo:page-sequence>

<!-- table 2 -->
<fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block space-after="106pt">2. Before the table</fo:block>
<fo:table width="100%" table-layout="fixed"
border-collapse="separate" border="4pt solid black">
<fo:table-column number-columns-repeated="2"
column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="2pt solid blue">
<fo:block>Cell 1.1 Line 1</fo:block>
<fo:block>Cell 1.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid teal" number-rows-spanned="2">
<fo:block>Cell 1.2 Line 1</fo:block>
<fo:block>Cell 1.2 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row keep-with-previous="always">
<fo:table-cell border="2pt solid green">
<fo:block>Cell 2.1 Line 1</fo:block>
<fo:block>Cell 2.1 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>After the table</fo:block>
</fo:flow>
</fo:page-sequence>

<!-- table 3 -->
<fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block space-after="124">3. Before the table</fo:block>
<fo:block>Before the table</fo:block>
<fo:table width="100%" table-layout="fixed"
border-collapse="collapse" border="4pt solid black">
<fo:table-column number-columns-repeated="2"
column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row keep-with-previous="always">
<fo:table-cell border="2pt solid blue" number-rows-spanned="2">
<fo:block>Cell 1.1 Line 1</fo:block>
<fo:block>Cell 1.1 Line 2</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid teal">
<fo:block>Cell 1.2 Line 1</fo:block>
<fo:block>Cell 1.2 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell border="2pt solid olive">
<fo:block>Cell 2.1 Line 1</fo:block>
<fo:block>Cell 2.1 Line 2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>After the table</fo:block>
</fo:flow>
</fo:page-sequence>

</fo:root>
</fo>
<checks>

<!-- table 1 -->
<eval expected="2" xpath="count(//pageSequence[1]/pageViewport)"/>
<!-- page 1 -->
<eval expected="2" xpath="count(//pageViewport[@nr=1]//flow/block)"/>
<eval expected="1. Before the table" xpath="//pageViewport[@nr=1]//flow/block[1]/lineArea"/>
<eval expected="12000" xpath="//pageViewport[@nr=1]//flow/block[2]/@bpd"/>
<eval expected="16000" xpath="//pageViewport[@nr=1]//flow/block[2]/@bpda"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=1]//flow/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=1]//flow/block[2]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@bpda"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=1]//flow/block[2]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 1" xpath="//pageViewport[@nr=1]//flow/block[2]/block[1]/block/lineArea"/>
<!-- cell 1.2 -->
<eval expected="10000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@bpda"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=1]//flow/block[2]/block[2]/block)"/>
<eval expected="Cell 1.2 Line 1" xpath="//pageViewport[@nr=1]//flow/block[2]/block[2]/block/lineArea"/>
<!-- page 2 -->
<eval expected="2" xpath="count(//pageViewport[@nr=2]//flow/block)"/>
<eval expected="After the table" xpath="//pageViewport[@nr=2]//flow/block[2]/lineArea"/>
<eval expected="36000" xpath="//pageViewport[@nr=2]//flow/block[1]/@bpd"/>
<eval expected="40000" xpath="//pageViewport[@nr=2]//flow/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=2]//flow/block[1]/@border-before"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=2]//flow/block[1]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@border-before"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block[1]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 2" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/block/lineArea"/>
<!-- cell 1.2 -->
<eval expected="10000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@border-before"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block[1]/block[2]/block)"/>
<eval expected="Cell 1.2 Line 2" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/block/lineArea"/>
<!-- cell 2.1 -->
<eval expected="20000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@bpd"/>
<eval expected="24000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@bpda"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@border-before"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[3]/@border-after"/>
<!-- cell 2.2 -->
<eval expected="20000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@bpd"/>
<eval expected="24000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@bpda"/>
<eval expected="(solid,#808000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@border-before"/>
<eval expected="(solid,#808000,2000)" xpath="//pageViewport[@nr=2]//flow/block[1]/block[4]/@border-after"/>

<!-- table 2 -->
<eval expected="2" xpath="count(//pageSequence[2]/pageViewport)"/>
<!-- page 1 -->
<eval expected="2" xpath="count(//pageViewport[@nr=3]//flow/block)"/>
<eval expected="2. Before the table" xpath="//pageViewport[@nr=3]//flow/block[1]/lineArea"/>
<eval expected="12000" xpath="//pageViewport[@nr=3]//flow/block[2]/@bpd"/>
<eval expected="16000" xpath="//pageViewport[@nr=3]//flow/block[2]/@bpda"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=3]//flow/block[2]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@bpda"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=3]//flow/block[2]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 1" xpath="//pageViewport[@nr=3]//flow/block[2]/block[1]/block/lineArea"/>
<!-- cell 1.2 -->
<eval expected="10000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@bpda"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@border-before"/>
<eval expected="" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=3]//flow/block[2]/block[2]/block)"/>
<eval expected="Cell 1.2 Line 1" xpath="//pageViewport[@nr=3]//flow/block[2]/block[2]/block/lineArea"/>
<!-- page 2 -->
<eval expected="2" xpath="count(//pageViewport[@nr=4]//flow/block)"/>
<eval expected="After the table" xpath="//pageViewport[@nr=4]//flow/block[2]/lineArea"/>
<eval expected="36000" xpath="//pageViewport[@nr=4]//flow/block[1]/@bpd"/>
<eval expected="40000" xpath="//pageViewport[@nr=4]//flow/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=4]//flow/block[1]/@border-before"/>
<eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=4]//flow/block[1]/@border-after"/>
<!-- cell 1.1 -->
<eval expected="10000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@bpd"/>
<eval expected="12000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@border-before"/>
<eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=4]//flow/block[1]/block[1]/block)"/>
<eval expected="Cell 1.1 Line 2" xpath="//pageViewport[@nr=4]//flow/block[1]/block[1]/block/lineArea"/>
<!-- cell 2.1 -->
<eval expected="20000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@bpd"/>
<eval expected="24000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@bpda"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@border-before"/>
<eval expected="(solid,#008000,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[2]/@border-after"/>
<!-- cell 1.2 -->
<eval expected="34000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@bpd"/>
<eval expected="36000" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@bpda"/>
<eval expected="" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@border-before"/>
<eval expected="(solid,#008080,2000)" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/@border-after"/>
<eval expected="1" xpath="count(//pageViewport[@nr=4]//flow/block[1]/block[3]/block)"/>
<eval expected="Cell 1.2 Line 2" xpath="//pageViewport[@nr=4]//flow/block[1]/block[3]/block/lineArea"/>

<!-- table 3 -->
<eval expected="2" xpath="count(//pageSequence[3]/pageViewport)"/>
<!-- page 1 -->
<eval expected="1" xpath="count(//pageViewport[@nr=5]//flow/block)"/>
<eval expected="3. Before the table" xpath="//pageViewport[@nr=5]//flow/block[1]/lineArea"/>
<!-- page 2 -->
<eval expected="3" xpath="count(//pageViewport[@nr=6]//flow/block)"/>
<eval expected="Before the table" xpath="//pageViewport[@nr=6]//flow/block[1]/lineArea"/>
<eval expected="46000" xpath="//pageViewport[@nr=6]//flow/block[2]/@bpd"/>
<eval expected="46000" xpath="//pageViewport[@nr=6]//flow/block[2]/@bpda"/>
<eval expected="After the table" xpath="//pageViewport[@nr=6]//flow/block[3]/lineArea"/>

</checks>
</testcase>

+ 113
- 0
test/layoutengine/standard-testcases/table_backgrounds_2.xml View File

@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks background painting for fo:table-row, fo:table-body and fo:table-column
when the cells use padding.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell id="bg-cell" padding="2pt 3pt 4pt 5pt" border="solid 2pt" background-color="lightgray">
<fo:block>background on cell</fo:block>
</fo:table-cell>
<fo:table-cell padding="2pt 3pt 4pt 5pt" border="solid 2pt" background-color="lightgray">
<fo:block>background on cell</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row background-color="yellow">
<fo:table-cell id="bg-row" padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on row</fo:block>
</fo:table-cell>
<fo:table-cell padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on row</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
<fo:table-body background-color="orange">
<fo:table-row>
<fo:table-cell id="bg-body" padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on body</fo:block>
</fo:table-cell>
<fo:table-cell padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on body</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"
background-color="violet"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell id="bg-col" padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on column</fo:block>
</fo:table-cell>
<fo:table-cell padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on column</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:table table-layout="fixed" width="100%" background-color="red">
<fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell id="bg-table" padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on table</fo:block>
</fo:table-cell>
<fo:table-cell padding="2pt 3pt 4pt 5pt" border="solid 2pt">
<fo:block>background on table</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="20400" xpath="//block[@prod-id='bg-row']/preceding-sibling::block[1]/@bpd"/>
<eval expected="178000" xpath="//block[@prod-id='bg-row']/preceding-sibling::block[1]/@ipd"/>
<eval expected="23400" xpath="//block[@prod-id='bg-row']/preceding-sibling::block[1]/@top-offset"/>
<eval expected="1000" xpath="//block[@prod-id='bg-row']/preceding-sibling::block[1]/@left-offset"/>
<eval expected="20400" xpath="//block[@prod-id='bg-body']/preceding-sibling::block[1]/@bpd"/>
<eval expected="178000" xpath="//block[@prod-id='bg-body']/preceding-sibling::block[1]/@ipd"/>
<eval expected="45800" xpath="//block[@prod-id='bg-body']/preceding-sibling::block[1]/@top-offset"/>
<eval expected="1000" xpath="//block[@prod-id='bg-body']/preceding-sibling::block[1]/@left-offset"/>

<eval expected="20400" xpath="//block[@prod-id='bg-col']/preceding-sibling::block[1]/@bpd"/>
<eval expected="178000" xpath="//block[@prod-id='bg-col']/preceding-sibling::block[1]/@ipd"/>
<eval expected="1000" xpath="//block[@prod-id='bg-col']/preceding-sibling::block[1]/@top-offset"/>
<eval expected="1000" xpath="//block[@prod-id='bg-col']/preceding-sibling::block[1]/@left-offset"/>
</checks>
</testcase>

+ 0
- 130
test/layoutengine/standard-testcases/table_border-collapse_collapse_1.xml View File

@@ -1,130 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks tables with collapse border model. Simple cell borders to start with.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in" margin="20pt">
<fo:region-body margin="0pt"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:block-container height="20pt" background-color="lightgray">
<fo:block>block before table</fo:block>
</fo:block-container>
<fo:block margin="0pt" border="groove 5pt green" border-right="15pt" height="20pt">normal border here</fo:block>
<fo:block-container margin-left="150pt" width="150pt + 7.5pt" height="5pt" background-color="gray">
<fo:block/>
</fo:block-container>
<fo:block-container margin-left="150pt + 7.5pt" width="150pt - 7.5pt - 7.5pt" height="5pt" background-color="gray">
<fo:block/>
</fo:block-container>
<fo:table table-layout="fixed" width="100%" border-collapse="collapse" background-color="rgb(90%, 90%, 100%)">
<fo:table-column column-width="150pt"/>
<fo:table-column column-width="150pt"/>
<fo:table-body>
<fo:table-row height="50pt">
<fo:table-cell border="solid 15pt blue">
<fo:block text-align="justify">cell1 cell1 cell1 cell1 cell1 cell1 cell1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="yellow" border="solid 5pt black" border-right="groove 15pt red" border-top="dotted 5pt black" border-bottom="dotted 5pt green">
<fo:block text-align="justify">cell2 cell2 cell2 cell2 cell2 cell2 cell2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell background-color="orange">
<fo:block>cell3</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 10pt red" border-top="dotted 5pt red">
<fo:block>cell4</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block background-color="lightgray">block after table</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<!-- table dimensions -->
<eval expected="320000" xpath="//flow/block[5]/@ipd"/>
<eval expected="71900" xpath="//flow/block[5]/@bpd"/>
<!-- cell 1 -->
<true xpath="//flow/block[5]/block[1]/@is-reference-area"/>
<eval expected="7500" xpath="//flow/block[5]/block[1]/@left-offset"/>
<eval expected="7500" xpath="//flow/block[5]/block[1]/@top-offset"/>
<eval expected="135000" xpath="//flow/block[5]/block[1]/@ipd"/>
<eval expected="35000" xpath="//flow/block[5]/block[1]/@bpd"/>
<eval expected="(solid,#0000ff,15000,collapse-outer)" xpath="//flow/block[5]/block[1]/@border-before"/>
<eval expected="(solid,#0000ff,15000,collapse-inner)" xpath="//flow/block[5]/block[1]/@border-after"/>
<eval expected="(solid,#0000ff,15000,collapse-outer)" xpath="//flow/block[5]/block[1]/@border-start"/>
<eval expected="(solid,#0000ff,15000,collapse-inner)" xpath="//flow/block[5]/block[1]/@border-end"/>
<eval expected="135000" xpath="//flow/block[5]/block[1]/block[1]/@ipd"/>
<eval expected="14400" xpath="//flow/block[5]/block[1]/block[1]/@bpd"/>

<!-- cell 2 -->
<true xpath="//flow/block[5]/block[2]/@is-reference-area"/>
<eval expected="157500" xpath="//flow/block[5]/block[2]/@left-offset"/>
<eval expected="2500" xpath="//flow/block[5]/block[2]/@top-offset"/>
<eval expected="135000" xpath="//flow/block[5]/block[2]/@ipd"/>
<eval expected="40000" xpath="//flow/block[5]/block[2]/@bpd"/>
<eval expected="(dotted,#000000,5000,collapse-outer)" xpath="//flow/block[5]/block[2]/@border-before"/>
<eval expected="(dotted,#00ff00,5000,collapse-inner)" xpath="//flow/block[5]/block[2]/@border-after"/>
<eval expected="(solid,#0000ff,15000,collapse-inner)" xpath="//flow/block[5]/block[2]/@border-start"/>
<eval expected="(groove,#ff0000,15000,collapse-outer)" xpath="//flow/block[5]/block[2]/@border-end"/>
<eval expected="color=#ffff00,repeat=0,horiz=0,vertical=0" xpath="//flow/block[5]/block[2]/@background"/>
<eval expected="135000" xpath="//flow/block[5]/block[2]/block[1]/@ipd"/>
<eval expected="14400" xpath="//flow/block[5]/block[2]/block[1]/@bpd"/>

<!-- cell 3 -->
<true xpath="//flow/block[5]/block[3]/@is-reference-area"/>
<true xpath="not(boolean(//flow/block[5]/block[3]/@left-offset)) or (//flow/block[5]/block[3]/@left-offset = 0)"/>
<eval expected="57500" xpath="//flow/block[5]/block[3]/@top-offset"/>
<eval expected="145000" xpath="//flow/block[5]/block[3]/@ipd"/>
<eval expected="14400" xpath="//flow/block[5]/block[3]/@bpd"/>
<eval expected="(solid,#0000ff,15000,collapse-inner)" xpath="//flow/block[5]/block[3]/@border-before"/>
<true xpath="not(boolean(//flow/block[5]/block[3]/@border-after))"/>
<true xpath="not(boolean(//flow/block[5]/block[3]/@border-start))"/>
<eval expected="(solid,#ff0000,10000,collapse-inner)" xpath="//flow/block[5]/block[3]/@border-end"/>
<eval expected="color=#ffa500,repeat=0,horiz=0,vertical=0" xpath="//flow/block[5]/block[3]/@background"/>
<eval expected="145000" xpath="//flow/block[5]/block[3]/block[1]/@ipd"/>
<eval expected="14400" xpath="//flow/block[5]/block[3]/block[1]/@bpd"/>

<!-- cell 4 -->
<true xpath="//flow/block[5]/block[4]/@is-reference-area"/>
<eval expected="155000" xpath="//flow/block[5]/block[4]/@left-offset"/>
<eval expected="52500" xpath="//flow/block[5]/block[4]/@top-offset"/>
<eval expected="140000" xpath="//flow/block[5]/block[4]/@ipd"/>
<eval expected="14400" xpath="//flow/block[5]/block[4]/@bpd"/>
<eval expected="(dotted,#ff0000,5000,collapse-inner)" xpath="//flow/block[5]/block[3]/@border-before"/>
<eval expected="(solid,#ff0000,10000,collapse-outer)" xpath="//flow/block[5]/block[3]/@border-after"/>
<eval expected="(solid,#ff0000,10000,collapse-inner)" xpath="//flow/block[5]/block[3]/@border-start"/>
<eval expected="(solid,#ff0000,10000,collapse-outer)" xpath="//flow/block[5]/block[3]/@border-end"/>
<eval expected="140000" xpath="//flow/block[5]/block[4]/block[1]/@ipd"/>
<eval expected="14400" xpath="//flow/block[5]/block[4]/block[1]/@bpd"/>
</checks>
</testcase>

+ 0
- 70
test/layoutengine/standard-testcases/table_border-collapse_collapse_2.xml View File

@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks tables with collapse border model. Simple cell borders to start with.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in" margin="20pt">
<fo:region-body margin="0pt"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:block background-color="lightgray">block before table</fo:block>
<fo:table table-layout="fixed" width="100%" border-collapse="collapse" padding="5pt">
<fo:table-column column-width="2in"/>
<fo:table-column column-width="2in"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="solid 10pt blue">
<fo:block>cell1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="yellow" border="solid 5pt black">
<fo:block>cell2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell background-color="orange" border="dotted 15pt black" number-columns-spanned="2">
<fo:block>spanned</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row border="solid 15pt green">
<fo:table-cell>
<fo:block>cell4</fo:block>
</fo:table-cell>
<fo:table-cell background-color="yellow">
<fo:block>cell5</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block background-color="lightgray">block after table</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="add checks here" xpath="false"/>
</checks>
</testcase>

+ 1
- 1
test/layoutengine/standard-testcases/table_border-collapse_separate_1.xml View File

@@ -31,7 +31,7 @@
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" border-collapse="separate">
<fo:table table-layout="fixed" width="100%" border-collapse="separate">
<fo:table-column column-width="160pt"/>
<fo:table-column column-width="200pt"/>
<fo:table-body>

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


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save