123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /*
- * 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.pcl.fonts;
-
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- import org.junit.Before;
- import org.junit.Test;
-
- import static org.junit.Assert.assertArrayEquals;
- import static org.junit.Assert.assertEquals;
- import static org.mockito.Mockito.mock;
- import static org.mockito.Mockito.when;
-
- import org.apache.fop.fonts.CustomFont;
- import org.apache.fop.fonts.SingleByteFont;
- import org.apache.fop.render.java2d.CustomFontMetricsMapper;
- import org.apache.fop.render.pcl.fonts.PCLFontSegment.SegmentID;
- import org.apache.fop.render.pcl.fonts.truetype.PCLTTFFontReader;
-
- public class PCLTTFFontReaderTestCase {
-
- private CustomFontMetricsMapper customFont = mock(CustomFontMetricsMapper.class);
- private PCLByteWriterUtil byteWriter;
- private static final String TEST_FONT_A = "./test/resources/fonts/ttf/DejaVuLGCSerif.ttf";
-
- @Before
- public void setUp() {
- byteWriter = new PCLByteWriterUtil();
- }
-
- @Test
- public void verifyFontAData() throws Exception {
- CustomFont sbFont = mock(CustomFont.class);
- when(sbFont.getInputStream()).thenReturn(new FileInputStream(new File(TEST_FONT_A)));
- when(customFont.getRealFont()).thenReturn(sbFont);
- SingleByteFont font = mock(SingleByteFont.class);
- when(font.getGIDFromChar('h')).thenReturn(104);
- when(font.getGIDFromChar('e')).thenReturn(101);
- when(font.getGIDFromChar('l')).thenReturn(108);
- when(font.getGIDFromChar('o')).thenReturn(111);
- PCLTTFFontReader reader = new MockPCLTTFFontReader(customFont, byteWriter);
- reader.setFont(font);
- verifyFontData(reader);
- validateOffsets(reader);
- validateFontSegments(reader);
- }
-
- /**
- * Compares the input font data against a sample of the data read and calculated by the reader. The assertions are
- * made against data taken from the TrueType Font Analyzer tool.
- * @param reader The reader
- */
- private void verifyFontData(PCLTTFFontReader reader) {
- assertEquals(reader.getCellWidth(), 5015); // Bounding box X2 - X1
- assertEquals(reader.getCellHeight(), 3254); // Bounding box Y2 - Y1
- assertEquals(reader.getCapHeight(), 0); // OS2Table.capHeight
- assertEquals(reader.getFontName(), "DejaVu LGC Serif"); // Full name read by TTFFont object
- assertEquals(reader.getFirstCode(), 32); // Always 32 for bound font
- assertEquals(reader.getLastCode(), 255); // Always 255 for bound font
-
- // Values that require conversion tables (See PCLTTFFontReader.java)
- assertEquals(reader.getStrokeWeight(), 0); // Weight Class 400 (regular) should be equivalent 0
- assertEquals(reader.getSerifStyle(), 128); // Serif Style 0 should equal 0
- assertEquals(reader.getWidthType(), 0); // Width Class 5 (regular) should be equivalent 0
- }
-
- private void validateOffsets(PCLTTFFontReader reader) throws IOException {
- // Offsets are stored with their character ID with the array [offset, length]
- Map<Integer, int[]> offsets = reader.getCharacterOffsets();
-
- // Test data
- int[] charC = {27644, 144}; // Char index = 99
- int[] charDollar = {16044, 264}; // Char index = 36
- int[] charOne = {17808, 176}; // Char index = 49
- int[] charUpperD = {21236, 148}; // Char index = 68
- int[] charUpperJ = {22140, 176}; // Char index = 74
-
- assertArrayEquals(offsets.get(99), charC);
- assertArrayEquals(offsets.get(36), charDollar);
- assertArrayEquals(offsets.get(49), charOne);
- assertArrayEquals(offsets.get(68), charUpperD);
- assertArrayEquals(offsets.get(74), charUpperJ);
- }
-
- /**
- * Verifies the font segment data copied originally from the TrueType font. Data was verified using TrueType Font
- * Analyzer and PCLParaphernalia tool.
- * @param reader The reader
- * @throws IOException
- */
- private void validateFontSegments(PCLTTFFontReader reader) throws IOException {
- HashMap<Character, Integer> mappedChars = new HashMap<Character, Integer>();
- mappedChars.put('H', 1);
- mappedChars.put('e', 1);
- mappedChars.put('l', 1);
- mappedChars.put('o', 1);
-
- List<PCLFontSegment> segments = reader.getFontSegments(mappedChars);
- assertEquals(segments.size(), 5);
- for (PCLFontSegment segment : segments) {
- if (segment.getIdentifier() == SegmentID.PA) {
- // Panose
- assertEquals(segment.getData().length, 10);
- byte[] panose = {2, 6, 6, 3, 5, 6, 5, 2, 2, 4};
- assertArrayEquals(segment.getData(), panose);
- } else if (segment.getIdentifier() == SegmentID.GT) {
- verifyGlobalTrueTypeData(segment, mappedChars.size());
- } else if (segment.getIdentifier() == SegmentID.NULL) {
- // Terminating segment
- assertEquals(segment.getData().length, 0);
- }
- }
- }
-
- private void verifyGlobalTrueTypeData(PCLFontSegment segment, int mappedCharsSize)
- throws IOException {
- byte[] ttfData = segment.getData();
- int currentPos = 0;
- //Version
- assertEquals(readInt(new byte[]{ttfData[currentPos++], ttfData[currentPos++]}), 1);
- assertEquals(readInt(new byte[]{ttfData[currentPos++], ttfData[currentPos++]}), 0);
- //Number of tables
- int numTables = readInt(new byte[]{ttfData[currentPos++], ttfData[currentPos++]});
- assertEquals(numTables, 8);
- //Search range
- assertEquals(readInt(new byte[]{ttfData[currentPos++], ttfData[currentPos++]}), 128);
- //Entry Selector
- assertEquals(readInt(new byte[]{ttfData[currentPos++], ttfData[currentPos++]}), 3);
- //Range shift
- assertEquals(readInt(new byte[]{ttfData[currentPos++], ttfData[currentPos++]}), 0);
- String[] validTags = {"head", "hhea", "hmtx", "maxp", "gdir"};
- int matches = 0;
- for (int i = 0; i < numTables; i++) {
- String tag = readTag(new byte[]{ttfData[currentPos++], ttfData[currentPos++],
- ttfData[currentPos++], ttfData[currentPos++]});
- if (Arrays.asList(validTags).contains(tag)) {
- matches++;
- }
- if (tag.equals("hmtx")) {
- currentPos += 4;
- int offset = readLong(new byte[]{ttfData[currentPos++], ttfData[currentPos++],
- ttfData[currentPos++], ttfData[currentPos++]});
- int length = readLong(new byte[]{ttfData[currentPos++], ttfData[currentPos++],
- ttfData[currentPos++], ttfData[currentPos++]});
- verifyHmtx(ttfData, offset, length, mappedCharsSize);
- } else {
- currentPos += 12;
- }
- }
- assertEquals(matches, 5);
- }
-
- private void verifyHmtx(byte[] ttfData, int offset, int length, int mappedCharsSize)
- throws IOException {
- ByteArrayInputStream bais = new ByteArrayInputStream(ttfData);
- byte[] subsetHmtx = new byte[length];
- bais.skip(offset);
- bais.read(subsetHmtx);
- assertEquals(subsetHmtx.length, (mappedCharsSize + 32) * 4);
- }
-
- private int readInt(byte[] bytes) {
- return ((0xFF & bytes[0]) << 8) | (0xFF & bytes[1]);
- }
-
- private int readLong(byte[] bytes) {
- return ((0xFF & bytes[0]) << 24) | ((0xFF & bytes[1]) << 16) | ((0xFF & bytes[2]) << 8)
- | (0xFF & bytes[3]);
- }
-
- private String readTag(byte[] tag) {
- return new String(tag);
- }
- }
|