font_info/
vmo_stream.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![cfg(target_os = "fuchsia")]

use crate::sources::FTStreamProvider;
use anyhow::Error;
use freetype_ffi::{FT_Stream, FT_StreamRec};

use libc::{c_uchar, c_ulong, c_void};
use std::{cmp, ptr, slice};

struct VmoStreamInternal {
    vmo: zx::Vmo,
    stream_rec: FT_StreamRec,
}

impl VmoStreamInternal {
    /// Caller must ensure that the returned FT_Stream is not used after VmoStream is dropped.
    unsafe fn ft_stream(&self) -> FT_Stream {
        &self.stream_rec as FT_Stream
    }

    fn read(&mut self, offset: u64, read_buffer: &mut [u8]) -> u64 {
        if read_buffer.len() == 0 || offset >= self.stream_rec.size as u64 {
            return 0;
        }
        let read_size = cmp::min(read_buffer.len(), (self.stream_rec.size - offset) as usize);
        match self.vmo.read(&mut read_buffer[..read_size], offset) {
            Ok(_) => read_size as u64,
            Err(err) => {
                println!("Error when reading from font VMO: {:?}", err);
                0
            }
        }
    }

    // Unsafe callback called by freetype to read from the stream.
    unsafe extern "C" fn read_func(
        stream: FT_Stream,
        offset: c_ulong,
        buffer: *mut c_uchar,
        count: c_ulong,
    ) -> c_ulong {
        let wrapper = &mut *((*stream).descriptor as *mut VmoStreamInternal);
        if buffer.is_null() || count == 0 {
            return 0;
        }
        let buffer_slice = slice::from_raw_parts_mut(buffer as *mut u8, count as usize);
        wrapper.read(offset as u64, buffer_slice) as c_ulong
    }

    extern "C" fn close_func(_stream: FT_Stream) {
        // No-op. Stream will be closed when the VmoStream is dropped.
    }
}

/// Implements FT_Stream for a VMO.
pub(crate) struct VmoStream {
    /// VmoStreamInternal needs to be boxed to ensure that it's not moved. This allows to set
    /// `stream_rec.descriptor` to point to the containing `VmoStreamInternal` instance.
    internal: Box<VmoStreamInternal>,
}

impl VmoStream {
    pub fn new(vmo: zx::Vmo, vmo_size: usize) -> Result<VmoStream, Error> {
        let mut internal = Box::new(VmoStreamInternal {
            vmo,
            stream_rec: FT_StreamRec {
                base: ptr::null(),
                size: vmo_size as c_ulong,
                pos: 0,

                descriptor: ptr::null_mut(),
                pathname: ptr::null_mut(),
                read: VmoStreamInternal::read_func,
                close: VmoStreamInternal::close_func,

                memory: ptr::null_mut(),
                cursor: ptr::null_mut(),
                limit: ptr::null_mut(),
            },
        });

        internal.stream_rec.descriptor = &mut *internal as *mut VmoStreamInternal as *mut c_void;

        Ok(VmoStream { internal })
    }

    /// Unsafe to call FreeType FFI.
    /// Caller must ensure that the returned `FT_Stream` is not used after `VmoStream` is dropped.
    pub unsafe fn ft_stream(&self) -> FT_Stream {
        self.internal.ft_stream()
    }
}

impl FTStreamProvider for VmoStream {
    /// Unsafe to call FreeType FFI.
    /// Caller must ensure that the returned `FT_Stream` is not used after `VmoStream` is dropped.
    unsafe fn ft_stream(&self) -> FT_Stream {
        VmoStream::ft_stream(self)
    }
}