blob: 4c1473715e383a8235159864ca6136ee776f1157 [file] [log] [blame]
// Copyright 2015 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/font_service/public/cpp/font_service_thread.h"
#include <utility>
#include "base/bind.h"
#include "base/files/file.h"
#include "base/synchronization/waitable_event.h"
#include "components/font_service/public/cpp/mapped_font_file.h"
namespace font_service {
namespace internal {
namespace {
const char kFontThreadName[] = "Font_Proxy_Thread";
} // namespace
FontServiceThread::FontServiceThread(mojom::FontServicePtr font_service)
: base::Thread(kFontThreadName),
font_service_info_(font_service.PassInterface()),
weak_factory_(this) {
Start();
}
bool FontServiceThread::MatchFamilyName(
const char family_name[],
SkFontStyle requested_style,
SkFontConfigInterface::FontIdentity* out_font_identity,
SkString* out_family_name,
SkFontStyle* out_style) {
DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
bool out_valid = false;
// This proxies to the other thread, which proxies to mojo. Only on the reply
// from mojo do we return from this.
base::WaitableEvent done_event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
task_runner()->PostTask(
FROM_HERE,
base::Bind(&FontServiceThread::MatchFamilyNameImpl, this, &done_event,
family_name, requested_style, &out_valid, out_font_identity,
out_family_name, out_style));
done_event.Wait();
return out_valid;
}
scoped_refptr<MappedFontFile> FontServiceThread::OpenStream(
const SkFontConfigInterface::FontIdentity& identity) {
DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
base::File stream_file;
// This proxies to the other thread, which proxies to mojo. Only on the reply
// from mojo do we return from this.
base::WaitableEvent done_event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
task_runner()->PostTask(FROM_HERE,
base::Bind(&FontServiceThread::OpenStreamImpl, this,
&done_event, &stream_file, identity.fID));
done_event.Wait();
if (!stream_file.IsValid()) {
// The font-service may have been killed.
return nullptr;
}
// Converts the file to out internal type.
scoped_refptr<MappedFontFile> mapped_font_file =
new MappedFontFile(identity.fID);
if (!mapped_font_file->Initialize(std::move(stream_file)))
return nullptr;
return mapped_font_file;
}
FontServiceThread::~FontServiceThread() {
Stop();
}
void FontServiceThread::MatchFamilyNameImpl(
base::WaitableEvent* done_event,
const char family_name[],
SkFontStyle requested_style,
bool* out_valid,
SkFontConfigInterface::FontIdentity* out_font_identity,
SkString* out_family_name,
SkFontStyle* out_style) {
DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId());
if (font_service_.encountered_error()) {
*out_valid = false;
done_event->Signal();
return;
}
mojom::TypefaceStylePtr style(mojom::TypefaceStyle::New());
style->weight = requested_style.weight();
style->width = requested_style.width();
style->slant = static_cast<mojom::TypefaceSlant>(requested_style.slant());
pending_waitable_events_.insert(done_event);
font_service_->MatchFamilyName(
family_name, std::move(style),
base::Bind(&FontServiceThread::OnMatchFamilyNameComplete, this,
done_event, out_valid, out_font_identity, out_family_name,
out_style));
}
void FontServiceThread::OnMatchFamilyNameComplete(
base::WaitableEvent* done_event,
bool* out_valid,
SkFontConfigInterface::FontIdentity* out_font_identity,
SkString* out_family_name,
SkFontStyle* out_style,
mojom::FontIdentityPtr font_identity,
const std::string& family_name,
mojom::TypefaceStylePtr style) {
DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId());
pending_waitable_events_.erase(done_event);
*out_valid = !font_identity.is_null();
if (font_identity) {
out_font_identity->fID = font_identity->id;
out_font_identity->fTTCIndex = font_identity->ttc_index;
out_font_identity->fString = font_identity->str_representation.data();
// TODO(erg): fStyle isn't set. This is rather odd, however it matches the
// behaviour of the current Linux IPC version.
*out_family_name = family_name.data();
*out_style = SkFontStyle(style->weight,
style->width,
static_cast<SkFontStyle::Slant>(style->slant));
}
done_event->Signal();
}
void FontServiceThread::OpenStreamImpl(base::WaitableEvent* done_event,
base::File* output_file,
const uint32_t id_number) {
DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId());
if (font_service_.encountered_error()) {
done_event->Signal();
return;
}
pending_waitable_events_.insert(done_event);
font_service_->OpenStream(
id_number, base::Bind(&FontServiceThread::OnOpenStreamComplete, this,
done_event, output_file));
}
void FontServiceThread::OnOpenStreamComplete(base::WaitableEvent* done_event,
base::File* output_file,
base::File file) {
pending_waitable_events_.erase(done_event);
*output_file = std::move(file);
done_event->Signal();
}
void FontServiceThread::OnFontServiceConnectionError() {
std::set<base::WaitableEvent*> events;
events.swap(pending_waitable_events_);
for (base::WaitableEvent* event : events)
event->Signal();
}
void FontServiceThread::Init() {
font_service_.Bind(std::move(font_service_info_));
font_service_.set_connection_error_handler(
base::Bind(&FontServiceThread::OnFontServiceConnectionError,
weak_factory_.GetWeakPtr()));
}
void FontServiceThread::CleanUp() {
font_service_.reset();
}
} // namespace internal
} // namespace font_service