blob: d77460aebf6893239b5cddc5e5f7444d484aab54 [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.
#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h"
#include "base/debug/trace_event.h"
#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.h"
#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h"
#include "SkData.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTSearch.h"
SkFontMgr_Cobalt::SkFontMgr_Cobalt(
const char* directory, const SkTArray<SkString, true>& default_families)
: system_typeface_stream_manager_(
"Font.SystemTypeface",
COBALT_SYSTEM_TYPEFACE_CACHE_CAPACITY_IN_BYTES),
default_family_(NULL) {
TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::SkFontMgr_Cobalt()");
SkTDArray<FontFamily*> font_families;
{
TRACE_EVENT0("cobalt::renderer", "SkFontConfigParser::GetFontFamilies()");
SkFontConfigParser::GetFontFamilies(directory, &font_families);
}
BuildNameToFamilyMap(directory, &font_families);
font_families.deleteAll();
FindDefaultFamily(default_families);
}
SkTypeface* SkFontMgr_Cobalt::MatchFaceName(const char face_name[]) {
if (!face_name) {
return NULL;
}
SkAutoAsciiToLC face_name_to_lc(face_name);
std::string face_name_string(face_name_to_lc.lc(), face_name_to_lc.length());
// Lock the style sets mutex prior to accessing them.
SkAutoMutexAcquire scoped_mutex(style_sets_mutex_);
// Prioritize looking up the postscript name first since some of our client
// applications prefer this method to specify face names.
for (int i = 0; i <= 1; ++i) {
NameToStyleSetMap& name_to_style_set_map =
i == 0 ? font_postscript_name_to_style_set_map_
: full_font_name_to_style_set_map_;
NameToStyleSetMap::iterator style_set_iterator =
name_to_style_set_map.find(face_name_string);
if (style_set_iterator != name_to_style_set_map.end()) {
SkFontStyleSet_Cobalt* style_set = style_set_iterator->second;
SkTypeface* typeface =
i == 0 ? style_set->MatchFontPostScriptName(face_name_string)
: style_set->MatchFullFontName(face_name_string);
if (typeface != NULL) {
return typeface;
} else {
// If no typeface was successfully created then remove the entry from
// the map. It won't provide a successful result in subsequent calls
// either.
name_to_style_set_map.erase(style_set_iterator);
}
}
}
return NULL;
}
int SkFontMgr_Cobalt::onCountFamilies() const { return family_names_.count(); }
void SkFontMgr_Cobalt::onGetFamilyName(int index, SkString* family_name) const {
if (index < 0 || family_names_.count() <= index) {
family_name->reset();
return;
}
family_name->set(family_names_[index]);
}
SkFontStyleSet_Cobalt* SkFontMgr_Cobalt::onCreateStyleSet(int index) const {
if (index < 0 || family_names_.count() <= index) {
return NULL;
}
NameToStyleSetMap::const_iterator family_iterator =
name_to_family_map_.find(family_names_[index].c_str());
if (family_iterator != name_to_family_map_.end()) {
return SkRef(family_iterator->second);
}
return NULL;
}
SkFontStyleSet_Cobalt* SkFontMgr_Cobalt::onMatchFamily(
const char family_name[]) const {
if (!family_name) {
return NULL;
}
SkAutoAsciiToLC family_name_to_lc(family_name);
NameToStyleSetMap::const_iterator family_iterator = name_to_family_map_.find(
std::string(family_name_to_lc.lc(), family_name_to_lc.length()));
if (family_iterator != name_to_family_map_.end()) {
return SkRef(family_iterator->second);
}
return NULL;
}
SkTypeface* SkFontMgr_Cobalt::onMatchFamilyStyle(
const char family_name[], const SkFontStyle& style) const {
SkTypeface* typeface = NULL;
if (family_name) {
SkAutoTUnref<SkFontStyleSet> style_set(matchFamily(family_name));
typeface = style_set->matchStyle(style);
}
if (NULL == typeface) {
typeface = default_family_->matchStyle(style);
}
return typeface;
}
SkTypeface* SkFontMgr_Cobalt::onMatchFaceStyle(const SkTypeface* family_member,
const SkFontStyle& style) const {
// Lock the style sets mutex prior to calling private |SkFontStyleSet_Cobalt|
// functions that expect the mutex to already be locked.
SkAutoMutexAcquire scoped_mutex(style_sets_mutex_);
for (int i = 0; i < font_style_sets_.count(); ++i) {
if (font_style_sets_[i]->ContainsTypeface(family_member)) {
return font_style_sets_[i]->MatchStyleWithoutLocking(style);
}
}
return NULL;
}
SkTypeface* SkFontMgr_Cobalt::onMatchFamilyStyleCharacter(
const char family_name[], const SkFontStyle& style, const char bcp47_val[],
SkUnichar character) const {
const char** bcp47 = &bcp47_val;
int bcp47_count = bcp47_val ? 1 : 0;
// Remove const from the manager. SkFontMgr_Cobalt modifies its internals
// within FindFamilyStyleCharacter().
SkFontMgr_Cobalt* font_mgr = const_cast<SkFontMgr_Cobalt*>(this);
// Lock the style sets mutex prior to calling |FindFamilyStyleCharacter|. It
// expects the mutex to already be locked.
SkAutoMutexAcquire scoped_mutex(style_sets_mutex_);
// Search the fallback families for ones matching the requested language.
// They are given priority over other fallback families in checking for
// character support.
for (int bcp47_index = bcp47_count; bcp47_index-- > 0;) {
SkLanguage language(bcp47[bcp47_index]);
while (!language.GetTag().isEmpty()) {
SkTypeface* matching_typeface = font_mgr->FindFamilyStyleCharacter(
style, language.GetTag(), character);
if (matching_typeface) {
return matching_typeface;
}
language = language.GetParent();
}
}
// Try to find character among all fallback families with no language
// requirement. This will select the first encountered family that contains
// the character.
SkTypeface* matching_typeface =
font_mgr->FindFamilyStyleCharacter(style, SkString(), character);
// If no family was found that supports the character, then just fall back
// to the default family.
return matching_typeface ? matching_typeface
: default_family_->MatchStyleWithoutLocking(style);
}
SkTypeface* SkFontMgr_Cobalt::onCreateFromData(SkData* data,
int face_index) const {
SkAutoTUnref<SkStreamAsset> stream(new SkMemoryStream(data));
return createFromStream(stream, face_index);
}
SkTypeface* SkFontMgr_Cobalt::onCreateFromStream(SkStreamAsset* stream,
int face_index) const {
TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::onCreateFromStream()");
bool is_fixed_pitch;
SkTypeface::Style style;
SkString name;
if (!SkTypeface_FreeType::ScanFont(stream, face_index, &name, &style,
&is_fixed_pitch)) {
return NULL;
}
return SkNEW_ARGS(SkTypeface_CobaltStream,
(stream, face_index, style, is_fixed_pitch, name));
}
SkTypeface* SkFontMgr_Cobalt::onCreateFromFile(const char path[],
int face_index) const {
TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::onCreateFromFile()");
SkAutoTUnref<SkStreamAsset> stream(SkStream::NewFromFile(path));
return stream.get() ? createFromStream(stream, face_index) : NULL;
}
SkTypeface* SkFontMgr_Cobalt::onLegacyCreateTypeface(
const char family_name[], unsigned style_bits) const {
SkTypeface::Style old_style = (SkTypeface::Style)style_bits;
SkFontStyle style = SkFontStyle(
old_style & SkTypeface::kBold ? SkFontStyle::kBold_Weight
: SkFontStyle::kNormal_Weight,
SkFontStyle::kNormal_Width,
old_style & SkTypeface::kItalic ? SkFontStyle::kItalic_Slant
: SkFontStyle::kUpright_Slant);
return matchFamilyStyle(family_name, style);
}
void SkFontMgr_Cobalt::BuildNameToFamilyMap(const char* base_path,
SkTDArray<FontFamily*>* families) {
TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::BuildNameToFamilyMap()");
for (int i = 0; i < families->count(); i++) {
FontFamily& family = *(*families)[i];
bool named_family = family.names.count() > 0;
if (family.is_fallback_family) {
if (!named_family) {
SkString& fallback_name = family.names.push_back();
fallback_name.printf("%.2x##fallback", i);
}
}
SkAutoTUnref<SkFontStyleSet_Cobalt> new_set(
SkNEW_ARGS(SkFontStyleSet_Cobalt,
(family, base_path, &system_typeface_stream_manager_,
&style_sets_mutex_)));
// Verify that the set successfully added entries.
if (new_set->styles_.count() == 0) {
continue;
}
font_style_sets_.push_back().reset(SkRef(new_set.get()));
if (named_family) {
for (int j = 0; j < family.names.count(); j++) {
family_names_.push_back(family.names[j]);
name_to_family_map_.insert(
std::make_pair(family.names[j].c_str(), new_set.get()));
}
}
if (family.is_fallback_family) {
fallback_families_.push_back(new_set.get());
}
for (SkAutoTUnref<SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt>*
font_style_set_entry = new_set->styles_.begin();
font_style_set_entry != new_set->styles_.end();
++font_style_set_entry) {
// On the first pass through, process the full font name.
// On the second pass through, process the font postscript name.
for (int i = 0; i <= 1; ++i) {
const std::string& font_face_name =
i == 0 ? (*font_style_set_entry)->full_font_name
: (*font_style_set_entry)->font_postscript_name;
// If there is no font face name for this style entry, then there's
// nothing to add. Simply skip past it.
if (font_face_name.empty()) {
continue;
}
NameToStyleSetMap& font_face_name_style_set_map =
i == 0 ? full_font_name_to_style_set_map_
: font_postscript_name_to_style_set_map_;
if (font_face_name_style_set_map.find(font_face_name) ==
font_face_name_style_set_map.end()) {
font_face_name_style_set_map[font_face_name] = new_set.get();
} else {
// Purposely, not overwriting the entry gives priority to the
// earlier entry. This is consistent with how fonts.xml gives
// priority to fonts that are specified earlier in the file.
const std::string font_face_name_type =
i == 0 ? "Full Font" : "Postscript";
NOTREACHED() << font_face_name_type << " name [" << font_face_name
<< "] already registered in BuildNameToFamilyMap.";
}
}
}
}
}
void SkFontMgr_Cobalt::FindDefaultFamily(
const SkTArray<SkString, true>& default_families) {
CHECK(!font_style_sets_.empty());
for (size_t i = 0; i < default_families.count(); ++i) {
SkAutoTUnref<SkFontStyleSet_Cobalt> check_style_set(
onMatchFamily(default_families[i].c_str()));
if (NULL == check_style_set) {
continue;
}
SkAutoTUnref<SkTypeface> check_typeface(
check_style_set->MatchStyleWithoutLocking(SkFontStyle()));
if (NULL != check_typeface) {
default_family_ = check_style_set.get();
break;
}
}
if (NULL == default_family_) {
SkAutoTUnref<SkTypeface> check_typeface(
font_style_sets_[0]->MatchStyleWithoutLocking(SkFontStyle()));
if (NULL != check_typeface) {
default_family_ = font_style_sets_[0].get();
}
}
CHECK(default_family_);
}
SkTypeface* SkFontMgr_Cobalt::FindFamilyStyleCharacter(
const SkFontStyle& style, const SkString& language_tag,
SkUnichar character) {
if (!font_character_map::IsCharacterValid(character)) {
return NULL;
}
StyleSetArray* fallback_families = GetMatchingFallbackFamilies(language_tag);
for (int i = 0; i < fallback_families->size(); ++i) {
SkFontStyleSet_Cobalt* family = (*fallback_families)[i];
if (family->ContainsCharacter(style, character)) {
SkTypeface* matching_typeface = family->MatchStyleWithoutLocking(style);
if (matching_typeface) {
return matching_typeface;
}
}
}
return NULL;
}
SkFontMgr_Cobalt::StyleSetArray* SkFontMgr_Cobalt::GetMatchingFallbackFamilies(
const SkString& language_tag) {
if (language_tag.isEmpty()) {
return &fallback_families_;
}
StyleSetArray*& language_fallback_families =
language_fallback_families_map_[language_tag.c_str()];
// The fallback families for a specific language tag are lazily populated. If
// this is the first time that this tag has been encountered, then create and
// populate the fallback families now.
if (language_fallback_families == NULL) {
language_fallback_families_array_.push_back(new StyleSetArray);
language_fallback_families = *language_fallback_families_array_.rbegin();
for (StyleSetArray::iterator iter = fallback_families_.begin();
iter != fallback_families_.end(); ++iter) {
SkFontStyleSet_Cobalt* fallback_family = *iter;
if (fallback_family->language_.GetTag().startsWith(
language_tag.c_str())) {
language_fallback_families->push_back(fallback_family);
}
}
}
return language_fallback_families;
}