// Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package com.google.typography.font.compression; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.typography.font.sfntly.Font; import com.google.typography.font.sfntly.Tag; import com.google.typography.font.sfntly.table.core.CMap; import com.google.typography.font.sfntly.table.core.CMapTable; import com.google.typography.font.sfntly.table.core.MaximumProfileTable; import java.io.ByteArrayOutputStream; import java.util.List; import java.util.Map; /** * Experimental CMap encoder, based primarily on writing the _inverse_ encoding. * * @author raph@google.com (Raph Levien) */ public class CmapEncoder { public static byte[] encode(Font font) { int nGlyphs = font.getTable(Tag.maxp).numGlyphs(); CMapTable cmapTable = font.getTable(Tag.cmap); CMap cmap = getBestCMap(cmapTable); Map invEncoding = Maps.newHashMap(); List exceptions = Lists.newArrayList(); for (Integer i : cmap) { int glyphId = cmap.glyphId(i); if (invEncoding.containsKey(glyphId)) { exceptions.add(i); exceptions.add(glyphId); } else { invEncoding.put(glyphId, i); } } ByteArrayOutputStream os = new ByteArrayOutputStream(); int last = -1; for (int i = 0; i < nGlyphs; i++) { if (invEncoding.containsKey(i)) { int value = invEncoding.get(i); int delta = value - last; writeVShort(os, delta); last = value; } else { writeVShort(os, 0); } } for (int i : exceptions) { writeVShort(os, i); } return os.toByteArray(); } private static CMap getBestCMap(CMapTable cmapTable) { for (CMap cmap : cmapTable) { if (cmap.format() == CMap.CMapFormat.Format12.value()) { return cmap; } } for (CMap cmap : cmapTable) { if (cmap.format() == CMap.CMapFormat.Format4.value()) { return cmap; } } return null; } // A simple signed varint encoding static void writeVShort(ByteArrayOutputStream os, int value) { if (value >= 0x2000 || value < -0x2000) { os.write((byte)(0x80 | ((value >> 14) & 0x7f))); } if (value >= 0x40 || value < -0x40) { os.write((byte)(0x80 | ((value >> 7) & 0x7f))); } os.write((byte)(value & 0x7f)); } }