blob: 15ac87d6837d0cbb2e7791de1f9c7ff85c08f2dd [file] [log] [blame]
// Copyright 2018 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.
#![feature(async_await, await_macro, futures_api)]
use failure::{format_err, Error, ResultExt};
use fidl_fuchsia_fonts as fonts;
use fuchsia_app::client::{App, LaunchOptions, Launcher};
use fuchsia_async::Executor;
use fuchsia_zircon as zx;
use fuchsia_zircon::AsHandleRef;
#[derive(Debug, Eq, PartialEq)]
struct FontInfo {
vmo_koid: zx::Koid,
buffer_id: u32,
size: u64,
index: u32,
}
async fn get_font_info(
font_provider: &fonts::ProviderProxy, name: Option<String>, language: Option<Vec<String>>,
character: char,
) -> Result<FontInfo, Error> {
let font = await!(font_provider.get_font(&mut fonts::Request {
family: name.clone(),
weight: 400,
width: 5,
slant: fonts::Slant::Upright,
character: character as u32,
language: language,
fallback_group: fonts::FallbackGroup::None,
flags: 0,
}))?;
let font = *font.ok_or_else(|| format_err!("Received empty response for {:?}", name))?;
assert!(font.buffer.size > 0);
assert!(font.buffer.size <= font.buffer.vmo.get_size()?);
let vmo_koid = font.buffer.vmo.as_handle_ref().get_koid()?;
Ok(FontInfo {
vmo_koid,
buffer_id: font.buffer_id,
size: font.buffer.size,
index: font.font_index,
})
}
async fn get_font_info_basic(
font_provider: &fonts::ProviderProxy, name: Option<String>,
) -> Result<FontInfo, Error> {
await!(get_font_info(font_provider, name, None, '\0'))
}
fn start_provider_with_default_fonts() -> Result<(App, fonts::ProviderProxy), Error> {
let launcher = Launcher::new().context("Failed to open launcher service")?;
let app = launcher
.launch("fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx".to_string(), None)
.context("Failed to launch fonts::Provider")?;
let font_provider = app
.connect_to_service(fonts::ProviderMarker)
.context("Failed to connect to fonts::Provider")?;
Ok((app, font_provider))
}
async fn test_basic() -> Result<(), Error> {
let (_app, font_provider) = start_provider_with_default_fonts()?;
let default =
await!(get_font_info_basic(&font_provider, None)).context("Failed to load default font")?;
let roboto = await!(get_font_info_basic(
&font_provider,
Some("Roboto".to_string())
))
.context("Failed to load Roboto")?;
let roboto_slab = await!(get_font_info_basic(
&font_provider,
Some("Roboto Slab".to_string())
))
.context("Failed to load Roboto Slab")?;
// Roboto should be returned by default.
assert!(default == roboto);
// Roboto Slab request should return a different font.
assert!(default.vmo_koid != roboto_slab.vmo_koid);
assert!(default.buffer_id != roboto_slab.buffer_id);
Ok(())
}
async fn test_aliases() -> Result<(), Error> {
let (_app, font_provider) = start_provider_with_default_fonts()?;
// Both requests should return the same font.
let robotoslab = await!(get_font_info_basic(
&font_provider,
Some("RobotoSlab".to_string())
))
.context("Failed to load RobotoSlab")?;
let roboto_slab = await!(get_font_info_basic(
&font_provider,
Some("Roboto Slab".to_string())
))
.context("Failed to load Roboto Slab")?;
assert!(robotoslab == roboto_slab);
Ok(())
}
fn start_provider_with_test_fonts() -> Result<(App, fonts::ProviderProxy), Error> {
let mut launch_options = LaunchOptions::new();
launch_options.add_dir_to_namespace(
"/test_fonts".to_string(),
std::fs::File::open("/system/data/testdata/test_fonts")?,
)?;
let launcher = Launcher::new().context("Failed to open launcher service")?;
let app = launcher
.launch_with_options(
"fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx".to_string(),
Some(vec![
"--font-manifest".to_string(),
"/test_fonts/manifest.json".to_string(),
]),
launch_options,
)
.context("Failed to launch fonts::Provider")?;
let font_provider = app
.connect_to_service(fonts::ProviderMarker)
.context("Failed to connect to fonts::Provider")?;
Ok((app, font_provider))
}
async fn test_font_collections() -> Result<(), Error> {
let (_app, font_provider) = start_provider_with_test_fonts()?;
// Request Japanese and Simplified Chinese versions of Noto Sans CJK. Both
// fonts are part of the same TTC file, so font provider is expected to
// return the same buffer with different font index values.
let noto_sans_cjk_ja = await!(get_font_info(
&font_provider,
Some("NotoSansCJK".to_string()),
Some(vec!["ja".to_string()]),
'\0'
))
.context("Failed to load NotoSansCJK font")?;
let noto_sans_cjk_sc = await!(get_font_info(
&font_provider,
Some("NotoSansCJK".to_string()),
Some(vec!["zh-Hans".to_string()]),
'\0'
))
.context("Failed to load NotoSansCJK font")?;
assert!(noto_sans_cjk_ja.vmo_koid == noto_sans_cjk_sc.vmo_koid);
assert!(noto_sans_cjk_ja.index != noto_sans_cjk_sc.index);
Ok(())
}
async fn test_fallback() -> Result<(), Error> {
let (_app, font_provider) = start_provider_with_test_fonts()?;
let noto_sans_cjk_ja = await!(get_font_info(
&font_provider,
Some("NotoSansCJK".to_string()),
Some(vec!["ja".to_string()]),
'\0'
))
.context("Failed to load NotoSansCJK font")?;
let noto_sans_cjk_ja_by_char = await!(get_font_info(
&font_provider,
Some("Roboto".to_string()),
Some(vec!["ja".to_string()]),
'な'
))
.context("Failed to load NotoSansCJK font")?;
// Same font should be returned in both cases.
assert!(noto_sans_cjk_ja == noto_sans_cjk_ja_by_char);
Ok(())
}
// Verify that the fallback group of the requested font is taken into account for fallback.
async fn test_fallback_group() -> Result<(), Error> {
let (_app, font_provider) = start_provider_with_test_fonts()?;
let noto_serif_cjk_ja = await!(get_font_info(
&font_provider,
Some("Noto Serif CJK".to_string()),
Some(vec!["ja".to_string()]),
'\0'
))
.context("Failed to load Noto Serif CJK font")?;
let noto_serif_cjk_ja_by_char = await!(get_font_info(
&font_provider,
Some("Roboto Slab".to_string()),
Some(vec!["ja".to_string()]),
'な'
))
.context("Failed to load Noto Serif CJK font")?;
// The query above requested Roboto Slab, so it's expected to return
// Noto Serif CJK instead of Noto Sans CJK because Roboto Slab and
// Noto Serif CJK are both in serif fallback group.
assert!(noto_serif_cjk_ja == noto_serif_cjk_ja_by_char);
Ok(())
}
async fn test_get_family_info() -> Result<(), Error> {
let (_app, font_provider) = start_provider_with_default_fonts()?;
let family_info = await!(font_provider.get_family_info("robotoslab"))?;
assert!(family_info.is_some());
let family_info = family_info.unwrap();
assert!(family_info.name == "Roboto Slab");
assert!(family_info.styles.len() > 0);
Ok(())
}
async fn run_tests() -> Result<(), Error> {
await!(test_basic())?;
await!(test_aliases())?;
await!(test_font_collections())?;
await!(test_fallback())?;
await!(test_fallback_group())?;
await!(test_get_family_info())?;
Ok(())
}
fn main() -> Result<(), Error> {
let mut executor = Executor::new().context("Error creating executor")?;
executor.run_singlethreaded(run_tests())
}