1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/common/font_config_ipc_linux.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#include <sys/mman.h>
10#include <sys/socket.h>
11#include <sys/stat.h>
12#include <sys/uio.h>
13#include <unistd.h>
14
15#include "base/debug/trace_event.h"
16#include "base/file_util.h"
17#include "base/pickle.h"
18#include "base/posix/unix_domain_socket_linux.h"
19#include "skia/ext/refptr.h"
20#include "skia/ext/skia_utils_base.h"
21#include "third_party/skia/include/core/SkData.h"
22#include "third_party/skia/include/core/SkStream.h"
23
24namespace content {
25
26// Return a stream from the file descriptor, or NULL on failure.
27SkStream* StreamFromFD(int fd) {
28  skia::RefPtr<SkData> data = skia::AdoptRef(SkData::NewFromFD(fd));
29  if (!data) {
30    return NULL;
31  }
32  return new SkMemoryStream(data.get());
33}
34
35void CloseFD(int fd) {
36  int err = IGNORE_EINTR(close(fd));
37  DCHECK(!err);
38}
39
40FontConfigIPC::FontConfigIPC(int fd)
41    : fd_(fd) {
42}
43
44FontConfigIPC::~FontConfigIPC() {
45  CloseFD(fd_);
46}
47
48bool FontConfigIPC::matchFamilyName(const char familyName[],
49                                    SkTypeface::Style requestedStyle,
50                                    FontIdentity* outFontIdentity,
51                                    SkString* outFamilyName,
52                                    SkTypeface::Style* outStyle) {
53  TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::matchFamilyName");
54  size_t familyNameLen = familyName ? strlen(familyName) : 0;
55  if (familyNameLen > kMaxFontFamilyLength)
56    return false;
57
58  Pickle request;
59  request.WriteInt(METHOD_MATCH);
60  request.WriteData(familyName, familyNameLen);
61  request.WriteUInt32(requestedStyle);
62
63  uint8_t reply_buf[2048];
64  const ssize_t r = UnixDomainSocket::SendRecvMsg(fd_, reply_buf,
65                                                  sizeof(reply_buf), NULL,
66                                                  request);
67  if (r == -1)
68    return false;
69
70  Pickle reply(reinterpret_cast<char*>(reply_buf), r);
71  PickleIterator iter(reply);
72  bool result;
73  if (!reply.ReadBool(&iter, &result))
74    return false;
75  if (!result)
76    return false;
77
78  SkString     reply_family;
79  FontIdentity reply_identity;
80  uint32_t     reply_style;
81  if (!skia::ReadSkString(reply, &iter, &reply_family) ||
82      !skia::ReadSkFontIdentity(reply, &iter, &reply_identity) ||
83      !reply.ReadUInt32(&iter, &reply_style)) {
84    return false;
85  }
86
87  if (outFontIdentity)
88    *outFontIdentity = reply_identity;
89  if (outFamilyName)
90    *outFamilyName = reply_family;
91  if (outStyle)
92    *outStyle = static_cast<SkTypeface::Style>(reply_style);
93
94  return true;
95}
96
97SkStream* FontConfigIPC::openStream(const FontIdentity& identity) {
98  TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::openStream");
99  Pickle request;
100  request.WriteInt(METHOD_OPEN);
101  request.WriteUInt32(identity.fID);
102
103  int result_fd = -1;
104  uint8_t reply_buf[256];
105  const ssize_t r = UnixDomainSocket::SendRecvMsg(fd_, reply_buf,
106                                                  sizeof(reply_buf),
107                                                  &result_fd, request);
108
109  if (r == -1)
110    return NULL;
111
112  Pickle reply(reinterpret_cast<char*>(reply_buf), r);
113  bool result;
114  PickleIterator iter(reply);
115  if (!reply.ReadBool(&iter, &result) ||
116      !result) {
117    if (result_fd)
118      CloseFD(result_fd);
119    return NULL;
120  }
121
122  SkStream* stream = StreamFromFD(result_fd);
123  CloseFD(result_fd);
124  return stream;
125}
126
127}  // namespace content
128
129