blob: b1ad7cb0b3c47e552c7beb2cf0b003607ffed003 [file] [log] [blame]
// Copyright (c) 2012 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/common/font_config_ipc_linux.h"
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>
#include <functional>
#include <memory>
#include <utility>
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/memory/ref_counted.h"
#include "base/pickle.h"
#include "base/posix/unix_domain_socket.h"
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "skia/ext/skia_utils_base.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
namespace content {
std::size_t SkFontConfigInterfaceFontIdentityHash::operator()(
const SkFontConfigInterface::FontIdentity& sp) const {
std::hash<std::string> stringhash;
std::hash<int> inthash;
size_t r = inthash(sp.fID);
r = r * 41 + inthash(sp.fTTCIndex);
r = r * 41 + stringhash(sp.fString.c_str());
r = r * 41 + inthash(sp.fStyle.weight());
r = r * 41 + inthash(sp.fStyle.slant());
r = r * 41 + inthash(sp.fStyle.width());
return r;
}
// Wikpedia's main country selection page activates 21 fallback fonts,
// doubling this we should be on the generous side as an upper bound,
// but nevertheless not have the mapped typefaces cache grow excessively.
const size_t kMaxMappedTypefaces = 42;
void CloseFD(int fd) {
int err = IGNORE_EINTR(close(fd));
DCHECK(!err);
}
FontConfigIPC::FontConfigIPC(int fd)
: fd_(fd)
, mapped_typefaces_(kMaxMappedTypefaces) {
}
FontConfigIPC::~FontConfigIPC() {
CloseFD(fd_);
}
bool FontConfigIPC::matchFamilyName(const char familyName[],
SkFontStyle requestedStyle,
FontIdentity* outFontIdentity,
SkString* outFamilyName,
SkFontStyle* outStyle) {
TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::matchFamilyName");
size_t familyNameLen = familyName ? strlen(familyName) : 0;
if (familyNameLen > kMaxFontFamilyLength)
return false;
base::Pickle request;
request.WriteInt(METHOD_MATCH);
request.WriteData(familyName, familyNameLen);
skia::WriteSkFontStyle(&request, requestedStyle);
uint8_t reply_buf[2048];
const ssize_t r = base::UnixDomainSocket::SendRecvMsg(
fd_, reply_buf, sizeof(reply_buf), NULL, request);
if (r == -1)
return false;
base::Pickle reply(reinterpret_cast<char*>(reply_buf), r);
base::PickleIterator iter(reply);
bool result;
if (!iter.ReadBool(&result))
return false;
if (!result)
return false;
SkString reply_family;
FontIdentity reply_identity;
SkFontStyle reply_style;
if (!skia::ReadSkString(&iter, &reply_family) ||
!skia::ReadSkFontIdentity(&iter, &reply_identity) ||
!skia::ReadSkFontStyle(&iter, &reply_style)) {
return false;
}
if (outFontIdentity)
*outFontIdentity = reply_identity;
if (outFamilyName)
*outFamilyName = reply_family;
if (outStyle)
*outStyle = reply_style;
return true;
}
static void DestroyMemoryMappedFile(const void*, void* context) {
base::ThreadRestrictions::ScopedAllowIO allow_munmap;
delete static_cast<base::MemoryMappedFile*>(context);
}
SkMemoryStream* FontConfigIPC::mapFileDescriptorToStream(int fd) {
std::unique_ptr<base::MemoryMappedFile> mapped_font_file(
new base::MemoryMappedFile);
base::ThreadRestrictions::ScopedAllowIO allow_mmap;
mapped_font_file->Initialize(base::File(fd));
DCHECK(mapped_font_file->IsValid());
sk_sp<SkData> data =
SkData::MakeWithProc(mapped_font_file->data(), mapped_font_file->length(),
&DestroyMemoryMappedFile, mapped_font_file.get());
if (!data)
return nullptr;
ignore_result(mapped_font_file.release()); // Ownership transferred to SkDataB
return new SkMemoryStream(std::move(data));
}
SkStreamAsset* FontConfigIPC::openStream(const FontIdentity& identity) {
TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::openStream");
base::Pickle request;
request.WriteInt(METHOD_OPEN);
request.WriteUInt32(identity.fID);
int result_fd = -1;
uint8_t reply_buf[256];
const ssize_t r = base::UnixDomainSocket::SendRecvMsg(
fd_, reply_buf, sizeof(reply_buf), &result_fd, request);
if (r == -1)
return NULL;
base::Pickle reply(reinterpret_cast<char*>(reply_buf), r);
bool result;
base::PickleIterator iter(reply);
if (!iter.ReadBool(&result) || !result) {
if (result_fd)
CloseFD(result_fd);
return NULL;
}
return mapFileDescriptorToStream(result_fd);
}
sk_sp<SkTypeface> FontConfigIPC::makeTypeface(
const SkFontConfigInterface::FontIdentity& identity) {
base::AutoLock lock(lock_);
auto mapped_typefaces_it = mapped_typefaces_.Get(identity);
if (mapped_typefaces_it != mapped_typefaces_.end())
return mapped_typefaces_it->second;
SkStreamAsset* typeface_stream = openStream(identity);
if (!typeface_stream)
return nullptr;
sk_sp<SkTypeface> typeface_from_stream(
SkTypeface::MakeFromStream(typeface_stream, identity.fTTCIndex));
auto mapped_typefaces_insert_it =
mapped_typefaces_.Put(identity, std::move(typeface_from_stream));
return mapped_typefaces_insert_it->second;
}
} // namespace content