| /* |
| * Copyright 2018 The Android Open Source Project |
| * |
| * Licensed 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. |
| */ |
| |
| package android.graphics.fonts; |
| |
| import android.annotation.IntRange; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| |
| /** |
| * Provides a utility for font file operations. |
| * @hide |
| */ |
| public class FontFileUtil { |
| |
| private FontFileUtil() {} // Do not instanciate |
| |
| /** |
| * Unpack the weight value from packed integer. |
| */ |
| public static int unpackWeight(int packed) { |
| return packed & 0xFFFF; |
| } |
| |
| /** |
| * Unpack the italic value from packed integer. |
| */ |
| public static boolean unpackItalic(int packed) { |
| return (packed & 0x10000) != 0; |
| } |
| |
| /** |
| * Returns true if the analyzeStyle succeeded |
| */ |
| public static boolean isSuccess(int packed) { |
| return packed != ANALYZE_ERROR; |
| } |
| |
| private static int pack(@IntRange(from = 0, to = 1000) int weight, boolean italic) { |
| return weight | (italic ? 0x10000 : 0); |
| } |
| |
| private static final int SFNT_VERSION_1 = 0x00010000; |
| private static final int SFNT_VERSION_OTTO = 0x4F54544F; |
| private static final int TTC_TAG = 0x74746366; |
| private static final int OS2_TABLE_TAG = 0x4F532F32; |
| |
| private static final int ANALYZE_ERROR = 0xFFFFFFFF; |
| |
| /** |
| * Analyze the font file returns packed style info |
| */ |
| public static final int analyzeStyle(@NonNull ByteBuffer buffer, |
| @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] varSettings) { |
| int weight = -1; |
| int italic = -1; |
| if (varSettings != null) { |
| for (FontVariationAxis axis :varSettings) { |
| if ("wght".equals(axis.getTag())) { |
| weight = (int) axis.getStyleValue(); |
| } else if ("ital".equals(axis.getTag())) { |
| italic = (axis.getStyleValue() == 1.0f) ? 1 : 0; |
| } |
| } |
| } |
| |
| if (weight != -1 && italic != -1) { |
| // Both weight/italic style are specifeid by variation settings. |
| // No need to look into OS/2 table. |
| // TODO: Good to look HVAR table to check if this font supports wght/ital axes. |
| return pack(weight, italic == 1); |
| } |
| |
| ByteOrder originalOrder = buffer.order(); |
| buffer.order(ByteOrder.BIG_ENDIAN); |
| try { |
| int fontFileOffset = 0; |
| int magicNumber = buffer.getInt(0); |
| if (magicNumber == TTC_TAG) { |
| // TTC file. |
| if (ttcIndex >= buffer.getInt(8 /* offset to number of fonts in TTC */)) { |
| return ANALYZE_ERROR; |
| } |
| fontFileOffset = buffer.getInt( |
| 12 /* offset to array of offsets of font files */ + 4 * ttcIndex); |
| } |
| int sfntVersion = buffer.getInt(fontFileOffset); |
| |
| if (sfntVersion != SFNT_VERSION_1 && sfntVersion != SFNT_VERSION_OTTO) { |
| return ANALYZE_ERROR; |
| } |
| |
| int numTables = buffer.getShort(fontFileOffset + 4 /* offset to number of tables */); |
| int os2TableOffset = -1; |
| for (int i = 0; i < numTables; ++i) { |
| int tableOffset = fontFileOffset + 12 /* size of offset table */ |
| + i * 16 /* size of table record */; |
| if (buffer.getInt(tableOffset) == OS2_TABLE_TAG) { |
| os2TableOffset = buffer.getInt(tableOffset + 8 /* offset to the table */); |
| break; |
| } |
| } |
| |
| if (os2TableOffset == -1) { |
| // Couldn't find OS/2 table. use regular style |
| return pack(400, false); |
| } |
| |
| int weightFromOS2 = buffer.getShort(os2TableOffset + 4 /* offset to weight class */); |
| boolean italicFromOS2 = |
| (buffer.getShort(os2TableOffset + 62 /* offset to fsSelection */) & 1) != 0; |
| return pack(weight == -1 ? weightFromOS2 : weight, |
| italic == -1 ? italicFromOS2 : italic == 1); |
| } finally { |
| buffer.order(originalOrder); |
| } |
| } |
| } |