font_info/
sources.rs

1// Copyright 2019 The Fuchsia 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
5use anyhow::Error;
6use freetype_ffi::{FT_Open_Args, FT_Stream, FT_OPEN_PATHNAME, FT_OPEN_STREAM};
7use std::ffi::CString;
8use std::{fmt, ptr};
9
10/// Describes the source of a font asset to be parsed.
11pub enum FontAssetSource {
12    /// Byte stream (e.g. from a VMO)
13    Stream(Box<dyn FTStreamProvider>),
14    /// Path to a local file
15    FilePath(String),
16}
17
18impl fmt::Debug for FontAssetSource {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            FontAssetSource::Stream(_) => write!(f, "FontAssetSource::Stream"),
22            FontAssetSource::FilePath(path) => write!(f, "FontAssetSource::FilePath(\"{}\")", path),
23        }
24    }
25}
26
27/// This struct ensures that the lifetime of `FT_Open_Args` and the resources it depends on is
28/// handled correctly.
29pub struct FTOpenArgs {
30    // All suppressed "dead code" below is used to ensure the lifetime of native_open_args is in
31    // sync with FontAssetSource it is based on.
32
33    // This is the asset source based on which the args are generated. If the asset source is a
34    // stream, this retains the stream provider.
35    #[allow(dead_code)]
36    pub(crate) source: FontAssetSource,
37    // Holds a reference to the C-style string from FontAssetSource, in case it is a string-based
38    // source.
39    #[allow(dead_code)]
40    pathname: Option<CString>,
41    // The FFI type that was obtained based on the asset source.  Access it through the AsRef
42    // trait implementation.
43    native_open_args: FT_Open_Args,
44}
45
46/// Allows viewing `FTOpenArgs` as a FFI type.
47impl AsRef<FT_Open_Args> for FTOpenArgs {
48    /// Views `FTOpenArgs` (a Rust type) as a FFI type `FT_Open_Args` for interfacing with low level
49    /// FFI libraries.
50    fn as_ref(&self) -> &FT_Open_Args {
51        &self.native_open_args
52    }
53}
54
55/// Converts a `FontAssetSource` to a wrapper around `FT_Open_Args`, which is required for reading a
56/// font with FreeType.
57impl TryFrom<FontAssetSource> for FTOpenArgs {
58    type Error = Error;
59
60    fn try_from(source: FontAssetSource) -> Result<Self, Error> {
61        let mut pathname: Option<CString> = None;
62        let native_open_args = match source {
63            FontAssetSource::Stream(ref provider) => {
64                FT_Open_Args {
65                    flags: FT_OPEN_STREAM,
66                    memory_base: ptr::null(),
67                    memory_size: 0,
68                    pathname: ptr::null(),
69                    // Unsafe to call FreeType FFI.
70                    // Caller must ensure that the returned `FT_Open_Args` is not used after the
71                    // `FontAssetSource` is dropped.
72                    stream: unsafe { provider.ft_stream() },
73                    driver: ptr::null_mut(),
74                    num_params: 0,
75                    params: ptr::null_mut(),
76                }
77            }
78            FontAssetSource::FilePath(ref path) => {
79                pathname = Some(CString::new(&path[..])?);
80                FT_Open_Args {
81                    flags: FT_OPEN_PATHNAME,
82                    memory_base: ptr::null(),
83                    memory_size: 0,
84                    // This won't ever be `None`, since we're assigning to `pathname` just above.
85                    pathname: pathname.as_ref().unwrap().as_ptr(),
86                    stream: ptr::null_mut(),
87                    driver: ptr::null_mut(),
88                    num_params: 0,
89                    params: ptr::null_mut(),
90                }
91            }
92        };
93        Ok(FTOpenArgs { source, pathname, native_open_args })
94    }
95}
96
97/// Provides a [FreeType stream](freetype_ffi::FTStream) for reading files.
98pub trait FTStreamProvider {
99    /// Unsafe to call FreeType FFI.
100    /// Caller must ensure that the returned [FT_Stream] is not used after `self` is dropped.
101    unsafe fn ft_stream(&self) -> FT_Stream;
102}
103
104/// Converts a [`fidl_fuchsia_mem::Buffer`] into a `FontAssetSource` by opening a stream from the
105/// VMO represented by the buffer.
106#[cfg(target_os = "fuchsia")]
107impl TryFrom<fidl_fuchsia_mem::Buffer> for FontAssetSource {
108    type Error = Error;
109
110    fn try_from(buffer: fidl_fuchsia_mem::Buffer) -> Result<FontAssetSource, Error> {
111        use crate::vmo_stream::VmoStream;
112        Ok(FontAssetSource::Stream(Box::new(VmoStream::new(buffer.vmo, buffer.size as usize)?)))
113    }
114}