1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics.fonts; 18 19 import android.icu.util.ULocale; 20 import android.os.LocaleList; 21 import android.util.Pair; 22 23 import java.io.File; 24 import java.util.Arrays; 25 import java.util.HashSet; 26 import java.util.Locale; 27 import java.util.Objects; 28 import java.util.Set; 29 30 public class NativeSystemFontHelper { 31 static { 32 System.loadLibrary("ctsgraphics_jni"); 33 } 34 35 /** 36 * Helper class for representing the system font obtained in native code. 37 */ 38 public static class FontDescriptor { 39 String mFilePath; 40 int mWeight; 41 int mSlant; 42 int mIndex; 43 FontVariationAxis[] mAxes; 44 LocaleList mLocale; 45 46 @Override equals(Object o)47 public boolean equals(Object o) { 48 if (o == this) { 49 return true; 50 } 51 if (o == null || !(o instanceof FontDescriptor)) { 52 return false; 53 } 54 FontDescriptor f = (FontDescriptor) o; 55 return f.mFilePath.equals(mFilePath) 56 && f.mWeight == mWeight 57 && f.mSlant == mSlant 58 && f.mIndex == mIndex 59 && Arrays.equals(f.mAxes, mAxes) 60 && localeListEquals(f.mLocale, mLocale); 61 } 62 63 @Override hashCode()64 public int hashCode() { 65 return Objects.hash(mFilePath, mWeight, mSlant, mIndex, Arrays.hashCode(mAxes), 66 mLocale); 67 } 68 localeEquals(Locale left, Locale right)69 public boolean localeEquals(Locale left, Locale right) { 70 ULocale ulocLeft = ULocale.addLikelySubtags(ULocale.forLocale(left)); 71 ULocale ulocRight = ULocale.addLikelySubtags(ULocale.forLocale(right)); 72 return ulocLeft.equals(ulocRight); 73 } 74 localeListEquals(LocaleList left, LocaleList right)75 public boolean localeListEquals(LocaleList left, LocaleList right) { 76 if (left == right) { 77 return true; 78 } 79 if (left == null || right == null) { 80 return false; 81 } 82 83 if (left.size() != right.size()) { 84 return false; 85 } 86 for (int i = 0; i < left.size(); ++i) { 87 if (!localeEquals(left.get(i), right.get(i))) { 88 return false; 89 } 90 } 91 return true; 92 } 93 94 @Override toString()95 public String toString() { 96 return "Font {" 97 + " path = " + mFilePath 98 + " weight = " + mWeight 99 + " slant = " + mSlant 100 + " index = " + mIndex 101 + " axes = " + FontVariationAxis.toFontVariationSettings(mAxes) 102 + " locale = " + mLocale 103 + "}"; 104 } 105 } 106 tagToStr(int tag)107 private static String tagToStr(int tag) { 108 char[] buf = new char[4]; 109 buf[0] = (char) ((tag >> 24) & 0xFF); 110 buf[1] = (char) ((tag >> 16) & 0xFF); 111 buf[2] = (char) ((tag >> 8) & 0xFF); 112 buf[3] = (char) (tag & 0xFF); 113 return String.valueOf(buf); 114 } 115 getAvailableFonts()116 public static Set<FontDescriptor> getAvailableFonts() { 117 long iterPtr = nOpenIterator(); 118 HashSet<FontDescriptor> nativeFonts = new HashSet<>(); 119 try { 120 for (long fontPtr = nNext(iterPtr); fontPtr != 0; fontPtr = nNext(iterPtr)) { 121 try { 122 FontDescriptor font = new FontDescriptor(); 123 font.mFilePath = nGetFilePath(fontPtr); 124 font.mWeight = nGetWeight(fontPtr); 125 font.mSlant = nIsItalic(fontPtr) 126 ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT; 127 font.mIndex = nGetCollectionIndex(fontPtr); 128 int axesSize = nGetAxisCount(fontPtr); 129 font.mAxes = new FontVariationAxis[axesSize]; 130 for (int i = 0; i < font.mAxes.length; ++i) { 131 font.mAxes[i] = new FontVariationAxis( 132 tagToStr(nGetAxisTag(fontPtr, i)), nGetAxisValue(fontPtr, i)); 133 } 134 135 font.mLocale = LocaleList.forLanguageTags(nGetLocale(fontPtr)); 136 nativeFonts.add(font); 137 } finally { 138 nCloseFont(fontPtr); 139 } 140 } 141 } finally { 142 nCloseIterator(iterPtr); 143 } 144 return nativeFonts; 145 } 146 matchFamilyStyleCharacter(String familyName, int weight, boolean italic, String languageTags, int familyVariant, String text)147 public static Pair<File, Integer> matchFamilyStyleCharacter(String familyName, int weight, 148 boolean italic, String languageTags, int familyVariant, String text) { 149 final long fontPtr = nMatchFamilyStyleCharacter(familyName, weight, italic, languageTags, 150 familyVariant, text); 151 final int runLength = nMatchFamilyStyleCharacter_runLength(familyName, weight, italic, 152 languageTags, familyVariant, text); 153 try { 154 return new Pair<>(new File(nGetFilePath(fontPtr)), runLength); 155 } finally { 156 nCloseFont(fontPtr); 157 } 158 } 159 nOpenIterator()160 private static native long nOpenIterator(); nCloseIterator(long ptr)161 private static native void nCloseIterator(long ptr); nNext(long ptr)162 private static native long nNext(long ptr); nCloseFont(long ptr)163 private static native void nCloseFont(long ptr); nGetFilePath(long ptr)164 private static native String nGetFilePath(long ptr); nGetWeight(long ptr)165 private static native int nGetWeight(long ptr); nIsItalic(long ptr)166 private static native boolean nIsItalic(long ptr); nGetLocale(long ptr)167 private static native String nGetLocale(long ptr); nGetCollectionIndex(long ptr)168 private static native int nGetCollectionIndex(long ptr); nGetAxisCount(long ptr)169 private static native int nGetAxisCount(long ptr); nGetAxisTag(long ptr, int index)170 private static native int nGetAxisTag(long ptr, int index); nGetAxisValue(long ptr, int index)171 private static native float nGetAxisValue(long ptr, int index); nMatchFamilyStyleCharacter(String familyName, int weight, boolean italic, String languageTags, int familyVariant, String text)172 private static native long nMatchFamilyStyleCharacter(String familyName, int weight, 173 boolean italic, String languageTags, int familyVariant, String text); nMatchFamilyStyleCharacter_runLength(String familyName, int weight, boolean italic, String languageTags, int familyVariant, String text)174 private static native int nMatchFamilyStyleCharacter_runLength(String familyName, int weight, 175 boolean italic, String languageTags, int familyVariant, String text); 176 } 177