123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.fonts.truetype;
-
- import java.io.ByteArrayInputStream;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.Map;
-
- import org.junit.Before;
- import org.junit.Test;
-
- import static org.junit.Assert.assertTrue;
-
- /**
- * Tests {@link GlyfTable}.
- */
- public class GlyfTableTestCase {
-
- private static final class DirData {
-
- final long offset;
- final long length;
-
- DirData(long offset, long length) {
- this.offset = offset;
- this.length = length;
- }
- }
-
- private FontFileReader subsetReader;
-
- private long[] glyphOffsets;
-
- private FontFileReader originalFontReader;
-
- @Before
- public void setUp() throws IOException {
- FileInputStream fontStream = new FileInputStream(
- "test/resources/fonts/ttf/DejaVuLGCSerif.ttf");
- try {
- originalFontReader = new FontFileReader(fontStream);
- } finally {
- fontStream.close();
- }
- }
-
- /**
- * Tests that composed glyphs are included in the glyph subset if a composite glyph is used.
- *
- * @throws IOException if an I/O error occurs
- */
- @Test
- public void testPopulateGlyphsWithComposites() throws IOException {
- // Glyph 408 -> U+01D8 "uni01D8" this is a composite glyph.
- int[] composedIndices = setupTest(408);
-
- int[] expected = new int[composedIndices.length];
- expected[1] = 6;
- expected[5] = 2;
- expected[6] = 4;
-
- assertArrayEquals(expected, composedIndices);
- }
-
- /**
- * Tests that no glyphs are added if there are no composite glyphs the subset.
- *
- * @throws IOException if an I/O error occurs
- */
- @Test
- public void testPopulateNoCompositeGlyphs() throws IOException {
- int[] composedIndices = setupTest(36, 37, 38); // "A", "B", "C"
- int[] expected = new int[composedIndices.length];
-
- // There should be NO composite glyphs
- assertArrayEquals(expected, composedIndices);
- }
-
- /**
- * Tests that glyphs aren't remapped twice if the glyph before a composite glyph has 0-length.
- *
- * @throws IOException if an I/O error occurs
- */
- @Test
- public void testGlyphsNotRemappedTwice() throws IOException {
- int composedGlyph = 12;
- // The order of these glyph indices, must NOT be changed! (see javadoc above)
- int[] composedIndices = setupTest(1, 2, 3, 16, 2014, 4, 7, 8, 13, 2015, composedGlyph);
-
- // There are 2 composed glyphs within the subset
- int[] expected = new int[composedIndices.length];
- expected[10] = composedGlyph;
-
- assertArrayEquals(expected, composedIndices);
- }
-
- /**
- * Tests that the correct glyph is included in the subset, when a composite glyph composed of a
- * composite glyph is used.
- *
- * @throws IOException if an I/O error occurs
- */
- @Test
- public void testSingleRecursionStep() throws IOException {
- // Glyph 2077 -> U+283F "uni283F" this is composed of a composite glyph (recursive).
- int[] composedIndices = setupTest(2077);
-
- int[] expected = new int[composedIndices.length];
- expected[1] = 2;
-
- assertArrayEquals(expected, composedIndices);
- }
-
- private int[] setupTest(int... glyphIndices) throws IOException {
- Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>();
- int index = 0;
- glyphs.put(0, index++); // Glyph 0 (.notdef) must ALWAYS be in the subset
-
- for (int glyphIndex : glyphIndices) {
- glyphs.put(glyphIndex, index++);
- }
- setupSubsetReader(glyphs);
- readLoca();
-
- return retrieveIndicesOfComposedGlyphs();
- }
-
- private void setupSubsetReader(Map<Integer, Integer> glyphs) throws IOException {
- TTFSubSetFile fontFile = new TTFSubSetFile();
- String header = OFFontLoader.readHeader(subsetReader);
- fontFile.readFont(originalFontReader, "Deja", header, glyphs);
- byte[] subsetFont = fontFile.getFontSubset();
- InputStream intputStream = new ByteArrayInputStream(subsetFont);
- subsetReader = new FontFileReader(intputStream);
- }
-
- private void readLoca() throws IOException {
- DirData loca = getTableData(OFTableName.LOCA.getName());
- int numberOfGlyphs = (int) (loca.length - 4) / 4;
- glyphOffsets = new long[numberOfGlyphs];
- subsetReader.seekSet(loca.offset);
-
- for (int i = 0; i < numberOfGlyphs; i++) {
- glyphOffsets[i] = subsetReader.readTTFULong();
- }
- }
-
- private int[] retrieveIndicesOfComposedGlyphs() throws IOException {
- DirData glyf = getTableData(OFTableName.GLYF.getName());
- int[] composedGlyphIndices = new int[glyphOffsets.length];
-
- for (int i = 0; i < glyphOffsets.length; i++) {
- long glyphOffset = glyphOffsets[i];
- if (i != glyphOffsets.length - 1 && glyphOffset == glyphOffsets[i + 1]) {
- continue;
- }
- subsetReader.seekSet(glyf.offset + glyphOffset);
- short numberOfContours = subsetReader.readTTFShort();
- if (numberOfContours < 0) {
- subsetReader.skip(8);
- subsetReader.readTTFUShort(); // flags
- int glyphIndex = subsetReader.readTTFUShort();
- composedGlyphIndices[i] = glyphIndex;
- }
- }
- return composedGlyphIndices;
- }
-
- private DirData getTableData(String tableName) throws IOException {
- subsetReader.seekSet(0);
- subsetReader.skip(12);
- String name;
- do {
- name = subsetReader.readTTFString(4);
- subsetReader.skip(4 * 3);
- } while (!name.equals(tableName));
-
- subsetReader.skip(-8); // We've found the table, go back to get the data we skipped over
- return new DirData(subsetReader.readTTFLong(), subsetReader.readTTFLong());
- }
-
- private void assertArrayEquals(int[] expected, int[] actual) {
- assertTrue(Arrays.equals(expected, actual));
- }
- }
|