blob: 27df7cf0e215bb84799ab90b4435a2d60fff7360 [file] [log] [blame]
/*
* Copyright (C) 2013 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.
*/
/**
* This is the implementation of the Typeface object. Historically, it has
* just been SkTypeface, but we are migrating to Minikin. For the time
* being, that choice is hidden under the USE_MINIKIN compile-time flag.
*/
#define LOG_TAG "TypefaceImpl"
#include "jni.h" // for jlong, remove when being passed proper type
#include "SkStream.h"
#include "SkTypeface.h"
#ifdef USE_MINIKIN
#include <vector>
#include <minikin/FontCollection.h>
#include <minikin/FontFamily.h>
#include <minikin/Layout.h>
#include "SkPaint.h"
#include "MinikinSkia.h"
#endif
#include "TypefaceImpl.h"
#include "Utils.h"
namespace android {
#ifdef USE_MINIKIN
// Any weight greater than or equal to this is considered "bold" for
// legacy API.
static const int kBoldThreshold = 6;
static FontStyle styleFromSkiaStyle(SkTypeface::Style skiaStyle) {
int weight = (skiaStyle & SkTypeface::kBold) != 0 ? 7 : 4;
bool italic = (skiaStyle & SkTypeface::kItalic) != 0;
return FontStyle(weight, italic);
}
TypefaceImpl* gDefaultTypeface = NULL;
pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
// This installs a default typeface (from a hardcoded path) that allows
// layouts to work (not crash on null pointer) before the default
// typeface is set.
// TODO: investigate why layouts are being created before Typeface.java
// class initialization.
static FontCollection *makeFontCollection() {
std::vector<FontFamily *>typefaces;
const char *fns[] = {
"/system/fonts/Roboto-Regular.ttf",
};
FontFamily *family = new FontFamily();
for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
const char *fn = fns[i];
ALOGD("makeFontCollection adding %s", fn);
SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
if (skFace != NULL) {
MinikinFont *font = new MinikinFontSkia(skFace);
family->addFont(font);
font->Unref();
} else {
ALOGE("failed to create font %s", fn);
}
}
typefaces.push_back(family);
FontCollection *result = new FontCollection(typefaces);
family->Unref();
return result;
}
static void getDefaultTypefaceOnce() {
Layout::init();
if (gDefaultTypeface == NULL) {
// We expect the client to set a default typeface, but provide a
// default so we can make progress before that happens.
gDefaultTypeface = new TypefaceImpl;
gDefaultTypeface->fFontCollection = makeFontCollection();
gDefaultTypeface->fStyle = FontStyle();
}
}
TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
if (src == NULL) {
pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
return gDefaultTypeface;
} else {
return src;
}
}
TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
TypefaceImpl* result = new TypefaceImpl;
if (result != 0) {
result->fFontCollection = resolvedFace->fFontCollection;
result->fFontCollection->Ref();
result->fStyle = styleFromSkiaStyle(style);
}
return result;
}
static TypefaceImpl* createFromSkTypeface(SkTypeface* typeface) {
if (typeface == NULL) {
return NULL;
}
MinikinFont* minikinFont = new MinikinFontSkia(typeface);
std::vector<FontFamily *> typefaces;
FontFamily* family = new FontFamily();
family->addFont(minikinFont);
minikinFont->Unref();
typefaces.push_back(family);
TypefaceImpl* result = new TypefaceImpl;
result->fFontCollection = new FontCollection(typefaces);
family->Unref();
result->fStyle = FontStyle(); // TODO: improve
return result;
}
// Delete when removing USE_MINIKIN ifdef
TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
SkTypeface* face = SkTypeface::CreateFromName(name, style);
return createFromSkTypeface(face);
}
// Delete when removing USE_MINIKIN ifdef
TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
SkTypeface* face = SkTypeface::CreateFromFile(filename);
return createFromSkTypeface(face);
}
// Delete when removing USE_MINIKIN ifdef
TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
SkStream* stream = new AssetStreamAdaptor(asset,
AssetStreamAdaptor::kYes_OwnAsset,
AssetStreamAdaptor::kYes_HasMemoryBase);
SkTypeface* face = SkTypeface::CreateFromStream(stream);
// SkTypeFace::CreateFromStream calls ref() on the stream, so we
// need to unref it here or it won't be freed later on
stream->unref();
return createFromSkTypeface(face);
}
TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
std::vector<FontFamily *>familyVec;
for (size_t i = 0; i < size; i++) {
FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
familyVec.push_back(family);
}
TypefaceImpl* result = new TypefaceImpl;
result->fFontCollection = new FontCollection(familyVec);
if (size == 0) {
ALOGW("createFromFamilies creating empty collection");
result->fStyle = FontStyle();
} else {
const FontStyle defaultStyle;
FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle);
SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
// TODO: probably better to query more precise style from family, will be important
// when we open up API to access 100..900 weights
result->fStyle = styleFromSkiaStyle(skTypeface->style());
}
return result;
}
void TypefaceImpl_unref(TypefaceImpl* face) {
if (face != NULL) {
face->fFontCollection->Unref();
}
delete face;
}
int TypefaceImpl_getStyle(TypefaceImpl* face) {
FontStyle style = face->fStyle;
int result = style.getItalic() ? SkTypeface::kItalic : 0;
if (style.getWeight() >= kBoldThreshold) {
result |= SkTypeface::kBold;
}
return result;
}
void TypefaceImpl_setDefault(TypefaceImpl* face) {
gDefaultTypeface = face;
}
#else // USE_MINIKIN
/* Just use SkTypeface instead. */
typedef SkTypeface TypefaceImpl;
TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
return SkTypeface::CreateFromTypeface(src, style);
}
TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
return SkTypeface::CreateFromName(name, style);
}
TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
return SkTypeface::CreateFromFile(filename);
}
TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
SkStream* stream = new AssetStreamAdaptor(asset,
AssetStreamAdaptor::kYes_OwnAsset,
AssetStreamAdaptor::kYes_HasMemoryBase);
SkTypeface* face = SkTypeface::CreateFromStream(stream);
// SkTypeFace::CreateFromStream calls ref() on the stream, so we
// need to unref it here or it won't be freed later on
stream->unref();
return face;
}
TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
// Should never be called in non-Minikin builds
return 0;
}
void TypefaceImpl_unref(TypefaceImpl* face) {
SkSafeUnref(face);
}
int TypefaceImpl_getStyle(TypefaceImpl* face) {
return face->style();
}
void TypefaceImpl_setDefault(TypefaceImpl* face) {
}
#endif // USE_MINIKIN
}