font_info/
vmo_stream.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
5#![cfg(target_os = "fuchsia")]
6
7use crate::sources::FTStreamProvider;
8use anyhow::Error;
9use freetype_ffi::{FT_Stream, FT_StreamRec};
10
11use libc::{c_uchar, c_ulong, c_void};
12use std::{cmp, ptr, slice};
13
14struct VmoStreamInternal {
15    vmo: zx::Vmo,
16    stream_rec: FT_StreamRec,
17}
18
19impl VmoStreamInternal {
20    /// Caller must ensure that the returned FT_Stream is not used after VmoStream is dropped.
21    unsafe fn ft_stream(&self) -> FT_Stream {
22        &self.stream_rec as FT_Stream
23    }
24
25    fn read(&mut self, offset: u64, read_buffer: &mut [u8]) -> u64 {
26        if read_buffer.len() == 0 || offset >= self.stream_rec.size as u64 {
27            return 0;
28        }
29        let read_size = cmp::min(read_buffer.len(), (self.stream_rec.size - offset) as usize);
30        match self.vmo.read(&mut read_buffer[..read_size], offset) {
31            Ok(_) => read_size as u64,
32            Err(err) => {
33                println!("Error when reading from font VMO: {:?}", err);
34                0
35            }
36        }
37    }
38
39    // Unsafe callback called by freetype to read from the stream.
40    unsafe extern "C" fn read_func(
41        stream: FT_Stream,
42        offset: c_ulong,
43        buffer: *mut c_uchar,
44        count: c_ulong,
45    ) -> c_ulong {
46        let wrapper = &mut *((*stream).descriptor as *mut VmoStreamInternal);
47        if buffer.is_null() || count == 0 {
48            return 0;
49        }
50        let buffer_slice = slice::from_raw_parts_mut(buffer as *mut u8, count as usize);
51        wrapper.read(offset as u64, buffer_slice) as c_ulong
52    }
53
54    extern "C" fn close_func(_stream: FT_Stream) {
55        // No-op. Stream will be closed when the VmoStream is dropped.
56    }
57}
58
59/// Implements FT_Stream for a VMO.
60pub(crate) struct VmoStream {
61    /// VmoStreamInternal needs to be boxed to ensure that it's not moved. This allows to set
62    /// `stream_rec.descriptor` to point to the containing `VmoStreamInternal` instance.
63    internal: Box<VmoStreamInternal>,
64}
65
66impl VmoStream {
67    pub fn new(vmo: zx::Vmo, vmo_size: usize) -> Result<VmoStream, Error> {
68        let mut internal = Box::new(VmoStreamInternal {
69            vmo,
70            stream_rec: FT_StreamRec {
71                base: ptr::null(),
72                size: vmo_size as c_ulong,
73                pos: 0,
74
75                descriptor: ptr::null_mut(),
76                pathname: ptr::null_mut(),
77                read: VmoStreamInternal::read_func,
78                close: VmoStreamInternal::close_func,
79
80                memory: ptr::null_mut(),
81                cursor: ptr::null_mut(),
82                limit: ptr::null_mut(),
83            },
84        });
85
86        internal.stream_rec.descriptor = &mut *internal as *mut VmoStreamInternal as *mut c_void;
87
88        Ok(VmoStream { internal })
89    }
90
91    /// Unsafe to call FreeType FFI.
92    /// Caller must ensure that the returned `FT_Stream` is not used after `VmoStream` is dropped.
93    pub unsafe fn ft_stream(&self) -> FT_Stream {
94        self.internal.ft_stream()
95    }
96}
97
98impl FTStreamProvider for VmoStream {
99    /// Unsafe to call FreeType FFI.
100    /// Caller must ensure that the returned `FT_Stream` is not used after `VmoStream` is dropped.
101    unsafe fn ft_stream(&self) -> FT_Stream {
102        VmoStream::ft_stream(self)
103    }
104}