blob: 534bdf69da5871baacd9fae4788cadb279503e95 [file] [log] [blame]
// Copyright 2020 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 "content/browser/font_access/font_enumeration_cache_mac.h"
#import <AppKit/AppKit.h>
#import <CoreText/CoreText.h>
#include "base/feature_list.h"
#include "base/mac/foundation_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/strings/sys_string_conversions.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "third_party/blink/public/common/features.h"
namespace content {
namespace {
base::ScopedCFTypeRef<CFStringRef> GetLocalizedString(CTFontDescriptorRef fd,
CFStringRef attribute) {
return base::ScopedCFTypeRef<CFStringRef>(base::mac::CFCast<CFStringRef>(
CTFontDescriptorCopyLocalizedAttribute(fd, attribute, nullptr)));
}
base::ScopedCFTypeRef<CFStringRef> GetString(CTFontDescriptorRef fd,
CFStringRef attribute) {
return base::ScopedCFTypeRef<CFStringRef>(base::mac::CFCast<CFStringRef>(
CTFontDescriptorCopyAttribute(fd, attribute)));
}
} // namespace
FontEnumerationCacheMac::FontEnumerationCacheMac() = default;
FontEnumerationCacheMac::~FontEnumerationCacheMac() = default;
// static
FontEnumerationCache* FontEnumerationCache::GetInstance() {
static base::NoDestructor<FontEnumerationCacheMac> instance;
return instance.get();
}
void FontEnumerationCacheMac::SchedulePrepareFontEnumerationCache() {
DCHECK(base::FeatureList::IsEnabled(blink::features::kFontAccess));
scoped_refptr<base::SequencedTaskRunner> results_task_runner =
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::BEST_EFFORT});
results_task_runner->PostTask(
FROM_HERE,
base::BindOnce(&FontEnumerationCacheMac::PrepareFontEnumerationCache,
// Safe because this is an initialized singleton.
base::Unretained(this)));
}
void FontEnumerationCacheMac::PrepareFontEnumerationCache() {
DCHECK(!enumeration_cache_built_->IsSet());
@autoreleasepool {
// Metrics.
const base::ElapsedTimer start_timer;
auto font_enumeration_table =
std::make_unique<blink::FontEnumerationTable>();
CFTypeRef values[1] = {kCFBooleanTrue};
base::ScopedCFTypeRef<CFDictionaryRef> options(CFDictionaryCreate(
kCFAllocatorDefault,
(const void**)kCTFontCollectionRemoveDuplicatesOption,
(const void**)&values,
/*numValues=*/1, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
base::ScopedCFTypeRef<CTFontCollectionRef> collection(
CTFontCollectionCreateFromAvailableFonts(options));
base::ScopedCFTypeRef<CFArrayRef> font_descs(
CTFontCollectionCreateMatchingFontDescriptors(collection));
// Used to filter duplicates.
std::set<std::string> fonts_seen;
int duplicate_count = 0;
for (CFIndex i = 0; i < CFArrayGetCount(font_descs); ++i) {
CTFontDescriptorRef fd = base::mac::CFCast<CTFontDescriptorRef>(
CFArrayGetValueAtIndex(font_descs, i));
base::ScopedCFTypeRef<CFStringRef> cf_postscript_name =
GetString(fd, kCTFontNameAttribute);
base::ScopedCFTypeRef<CFStringRef> cf_full_name =
GetLocalizedString(fd, kCTFontDisplayNameAttribute);
base::ScopedCFTypeRef<CFStringRef> cf_family =
GetString(fd, kCTFontFamilyNameAttribute);
base::ScopedCFTypeRef<CFStringRef> cf_style =
GetString(fd, kCTFontStyleNameAttribute);
std::string postscript_name =
base::SysCFStringRefToUTF8(cf_postscript_name.get());
if (fonts_seen.count(postscript_name) != 0) {
++duplicate_count;
// Skip duplicates.
continue;
}
fonts_seen.insert(postscript_name);
blink::FontEnumerationTable_FontMetadata metadata;
metadata.set_postscript_name(postscript_name.c_str());
metadata.set_full_name(
base::SysCFStringRefToUTF8(cf_full_name.get()).c_str());
metadata.set_family(base::SysCFStringRefToUTF8(cf_family.get()).c_str());
metadata.set_style(base::SysCFStringRefToUTF8(cf_style.get()).c_str());
blink::FontEnumerationTable_FontMetadata* added_font_meta =
font_enumeration_table->add_fonts();
*added_font_meta = metadata;
}
BuildEnumerationCache(std::move(font_enumeration_table));
base::UmaHistogramCounts100(
"Fonts.AccessAPI.EnumerationCache.DuplicateFontCount", duplicate_count);
base::UmaHistogramMediumTimes("Fonts.AccessAPI.EnumerationTime",
start_timer.Elapsed());
// Respond to pending and future requests.
StartCallbacksTaskQueue();
}
}
} // namespace content