All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.io.font.otf.OtfReadCommon Maven / Gradle / Ivy

/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
 */
package com.itextpdf.io.font.otf;

import com.itextpdf.io.font.FontProgram;
import com.itextpdf.io.source.RandomAccessFileOrArray;
import com.itextpdf.commons.utils.MessageFormatUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class OtfReadCommon {
    public static int[] readUShortArray(RandomAccessFileOrArray rf, int size, int location) throws java.io.IOException {
        int[] ret = new int[size];
        for (int k = 0; k < size; ++k) {
            int offset = rf.readUnsignedShort();
            ret[k] = offset == 0 ? offset : offset + location;
        }
        return ret;
    }

    public static int[] readUShortArray(RandomAccessFileOrArray rf, int size) throws java.io.IOException {
        return readUShortArray(rf, size, 0);
    }

    public static void readCoverages(RandomAccessFileOrArray rf, int[] locations, List> coverage)
            throws java.io.IOException {
        for (int location : locations) {
            coverage.add(new HashSet<>(readCoverageFormat(rf, location)));
        }
    }

    public static List readCoverageFormat(RandomAccessFileOrArray rf, int coverageLocation)
            throws java.io.IOException {
        rf.seek(coverageLocation);
        int coverageFormat = rf.readShort();
        List glyphIds;
        if (coverageFormat == 1) {
            int glyphCount = rf.readUnsignedShort();
            glyphIds = new ArrayList<>(glyphCount);
            for (int i = 0; i < glyphCount; i++) {
                int coverageGlyphId = rf.readUnsignedShort();
                glyphIds.add(coverageGlyphId);
            }
        } else if (coverageFormat == 2) {
            int rangeCount = rf.readUnsignedShort();
            glyphIds = new ArrayList<>();
            for (int i = 0; i < rangeCount; i++) {
                readRangeRecord(rf, glyphIds);
            }

        } else {
            throw new UnsupportedOperationException(
                    MessageFormatUtil.format("Invalid coverage format: {0}", coverageFormat));
        }

        return Collections.unmodifiableList(glyphIds);
    }

    private static void readRangeRecord(RandomAccessFileOrArray rf, List glyphIds) throws java.io.IOException {
        int startGlyphId = rf.readUnsignedShort();
        int endGlyphId = rf.readUnsignedShort();
        @SuppressWarnings("unused")
        int startCoverageIndex = rf.readShort();
        for (int glyphId = startGlyphId; glyphId <= endGlyphId; glyphId++) {
            glyphIds.add(glyphId);
        }
    }

    public static GposValueRecord readGposValueRecord(OpenTypeFontTableReader tableReader, int mask)
            throws java.io.IOException {
        GposValueRecord vr = new GposValueRecord();
        if ((mask & 0x0001) != 0) {
            vr.XPlacement =
                    FontProgram.convertGlyphSpaceToTextSpace(tableReader.rf.readShort()) / tableReader.getUnitsPerEm();
        }
        if ((mask & 0x0002) != 0) {
            vr.YPlacement =
                    FontProgram.convertGlyphSpaceToTextSpace(tableReader.rf.readShort()) / tableReader.getUnitsPerEm();
        }
        if ((mask & 0x0004) != 0) {
            vr.XAdvance =
                    FontProgram.convertGlyphSpaceToTextSpace(tableReader.rf.readShort()) / tableReader.getUnitsPerEm();
        }
        if ((mask & 0x0008) != 0) {
            vr.YAdvance =
                    FontProgram.convertGlyphSpaceToTextSpace(tableReader.rf.readShort()) / tableReader.getUnitsPerEm();
        }
        if ((mask & 0x0010) != 0) {
            tableReader.rf.skip(2);
        }
        if ((mask & 0x0020) != 0) {
            tableReader.rf.skip(2);
        }
        if ((mask & 0x0040) != 0) {
            tableReader.rf.skip(2);
        }
        if ((mask & 0x0080) != 0) {
            tableReader.rf.skip(2);
        }
        return vr;
    }

    public static GposAnchor readGposAnchor(OpenTypeFontTableReader tableReader, int location)
            throws java.io.IOException {
        if (location == 0) {
            return null;
        }
        tableReader.rf.seek(location);
        int format = tableReader.rf.readUnsignedShort();
        GposAnchor t = null;

        switch (format) {
            default:
                t = new GposAnchor();
                t.XCoordinate = FontProgram.convertGlyphSpaceToTextSpace(tableReader.rf.readShort())
                        / tableReader.getUnitsPerEm();
                t.YCoordinate = FontProgram.convertGlyphSpaceToTextSpace(tableReader.rf.readShort())
                        / tableReader.getUnitsPerEm();
                break;
        }

        return t;
    }

    public static List readMarkArray(OpenTypeFontTableReader tableReader, int location)
            throws java.io.IOException {
        tableReader.rf.seek(location);
        int markCount = tableReader.rf.readUnsignedShort();
        int[] classes = new int[markCount];
        int[] locations = new int[markCount];
        for (int k = 0; k < markCount; ++k) {
            classes[k] = tableReader.rf.readUnsignedShort();
            int offset = tableReader.rf.readUnsignedShort();
            locations[k] = location + offset;
        }
        List marks = new ArrayList();
        for (int k = 0; k < markCount; ++k) {
            OtfMarkRecord rec = new OtfMarkRecord();
            rec.markClass = classes[k];
            rec.anchor = readGposAnchor(tableReader, locations[k]);
            marks.add(rec);
        }
        return marks;
    }

    public static SubstLookupRecord[] readSubstLookupRecords(RandomAccessFileOrArray rf, int substCount)
            throws java.io.IOException {
        SubstLookupRecord[] substLookUpRecords = new SubstLookupRecord[substCount];
        for (int i = 0; i < substCount; ++i) {
            SubstLookupRecord slr = new SubstLookupRecord();
            slr.sequenceIndex = rf.readUnsignedShort();
            slr.lookupListIndex = rf.readUnsignedShort();
            substLookUpRecords[i] = slr;
        }
        return substLookUpRecords;
    }

    public static PosLookupRecord[] readPosLookupRecords(RandomAccessFileOrArray rf, int recordCount)
            throws java.io.IOException {
        PosLookupRecord[] posLookUpRecords = new PosLookupRecord[recordCount];
        for (int i = 0; i < recordCount; ++i) {
            PosLookupRecord lookupRecord = new PosLookupRecord();
            lookupRecord.sequenceIndex = rf.readUnsignedShort();
            lookupRecord.lookupListIndex = rf.readUnsignedShort();
            posLookUpRecords[i] = lookupRecord;
        }
        return posLookUpRecords;
    }

    public static GposAnchor[] readAnchorArray(OpenTypeFontTableReader tableReader, int[] locations, int left,
            int right) throws java.io.IOException {
        GposAnchor[] anchors = new GposAnchor[right - left];
        for (int i = left; i < right; i++) {
            anchors[i - left] = readGposAnchor(tableReader, locations[i]);
        }
        return anchors;
    }

    public static List readBaseArray(OpenTypeFontTableReader tableReader, int classCount, int location)
            throws java.io.IOException {
        List baseArray = new ArrayList<>();
        tableReader.rf.seek(location);
        int baseCount = tableReader.rf.readUnsignedShort();
        int[] anchorLocations = readUShortArray(tableReader.rf, baseCount * classCount, location);
        int idx = 0;
        for (int k = 0; k < baseCount; ++k) {
            baseArray.add(readAnchorArray(tableReader, anchorLocations, idx, idx + classCount));
            idx += classCount;
        }
        return baseArray;
    }

    public static List> readLigatureArray(OpenTypeFontTableReader tableReader, int classCount,
            int location) throws java.io.IOException {
        List> ligatureArray = new ArrayList<>();
        tableReader.rf.seek(location);
        int ligatureCount = tableReader.rf.readUnsignedShort();
        int[] ligatureAttachLocations = readUShortArray(tableReader.rf, ligatureCount, location);
        for (int liga = 0; liga < ligatureCount; ++liga) {
            int ligatureAttachLocation = ligatureAttachLocations[liga];
            List ligatureAttach = new ArrayList<>();
            tableReader.rf.seek(ligatureAttachLocation);
            int componentCount = tableReader.rf.readUnsignedShort();
            final int[] componentRecordsLocation = readUShortArray(tableReader.rf, classCount * componentCount,
                    ligatureAttachLocation);
            int idx = 0;
            for (int k = 0; k < componentCount; ++k) {
                ligatureAttach.add(readAnchorArray(tableReader, componentRecordsLocation, idx, idx + classCount));
                idx += classCount;
            }
            ligatureArray.add(ligatureAttach);
        }
        return ligatureArray;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy