Cache Typefaces in shadow/flat/CustomStyleSpan

Summary: @public `Typeface` handling in `shadow/flat/CustomStyleSpan` wasn't very efficient. This diff introduces `TypefaceCache` to avoid allocating duplicated `Typeface`s.

Reviewed By: sriramramani

Differential Revision: D2564363
This commit is contained in:
Denis Koroskin 2015-12-07 17:15:54 -08:00 committed by Ahmed El-Helw
parent 5c2f536e9a
commit 007318eb52
2 changed files with 80 additions and 6 deletions

View File

@ -84,14 +84,10 @@ import android.text.style.MetricAffectingSpan;
return;
}
// TODO: optimize this part (implemented in a followup patch)
if (mFontFamily != null) {
// efficient in API 21+
typeface = Typeface.create(mFontFamily, newStyle);
typeface = TypefaceCache.getTypeface(mFontFamily, newStyle);
} else {
// efficient in API 16+
typeface = Typeface.create(typeface, newStyle);
typeface = TypefaceCache.getTypeface(typeface, newStyle);
}
ds.setTypeface(typeface);

View File

@ -0,0 +1,78 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.flat;
import java.util.HashMap;
import android.graphics.Typeface;
/**
* TypefaceCache provides methods to resolve typeface from font family, or existing typeface
* with a different style.
*/
/* package */ final class TypefaceCache {
private static final int MAX_STYLES = 4; // NORMAL = 0, BOLD = 1, ITALIC = 2, BOLD_ITALIC = 3
private static final HashMap<String, Typeface[]> FONTFAMILY_CACHE = new HashMap<>();
private static final HashMap<Typeface, Typeface[]> TYPEFACE_CACHE = new HashMap<>();
/**
* Returns a Typeface for a given a FontFamily and style.
*/
public static Typeface getTypeface(String fontFamily, int style) {
Typeface[] cache = FONTFAMILY_CACHE.get(fontFamily);
if (cache == null) {
// cache is empty, create one.
cache = new Typeface[MAX_STYLES];
FONTFAMILY_CACHE.put(fontFamily, cache);
} else if (cache[style] != null) {
// return cached value.
return cache[style];
}
Typeface typeface = Typeface.create(fontFamily, style);
cache[style] = typeface;
TYPEFACE_CACHE.put(typeface, cache);
return typeface;
}
/**
* Returns a derivative of a given Typeface with a different style.
*/
public static Typeface getTypeface(Typeface typeface, int style) {
if (typeface == null) {
return Typeface.defaultFromStyle(style);
}
Typeface[] cache = TYPEFACE_CACHE.get(typeface);
if (cache == null) {
// This should not happen because all Typefaces are coming from TypefaceCache,
// and thus should be registered in TYPEFACE_CACHE.
// If we get here, it's a bug and one of the 2 scenarios happened:
// a) TypefaceCache created a Typeface and didn't put it into TYPEFACE_CACHE.
// b) someone else created a Typeface bypassing TypefaceCache so it's not registered here.
//
// If it's not registered, we can just register it manually for consistency, and so that
// next time someone requests a un unknown Typeface, it's already cached and we don't create
// extra copies.
cache = new Typeface[MAX_STYLES];
cache[typeface.getStyle()] = typeface;
} else if (cache[style] != null) {
// return cached value.
return cache[style];
}
typeface = Typeface.create(typeface, style);
cache[style] = typeface;
TYPEFACE_CACHE.put(typeface, cache);
return typeface;
}
}