diff options
Diffstat (limited to 'test')
22 files changed, 1176 insertions, 53 deletions
diff --git a/test/java/org/apache/fop/afp/fonts/IntegerKeyStoreTestCase.java b/test/java/org/apache/fop/afp/fonts/IntegerKeyStoreTestCase.java new file mode 100644 index 000000000..96c0618a7 --- /dev/null +++ b/test/java/org/apache/fop/afp/fonts/IntegerKeyStoreTestCase.java @@ -0,0 +1,48 @@ +/* + * 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.afp.fonts; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +public class IntegerKeyStoreTestCase { + + @Test + public void getAndPut() { + IntegerKeyStore<Integer> sut = new IntegerKeyStore<Integer>(); + assertNull(sut.get(0)); + sut.put(0, 0); + assertEquals(Integer.valueOf(0), sut.get(0)); + sut.put(0, 1); + assertEquals(Integer.valueOf(1), sut.get(0)); + sut.put(0, null); + assertNull(sut.get(0)); + try { + sut.put(-1, 0); + fail("Negative index"); + } catch (IndexOutOfBoundsException e) { + // As expected + } + } + +} diff --git a/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java b/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java index 20212b002..4c89d00da 100644 --- a/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java +++ b/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java @@ -24,11 +24,11 @@ import java.io.File; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; + import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.apps.io.ResourceResolverFactory; -import static org.junit.Assert.assertEquals; - /** * */ @@ -58,4 +58,17 @@ public class DejaVuLGCSerifTestCase { public void testFontName() { assertEquals("DejaVuLGCSerif", font.getFontName()); } + + @Test + public void testUnderline() { + assertEquals(-840, font.getUnderlinePosition(10)); + assertEquals(430, font.getUnderlineThickness(10)); + } + + @Test + public void testStrikeout() { + assertEquals(2340, font.getStrikeoutPosition(10)); + assertEquals(490, font.getStrikeoutThickness(10)); + } + } diff --git a/test/java/org/apache/fop/fonts/FontEventProcessingTestCase.java b/test/java/org/apache/fop/fonts/FontEventProcessingTestCase.java index 509ee56f4..b4271ba60 100644 --- a/test/java/org/apache/fop/fonts/FontEventProcessingTestCase.java +++ b/test/java/org/apache/fop/fonts/FontEventProcessingTestCase.java @@ -52,13 +52,4 @@ public class FontEventProcessingTestCase { MimeConstants.MIME_PDF); } - @Test - public void testSVGFontStrokedAsShapes() throws Exception { - // svg-fonts.fo embeds two fonts; one that is present in the system and the other is not; the - // missing font is stroked as shapes while the fonts that exists is stroked as text - InputStream inStream = getClass().getResourceAsStream("svg-fonts.fo"); - eventsTests.doTest(inStream, null, FontEventProducer.class.getName() + ".svgTextStrokedAsShapes", - MimeConstants.MIME_PDF); - } - } diff --git a/test/java/org/apache/fop/fonts/svg-fonts.fo b/test/java/org/apache/fop/fonts/svg-fonts.fo deleted file mode 100644 index 0c5f3f599..000000000 --- a/test/java/org/apache/fop/fonts/svg-fonts.fo +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" standalone="no"?> -<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="page"> - <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> - <fo:instream-foreign-object> - <svg:svg width="250" height="50"> - <svg:font horiz-adv-x="1000"> - <svg:font-face font-family="Missing" units-per-em="1000" underline-position="-100" - underline-thickness="50" /> - <svg:glyph unicode="A" horiz-adv-x="686" d="M162,186l362,0l78,-186l84,0l-308,708l-70,0l-308,-708l84,0M343,624l153,-372l-307,0z" /> - <svg:glyph unicode="C" horiz-adv-x="704" d="M620,154C567,72 491,48 417,48C235,48 126,191 126,354C126,517 235,660 417,660C492,660 571,613 599,567l63,47C600,693 505,726 417,726C206,726 48,569 48,354C48,139 206,-18 417,-18C534,-18 632,39 679,112z" /> - <svg:glyph unicode="F" horiz-adv-x="556" d="M168,335l330,0l0,66l-330,0l0,241l355,0l0,66l-427,0l0,-708l72,0z" /> - <svg:glyph unicode="G" horiz-adv-x="778" d="M673,631C610,694 529,726 417,726C206,726 48,569 48,354C48,139 206,-18 417,-18C503,-18 606,7 685,54l0,347l-241,0l0,-66l169,0l0,-237C560,68 490,48 417,48C235,48 126,191 126,354C126,517 235,660 417,660C504,660 571,629 619,578z" /> - </svg:font> - <svg:font horiz-adv-x="1000"> - <!-- this is not Helvetica but it is here to increase coverage and show the code takes expected path --> - <svg:font-face font-family="Helvetica" units-per-em="1000" underline-position="-100" - underline-thickness="50" /> - <svg:glyph unicode="A" horiz-adv-x="686" d="M162,186l362,0l78,-186l84,0l-308,708l-70,0l-308,-708l84,0M343,624l153,-372l-307,0z" /> - <svg:glyph unicode="C" horiz-adv-x="704" d="M620,154C567,72 491,48 417,48C235,48 126,191 126,354C126,517 235,660 417,660C492,660 571,613 599,567l63,47C600,693 505,726 417,726C206,726 48,569 48,354C48,139 206,-18 417,-18C534,-18 632,39 679,112z" /> - <svg:glyph unicode="F" horiz-adv-x="556" d="M168,335l330,0l0,66l-330,0l0,241l355,0l0,66l-427,0l0,-708l72,0z" /> - <svg:glyph unicode="G" horiz-adv-x="778" d="M673,631C610,694 529,726 417,726C206,726 48,569 48,354C48,139 206,-18 417,-18C503,-18 606,7 685,54l0,347l-241,0l0,-66l169,0l0,-237C560,68 490,48 417,48C235,48 126,191 126,354C126,517 235,660 417,660C504,660 571,629 619,578z" /> - </svg:font> - <svg:text x="20" y="20" font-family="Missing" font-size="12">ACFG</svg:text> - <svg:text x="20" y="40" font-family="Helvetica" font-size="12">ACFG</svg:text> - </svg:svg> - </fo:instream-foreign-object> - </fo:block> - </fo:flow> - </fo:page-sequence> -</fo:root> diff --git a/test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java b/test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java index e04347032..2d583dd3e 100644 --- a/test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java +++ b/test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java @@ -26,12 +26,12 @@ import java.util.Map; import org.junit.Test; -import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; + /** * Class for testing org.apache.fop.fonts.truetype.TTFFile */ @@ -426,6 +426,24 @@ public class TTFFileTestCase { assertEquals(true, droidmonoTTFFile.isEmbeddable()); } + /** Underline position and thickness. */ + @Test + public void testUnderline() { + assertEquals(-63, dejavuTTFFile.getUnderlinePosition()); + assertEquals(43, dejavuTTFFile.getUnderlineThickness()); + assertEquals(-75, droidmonoTTFFile.getUnderlinePosition()); + assertEquals(49, droidmonoTTFFile.getUnderlineThickness()); + } + + /** Strikeout position and thickness. */ + @Test + public void testStrikeout() { + assertEquals(258, dejavuTTFFile.getStrikeoutPosition()); + assertEquals(49, dejavuTTFFile.getStrikeoutThickness()); + assertEquals(243, droidmonoTTFFile.getStrikeoutPosition()); + assertEquals(49, droidmonoTTFFile.getStrikeoutThickness()); + } + /** * Test readFont() - Add implementation if necessary. */ diff --git a/test/java/org/apache/fop/fonts/type1/AFMParserTestCase.java b/test/java/org/apache/fop/fonts/type1/AFMParserTestCase.java index 93443a0d9..31a613567 100644 --- a/test/java/org/apache/fop/fonts/type1/AFMParserTestCase.java +++ b/test/java/org/apache/fop/fonts/type1/AFMParserTestCase.java @@ -19,9 +19,6 @@ package org.apache.fop.fonts.type1; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import java.awt.Rectangle; import java.io.IOException; import java.io.InputStream; @@ -29,6 +26,9 @@ import java.util.List; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * Test case for {@link AFMParser}. */ @@ -128,4 +128,13 @@ public class AFMParserTestCase { private boolean objectEquals(Object o1, Object o2) { return o1 == null ? o2 == null : (o1 == o2 || o1.equals(o2)); } + + @Test + public void testUnderlinePositionAndThickness() throws IOException { + AFMFile afm = sut.parse(getClass().getResourceAsStream("underline.afm"), null); + AFMWritingDirectionMetrics metrics = afm.getWritingDirectionMetrics(0); + assertEquals(-96, metrics.getUnderlinePosition()); + assertEquals(58, metrics.getUnderlineThickness()); + } + } diff --git a/test/java/org/apache/fop/fonts/type1/underline.afm b/test/java/org/apache/fop/fonts/type1/underline.afm new file mode 100644 index 000000000..8137b41eb --- /dev/null +++ b/test/java/org/apache/fop/fonts/type1/underline.afm @@ -0,0 +1,4 @@ +StartFontMetrics 2.0 +UnderlinePosition -96 +UnderlineThickness 58 +EndFontMetrics diff --git a/test/java/org/apache/fop/svg/NativeTextPainterTest.java b/test/java/org/apache/fop/svg/NativeTextPainterTest.java new file mode 100644 index 000000000..1c2c3b582 --- /dev/null +++ b/test/java/org/apache/fop/svg/NativeTextPainterTest.java @@ -0,0 +1,78 @@ +/* + * 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; + +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.io.File; +import java.io.IOException; + +import org.w3c.dom.Document; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.dom.svg.SAXSVGDocumentFactory; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.gvt.TextPainter; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.base14.Base14FontCollection; +import org.apache.fop.svg.font.FOPFontFamilyResolverImpl; + +abstract class NativeTextPainterTest { + + protected final void runTest(String testcase, OperatorValidator validator) throws Exception { + FontInfo fontInfo = createFontInfo(); + BridgeContext bridgeContext = createBridgeContext(fontInfo); + GraphicsNode svg = loadSVG(bridgeContext, testcase); + Graphics2D g2d = createGraphics2D(fontInfo, validator); + svg.paint(g2d); + validator.end(); + } + + private FontInfo createFontInfo() { + FontInfo fontInfo = new FontInfo(); + new Base14FontCollection(true).setup(0, fontInfo); + return fontInfo; + } + + private BridgeContext createBridgeContext(FontInfo fontInfo) { + FOUserAgent userAgent = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent(); + SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new FOPFontFamilyResolverImpl(fontInfo), + new AffineTransform()); + BridgeContext bridgeContext = new BridgeContext(svgUserAgent); + bridgeContext.setTextPainter(createTextPainter(fontInfo)); + return bridgeContext; + } + + protected abstract TextPainter createTextPainter(FontInfo fontInfo); + + private GraphicsNode loadSVG(BridgeContext bridgeContext, String resourceName) throws IOException { + SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(null); + Document svg = factory.createDocument(null, getClass().getResourceAsStream(resourceName)); + GVTBuilder builder = new GVTBuilder(); + return builder.build(bridgeContext, svg); + } + + protected abstract Graphics2D createGraphics2D(FontInfo fontInfo, OperatorValidator validator); + +} diff --git a/test/java/org/apache/fop/svg/OperatorValidator.java b/test/java/org/apache/fop/svg/OperatorValidator.java new file mode 100644 index 000000000..959adc9a1 --- /dev/null +++ b/test/java/org/apache/fop/svg/OperatorValidator.java @@ -0,0 +1,108 @@ +/* + * 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; + +import java.util.LinkedList; +import java.util.Queue; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +class OperatorValidator { + + private static interface Match { + + boolean match(String line); + } + + private static class MatchSequence implements OperatorValidator.Match { + + private final Queue<OperatorValidator.Match> expectedMatches = new LinkedList<OperatorValidator.Match>(); + + private OperatorValidator.Match currentMatch; + + private static final OperatorValidator.Match FINAL_MATCH = new Match() { + + public boolean match(String line) { + return false; + } + }; + + public boolean isExhausted() { + return currentMatch == FINAL_MATCH; + } + + public void addMatch(OperatorValidator.Match match) { + if (currentMatch == null) { + currentMatch = match; + } else { + expectedMatches.add(match); + } + } + + public boolean match(String line) { + boolean match = currentMatch.match(line); + if (match) { + if(expectedMatches.isEmpty()) { + currentMatch = FINAL_MATCH; + } else { + currentMatch = expectedMatches.remove(); + } + } + return match; + } + } + + private static class OperatorMatch implements OperatorValidator.Match { + + final String operator; + + final String line; + + OperatorMatch(String operator, String line) { + this.operator = operator; + this.line = line; + } + + public boolean match(String line) { + if (line.contains(operator)) { + assertEquals(this.line, line); + return true; + } + return false; + } + } + + private final OperatorValidator.MatchSequence matchSequence = new MatchSequence(); + + public OperatorValidator addOperatorMatch(String operator, String expectedLine) { + matchSequence.addMatch(new OperatorMatch(operator, expectedLine)); + return this; + } + + public void check(String line) { + matchSequence.match(line); + } + + public void end() { + assertTrue("Expected operators remain", matchSequence.isExhausted()); + } + +}
\ No newline at end of file diff --git a/test/java/org/apache/fop/svg/PDFTextPainterTestCase.java b/test/java/org/apache/fop/svg/PDFTextPainterTestCase.java new file mode 100644 index 000000000..52f18bb5e --- /dev/null +++ b/test/java/org/apache/fop/svg/PDFTextPainterTestCase.java @@ -0,0 +1,149 @@ +/* + * 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; + +import java.awt.Graphics2D; +import java.io.StringWriter; + +import org.junit.Test; + +import org.apache.batik.gvt.TextPainter; + +import org.apache.xmlgraphics.java2d.GraphicContext; + +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.svg.font.FOPFontFamilyResolverImpl; + +public class PDFTextPainterTestCase extends NativeTextPainterTest { + + private static class OperatorCheckingPDFGraphics2D extends PDFGraphics2D { + + OperatorCheckingPDFGraphics2D(FontInfo fontInfo, final OperatorValidator validator) { + super(false, fontInfo, new PDFDocument("test"), null, null, null, 0); + this.currentStream = new StringWriter() { + + @Override + public void write(String str) { + validator.check(str); + } + + }; + } + } + + @Override + protected TextPainter createTextPainter(FontInfo fontInfo) { + return new PDFTextPainter(fontInfo); + } + + @Override + protected Graphics2D createGraphics2D(FontInfo fontInfo, OperatorValidator validator) { + PDFGraphics2D g2d = new OperatorCheckingPDFGraphics2D(fontInfo, validator); + g2d.setGraphicContext(new GraphicContext()); + return g2d; + } + + @Test + public void testRotatedGlyph() throws Exception { + runTest("rotated-glyph.svg", new OperatorValidator() + .addOperatorMatch("Tm", "1 0 0 -1 40 110 Tm ") + .addOperatorMatch("TJ", "[(A)] TJ\n") + .addOperatorMatch("Tm", "0.70710677 0.7071068 0.7071068 -0.70710677 106.69999695 110 Tm ") + .addOperatorMatch("TJ", "[(B)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 173.3999939 110 Tm ") + .addOperatorMatch("TJ", "[(C)] TJ\n")); + } + + @Test + public void testDxDy() throws Exception { + runTest("dx-dy.svg", new OperatorValidator() + .addOperatorMatch("Tm", "1 0 0 -1 55 35 Tm ") + .addOperatorMatch("TJ", "[(ABCDE)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 55 75 Tm ") + .addOperatorMatch("TJ", "[(A)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 69 85 Tm ") + .addOperatorMatch("TJ", "[(B)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 109 80 Tm ") + .addOperatorMatch("TJ", "[(C)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 91 65 Tm ") + .addOperatorMatch("TJ", "[(D)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 127 75 Tm ") + .addOperatorMatch("TJ", "[(E)] TJ\n")); + } + + @Test + public void testSpacing() throws Exception { + runTest("spacing.svg", new OperatorValidator() + .addOperatorMatch("Tm", "1 0 0 -1 0 0 Tm ") + .addOperatorMatch("TJ", "[(V) 80 (A) 70 (V)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 0 0 Tm ") + .addOperatorMatch("TJ", "[(V) 80 (A) 70 (V)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 0 0 Tm ") + .addOperatorMatch("TJ", "[(V) -20 (A) -30 (V)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 0 0 Tm ") + .addOperatorMatch("TJ", "[(ab) -111 ( ) -389 (cd)] TJ\n")); + } + + @Test + public void testGlyphOrientation() throws Exception { + runTest("glyph-orientation.svg", new OperatorValidator() + .addOperatorMatch("Tm", "0 1 1 0 738.5 0 Tm ") + .addOperatorMatch("TJ", "[(A)] TJ\n") + .addOperatorMatch("Tm", "0 1 1 0 738.5 667 Tm ") + .addOperatorMatch("TJ", "[(B)] TJ\n") + .addOperatorMatch("Tm", "0 1 1 0 738.5 1334 Tm ") + .addOperatorMatch("TJ", "[(C)] TJ\n") + .addOperatorMatch("Tm", "0 1 1 0 738.5 2056 Tm ") + .addOperatorMatch("TJ", "[(D)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 2149 718 Tm ") + .addOperatorMatch("TJ", "[(E)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 2165.5 1643 Tm ") + .addOperatorMatch("TJ", "[(F)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 2124 2568 Tm ") + .addOperatorMatch("TJ", "[(G)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 2138.5 3493 Tm ") + .addOperatorMatch("TJ", "[(H)] TJ\n") + .addOperatorMatch("Tm", "0 -1 -1 0 718 5000 Tm ") + .addOperatorMatch("TJ", "[(I)] TJ\n") + .addOperatorMatch("Tm", "0 -1 -1 0 1643 5000 Tm ") + .addOperatorMatch("TJ", "[(J)] TJ\n") + .addOperatorMatch("Tm", "0 -1 -1 0 2568 5000 Tm ") + .addOperatorMatch("TJ", "[(K)] TJ\n") + .addOperatorMatch("Tm", "0 -1 -1 0 3493 5000 Tm ") + .addOperatorMatch("TJ", "[(L)] TJ\n")); + } + + @Test + public void testBaselineShift() throws Exception { + runTest("baseline-shift.svg", new OperatorValidator() + .addOperatorMatch("Tm", "1 0 0 -1 0 0 Tm ") + .addOperatorMatch("TJ", "[(AB)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 1334 -462.5 Tm ") + .addOperatorMatch("TJ", "[(CD)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 2778 0 Tm ") + .addOperatorMatch("TJ", "[(EF)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 4056 462.5 Tm ") + .addOperatorMatch("TJ", "[(GH)] TJ\n") + .addOperatorMatch("Tm", "1 0 0 -1 5556 0 Tm ") + .addOperatorMatch("TJ", "[(IJ)] TJ\n")); + } + +} diff --git a/test/java/org/apache/fop/svg/PSTextPainterTestCase.java b/test/java/org/apache/fop/svg/PSTextPainterTestCase.java new file mode 100644 index 000000000..2d5de7455 --- /dev/null +++ b/test/java/org/apache/fop/svg/PSTextPainterTestCase.java @@ -0,0 +1,77 @@ +/* + * 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; + +import java.awt.Graphics2D; +import java.io.IOException; + +import org.junit.Test; + +import org.apache.commons.io.output.NullOutputStream; + +import org.apache.batik.gvt.TextPainter; + +import org.apache.xmlgraphics.java2d.GraphicContext; +import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; +import org.apache.xmlgraphics.ps.PSGenerator; + +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.ps.PSTextPainter; + +public class PSTextPainterTestCase extends NativeTextPainterTest { + + private static class OperatorCheckingPSGraphics2D extends PSGraphics2D { + + OperatorCheckingPSGraphics2D(FontInfo fontInfo, final OperatorValidator validator) { + super(false, new PSGenerator(new NullOutputStream()) { + + @Override + public void writeln(String cmd) throws IOException { + validator.check(cmd); + } + + }); + } + } + + @Override + protected TextPainter createTextPainter(FontInfo fontInfo) { + return new PSTextPainter(fontInfo); + } + + @Override + protected Graphics2D createGraphics2D(FontInfo fontInfo, OperatorValidator validator) { + PSGraphics2D g2d = new OperatorCheckingPSGraphics2D(fontInfo, validator); + g2d.setGraphicContext(new GraphicContext()); + return g2d; + } + + @Test + public void testRotatedGlyph() throws Exception { + runTest("rotated-glyph.svg", new OperatorValidator() + .addOperatorMatch("Tm", "1 0 0 -1 40 110 Tm") + .addOperatorMatch("xshow", "(A)\n[0] xshow") + .addOperatorMatch("Tm", "0.70711 0.70711 0.70711 -0.70711 106.7 110 Tm") + .addOperatorMatch("xshow", "(B)\n[0] xshow") + .addOperatorMatch("Tm", "1 0 0 -1 173.39999 110 Tm") + .addOperatorMatch("xshow", "(C)\n[0] xshow")); + } + +} diff --git a/test/java/org/apache/fop/svg/baseline-shift.svg b/test/java/org/apache/fop/svg/baseline-shift.svg new file mode 100644 index 000000000..0f375b9af --- /dev/null +++ b/test/java/org/apache/fop/svg/baseline-shift.svg @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<svg width="150" height="60" xmlns="http://www.w3.org/2000/svg"> +<rect x="0" y="0" width="100%" height="100%" fill="none" stroke="black" stroke-width="2"/> +<g transform="translate(10, 40) scale(20) scale(0.001)"> +<text font-family="sans-serif" font-size="1000"> +AB<tspan baseline-shift="super">CD</tspan>EF<tspan baseline-shift="sub">GH</tspan>IJ +</text> +</g> +</svg> diff --git a/test/java/org/apache/fop/svg/dx-dy.svg b/test/java/org/apache/fop/svg/dx-dy.svg new file mode 100644 index 000000000..cfdc2de01 --- /dev/null +++ b/test/java/org/apache/fop/svg/dx-dy.svg @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg"> +<rect x="0" y="0" width="100%" height="100%" stroke="black" stroke-width="2" fill="none"/> +<g font-family="monospace" font-size="30"> + <text x="55" y="35">ABCDE</text> + <text x="55" y="75" dx="0 -4 22 -36 18" dy="0 10 -5 -15 10">ABCDE</text> +</g> +</svg> diff --git a/test/java/org/apache/fop/svg/font/BasicGlyphVectorTestCase.java b/test/java/org/apache/fop/svg/font/BasicGlyphVectorTestCase.java new file mode 100644 index 000000000..c6f062a84 --- /dev/null +++ b/test/java/org/apache/fop/svg/font/BasicGlyphVectorTestCase.java @@ -0,0 +1,193 @@ +/* + * 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.font; + +import java.awt.Rectangle; +import java.awt.font.GlyphMetrics; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.batik.gvt.font.GVTGlyphMetrics; +import org.apache.batik.gvt.font.GVTLineMetrics; + +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontMetrics; + +/** + * Tests all the methods of {@link FOPGVTGlyphVector} with a mocked font. + */ +public class BasicGlyphVectorTestCase extends FOPGVTGlyphVectorTest { + + private final int fontSize = 10000; + + @Before + public void createGlyphVector() { + FontMetrics metrics = mockFontMetrics(); + Font font = mockFont(metrics); + FOPGVTFont gvtFont = mockGVTFont(font); + CharacterIterator it = new StringCharacterIterator("ABC"); + glyphVector = new FOPGVTGlyphVector(gvtFont, it, null); + glyphVector.performDefaultLayout(); + } + + private FontMetrics mockFontMetrics() { + FontMetrics metrics = mock(FontMetrics.class); + when(metrics.getAscender(eq(fontSize))).thenReturn(8000000); + when(metrics.getDescender(eq(fontSize))).thenReturn(-4000000); + when(metrics.getWidth(eq(1), eq(fontSize))).thenReturn(10000000); + when(metrics.getBoundingBox(eq(1), eq(fontSize))).thenReturn( + new Rectangle(-1000000, -2000000, 3000000, 4000000)); + when(metrics.getWidth(eq(2), eq(fontSize))).thenReturn(11000000); + when(metrics.getBoundingBox(eq(2), eq(fontSize))).thenReturn( + new Rectangle(-5000000, -6000000, 7000000, 9000000)); + when(metrics.getWidth(eq(3), eq(fontSize))).thenReturn(12000000); + when(metrics.getBoundingBox(eq(3), eq(fontSize))).thenReturn( + new Rectangle(-9000000, -10000000, 11000000, 14000000)); + return metrics; + } + + private Font mockFont(FontMetrics metrics) { + Font font = mock(Font.class); + when(font.getFontMetrics()).thenReturn(metrics); + when(font.getFontSize()).thenReturn(fontSize); + when(font.mapChar(eq('A'))).thenReturn((char) 1); + when(font.mapChar(eq('B'))).thenReturn((char) 2); + when(font.mapChar(eq('C'))).thenReturn((char) 3); + return font; + } + + private FOPGVTFont mockGVTFont(Font font) { + FOPGVTFont gvtFont = mock(FOPGVTFont.class); + when(gvtFont.getFont()).thenReturn(font); + when(gvtFont.getLineMetrics(anyInt())).thenReturn( + new GVTLineMetrics(8, 0, null, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + return gvtFont; + } + + @Test + public void getGlyphCodeReturnsGlyphIndex() { + assertEquals(1, glyphVector.getGlyphCode(0)); + assertEquals(2, glyphVector.getGlyphCode(1)); + assertEquals(3, glyphVector.getGlyphCode(2)); + } + + @Test + public void testGetGlyphCodes() { + assertArrayEquals(new int[] {1, 2, 3}, glyphVector.getGlyphCodes(0, 3, null)); + assertArrayEquals(new int[] {2, 3}, glyphVector.getGlyphCodes(1, 2, null)); + } + + @Test + public void testGetGlyphMetrics() { + assertGlyphMetricsEqual(new GVTGlyphMetrics(10, 12, new Rectangle(-1, -2, 3, 4), GlyphMetrics.STANDARD), + glyphVector.getGlyphMetrics(0)); + assertGlyphMetricsEqual(new GVTGlyphMetrics(11, 12, new Rectangle(-5, -3, 7, 9), GlyphMetrics.STANDARD), + glyphVector.getGlyphMetrics(1)); + assertGlyphMetricsEqual(new GVTGlyphMetrics(12, 12, new Rectangle(-9, -4, 11, 14), GlyphMetrics.STANDARD), + glyphVector.getGlyphMetrics(2)); + } + + private void assertGlyphMetricsEqual(GVTGlyphMetrics expected, GVTGlyphMetrics actual) { + assertEquals(expected.getHorizontalAdvance(), actual.getHorizontalAdvance(), 0); + assertEquals(expected.getVerticalAdvance(), actual.getVerticalAdvance(), 0); + assertEquals(expected.getBounds2D(), actual.getBounds2D()); + assertEquals(expected.getLSB(), actual.getLSB(), 0); + assertEquals(expected.getRSB(), actual.getRSB(), 0); + assertEquals(expected.getType(), actual.getType()); + assertEquals(expected.isCombining(), actual.isCombining()); + assertEquals(expected.isComponent(), actual.isComponent()); + assertEquals(expected.isLigature(), actual.isLigature()); + assertEquals(expected.isStandard(), actual.isStandard()); + assertEquals(expected.isWhitespace(), actual.isWhitespace()); + } + + @Test + public void testGetGlyphPosition() { + assertEquals(new Point2D.Float(0, 0), glyphVector.getGlyphPosition(0)); + assertEquals(new Point2D.Float(10, 0), glyphVector.getGlyphPosition(1)); + assertEquals(new Point2D.Float(21, 0), glyphVector.getGlyphPosition(2)); + assertEquals(new Point2D.Float(33, 0), glyphVector.getGlyphPosition(3)); + } + + @Test + public void testGetGlyphPositions() { + float[] expectedPositions = new float[] {0, 0, 10, 0, 21, 0, 33, 0}; + assertArrayEquals(expectedPositions, glyphVector.getGlyphPositions(0, 4, null), 0); + assertArrayEquals(expectedPositions, glyphVector.getGlyphPositions(0, 4, new float[8]), 0); + } + + @Test + public void testGetGlyphOutline() { + assertEquals(new Rectangle(-1, -2, 3, 4), glyphVector.getGlyphOutline(0).getBounds()); + assertEquals(new Rectangle(5, -3, 7, 9), glyphVector.getGlyphOutline(1).getBounds()); + assertEquals(new Rectangle(12, -4, 11, 14), glyphVector.getGlyphOutline(2).getBounds()); + } + + @Test + public void testGetOutline() { + assertEquals(new Rectangle(-1, -4, 24, 14), glyphVector.getOutline().getBounds()); + } + + @Test + public void testGetLogicalBounds() { + assertEquals(new Rectangle(0, -8, 33, 12), glyphVector.getLogicalBounds()); + } + + @Test + public void testGetLogicalBoundsRotated() { + for (int i = 0; i < 3; i++) { + glyphVector.setGlyphTransform(i, new AffineTransform(0.7, 0.7, -0.7, 0.7, 0, 0)); + } + assertEquals(new Rectangle2D.Float(-2.8f, -5.6f, 37.8f, 16.8f), glyphVector.getLogicalBounds()); + } + + @Test + public void testGetBounds() { + assertEquals(new Rectangle(-1, -4, 24, 14), glyphVector.getBounds2D(null)); + } + + @Test + public void testGetGlyphVisualBounds() { + assertEquals(new Rectangle(-1, -2, 3, 4), glyphVector.getGlyphVisualBounds(0).getBounds()); + assertEquals(new Rectangle(5, -3, 7, 9), glyphVector.getGlyphVisualBounds(1).getBounds()); + assertEquals(new Rectangle(12, -4, 11, 14), glyphVector.getGlyphVisualBounds(2).getBounds()); + } + + @Test + public void testGetGlyphLogicalBounds() { + assertEquals(new Rectangle(0, -8, 10, 12), glyphVector.getGlyphLogicalBounds(0).getBounds()); + assertEquals(new Rectangle(10, -8, 11, 12), glyphVector.getGlyphLogicalBounds(1).getBounds()); + assertEquals(new Rectangle(21, -8, 12, 12), glyphVector.getGlyphLogicalBounds(2).getBounds()); + } + +} diff --git a/test/java/org/apache/fop/svg/font/FOPFontFamilyResolverTestCase.java b/test/java/org/apache/fop/svg/font/FOPFontFamilyResolverTestCase.java new file mode 100644 index 000000000..2f5668cbc --- /dev/null +++ b/test/java/org/apache/fop/svg/font/FOPFontFamilyResolverTestCase.java @@ -0,0 +1,127 @@ +/* + * 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.font; + +import java.awt.FontFormatException; +import java.awt.GraphicsEnvironment; +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Collections; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import org.apache.batik.gvt.font.GVTFontFamily; +import org.apache.batik.gvt.font.GVTLineMetrics; + +import org.apache.fop.fonts.FontInfo; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class FOPFontFamilyResolverTestCase { + + private static FontInfo fontInfo; + + private FOPFontFamilyResolver resolver; + + @BeforeClass + public static void setUpFontInfo() { + fontInfo = new FontInfoBuilder() + .useDejaVuLGCSerif() + .useDroidSansMono() + .build(); + } + + @Before + public void createFontFamilyResolver() { + resolver = new FOPFontFamilyResolverImpl(fontInfo); + } + + @Test + public void testResolve() { + assertNull(resolver.resolve("Unavailable")); + assertNotNull(resolver.resolve(FontInfoBuilder.DEJAVU_LGC_SERIF)); + } + + @Test + public void testGetFamilyThatCanDisplay() { + GVTFontFamily family = resolver.getFamilyThatCanDisplay('\u0180'); + assertEquals(FontInfoBuilder.DEJAVU_LGC_SERIF, family.getFamilyName()); + family = resolver.getFamilyThatCanDisplay('\u02F3'); + assertEquals(FontInfoBuilder.DROID_SANS_MONO, family.getFamilyName()); + family = resolver.getFamilyThatCanDisplay('\u02DF'); + assertNull(family); + } + + @Test + public void testDeriveFont() { + FOPGVTFontFamily family = (FOPGVTFontFamily) resolver.resolve(FontInfoBuilder.DEJAVU_LGC_SERIF); + FOPGVTFont font = family.deriveFont(10, Collections.emptyMap()); + assertEquals(10, font.getSize(), 0); + assertTrue(font.canDisplay('\u01F6')); + assertFalse(font.canDisplay('\u01F7')); + } + + @Test + @Ignore("FOP metrics don't match AWT, but not sure who is right and who is wrong") + public void testLineMetrics() throws FontFormatException, IOException { + FOPGVTFontFamily family = (FOPGVTFontFamily) resolver.resolve(FontInfoBuilder.DEJAVU_LGC_SERIF); + FOPGVTFont font = family.deriveFont(10, Collections.emptyMap()); + GVTLineMetrics fopMetrics = font.getLineMetrics("", null); + LineMetrics awtMetrics = getAWTLineMetrics(); + printDifference("Ascent", awtMetrics.getAscent(), fopMetrics.getAscent()); + printDifference("Descent", awtMetrics.getDescent(), fopMetrics.getDescent()); + printDifference("Height", awtMetrics.getHeight(), fopMetrics.getHeight()); + printDifference("Leading", awtMetrics.getLeading(), fopMetrics.getLeading()); + printDifference("StrikethroughOffset", awtMetrics.getStrikethroughOffset(), + fopMetrics.getStrikethroughOffset()); + printDifference("StrikethroughThickness", awtMetrics.getStrikethroughThickness(), + fopMetrics.getStrikethroughThickness()); + printDifference("UnderlineOffset", awtMetrics.getUnderlineOffset(), + fopMetrics.getUnderlineOffset()); + printDifference("UnderlineThickness", awtMetrics.getUnderlineThickness(), + fopMetrics.getUnderlineThickness()); + } + + private LineMetrics getAWTLineMetrics() throws FontFormatException, IOException { + File fontFile = new File("test/resources/fonts/ttf/DejaVuLGCSerif.ttf"); + java.awt.Font awtFont = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, fontFile).deriveFont(10f); + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + BufferedImage dummyImage = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_RGB); + FontRenderContext frc = ge.createGraphics(dummyImage).getFontRenderContext(); + LineMetrics awtMetrics = awtFont.getLineMetrics("ABC", frc); + return awtMetrics; + } + + private void printDifference(String value, float awt, float fop) { + System.out.println(String.format("%22s AWT: %10f FOP: %10f Difference: %.2f%%", value, awt, fop, + (fop - awt) / awt * 100)); + } + +} diff --git a/test/java/org/apache/fop/svg/font/FOPGVTFontTestCase.java b/test/java/org/apache/fop/svg/font/FOPGVTFontTestCase.java new file mode 100644 index 000000000..c7af068ce --- /dev/null +++ b/test/java/org/apache/fop/svg/font/FOPGVTFontTestCase.java @@ -0,0 +1,72 @@ +/* + * 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.font; + +import java.text.StringCharacterIterator; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.fop.fonts.Font; +import org.apache.fop.svg.font.FOPGVTFont; + +public class FOPGVTFontTestCase { + + private FOPGVTFont font; + + @Before + public void createFont() { + Font f = mock(Font.class); + when(f.hasChar(eq((char) 0))).thenReturn(false); + when(f.hasChar(eq((char) 1))).thenReturn(true); + font = new FOPGVTFont(f, null); + } + + @Test + public void testCanDisplayUpTo() { + char[] text = new char[] {1, 1, 1}; + testCanDisplayUpToVariants(text, -1, 0, 3); + testCanDisplayUpToVariants(text, -1, 1, 3); + text = new char[] {1, 1, 0, 1}; + testCanDisplayUpToVariants(text, 2, 0, 4); + testCanDisplayUpToVariants(text, 2, 1, 4); + testCanDisplayUpToVariants(text, 2, 2, 4); + testCanDisplayUpToVariants(text, -1, 3, 4); + testCanDisplayUpToVariants(text, -1, 1, 2); + } + + @Test + public void testCanDisplayUpToString() { + assertEquals(-1, font.canDisplayUpTo(new String(new char[] {1, 1, 1}))); + assertEquals(0, font.canDisplayUpTo(new String(new char[] {0, 1, 1}))); + assertEquals(1, font.canDisplayUpTo(new String(new char[] {1, 0, 1}))); + assertEquals(2, font.canDisplayUpTo(new String(new char[] {1, 1, 0}))); + } + + private void testCanDisplayUpToVariants(char[] text, int expected, int start, int limit) { + assertEquals(expected, font.canDisplayUpTo(text, start, limit)); + assertEquals(expected, font.canDisplayUpTo(new StringCharacterIterator(new String(text)), start, limit)); + } +} diff --git a/test/java/org/apache/fop/svg/font/FOPGVTGlyphVectorTest.java b/test/java/org/apache/fop/svg/font/FOPGVTGlyphVectorTest.java new file mode 100644 index 000000000..0995ab4df --- /dev/null +++ b/test/java/org/apache/fop/svg/font/FOPGVTGlyphVectorTest.java @@ -0,0 +1,27 @@ +/* + * 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.font; + + +public abstract class FOPGVTGlyphVectorTest { + + protected FOPGVTGlyphVector glyphVector; + +} diff --git a/test/java/org/apache/fop/svg/font/FontInfoBuilder.java b/test/java/org/apache/fop/svg/font/FontInfoBuilder.java new file mode 100644 index 000000000..f7a5825bd --- /dev/null +++ b/test/java/org/apache/fop/svg/font/FontInfoBuilder.java @@ -0,0 +1,102 @@ +/* + * 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.font; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.fop.apps.io.InternalResourceResolver; +import org.apache.fop.apps.io.ResourceResolverFactory; +import org.apache.fop.fonts.EmbeddingMode; +import org.apache.fop.fonts.EncodingMode; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontMetrics; +import org.apache.fop.fonts.truetype.TTFFontLoader; + +class FontInfoBuilder { + + public static final String DEJAVU_LGC_SERIF = "DejaVu LGC Serif"; + + public static final String DROID_SANS_MONO = "Droid Sans Mono"; + + private static final boolean USE_ADVANCED_BY_DEFAULT = true; + + private FontInfo fontInfo; + + private int fontKey; + + public FontInfoBuilder() { + reset(); + } + + private void reset() { + fontInfo = new FontInfo(); + fontKey = 1; + } + + public FontInfoBuilder useDejaVuLGCSerif() { + return useDejaVuLGCSerif(USE_ADVANCED_BY_DEFAULT); + } + + public FontInfoBuilder useDejaVuLGCSerif(boolean useAdvanced) { + try { + return useFont(DEJAVU_LGC_SERIF, "DejaVuLGCSerif.ttf", useAdvanced); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public FontInfoBuilder useDroidSansMono() { + return useDroidSansMono(USE_ADVANCED_BY_DEFAULT); + } + + public FontInfoBuilder useDroidSansMono(boolean useAdvanced) { + try { + return useFont(DROID_SANS_MONO, "DroidSansMono.ttf", useAdvanced); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private FontInfoBuilder useFont(String fontName, String filename, boolean useAdvanced) + throws IOException, URISyntaxException { + URI baseURI = new File("test/resources/fonts/ttf").toURI(); + InternalResourceResolver resolver = ResourceResolverFactory.createDefaultInternalResourceResolver(baseURI); + TTFFontLoader fontLoader = new TTFFontLoader(new URI(filename), null, true, + EmbeddingMode.AUTO, EncodingMode.AUTO, true, useAdvanced, resolver); + FontMetrics font = fontLoader.getFont(); + registerFont(font, "F" + fontKey++, fontName); + return this; + } + + private void registerFont(FontMetrics font, String key, String familyName) { + fontInfo.addMetrics(key, font); + fontInfo.addFontProperties(key, familyName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); + } + + public FontInfo build() { + FontInfo fontInfo = this.fontInfo; + reset(); + return fontInfo; + } +} diff --git a/test/java/org/apache/fop/svg/font/GlyphLayoutTestCase.java b/test/java/org/apache/fop/svg/font/GlyphLayoutTestCase.java new file mode 100644 index 000000000..34cba604a --- /dev/null +++ b/test/java/org/apache/fop/svg/font/GlyphLayoutTestCase.java @@ -0,0 +1,91 @@ +/* + * 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.font; + +import java.util.Collections; + +import org.junit.Test; + +import org.apache.fop.fonts.FontInfo; + +import static org.junit.Assert.assertEquals; + +/** + * Specifically tests glyph positioning from a real font. + */ +public class GlyphLayoutTestCase extends FOPGVTGlyphVectorTest { + + /** + * Glyph positioning using the legacy kern table. + */ + @Test + public void testBasicGlyphPositioning() throws Exception { + testGlyphLayout(false); + } + + /** + * Glyph positioning using GPOS sub-tables. + */ + @Test + public void testAdvancedGlyphPositioning() throws Exception { + testGlyphLayout(true); + } + + private void testGlyphLayout(boolean useAdvanced) { + FOPGVTFont font = loadFont(useAdvanced); + glyphVector = (FOPGVTGlyphVector) font.createGlyphVector(null, "L\u201DP,V.F,A\u2019LT."); + glyphVector.performDefaultLayout(); + // Values in font units (unitsPerEm = 2048), glyph width - kern + int[] widths = { + /* L */ 1360 - 491, + /* " */ 1047, + /* P */ 1378 - 415, + /* , */ 651, + /* V */ 1479 - 358, + /* . */ 651, + /* F */ 1421 - 319, + /* , */ 651, + /* A */ 1479 - 301, + /* ' */ 651, + /* L */ 1360 - 167, + /* T */ 1366 - 301, + /* . */ 651}; + checkGlyphPositions(13, widths); + } + + private FOPGVTFont loadFont(boolean useAdvanced) { + FontInfo fontInfo = new FontInfoBuilder().useDejaVuLGCSerif(useAdvanced).build(); + FOPFontFamilyResolver resolver = new FOPFontFamilyResolverImpl(fontInfo); + FOPGVTFontFamily family = resolver.resolve(FontInfoBuilder.DEJAVU_LGC_SERIF); + return family.deriveFont(1000, Collections.emptyMap()); + } + + private void checkGlyphPositions(int expectedGlyphCount, int[] widths) { + assertEquals(expectedGlyphCount, glyphVector.getNumGlyphs()); + float[] positions = new float[2 * (widths.length + 1)]; + for (int i = 0, n = 2; i < widths.length; i++, n += 2) { + positions[n] = positions[n - 2] + widths[i] / 2.048f; + } + for (int i = 0; i <= widths.length; i++) { + assertEquals(positions[2 * i], glyphVector.getGlyphPosition(i).getX(), 3); + } + } + +} diff --git a/test/java/org/apache/fop/svg/glyph-orientation.svg b/test/java/org/apache/fop/svg/glyph-orientation.svg new file mode 100644 index 000000000..4900a3b02 --- /dev/null +++ b/test/java/org/apache/fop/svg/glyph-orientation.svg @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<svg width="100" height="140" xmlns="http://www.w3.org/2000/svg"> +<rect x="0" y="0" width="100%" height="100%" fill="none" stroke="black" stroke-width="2"/> +<g transform="translate(10) scale(20) scale(0.001) translate(0, 1000)" + font-family="sans-serif" font-size="1000"> + <text x="1000" writing-mode="tb">ABCD</text> + <text x="2500" writing-mode="tb" glyph-orientation-vertical="0">EFGH</text> + <text x="0" y="5000" glyph-orientation-horizontal="270">IJKL</text> +</g> +</svg> diff --git a/test/java/org/apache/fop/svg/rotated-glyph.svg b/test/java/org/apache/fop/svg/rotated-glyph.svg new file mode 100644 index 000000000..8b942905e --- /dev/null +++ b/test/java/org/apache/fop/svg/rotated-glyph.svg @@ -0,0 +1,5 @@ +<?xml version="1.0"?> +<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg"> +<rect x="0" y="0" width="100%" height="100%" fill="none" stroke="black" stroke-width="2"/> +<text font-family="Helvetica" font-size="100" x="40" y="110" rotate="0 45 0">ABC</text> +</svg> diff --git a/test/java/org/apache/fop/svg/spacing.svg b/test/java/org/apache/fop/svg/spacing.svg new file mode 100644 index 000000000..943ab1d04 --- /dev/null +++ b/test/java/org/apache/fop/svg/spacing.svg @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<svg width="150" height="200" xmlns="http://www.w3.org/2000/svg"> +<rect x="0" y="0" width="100%" height="100%" stroke="black" stroke-width="2" fill="none"/> +<g transform="translate(10) scale(40) scale(0.001) translate(0, 1000)" + font-family="sans-serif" font-size="1000"> + <g transform=""> + <text>VAV</text> + <line x1="667" y1="-818" x2="667" y2="100" stroke-width="10" stroke="blue"/> + </g> + <g transform="translate(0, 1000)"> + <text kerning="0">VAV</text> + <line x1="667" y1="-818" x2="667" y2="100" stroke-width="10" stroke="blue"/> + </g> + <g transform="translate(0, 2000)"> + <text letter-spacing="100">VAV</text> + </g> + <g transform="translate(0, 3000)"> + <text word-spacing="500">ab cd</text> + </g> +</g> +</svg> |