blob: 0f8bc78cfdea6d74638d56f20a218d125e9b39a9 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/services/font/fontconfig_matching.h"
#include <fontconfig/fontconfig.h>
#include "base/files/file.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_util.h"
#include <memory>
namespace font_service {
base::Optional<FontConfigLocalMatching::FontConfigMatchResult>
FontConfigLocalMatching::FindFontByPostscriptNameOrFullFontName(
const std::string& font_name) {
// TODO(crbug.com/876652): This FontConfig-backed implementation will
// match PostScript and full font name in any language, and we're okay
// with that for now since it is what FireFox does.
base::Optional<FontConfigLocalMatching::FontConfigMatchResult>
postscript_result =
FindFontBySpecifiedName(FC_POSTSCRIPT_NAME, font_name);
if (postscript_result)
return postscript_result;
return FindFontBySpecifiedName(FC_FULLNAME, font_name);
}
base::Optional<FontConfigLocalMatching::FontConfigMatchResult>
FontConfigLocalMatching::FindFontBySpecifiedName(
const char* fontconfig_parameter_name,
const std::string& font_name) {
DCHECK(std::string(fontconfig_parameter_name) == std::string(FC_FULLNAME) ||
std::string(fontconfig_parameter_name) ==
std::string(FC_POSTSCRIPT_NAME));
if (!base::IsStringUTF8(font_name))
return base::nullopt;
std::unique_ptr<FcPattern, void (*)(FcPattern*)> pattern(FcPatternCreate(),
FcPatternDestroy);
const FcChar8* fc_font_name =
reinterpret_cast<const FcChar8*>(font_name.c_str());
// TODO(crbug.com/876652): We do not restrict the language that we match
// FC_POSTSCRIPT_NAME or FC_FULLNAME against. Pending spec clarification, see
// bug.
FcPatternAddString(pattern.get(), fontconfig_parameter_name, fc_font_name);
FcPatternAddBool(pattern.get(), FC_SCALABLE, true);
std::unique_ptr<FcObjectSet, void (*)(FcObjectSet*)> object_set(
FcObjectSetCreate(), FcObjectSetDestroy);
FcObjectSetAdd(object_set.get(), "file");
FcObjectSetAdd(object_set.get(), "index");
std::unique_ptr<FcFontSet, void (*)(FcFontSet*)> font_set(
FcFontList(nullptr, pattern.get(), object_set.get()), FcFontSetDestroy);
if (!font_set || !font_set->nfont)
return base::nullopt;
FcPattern* current = font_set->fonts[0];
FcChar8* c_filename;
if (FcPatternGetString(current, FC_FILE, 0, &c_filename) != FcResultMatch)
return base::nullopt;
// We only want to return sfnt (TrueType) based fonts. We don't have a
// very good way of detecting this so we'll filter based on the
// filename.
bool is_sfnt = false;
static const char kSFNTExtensions[][5] = {".ttf", ".otc", ".TTF", ".ttc", ""};
for (size_t j = 0;; j++) {
if (kSFNTExtensions[j][0] == 0) {
// None of the extensions matched.
break;
}
if (base::EndsWith(std::string(reinterpret_cast<char*>(c_filename)),
kSFNTExtensions[j], base::CompareCase::SENSITIVE)) {
is_sfnt = true;
break;
}
}
if (!is_sfnt)
return base::nullopt;
base::FilePath font_file_path(reinterpret_cast<const char*>(c_filename));
base::File verify_file_exists(font_file_path,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!verify_file_exists.IsValid())
return base::nullopt;
int ttc_index = 0;
FcPatternGetInteger(current, FC_INDEX, 0, &ttc_index);
if (ttc_index < 0)
return base::nullopt;
FontConfigMatchResult match_result;
match_result.file_path = font_file_path;
match_result.ttc_index = ttc_index;
return match_result;
}
} // namespace font_service