Initial commit.

This commit is contained in:
Evgeniy Reizner 2020-07-04 12:39:48 +03:00
commit 1aec64f5f7
604 changed files with 117597 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/target
Cargo.lock
.directory
.idea
*.iml

11
.travis.yml Normal file
View File

@ -0,0 +1,11 @@
dist: bionic
language: rust
rust:
- stable
- nightly
script:
- if [ $TRAVIS_RUST_VERSION == "nightly" ]; then
env RUSTFLAGS="-Z sanitizer=address" cargo +nightly test --target x86_64-unknown-linux-gnu;
else
cargo test;
fi

25
CHANGELOG.md Normal file
View File

@ -0,0 +1,25 @@
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
At this point, this is just a simple Rust bindings to a stripped down harfbuzz.
### Added
- An absolute minimum Rust API.
- harfbuzz's shaping test suite had been ported to Rust.
### Changed
- harfbuzz source code was reformatted using clang-format.
### Removed
- Subsetting. This is probably a bit controversial, but I want to port only the shaper for now.
This is also removes around 7000 LOC.
- Arabic fallback shaper. Since it requires subsetting.
- Unused TrueType tables: BASE, COLR, CPAL, JSTF, MATH, STAT, bsln, fdsc, gasp, just, lcar, ltag, meta, name, opbd.
- All external dependencies: coretext, directwrite, freetype, gdi, glib, gobject, graphite, icu, uniscribe.
Embedded harfbuzz relies only on internal TrueType implementation.
- Most of the non-shaping harfbuzz API.

22
Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
name = "rustybuzz"
version = "0.1.0"
authors = ["Evgeniy Reizner <razrfalcon@gmail.com>"]
edition = "2018"
description = "An incremental harfbuzz port to Rust."
documentation = "https://docs.rs/rustybuzz/"
readme = "README.md"
repository = "https://github.com/RazrFalcon/rustybuzz"
license = "MIT"
keywords = ["text", "shaping", "opentype", "truetype"]
categories = ["text-processing"]
[dependencies]
bitflags = "1.2"
[dev-dependencies]
pico-args = "0.3"
libc = "0.2"
[build-dependencies]
cc = { version = "1.0", features = ["parallel"] }

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) HarfBuzz developers
Copyright (c) 2020 Evgeniy Reizner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

36
README.md Normal file
View File

@ -0,0 +1,36 @@
# rustybuzz
[![Build Status](https://travis-ci.org/RazrFalcon/rustybuzz.svg?branch=master)](https://travis-ci.org/RazrFalcon/rustybuzz)
[![Crates.io](https://img.shields.io/crates/v/rustybuzz.svg)](https://crates.io/crates/rustybuzz)
[![Documentation](https://docs.rs/rustybuzz/badge.svg)](https://docs.rs/rustybuzz)
`rustybuzz` is an attempt to incrementally port [harfbuzz](https://github.com/harfbuzz/harfbuzz)'s
shaping algorithm to Rust.
But while `harfbuzz` does a lot of things (shaping, subsetting, font properties querying, etc.),
`rustybuzz` is *strictly* a shaper.
You can use it already, since we are simply linking the `harfbuzz` statically.
And we're testing `rustybuzz` against the `harfbuzz`'s test suite.
The final goal is to produce exactly the same results as harfbuzz.
The current progress can be found at [CHANGELOG.md](./CHANGELOG.md)
Embedded `harfbuzz` version: 2.6.8
## Prior work
This is mine yet another attempt to port harfbuzz to Rust.
The previous attempt can be found at [rustybuzz-old](https://github.com/RazrFalcon/rustybuzz-old).
This time I'm focusing on delivering a well-tested bindings for a stripped-down harfbuzz fork
with some parts reimplemented in Rust.
The problem is that harfbuzz code is very interconnected and it's hard to swap out random parts.
Also, despite having almost 1800 tests, there are still a lot of white spots which I will
try to fill first. Since it's way too easy to miss some important edge-case.
## License
`rustybuzz` is licensed under the **MIT**.
`harfbuzz` is [licensed](https://github.com/harfbuzz/harfbuzz/blob/master/COPYING) under the **Old MIT**

49
build.rs Normal file
View File

@ -0,0 +1,49 @@
fn main() {
let mut build = cc::Build::new();
build.cpp(true);
build.flag("-std=c++11");
build.file("harfbuzz/src/hb-aat-layout.cc");
build.file("harfbuzz/src/hb-aat-map.cc");
build.file("harfbuzz/src/hb-blob.cc");
build.file("harfbuzz/src/hb-buffer.cc");
build.file("harfbuzz/src/hb-buffer-serialize.cc");
build.file("harfbuzz/src/hb-common.cc");
build.file("harfbuzz/src/hb-face.cc");
build.file("harfbuzz/src/hb-fallback-shape.cc");
build.file("harfbuzz/src/hb-font.cc");
build.file("harfbuzz/src/hb-map.cc");
build.file("harfbuzz/src/hb-number.cc");
build.file("harfbuzz/src/hb-ot-cff1-table.cc");
build.file("harfbuzz/src/hb-ot-cff2-table.cc");
build.file("harfbuzz/src/hb-ot-face.cc");
build.file("harfbuzz/src/hb-ot-font.cc");
build.file("harfbuzz/src/hb-ot-layout.cc");
build.file("harfbuzz/src/hb-ot-map.cc");
build.file("harfbuzz/src/hb-ot-metrics.cc");
build.file("harfbuzz/src/hb-ot-shape.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-arabic.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-default.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-hangul.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-hebrew.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-indic.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-indic-table.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-khmer.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-myanmar.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-thai.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-use.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-use-table.cc");
build.file("harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc");
build.file("harfbuzz/src/hb-ot-shape-fallback.cc");
build.file("harfbuzz/src/hb-ot-shape-normalize.cc");
build.file("harfbuzz/src/hb-ot-tag.cc");
build.file("harfbuzz/src/hb-ot-var.cc");
build.file("harfbuzz/src/hb-set.cc");
build.file("harfbuzz/src/hb-shape.cc");
build.file("harfbuzz/src/hb-shape-plan.cc");
build.file("harfbuzz/src/hb-shaper.cc");
build.file("harfbuzz/src/hb-static.cc");
build.file("harfbuzz/src/hb-ucd.cc");
build.file("harfbuzz/src/hb-unicode.cc");
build.include("harfbuzz/src");
build.compile("librustybuzz.a");
}

273
examples/shape.rs Normal file
View File

@ -0,0 +1,273 @@
use std::io::Read;
use std::path::PathBuf;
use std::str::FromStr;
const HELP: &str = "\
USAGE:
shape [OPTIONS] [FONT-FILE] [TEXT]
OPTIONS:
-h, --help Show help options
--version Show version number
--font-file FILENAME Set font file-name
--face-index INDEX Set face index [default: 0]
--font-size NUMBER Font size [default: upem]
--font-ptem NUMBER Set font point-size
--variations LIST Set comma-separated list of font variations
--text TEXT Set input text
-u, --unicodes LIST Set comma-separated list of input Unicode codepoints
Examples: 'U+0056,U+0057'
--text-before TEXT Set text context before each line
--text-after TEXT Set text context after each line
--direction DIRECTION Set text direction
[possible values: ltr, rtl, ttb, btt]
--language LANG Set text language [default: LC_CTYPE]
--script TAG Set text script as ISO-15924 tag
--invisible-glyph CHAR Glyph value to replace Default-Ignorables with
--utf8-clusters Use UTF-8 byte indices, not char indices
--cluster-level N Cluster merging level [default: 0]
[possible values: 0, 1, 2]
--normalize-glyphs Rearrange glyph clusters in nominal order
--features LIST Set comma-separated list of font features
--no-glyph-names Output glyph indices instead of names
--no-positions Do not output glyph positions
--no-advances Do not output glyph advances
--no-clusters Do not output cluster indices
--show-extents Output glyph extents
--show-flags Output glyph flags
--ned No Extra Data; Do not output clusters or advances
ARGS:
[FONT-FILE] An optional path to font file
[TEXT] An optional text
";
struct Args {
help: bool,
version: bool,
font_file: Option<PathBuf>,
face_index: u32,
font_size: Option<f32>,
font_ptem: Option<f32>,
variations: Vec<rustybuzz::Variation>,
text: Option<String>,
unicodes: Option<String>,
direction: Option<rustybuzz::Direction>,
language: rustybuzz::Language,
script: Option<rustybuzz::Tag>,
utf8_clusters: bool,
cluster_level: rustybuzz::BufferClusterLevel,
features: Vec<rustybuzz::Feature>,
no_glyph_names: bool,
no_positions: bool,
no_advances: bool,
no_clusters: bool,
show_extents: bool,
show_flags: bool,
ned: bool,
free: Vec<String>,
}
fn parse_args() -> Result<Args, pico_args::Error> {
let mut args = pico_args::Arguments::from_env();
let args = Args {
help: args.contains(["-h", "--help"]),
version: args.contains("--version"),
font_file: args.opt_value_from_str("--font-file")?,
face_index: args.opt_value_from_str("--face-index")?.unwrap_or(0),
font_size: args.opt_value_from_str("--font-size")?,
font_ptem: args.opt_value_from_str("--font-ptem")?,
variations: args.opt_value_from_fn("--variations", parse_variations)?.unwrap_or_default(),
text: args.opt_value_from_str("--text")?,
unicodes: args.opt_value_from_fn(["-u", "--unicodes"], parse_unicodes)?,
direction: args.opt_value_from_str("--direction")?,
language: args.opt_value_from_str("--language")?.unwrap_or(system_language()),
script: args.opt_value_from_str("--script")?,
utf8_clusters: args.contains("--utf8-clusters"),
cluster_level: args.opt_value_from_fn("--cluster-level", parse_cluster)?.unwrap_or_default(),
features: args.opt_value_from_fn("--features", parse_features)?.unwrap_or_default(),
no_glyph_names: args.contains("--no-glyph-names"),
no_positions: args.contains("--no-positions"),
no_advances: args.contains("--no-advances"),
no_clusters: args.contains("--no-clusters"),
show_extents: args.contains("--show-extents"),
show_flags: args.contains("--show-flags"),
ned: args.contains("--ned"),
free: args.free()?,
};
Ok(args)
}
fn main() {
let args = match parse_args() {
Ok(v) => v,
Err(e) => {
eprintln!("Error: {}.", e);
std::process::exit(1);
}
};
if args.version {
println!("{}", env!("CARGO_PKG_VERSION"));
return;
}
if args.help {
print!("{}", HELP);
return;
}
let mut font_set_as_free_arg = false;
let font_path = if let Some(path) = args.font_file {
path.clone()
} else if !args.free.is_empty() {
font_set_as_free_arg = true;
PathBuf::from(&args.free[0])
} else {
eprintln!("Error: font is not set.");
std::process::exit(1);
};
if !font_path.exists() {
eprintln!("Error: '{}' does not exist.", font_path.display());
std::process::exit(1);
}
let font_data = std::fs::read(font_path).unwrap();
let mut font = rustybuzz::Font::from_data(&font_data, args.face_index).unwrap();
if let Some(ptem) = args.font_ptem {
font.set_ptem(ptem);
}
if let Some(size) = args.font_size {
font.set_scale(size as i32, size as i32);
}
if !args.variations.is_empty() {
font.set_variations(&args.variations);
}
let text = if args.free.len() == 2 && font_set_as_free_arg {
&args.free[1]
} else if args.free.len() == 1 && !font_set_as_free_arg {
&args.free[0]
} else if let Some(ref text) = args.unicodes {
text
} else if let Some(ref text) = args.text {
text
} else {
eprintln!("Error: text is not set.");
std::process::exit(1);
};
let mut buffer = rustybuzz::UnicodeBuffer::new();
buffer.push_str(text);
if let Some(d) = args.direction {
buffer.set_direction(d);
}
buffer.set_language(args.language);
if let Some(script) = args.script {
buffer.set_script(script);
}
buffer.set_cluster_level(args.cluster_level);
if !args.utf8_clusters {
buffer.reset_clusters();
}
let glyph_buffer = rustybuzz::shape(&font, &args.features, buffer);
let mut format_flags = rustybuzz::SerializeFlags::default();
if args.no_glyph_names {
format_flags |= rustybuzz::SerializeFlags::NO_GLYPH_NAMES;
}
if args.no_clusters || args.ned {
format_flags |= rustybuzz::SerializeFlags::NO_CLUSTERS;
}
if args.no_positions {
format_flags |= rustybuzz::SerializeFlags::NO_POSITIONS;
}
if args.no_advances || args.ned {
format_flags |= rustybuzz::SerializeFlags::NO_ADVANCES;
}
if args.show_extents {
format_flags |= rustybuzz::SerializeFlags::GLYPH_EXTENTS;
}
if args.show_flags {
format_flags |= rustybuzz::SerializeFlags::GLYPH_FLAGS;
}
let mut serializer = glyph_buffer.serializer(
Some(&font),
rustybuzz::SerializeFormat::Text,
format_flags,
);
let mut string = String::new();
serializer.read_to_string(&mut string).unwrap();
println!("{}", string);
}
fn parse_unicodes(s: &str) -> Result<String, String> {
use std::convert::TryFrom;
let mut text = String::new();
for u in s.split(',') {
let u = u32::from_str_radix(&u[2..], 16)
.map_err(|_| format!("'{}' is not a valid codepoint", u))?;
let c = char::try_from(u).map_err(|_| format!("{} is not a valid codepoint", u))?;
text.push(c);
}
Ok(text)
}
fn parse_features(s: &str) -> Result<Vec<rustybuzz::Feature>, String> {
let mut features = Vec::new();
for f in s.split(',') {
features.push(rustybuzz::Feature::from_str(&f)?);
}
Ok(features)
}
fn parse_variations(s: &str) -> Result<Vec<rustybuzz::Variation>, String> {
let mut variations = Vec::new();
for v in s.split(',') {
variations.push(rustybuzz::Variation::from_str(&v)?);
}
Ok(variations)
}
fn parse_cluster(s: &str) -> Result<rustybuzz::BufferClusterLevel, String> {
match s {
"0" => Ok(rustybuzz::BufferClusterLevel::MonotoneGraphemes),
"1" => Ok(rustybuzz::BufferClusterLevel::MonotoneCharacters),
"2" => Ok(rustybuzz::BufferClusterLevel::Characters),
_ => Err(format!("invalid cluster level"))
}
}
fn system_language() -> rustybuzz::Language {
unsafe {
libc::setlocale(libc::LC_ALL, b"\0" as *const _ as *const i8);
let s = libc::setlocale(libc::LC_CTYPE, std::ptr::null());
let s = std::ffi::CStr::from_ptr(s);
let s = s.to_str().expect("locale must be ASCII");
rustybuzz::Language::from_str(s).unwrap()
}
}

14
harfbuzz/AUTHORS Normal file
View File

@ -0,0 +1,14 @@
Behdad Esfahbod
David Corbett
David Turner
Ebrahim Byagowi
Garret Rieger
Jonathan Kew
Khaled Hosny
Lars Knoll
Martin Hosken
Owen Taylor
Roderick Sheeter
Roozbeh Pournader
Simon Hausmann
Werner Lemberg

37
harfbuzz/COPYING Normal file
View File

@ -0,0 +1,37 @@
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
For parts of HarfBuzz that are licensed under different licenses see individual
files names COPYING in subdirectories where applicable.
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Google, Inc.
Copyright © 2019 Facebook, Inc.
Copyright © 2012 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2006 Behdad Esfahbod
Copyright © 2005 David Turner
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright © 1998-2004 David Turner and Werner Lemberg
For full copyright notices consult the individual files in the package.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the
above copyright notice and the following two paragraphs appear in
all copies of this software.
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

3
harfbuzz/README.md Normal file
View File

@ -0,0 +1,3 @@
# harfbuzz
This directory contains modified harfbuzz 2.6.8 sources.

7
harfbuzz/THANKS Normal file
View File

@ -0,0 +1,7 @@
Bradley Grainger
Kenichi Ishibashi
Ivan Kuckir <https://photopea.com/>
Ryan Lortie
Jeff Muizelaar
suzuki toshiya
Philip Withnall

87
harfbuzz/src/config.h Normal file
View File

@ -0,0 +1,87 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* The normal alignment of `struct{char;}', in bytes. */
#define ALIGNOF_STRUCT_CHAR__ 1
/* Define to 1 if you have the `atexit' function. */
#define HAVE_ATEXIT 1
/* Have Core Text backend */
/* #undef HAVE_CORETEXT */
/* define if the compiler supports basic C++11 syntax */
#define HAVE_CXX11 1
/* Have DirectWrite library */
/* #undef HAVE_DIRECTWRITE */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `getpagesize' function. */
#define HAVE_GETPAGESIZE 1
#define HB_NO_UNICODE_FUNCS 1
/* Have Intel __sync_* atomic primitives */
#define HAVE_INTEL_ATOMIC_PRIMITIVES 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `isatty' function. */
#define HAVE_ISATTY 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `mmap' function. */
#define HAVE_MMAP 1
/* Define to 1 if you have the `mprotect' function. */
#define HAVE_MPROTECT 1
/* Have POSIX threads */
#define HAVE_PTHREAD 1
/* Have PTHREAD_PRIO_INHERIT. */
#define HAVE_PTHREAD_PRIO_INHERIT 1
/* Define to 1 if you have the <stdbool.h> header file. */
#define HAVE_STDBOOL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `sysconf' function. */
#define HAVE_SYSCONF 1
/* Define to 1 if you have the <sys/mman.h> header file. */
#define HAVE_SYS_MMAN_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
#define _DARWIN_USE_64_BIT_INODE 1
#endif

View File

@ -0,0 +1,90 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH
#define HB_AAT_LAYOUT_ANKR_TABLE_HH
#include "hb-aat-layout-common.hh"
/*
* ankr -- Anchor Point
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ankr.html
*/
#define HB_AAT_TAG_ankr HB_TAG('a', 'n', 'k', 'r')
namespace AAT {
using namespace OT;
struct Anchor
{
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
public:
FWORD xCoordinate;
FWORD yCoordinate;
public:
DEFINE_SIZE_STATIC(4);
};
typedef LArrayOf<Anchor> GlyphAnchors;
struct ankr
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
const Anchor &get_anchor(hb_codepoint_t glyph_id, unsigned int i, unsigned int num_glyphs) const
{
const NNOffsetTo<GlyphAnchors> *offset = (this + lookupTable).get_value(glyph_id, num_glyphs);
if (!offset)
return Null(Anchor);
const GlyphAnchors &anchors = &(this + anchorData) + *offset;
return anchors[i];
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && version == 0 && c->check_range(this, anchorData) &&
lookupTable.sanitize(c, this, &(this + anchorData))));
}
protected:
HBUINT16 version; /* Version number (set to zero) */
HBUINT16 flags; /* Flags (currently unused; set to zero) */
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>> lookupTable; /* Offset to the table's lookup table */
LNNOffsetTo<HBUINT8> anchorData; /* Offset to the glyph data table */
public:
DEFINE_SIZE_STATIC(12);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_ANKR_TABLE_HH */

View File

@ -0,0 +1,822 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_COMMON_HH
#define HB_AAT_LAYOUT_COMMON_HH
#include "hb-aat-layout.hh"
#include "hb-open-type.hh"
namespace AAT {
using namespace OT;
/*
* Lookup Table
*/
template <typename T> struct Lookup;
template <typename T> struct LookupFormat0
{
friend struct Lookup<T>;
private:
const T *get_value(hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
if (unlikely(glyph_id >= num_glyphs))
return nullptr;
return &arrayZ[glyph_id];
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(arrayZ.sanitize(c, c->get_num_glyphs()));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(arrayZ.sanitize(c, c->get_num_glyphs(), base));
}
protected:
HBUINT16 format; /* Format identifier--format = 0 */
UnsizedArrayOf<T> arrayZ; /* Array of lookup values, indexed by glyph index. */
public:
DEFINE_SIZE_UNBOUNDED(2);
};
template <typename T> struct LookupSegmentSingle
{
static constexpr unsigned TerminationWordCount = 2u;
int cmp(hb_codepoint_t g) const
{
return g < first ? -1 : g <= last ? 0 : +1;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && value.sanitize(c));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && value.sanitize(c, base));
}
HBGlyphID last; /* Last GlyphID in this segment */
HBGlyphID first; /* First GlyphID in this segment */
T value; /* The lookup value (only one) */
public:
DEFINE_SIZE_STATIC(4 + T::static_size);
};
template <typename T> struct LookupFormat2
{
friend struct Lookup<T>;
private:
const T *get_value(hb_codepoint_t glyph_id) const
{
const LookupSegmentSingle<T> *v = segments.bsearch(glyph_id);
return v ? &v->value : nullptr;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(segments.sanitize(c));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(segments.sanitize(c, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 2 */
VarSizedBinSearchArrayOf<LookupSegmentSingle<T>> segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
public:
DEFINE_SIZE_ARRAY(8, segments);
};
template <typename T> struct LookupSegmentArray
{
static constexpr unsigned TerminationWordCount = 2u;
const T *get_value(hb_codepoint_t glyph_id, const void *base) const
{
return first <= glyph_id && glyph_id <= last ? &(base + valuesZ)[glyph_id - first] : nullptr;
}
int cmp(hb_codepoint_t g) const
{
return g < first ? -1 : g <= last ? 0 : +1;
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && first <= last && valuesZ.sanitize(c, base, last - first + 1));
}
template <typename... Ts> bool sanitize(hb_sanitize_context_t *c, const void *base, Ts &&... ds) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && first <= last &&
valuesZ.sanitize(c, base, last - first + 1, hb_forward<Ts>(ds)...));
}
HBGlyphID last; /* Last GlyphID in this segment */
HBGlyphID first; /* First GlyphID in this segment */
NNOffsetTo<UnsizedArrayOf<T>> valuesZ; /* A 16-bit offset from the start of
* the table to the data. */
public:
DEFINE_SIZE_STATIC(6);
};
template <typename T> struct LookupFormat4
{
friend struct Lookup<T>;
private:
const T *get_value(hb_codepoint_t glyph_id) const
{
const LookupSegmentArray<T> *v = segments.bsearch(glyph_id);
return v ? v->get_value(glyph_id, this) : nullptr;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(segments.sanitize(c, this));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(segments.sanitize(c, this, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 4 */
VarSizedBinSearchArrayOf<LookupSegmentArray<T>> segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
public:
DEFINE_SIZE_ARRAY(8, segments);
};
template <typename T> struct LookupSingle
{
static constexpr unsigned TerminationWordCount = 1u;
int cmp(hb_codepoint_t g) const
{
return glyph.cmp(g);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && value.sanitize(c));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && value.sanitize(c, base));
}
HBGlyphID glyph; /* Last GlyphID */
T value; /* The lookup value (only one) */
public:
DEFINE_SIZE_STATIC(2 + T::static_size);
};
template <typename T> struct LookupFormat6
{
friend struct Lookup<T>;
private:
const T *get_value(hb_codepoint_t glyph_id) const
{
const LookupSingle<T> *v = entries.bsearch(glyph_id);
return v ? &v->value : nullptr;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(entries.sanitize(c));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(entries.sanitize(c, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 6 */
VarSizedBinSearchArrayOf<LookupSingle<T>> entries; /* The actual entries, sorted by glyph index. */
public:
DEFINE_SIZE_ARRAY(8, entries);
};
template <typename T> struct LookupFormat8
{
friend struct Lookup<T>;
private:
const T *get_value(hb_codepoint_t glyph_id) const
{
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph]
: nullptr;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && valueArrayZ.sanitize(c, glyphCount));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && valueArrayZ.sanitize(c, glyphCount, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 8 */
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
UnsizedArrayOf<T> valueArrayZ; /* The lookup values (indexed by the glyph index
* minus the value of firstGlyph). */
public:
DEFINE_SIZE_ARRAY(6, valueArrayZ);
};
template <typename T> struct LookupFormat10
{
friend struct Lookup<T>;
private:
const typename T::type get_value_or_null(hb_codepoint_t glyph_id) const
{
if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
return Null(T);
const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
unsigned int v = 0;
unsigned int count = valueSize;
for (unsigned int i = 0; i < count; i++)
v = (v << 8) | *p++;
return v;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && valueSize <= 4 && valueArrayZ.sanitize(c, glyphCount * valueSize));
}
protected:
HBUINT16 format; /* Format identifier--format = 8 */
HBUINT16 valueSize; /* Byte size of each value. */
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
UnsizedArrayOf<HBUINT8> valueArrayZ; /* The lookup values (indexed by the glyph index
* minus the value of firstGlyph). */
public:
DEFINE_SIZE_ARRAY(8, valueArrayZ);
};
template <typename T> struct Lookup
{
const T *get_value(hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
switch (u.format) {
case 0:
return u.format0.get_value(glyph_id, num_glyphs);
case 2:
return u.format2.get_value(glyph_id);
case 4:
return u.format4.get_value(glyph_id);
case 6:
return u.format6.get_value(glyph_id);
case 8:
return u.format8.get_value(glyph_id);
default:
return nullptr;
}
}
const typename T::type get_value_or_null(hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
switch (u.format) {
/* Format 10 cannot return a pointer. */
case 10:
return u.format10.get_value_or_null(glyph_id);
default:
const T *v = get_value(glyph_id, num_glyphs);
return v ? *v : Null(T);
}
}
typename T::type get_class(hb_codepoint_t glyph_id, unsigned int num_glyphs, unsigned int outOfRange) const
{
const T *v = get_value(glyph_id, num_glyphs);
return v ? *v : outOfRange;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (!u.format.sanitize(c))
return_trace(false);
switch (u.format) {
case 0:
return_trace(u.format0.sanitize(c));
case 2:
return_trace(u.format2.sanitize(c));
case 4:
return_trace(u.format4.sanitize(c));
case 6:
return_trace(u.format6.sanitize(c));
case 8:
return_trace(u.format8.sanitize(c));
case 10:
return_trace(u.format10.sanitize(c));
default:
return_trace(true);
}
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
if (!u.format.sanitize(c))
return_trace(false);
switch (u.format) {
case 0:
return_trace(u.format0.sanitize(c, base));
case 2:
return_trace(u.format2.sanitize(c, base));
case 4:
return_trace(u.format4.sanitize(c, base));
case 6:
return_trace(u.format6.sanitize(c, base));
case 8:
return_trace(u.format8.sanitize(c, base));
case 10:
return_trace(false); /* We don't support format10 here currently. */
default:
return_trace(true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
LookupFormat0<T> format0;
LookupFormat2<T> format2;
LookupFormat4<T> format4;
LookupFormat6<T> format6;
LookupFormat8<T> format8;
LookupFormat10<T> format10;
} u;
public:
DEFINE_SIZE_UNION(2, format);
};
/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined
* special NULL objects for Lookup<> objects, but since it's template our macros
* don't work. So we have to hand-code them here. UGLY. */
} // namespace AAT
/* Ugly hand-coded null objects for template Lookup<> :(. */
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
template <typename T> struct Null<AAT::Lookup<T>>
{
static AAT::Lookup<T> const &get_null()
{
return *reinterpret_cast<const AAT::Lookup<T> *>(_hb_Null_AAT_Lookup);
}
};
namespace AAT {
enum { DELETED_GLYPH = 0xFFFF };
/*
* (Extended) State Table
*/
template <typename T> struct Entry
{
bool sanitize(hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE(this);
/* Note, we don't recurse-sanitize data because we don't access it.
* That said, in our DEFINE_SIZE_STATIC we access T::static_size,
* which ensures that data has a simple sanitize(). To be determined
* if I need to remove that as well.
*
* HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
* assertion wouldn't be checked, hence the line below. */
static_assert(T::static_size, "");
return_trace(c->check_struct(this));
}
public:
HBUINT16 newState; /* Byte offset from beginning of state table
* to the new state. Really?!?! Or just state
* number? The latter in morx for sure. */
HBUINT16 flags; /* Table specific. */
T data; /* Optional offsets to per-glyph tables. */
public:
DEFINE_SIZE_STATIC(4 + T::static_size);
};
template <> struct Entry<void>
{
bool sanitize(hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
public:
HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */
HBUINT16 flags; /* Table specific. */
public:
DEFINE_SIZE_STATIC(4);
};
template <typename Types, typename Extra> struct StateTable
{
typedef typename Types::HBUINT HBUINT;
typedef typename Types::HBUSHORT HBUSHORT;
typedef typename Types::ClassTypeNarrow ClassType;
enum State {
STATE_START_OF_TEXT = 0,
STATE_START_OF_LINE = 1,
};
enum Class {
CLASS_END_OF_TEXT = 0,
CLASS_OUT_OF_BOUNDS = 1,
CLASS_DELETED_GLYPH = 2,
CLASS_END_OF_LINE = 3,
};
int new_state(unsigned int newState) const
{
return Types::extended ? newState : ((int)newState - (int)stateArrayTable) / (int)nClasses;
}
unsigned int get_class(hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
if (unlikely(glyph_id == DELETED_GLYPH))
return CLASS_DELETED_GLYPH;
return (this + classTable).get_class(glyph_id, num_glyphs, 1);
}
const Entry<Extra> *get_entries() const
{
return (this + entryTable).arrayZ;
}
const Entry<Extra> &get_entry(int state, unsigned int klass) const
{
if (unlikely(klass >= nClasses))
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this + stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this + entryTable).arrayZ;
unsigned int entry = states[state * nClasses + klass];
DEBUG_MSG(APPLY, nullptr, "e%u", entry);
return entries[entry];
}
bool sanitize(hb_sanitize_context_t *c, unsigned int *num_entries_out = nullptr) const
{
TRACE_SANITIZE(this);
if (unlikely(!(c->check_struct(this) && nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
classTable.sanitize(c, this))))
return_trace(false);
const HBUSHORT *states = (this + stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this + entryTable).arrayZ;
unsigned int num_classes = nClasses;
if (unlikely(hb_unsigned_mul_overflows(num_classes, states[0].static_size)))
return_trace(false);
unsigned int row_stride = num_classes * states[0].static_size;
/* Apple 'kern' table has this peculiarity:
*
* "Because the stateTableOffset in the state table header is (strictly
* speaking) redundant, some 'kern' tables use it to record an initial
* state where that should not be StartOfText. To determine if this is
* done, calculate what the stateTableOffset should be. If it's different
* from the actual stateTableOffset, use it as the initial state."
*
* We implement this by calling the initial state zero, but allow *negative*
* states if the start state indeed was not the first state. Since the code
* is shared, this will also apply to 'mort' table. The 'kerx' / 'morx'
* tables are not affected since those address states by index, not offset.
*/
int min_state = 0;
int max_state = 0;
unsigned int num_entries = 0;
int state_pos = 0;
int state_neg = 0;
unsigned int entry = 0;
while (min_state < state_neg || state_pos <= max_state) {
if (min_state < state_neg) {
/* Negative states. */
if (unlikely(hb_unsigned_mul_overflows(min_state, num_classes)))
return_trace(false);
if (unlikely(!c->check_range(&states[min_state * num_classes], -min_state, row_stride)))
return_trace(false);
if ((c->max_ops -= state_neg - min_state) <= 0)
return_trace(false);
{ /* Sweep new states. */
const HBUSHORT *stop = &states[min_state * num_classes];
if (unlikely(stop > states))
return_trace(false);
for (const HBUSHORT *p = states; stop < p; p--)
num_entries = hb_max(num_entries, *(p - 1) + 1);
state_neg = min_state;
}
}
if (state_pos <= max_state) {
/* Positive states. */
if (unlikely(!c->check_range(states, max_state + 1, row_stride)))
return_trace(false);
if ((c->max_ops -= max_state - state_pos + 1) <= 0)
return_trace(false);
{ /* Sweep new states. */
if (unlikely(hb_unsigned_mul_overflows((max_state + 1), num_classes)))
return_trace(false);
const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
if (unlikely(stop < states))
return_trace(false);
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
num_entries = hb_max(num_entries, *p + 1);
state_pos = max_state + 1;
}
}
if (unlikely(!c->check_array(entries, num_entries)))
return_trace(false);
if ((c->max_ops -= num_entries - entry) <= 0)
return_trace(false);
{ /* Sweep new entries. */
const Entry<Extra> *stop = &entries[num_entries];
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++) {
int newState = new_state(p->newState);
min_state = hb_min(min_state, newState);
max_state = hb_max(max_state, newState);
}
entry = num_entries;
}
}
if (num_entries_out)
*num_entries_out = num_entries;
return_trace(true);
}
protected:
HBUINT nClasses; /* Number of classes, which is the number of indices
* in a single line in the state array. */
NNOffsetTo<ClassType, HBUINT> classTable; /* Offset to the class table. */
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT> stateArrayTable; /* Offset to the state array. */
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT> entryTable; /* Offset to the entry array. */
public:
DEFINE_SIZE_STATIC(4 * sizeof(HBUINT));
};
template <typename HBUCHAR> struct ClassTable
{
unsigned int get_class(hb_codepoint_t glyph_id, unsigned int outOfRange) const
{
unsigned int i = glyph_id - firstGlyph;
return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
}
unsigned int get_class(hb_codepoint_t glyph_id, unsigned int num_glyphs HB_UNUSED, unsigned int outOfRange) const
{
return get_class(glyph_id, outOfRange);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && classArray.sanitize(c));
}
protected:
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
* firstGlyph). */
public:
DEFINE_SIZE_ARRAY(4, classArray);
};
struct ObsoleteTypes
{
static constexpr bool extended = false;
typedef HBUINT16 HBUINT;
typedef HBUINT8 HBUSHORT;
typedef ClassTable<HBUINT8> ClassTypeNarrow;
typedef ClassTable<HBUINT16> ClassTypeWide;
template <typename T> static unsigned int offsetToIndex(unsigned int offset, const void *base, const T *array)
{
return (offset - ((const char *)array - (const char *)base)) / T::static_size;
}
template <typename T> static unsigned int byteOffsetToIndex(unsigned int offset, const void *base, const T *array)
{
return offsetToIndex(offset, base, array);
}
template <typename T> static unsigned int wordOffsetToIndex(unsigned int offset, const void *base, const T *array)
{
return offsetToIndex(2 * offset, base, array);
}
};
struct ExtendedTypes
{
static constexpr bool extended = true;
typedef HBUINT32 HBUINT;
typedef HBUINT16 HBUSHORT;
typedef Lookup<HBUINT16> ClassTypeNarrow;
typedef Lookup<HBUINT16> ClassTypeWide;
template <typename T>
static unsigned int offsetToIndex(unsigned int offset, const void *base HB_UNUSED, const T *array HB_UNUSED)
{
return offset;
}
template <typename T>
static unsigned int byteOffsetToIndex(unsigned int offset, const void *base HB_UNUSED, const T *array HB_UNUSED)
{
return offset / 2;
}
template <typename T>
static unsigned int wordOffsetToIndex(unsigned int offset, const void *base HB_UNUSED, const T *array HB_UNUSED)
{
return offset;
}
};
template <typename Types, typename EntryData> struct StateTableDriver
{
StateTableDriver(const StateTable<Types, EntryData> &machine_, hb_buffer_t *buffer_, hb_face_t *face_)
: machine(machine_)
, buffer(buffer_)
, num_glyphs(face_->get_num_glyphs())
{
}
template <typename context_t> void drive(context_t *c)
{
if (!c->in_place)
buffer->clear_output();
int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
for (buffer->idx = 0; buffer->successful;) {
unsigned int klass = buffer->idx < buffer->len
? machine.get_class(buffer->info[buffer->idx].codepoint, num_glyphs)
: (unsigned)StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
DEBUG_MSG(APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const Entry<EntryData> &entry = machine.get_entry(state, klass);
/* Unsafe-to-break before this if not in state 0, as things might
* go differently if we start from state 0 here.
*
* Ugh. The indexing here is ugly... */
if (state && buffer->backtrack_len() && buffer->idx < buffer->len) {
/* If there's no action and we're just epsilon-transitioning to state 0,
* safe to break. */
if (c->is_actionable(this, entry) ||
!(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
entry.flags == context_t::DontAdvance))
buffer->unsafe_to_break_from_outbuffer(buffer->backtrack_len() - 1, buffer->idx + 1);
}
/* Unsafe-to-break if end-of-text would kick in here. */
if (buffer->idx + 2 <= buffer->len) {
const Entry<EntryData> &end_entry =
machine.get_entry(state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
if (c->is_actionable(this, end_entry))
buffer->unsafe_to_break(buffer->idx, buffer->idx + 2);
}
c->transition(this, entry);
state = machine.new_state(entry.newState);
DEBUG_MSG(APPLY, nullptr, "s%d", state);
if (buffer->idx == buffer->len)
break;
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
buffer->next_glyph();
}
if (!c->in_place) {
for (; buffer->successful && buffer->idx < buffer->len;)
buffer->next_glyph();
buffer->swap_buffers();
}
}
public:
const StateTable<Types, EntryData> &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs;
};
struct ankr;
struct hb_aat_apply_context_t : hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
const char *get_name()
{
return "APPLY";
}
template <typename T> return_t dispatch(const T &obj)
{
return obj.apply(this);
}
static return_t default_return_value()
{
return false;
}
bool stop_sublookup_iteration(return_t r) const
{
return r;
}
const hb_ot_shape_plan_t *plan;
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
HB_INTERNAL hb_aat_apply_context_t(const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob = const_cast<hb_blob_t *>(&Null(hb_blob_t)));
HB_INTERNAL ~hb_aat_apply_context_t();
HB_INTERNAL void set_ankr_table(const AAT::ankr *ankr_table_);
void set_lookup_index(unsigned int i)
{
lookup_index = i;
}
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_COMMON_HH */

View File

@ -0,0 +1,232 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH
#define HB_AAT_LAYOUT_FEAT_TABLE_HH
#include "hb-aat-layout-common.hh"
/*
* feat -- Feature Name
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html
*/
#define HB_AAT_TAG_feat HB_TAG('f', 'e', 'a', 't')
namespace AAT {
struct SettingName
{
friend struct FeatureName;
int cmp(hb_aat_layout_feature_selector_t key) const
{
return (int)key - (int)setting;
}
hb_aat_layout_feature_selector_t get_selector() const
{
return (hb_aat_layout_feature_selector_t)(unsigned)setting;
}
hb_aat_layout_feature_selector_info_t get_info(hb_aat_layout_feature_selector_t default_selector) const
{
return {nameIndex,
(hb_aat_layout_feature_selector_t)(unsigned int)setting,
default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
? (hb_aat_layout_feature_selector_t)(setting + 1)
: default_selector,
0};
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this)));
}
protected:
HBUINT16 setting; /* The setting. */
NameID nameIndex; /* The name table index for the setting's name. */
public:
DEFINE_SIZE_STATIC(4);
};
DECLARE_NULL_NAMESPACE_BYTES(AAT, SettingName);
struct feat;
struct FeatureName
{
int cmp(hb_aat_layout_feature_type_t key) const
{
return (int)key - (int)feature;
}
enum {
Exclusive = 0x8000, /* If set, the feature settings are mutually exclusive. */
NotDefault = 0x4000, /* If clear, then the setting with an index of 0 in
* the setting name array for this feature should
* be taken as the default for the feature
* (if one is required). If set, then bits 0-15 of this
* featureFlags field contain the index of the setting
* which is to be taken as the default. */
IndexMask = 0x00FF /* If bits 30 and 31 are set, then these sixteen bits
* indicate the index of the setting in the setting name
* array for this feature which should be taken
* as the default. */
};
unsigned int get_selector_infos(unsigned int start_offset,
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *pdefault_index, /* OUT. May be NULL. */
const void *base) const
{
hb_array_t<const SettingName> settings_table = (base + settingTableZ).as_array(nSettings);
static_assert(Index::NOT_FOUND_INDEX == HB_AAT_LAYOUT_NO_SELECTOR_INDEX, "");
hb_aat_layout_feature_selector_t default_selector = HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID;
unsigned int default_index = Index::NOT_FOUND_INDEX;
if (featureFlags & Exclusive) {
default_index = (featureFlags & NotDefault) ? featureFlags & IndexMask : 0;
default_selector = settings_table[default_index].get_selector();
}
if (pdefault_index)
*pdefault_index = default_index;
if (selectors_count) {
+settings_table.sub_array(start_offset, selectors_count) |
hb_map([=](const SettingName &setting) { return setting.get_info(default_selector); }) |
hb_sink(hb_array(selectors, *selectors_count));
}
return settings_table.length;
}
hb_aat_layout_feature_type_t get_feature_type() const
{
return (hb_aat_layout_feature_type_t)(unsigned int)feature;
}
hb_ot_name_id_t get_feature_name_id() const
{
return nameIndex;
}
bool is_exclusive() const
{
return featureFlags & Exclusive;
}
/* A FeatureName with no settings is meaningless */
bool has_data() const
{
return nSettings;
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && (base + settingTableZ).sanitize(c, nSettings)));
}
protected:
HBUINT16 feature; /* Feature type. */
HBUINT16 nSettings; /* The number of records in the setting name array. */
LNNOffsetTo<UnsizedArrayOf<SettingName>> settingTableZ; /* Offset in bytes from the beginning of this table to
* this feature's setting name array. The actual type of
* record this offset refers to will depend on the
* exclusivity value, as described below. */
HBUINT16 featureFlags; /* Single-bit flags associated with the feature type. */
HBINT16 nameIndex; /* The name table index for the feature's name.
* This index has values greater than 255 and
* less than 32768. */
public:
DEFINE_SIZE_STATIC(12);
};
struct feat
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
bool has_data() const
{
return version.to_int();
}
unsigned int
get_feature_types(unsigned int start_offset, unsigned int *count, hb_aat_layout_feature_type_t *features) const
{
if (count) {
+namesZ.as_array(featureNameCount).sub_array(start_offset, count) | hb_map(&FeatureName::get_feature_type) |
hb_sink(hb_array(features, *count));
}
return featureNameCount;
}
bool exposes_feature(hb_aat_layout_feature_type_t feature_type) const
{
return get_feature(feature_type).has_data();
}
const FeatureName &get_feature(hb_aat_layout_feature_type_t feature_type) const
{
return namesZ.bsearch(featureNameCount, feature_type);
}
hb_ot_name_id_t get_feature_name_id(hb_aat_layout_feature_type_t feature) const
{
return get_feature(feature).get_feature_name_id();
}
unsigned int get_selector_infos(hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */) const
{
return get_feature(feature_type)
.get_selector_infos(start_offset, selectors_count, selectors, default_index, this);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && version.major == 1 && namesZ.sanitize(c, featureNameCount, this)));
}
protected:
FixedVersion<> version; /* Version number of the feature name table
* (0x00010000 for the current version). */
HBUINT16 featureNameCount;
/* The number of entries in the feature name array. */
HBUINT16 reserved1; /* Reserved (set to zero). */
HBUINT32 reserved2; /* Reserved (set to zero). */
SortedUnsizedArrayOf<FeatureName> namesZ; /* The feature name array. */
public:
DEFINE_SIZE_ARRAY(12, namesZ);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_FEAT_TABLE_HH */

View File

@ -0,0 +1,974 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
#define HB_AAT_LAYOUT_KERX_TABLE_HH
#include "hb-kern.hh"
#include "hb-aat-layout-ankr-table.hh"
/*
* kerx -- Extended Kerning
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
*/
#define HB_AAT_TAG_kerx HB_TAG('k', 'e', 'r', 'x')
namespace AAT {
using namespace OT;
static inline int kerxTupleKern(int value, unsigned int tupleCount, const void *base, hb_aat_apply_context_t *c)
{
if (likely(!tupleCount || !c))
return value;
unsigned int offset = value;
const FWORD *pv = &StructAtOffset<FWORD>(base, offset);
if (unlikely(!c->sanitizer.check_array(pv, tupleCount)))
return 0;
return *pv;
}
struct hb_glyph_pair_t
{
hb_codepoint_t left;
hb_codepoint_t right;
};
struct KernPair
{
int get_kerning() const
{
return value;
}
int cmp(const hb_glyph_pair_t &o) const
{
int ret = left.cmp(o.left);
if (ret)
return ret;
return right.cmp(o.right);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
protected:
HBGlyphID left;
HBGlyphID right;
FWORD value;
public:
DEFINE_SIZE_STATIC(6);
};
template <typename KernSubTableHeader> struct KerxSubTableFormat0
{
int get_kerning(hb_codepoint_t left, hb_codepoint_t right, hb_aat_apply_context_t *c = nullptr) const
{
hb_glyph_pair_t pair = {left, right};
int v = pairs.bsearch(pair).get_kerning();
return kerxTupleKern(v, header.tuple_count(), this, c);
}
bool apply(hb_aat_apply_context_t *c) const
{
TRACE_APPLY(this);
if (!c->plan->requested_kerning)
return false;
if (header.coverage & header.Backwards)
return false;
accelerator_t accel(*this, c);
hb_kern_machine_t<accelerator_t> machine(accel, header.coverage & header.CrossStream);
machine.kern(c->font, c->buffer, c->plan->kern_mask);
return_trace(true);
}
struct accelerator_t
{
const KerxSubTableFormat0 &table;
hb_aat_apply_context_t *c;
accelerator_t(const KerxSubTableFormat0 &table_, hb_aat_apply_context_t *c_)
: table(table_)
, c(c_)
{
}
int get_kerning(hb_codepoint_t left, hb_codepoint_t right) const
{
return table.get_kerning(left, right, c);
}
};
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(pairs.sanitize(c)));
}
protected:
KernSubTableHeader header;
BinSearchArrayOf<KernPair, typename KernSubTableHeader::Types::HBUINT> pairs; /* Sorted kern records. */
public:
DEFINE_SIZE_ARRAY(KernSubTableHeader::static_size + 16, pairs);
};
template <bool extended> struct Format1Entry;
template <> struct Format1Entry<true>
{
enum Flags {
Push = 0x8000, /* If set, push this glyph on the kerning stack. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. */
Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */
Reserved = 0x1FFF, /* Not used; set to 0. */
};
struct EntryData
{
HBUINT16 kernActionIndex; /* Index into the kerning value array. If
* this index is 0xFFFF, then no kerning
* is to be performed. */
public:
DEFINE_SIZE_STATIC(2);
};
static bool performAction(const Entry<EntryData> &entry)
{
return entry.data.kernActionIndex != 0xFFFF;
}
static unsigned int kernActionIndex(const Entry<EntryData> &entry)
{
return entry.data.kernActionIndex;
}
};
template <> struct Format1Entry<false>
{
enum Flags {
Push = 0x8000, /* If set, push this glyph on the kerning stack. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. */
Offset = 0x3FFF, /* Byte offset from beginning of subtable to the
* value table for the glyphs on the kerning stack. */
Reset = 0x0000, /* Not supported? */
};
typedef void EntryData;
static bool performAction(const Entry<EntryData> &entry)
{
return entry.flags & Offset;
}
static unsigned int kernActionIndex(const Entry<EntryData> &entry)
{
return entry.flags & Offset;
}
};
template <typename KernSubTableHeader> struct KerxSubTableFormat1
{
typedef typename KernSubTableHeader::Types Types;
typedef typename Types::HBUINT HBUINT;
typedef Format1Entry<Types::extended> Format1EntryT;
typedef typename Format1EntryT::EntryData EntryData;
struct driver_context_t
{
static constexpr bool in_place = true;
enum {
DontAdvance = Format1EntryT::DontAdvance,
};
driver_context_t(const KerxSubTableFormat1 *table_, hb_aat_apply_context_t *c_)
: c(c_)
, table(table_)
,
/* Apparently the offset kernAction is from the beginning of the state-machine,
* similar to offsets in morx table, NOT from beginning of this table, like
* other subtables in kerx. Discovered via testing. */
kernAction(&table->machine + table->kernAction)
, depth(0)
, crossStream(table->header.coverage & table->header.CrossStream)
{
}
bool is_actionable(StateTableDriver<Types, EntryData> *driver HB_UNUSED, const Entry<EntryData> &entry)
{
return Format1EntryT::performAction(entry);
}
void transition(StateTableDriver<Types, EntryData> *driver, const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags;
if (flags & Format1EntryT::Reset)
depth = 0;
if (flags & Format1EntryT::Push) {
if (likely(depth < ARRAY_LENGTH(stack)))
stack[depth++] = buffer->idx;
else
depth = 0; /* Probably not what CoreText does, but better? */
}
if (Format1EntryT::performAction(entry) && depth) {
unsigned int tuple_count = hb_max(1u, table->header.tuple_count());
unsigned int kern_idx = Format1EntryT::kernActionIndex(entry);
kern_idx = Types::byteOffsetToIndex(kern_idx, &table->machine, kernAction.arrayZ);
const FWORD *actions = &kernAction[kern_idx];
if (!c->sanitizer.check_array(actions, depth, tuple_count)) {
depth = 0;
return;
}
hb_mask_t kern_mask = c->plan->kern_mask;
/* From Apple 'kern' spec:
* "Each pops one glyph from the kerning stack and applies the kerning value to it.
* The end of the list is marked by an odd value... */
bool last = false;
while (!last && depth) {
unsigned int idx = stack[--depth];
int v = *actions;
actions += tuple_count;
if (idx >= buffer->len)
continue;
/* "The end of the list is marked by an odd value..." */
last = v & 1;
v &= ~1;
hb_glyph_position_t &o = buffer->pos[idx];
if (HB_DIRECTION_IS_HORIZONTAL(buffer->props.direction)) {
if (crossStream) {
/* The following flag is undocumented in the spec, but described
* in the 'kern' table example. */
if (v == -0x8000) {
o.attach_type() = ATTACH_TYPE_NONE;
o.attach_chain() = 0;
o.y_offset = 0;
} else if (o.attach_type()) {
o.y_offset += c->font->em_scale_y(v);
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
} else if (buffer->info[idx].mask & kern_mask) {
o.x_advance += c->font->em_scale_x(v);
o.x_offset += c->font->em_scale_x(v);
}
} else {
if (crossStream) {
/* CoreText doesn't do crossStream kerning in vertical. We do. */
if (v == -0x8000) {
o.attach_type() = ATTACH_TYPE_NONE;
o.attach_chain() = 0;
o.x_offset = 0;
} else if (o.attach_type()) {
o.x_offset += c->font->em_scale_x(v);
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
} else if (buffer->info[idx].mask & kern_mask) {
o.y_advance += c->font->em_scale_y(v);
o.y_offset += c->font->em_scale_y(v);
}
}
}
}
}
private:
hb_aat_apply_context_t *c;
const KerxSubTableFormat1 *table;
const UnsizedArrayOf<FWORD> &kernAction;
unsigned int stack[8];
unsigned int depth;
bool crossStream;
};
bool apply(hb_aat_apply_context_t *c) const
{
TRACE_APPLY(this);
if (!c->plan->requested_kerning && !(header.coverage & header.CrossStream))
return false;
driver_context_t dc(this, c);
StateTableDriver<Types, EntryData> driver(machine, c->buffer, c->font->face);
driver.drive(&dc);
return_trace(true);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
/* The rest of array sanitizations are done at run-time. */
return_trace(likely(c->check_struct(this) && machine.sanitize(c)));
}
protected:
KernSubTableHeader header;
StateTable<Types, EntryData> machine;
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction;
public:
DEFINE_SIZE_STATIC(KernSubTableHeader::static_size + 5 * sizeof(HBUINT));
};
template <typename KernSubTableHeader> struct KerxSubTableFormat2
{
typedef typename KernSubTableHeader::Types Types;
typedef typename Types::HBUINT HBUINT;
int get_kerning(hb_codepoint_t left, hb_codepoint_t right, hb_aat_apply_context_t *c) const
{
unsigned int num_glyphs = c->sanitizer.get_num_glyphs();
unsigned int l = (this + leftClassTable).get_class(left, num_glyphs, 0);
unsigned int r = (this + rightClassTable).get_class(right, num_glyphs, 0);
const UnsizedArrayOf<FWORD> &arrayZ = this + array;
unsigned int kern_idx = l + r;
kern_idx = Types::offsetToIndex(kern_idx, this, arrayZ.arrayZ);
const FWORD *v = &arrayZ[kern_idx];
if (unlikely(!v->sanitize(&c->sanitizer)))
return 0;
return kerxTupleKern(*v, header.tuple_count(), this, c);
}
bool apply(hb_aat_apply_context_t *c) const
{
TRACE_APPLY(this);
if (!c->plan->requested_kerning)
return false;
if (header.coverage & header.Backwards)
return false;
accelerator_t accel(*this, c);
hb_kern_machine_t<accelerator_t> machine(accel, header.coverage & header.CrossStream);
machine.kern(c->font, c->buffer, c->plan->kern_mask);
return_trace(true);
}
struct accelerator_t
{
const KerxSubTableFormat2 &table;
hb_aat_apply_context_t *c;
accelerator_t(const KerxSubTableFormat2 &table_, hb_aat_apply_context_t *c_)
: table(table_)
, c(c_)
{
}
int get_kerning(hb_codepoint_t left, hb_codepoint_t right) const
{
return table.get_kerning(left, right, c);
}
};
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && leftClassTable.sanitize(c, this) &&
rightClassTable.sanitize(c, this) && c->check_range(this, array)));
}
protected:
KernSubTableHeader header;
HBUINT rowWidth; /* The width, in bytes, of a row in the table. */
NNOffsetTo<typename Types::ClassTypeWide, HBUINT> leftClassTable; /* Offset from beginning of this subtable to
* left-hand class table. */
NNOffsetTo<typename Types::ClassTypeWide, HBUINT> rightClassTable; /* Offset from beginning of this subtable to
* right-hand class table. */
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> array; /* Offset from beginning of this subtable to
* the start of the kerning array. */
public:
DEFINE_SIZE_STATIC(KernSubTableHeader::static_size + 4 * sizeof(HBUINT));
};
template <typename KernSubTableHeader> struct KerxSubTableFormat4
{
typedef ExtendedTypes Types;
struct EntryData
{
HBUINT16 ankrActionIndex; /* Either 0xFFFF (for no action) or the index of
* the action to perform. */
public:
DEFINE_SIZE_STATIC(2);
};
struct driver_context_t
{
static constexpr bool in_place = true;
enum Flags {
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* Not used; set to 0. */
};
enum SubTableFlags {
ActionType = 0xC0000000, /* A two-bit field containing the action type. */
Unused = 0x3F000000, /* Unused - must be zero. */
Offset = 0x00FFFFFF, /* Masks the offset in bytes from the beginning
* of the subtable to the beginning of the control
* point table. */
};
driver_context_t(const KerxSubTableFormat4 *table, hb_aat_apply_context_t *c_)
: c(c_)
, action_type((table->flags & ActionType) >> 30)
, ankrData((HBUINT16 *)((const char *)&table->machine + (table->flags & Offset)))
, mark_set(false)
, mark(0)
{
}
bool is_actionable(StateTableDriver<Types, EntryData> *driver HB_UNUSED, const Entry<EntryData> &entry)
{
return entry.data.ankrActionIndex != 0xFFFF;
}
void transition(StateTableDriver<Types, EntryData> *driver, const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) {
hb_glyph_position_t &o = buffer->cur_pos();
switch (action_type) {
case 0: /* Control Point Actions.*/
{
/* indexed into glyph outline. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
if (!c->sanitizer.check_array(data, 2))
return;
HB_UNUSED unsigned int markControlPoint = *data++;
HB_UNUSED unsigned int currControlPoint = *data++;
hb_position_t markX = 0;
hb_position_t markY = 0;
hb_position_t currX = 0;
hb_position_t currY = 0;
if (!c->font->get_glyph_contour_point_for_origin(c->buffer->info[mark].codepoint,
markControlPoint,
HB_DIRECTION_LTR /*XXX*/,
&markX,
&markY) ||
!c->font->get_glyph_contour_point_for_origin(
c->buffer->cur().codepoint, currControlPoint, HB_DIRECTION_LTR /*XXX*/, &currX, &currY))
return;
o.x_offset = markX - currX;
o.y_offset = markY - currY;
} break;
case 1: /* Anchor Point Actions. */
{
/* Indexed into 'ankr' table. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
if (!c->sanitizer.check_array(data, 2))
return;
unsigned int markAnchorPoint = *data++;
unsigned int currAnchorPoint = *data++;
const Anchor &markAnchor = c->ankr_table->get_anchor(
c->buffer->info[mark].codepoint, markAnchorPoint, c->sanitizer.get_num_glyphs());
const Anchor &currAnchor = c->ankr_table->get_anchor(
c->buffer->cur().codepoint, currAnchorPoint, c->sanitizer.get_num_glyphs());
o.x_offset =
c->font->em_scale_x(markAnchor.xCoordinate) - c->font->em_scale_x(currAnchor.xCoordinate);
o.y_offset =
c->font->em_scale_y(markAnchor.yCoordinate) - c->font->em_scale_y(currAnchor.yCoordinate);
} break;
case 2: /* Control Point Coordinate Actions. */
{
const FWORD *data = (const FWORD *)&ankrData[entry.data.ankrActionIndex];
if (!c->sanitizer.check_array(data, 4))
return;
int markX = *data++;
int markY = *data++;
int currX = *data++;
int currY = *data++;
o.x_offset = c->font->em_scale_x(markX) - c->font->em_scale_x(currX);
o.y_offset = c->font->em_scale_y(markY) - c->font->em_scale_y(currY);
} break;
}
o.attach_type() = ATTACH_TYPE_MARK;
o.attach_chain() = (int)mark - (int)buffer->idx;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
if (entry.flags & Mark) {
mark_set = true;
mark = buffer->idx;
}
}
private:
hb_aat_apply_context_t *c;
unsigned int action_type;
const HBUINT16 *ankrData;
bool mark_set;
unsigned int mark;
};
bool apply(hb_aat_apply_context_t *c) const
{
TRACE_APPLY(this);
driver_context_t dc(this, c);
StateTableDriver<Types, EntryData> driver(machine, c->buffer, c->font->face);
driver.drive(&dc);
return_trace(true);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
/* The rest of array sanitizations are done at run-time. */
return_trace(likely(c->check_struct(this) && machine.sanitize(c)));
}
protected:
KernSubTableHeader header;
StateTable<Types, EntryData> machine;
HBUINT32 flags;
public:
DEFINE_SIZE_STATIC(KernSubTableHeader::static_size + 20);
};
template <typename KernSubTableHeader> struct KerxSubTableFormat6
{
enum Flags {
ValuesAreLong = 0x00000001,
};
bool is_long() const
{
return flags & ValuesAreLong;
}
int get_kerning(hb_codepoint_t left, hb_codepoint_t right, hb_aat_apply_context_t *c) const
{
unsigned int num_glyphs = c->sanitizer.get_num_glyphs();
if (is_long()) {
const typename U::Long &t = u.l;
unsigned int l = (this + t.rowIndexTable).get_value_or_null(left, num_glyphs);
unsigned int r = (this + t.columnIndexTable).get_value_or_null(right, num_glyphs);
unsigned int offset = l + r;
if (unlikely(offset < l))
return 0; /* Addition overflow. */
if (unlikely(hb_unsigned_mul_overflows(offset, sizeof(FWORD32))))
return 0;
const FWORD32 *v = &StructAtOffset<FWORD32>(&(this + t.array), offset * sizeof(FWORD32));
if (unlikely(!v->sanitize(&c->sanitizer)))
return 0;
return kerxTupleKern(*v, header.tuple_count(), &(this + vector), c);
} else {
const typename U::Short &t = u.s;
unsigned int l = (this + t.rowIndexTable).get_value_or_null(left, num_glyphs);
unsigned int r = (this + t.columnIndexTable).get_value_or_null(right, num_glyphs);
unsigned int offset = l + r;
const FWORD *v = &StructAtOffset<FWORD>(&(this + t.array), offset * sizeof(FWORD));
if (unlikely(!v->sanitize(&c->sanitizer)))
return 0;
return kerxTupleKern(*v, header.tuple_count(), &(this + vector), c);
}
}
bool apply(hb_aat_apply_context_t *c) const
{
TRACE_APPLY(this);
if (!c->plan->requested_kerning)
return false;
if (header.coverage & header.Backwards)
return false;
accelerator_t accel(*this, c);
hb_kern_machine_t<accelerator_t> machine(accel, header.coverage & header.CrossStream);
machine.kern(c->font, c->buffer, c->plan->kern_mask);
return_trace(true);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) &&
(is_long() ? (u.l.rowIndexTable.sanitize(c, this) &&
u.l.columnIndexTable.sanitize(c, this) && c->check_range(this, u.l.array))
: (u.s.rowIndexTable.sanitize(c, this) &&
u.s.columnIndexTable.sanitize(c, this) && c->check_range(this, u.s.array))) &&
(header.tuple_count() == 0 || c->check_range(this, vector))));
}
struct accelerator_t
{
const KerxSubTableFormat6 &table;
hb_aat_apply_context_t *c;
accelerator_t(const KerxSubTableFormat6 &table_, hb_aat_apply_context_t *c_)
: table(table_)
, c(c_)
{
}
int get_kerning(hb_codepoint_t left, hb_codepoint_t right) const
{
return table.get_kerning(left, right, c);
}
};
protected:
KernSubTableHeader header;
HBUINT32 flags;
HBUINT16 rowCount;
HBUINT16 columnCount;
union U {
struct Long
{
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
} l;
struct Short
{
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
} s;
} u;
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
public:
DEFINE_SIZE_STATIC(KernSubTableHeader::static_size + 24);
};
struct KerxSubTableHeader
{
typedef ExtendedTypes Types;
unsigned tuple_count() const
{
return tupleCount;
}
bool is_horizontal() const
{
return !(coverage & Vertical);
}
enum Coverage {
Vertical = 0x80000000u, /* Set if table has vertical kerning values. */
CrossStream = 0x40000000u, /* Set if table has cross-stream kerning values. */
Variation = 0x20000000u, /* Set if table has variation kerning values. */
Backwards = 0x10000000u, /* If clear, process the glyphs forwards, that
* is, from first to last in the glyph stream.
* If we, process them from last to first.
* This flag only applies to state-table based
* 'kerx' subtables (types 1 and 4). */
Reserved = 0x0FFFFF00u, /* Reserved, set to zero. */
SubtableType = 0x000000FFu, /* Subtable type. */
};
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this)));
}
public:
HBUINT32 length;
HBUINT32 coverage;
HBUINT32 tupleCount;
public:
DEFINE_SIZE_STATIC(12);
};
struct KerxSubTable
{
friend struct kerx;
unsigned int get_size() const
{
return u.header.length;
}
unsigned int get_type() const
{
return u.header.coverage & u.header.SubtableType;
}
template <typename context_t, typename... Ts> typename context_t::return_t dispatch(context_t *c, Ts &&... ds) const
{
unsigned int subtable_type = get_type();
TRACE_DISPATCH(this, subtable_type);
switch (subtable_type) {
case 0:
return_trace(c->dispatch(u.format0, hb_forward<Ts>(ds)...));
case 1:
return_trace(c->dispatch(u.format1, hb_forward<Ts>(ds)...));
case 2:
return_trace(c->dispatch(u.format2, hb_forward<Ts>(ds)...));
case 4:
return_trace(c->dispatch(u.format4, hb_forward<Ts>(ds)...));
case 6:
return_trace(c->dispatch(u.format6, hb_forward<Ts>(ds)...));
default:
return_trace(c->default_return_value());
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (!u.header.sanitize(c) || u.header.length <= u.header.static_size || !c->check_range(this, u.header.length))
return_trace(false);
return_trace(dispatch(c));
}
public:
union {
KerxSubTableHeader header;
KerxSubTableFormat0<KerxSubTableHeader> format0;
KerxSubTableFormat1<KerxSubTableHeader> format1;
KerxSubTableFormat2<KerxSubTableHeader> format2;
KerxSubTableFormat4<KerxSubTableHeader> format4;
KerxSubTableFormat6<KerxSubTableHeader> format6;
} u;
public:
DEFINE_SIZE_MIN(12);
};
/*
* The 'kerx' Table
*/
template <typename T> struct KerxTable
{
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
const T *thiz() const
{
return static_cast<const T *>(this);
}
bool has_state_machine() const
{
typedef typename T::SubTable SubTable;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++) {
if (st->get_type() == 1)
return true;
st = &StructAfter<SubTable>(*st);
}
return false;
}
bool has_cross_stream() const
{
typedef typename T::SubTable SubTable;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++) {
if (st->u.header.coverage & st->u.header.CrossStream)
return true;
st = &StructAfter<SubTable>(*st);
}
return false;
}
int get_h_kerning(hb_codepoint_t left, hb_codepoint_t right) const
{
typedef typename T::SubTable SubTable;
int v = 0;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++) {
if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) ||
!st->u.header.is_horizontal())
continue;
v += st->get_kerning(left, right);
st = &StructAfter<SubTable>(*st);
}
return v;
}
bool apply(AAT::hb_aat_apply_context_t *c) const
{
typedef typename T::SubTable SubTable;
bool ret = false;
bool seenCrossStream = false;
c->set_lookup_index(0);
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++) {
bool reverse;
if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
goto skip;
if (HB_DIRECTION_IS_HORIZONTAL(c->buffer->props.direction) != st->u.header.is_horizontal())
goto skip;
reverse = bool(st->u.header.coverage & st->u.header.Backwards) !=
HB_DIRECTION_IS_BACKWARD(c->buffer->props.direction);
if (!c->buffer->message(c->font, "start subtable %d", c->lookup_index))
goto skip;
if (!seenCrossStream && (st->u.header.coverage & st->u.header.CrossStream)) {
/* Attach all glyphs into a chain. */
seenCrossStream = true;
hb_glyph_position_t *pos = c->buffer->pos;
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++) {
pos[i].attach_type() = ATTACH_TYPE_CURSIVE;
pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD(c->buffer->props.direction) ? -1 : +1;
/* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
* since there needs to be a non-zero attachment for post-positioning to
* be needed. */
}
}
if (reverse)
c->buffer->reverse();
{
/* See comment in sanitize() for conditional here. */
hb_sanitize_with_object_t with(&c->sanitizer, i < count - 1 ? st : (const SubTable *)nullptr);
ret |= st->dispatch(c);
}
if (reverse)
c->buffer->reverse();
(void)c->buffer->message(c->font, "end subtable %d", c->lookup_index);
skip:
st = &StructAfter<SubTable>(*st);
c->set_lookup_index(c->lookup_index + 1);
}
return ret;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (unlikely(!thiz()->version.sanitize(c) || (unsigned)thiz()->version < (unsigned)T::minVersion ||
!thiz()->tableCount.sanitize(c)))
return_trace(false);
typedef typename T::SubTable SubTable;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++) {
if (unlikely(!st->u.header.sanitize(c)))
return_trace(false);
/* OpenType kern table has 2-byte subtable lengths. That's limiting.
* MS implementation also only supports one subtable, of format 0,
* anyway. Certain versions of some fonts, like Calibry, contain
* kern subtable that exceeds 64kb. Looks like, the subtable length
* is simply ignored. Which makes sense. It's only needed if you
* have multiple subtables. To handle such fonts, we just ignore
* the length for the last subtable. */
hb_sanitize_with_object_t with(c, i < count - 1 ? st : (const SubTable *)nullptr);
if (unlikely(!st->sanitize(c)))
return_trace(false);
st = &StructAfter<SubTable>(*st);
}
return_trace(true);
}
};
struct kerx : KerxTable<kerx>
{
friend struct KerxTable<kerx>;
static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
static constexpr unsigned minVersion = 2u;
typedef KerxSubTableHeader SubTableHeader;
typedef SubTableHeader::Types Types;
typedef KerxSubTable SubTable;
bool has_data() const
{
return version;
}
protected:
HBUINT16 version; /* The version number of the extended kerning table
* (currently 2, 3, or 4). */
HBUINT16 unused; /* Set to 0. */
HBUINT32 tableCount; /* The number of subtables included in the extended kerning
* table. */
SubTable firstSubTable; /* Subtables. */
/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
public:
DEFINE_SIZE_MIN(8);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,221 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
#define HB_AAT_LAYOUT_TRAK_TABLE_HH
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
/*
* trak -- Tracking
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
*/
#define HB_AAT_TAG_trak HB_TAG('t', 'r', 'a', 'k')
namespace AAT {
struct TrackTableEntry
{
friend struct TrackData;
float get_track_value() const
{
return track.to_float();
}
int get_value(const void *base, unsigned int index, unsigned int table_size) const
{
return (base + valuesZ).as_array(table_size)[index];
}
public:
bool sanitize(hb_sanitize_context_t *c, const void *base, unsigned int table_size) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && (valuesZ.sanitize(c, base, table_size))));
}
protected:
HBFixed track; /* Track value for this record. */
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
NNOffsetTo<UnsizedArrayOf<FWORD>> valuesZ; /* Offset from start of tracking table to
* per-size tracking values for this track. */
public:
DEFINE_SIZE_STATIC(8);
};
struct TrackData
{
float
interpolate_at(unsigned int idx, float target_size, const TrackTableEntry &trackTableEntry, const void *base) const
{
unsigned int sizes = nSizes;
hb_array_t<const HBFixed> size_table((base + sizeTable).arrayZ, sizes);
float s0 = size_table[idx].to_float();
float s1 = size_table[idx + 1].to_float();
float t = unlikely(s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
return t * trackTableEntry.get_value(base, idx + 1, sizes) +
(1.f - t) * trackTableEntry.get_value(base, idx, sizes);
}
int get_tracking(const void *base, float ptem) const
{
/*
* Choose track.
*/
const TrackTableEntry *trackTableEntry = nullptr;
unsigned int count = nTracks;
for (unsigned int i = 0; i < count; i++) {
/* Note: Seems like the track entries are sorted by values. But the
* spec doesn't explicitly say that. It just mentions it in the example. */
/* For now we only seek for track entries with zero tracking value */
if (trackTable[i].get_track_value() == 0.f) {
trackTableEntry = &trackTable[i];
break;
}
}
if (!trackTableEntry)
return 0.;
/*
* Choose size.
*/
unsigned int sizes = nSizes;
if (!sizes)
return 0.;
if (sizes == 1)
return trackTableEntry->get_value(base, 0, sizes);
hb_array_t<const HBFixed> size_table((base + sizeTable).arrayZ, sizes);
unsigned int size_index;
for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float() >= ptem)
break;
return roundf(interpolate_at(size_index ? size_index - 1 : 0, ptem, *trackTableEntry, base));
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && sizeTable.sanitize(c, base, nSizes) &&
trackTable.sanitize(c, nTracks, base, nSizes)));
}
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
LNNOffsetTo<UnsizedArrayOf<HBFixed>> sizeTable; /* Offset from start of the tracking table to
* Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry> trackTable; /* Array[nTracks] of TrackTableEntry records. */
public:
DEFINE_SIZE_ARRAY(8, trackTable);
};
struct trak
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
bool has_data() const
{
return version.to_int();
}
bool apply(hb_aat_apply_context_t *c) const
{
TRACE_APPLY(this);
hb_mask_t trak_mask = c->plan->trak_mask;
const float ptem = c->font->ptem;
if (unlikely(ptem <= 0.f))
return_trace(false);
hb_buffer_t *buffer = c->buffer;
if (HB_DIRECTION_IS_HORIZONTAL(buffer->props.direction)) {
const TrackData &trackData = this + horizData;
int tracking = trackData.get_tracking(this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_x(tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_x(tracking);
foreach_grapheme(buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask))
continue;
buffer->pos[start].x_advance += advance_to_add;
buffer->pos[start].x_offset += offset_to_add;
}
} else {
const TrackData &trackData = this + vertData;
int tracking = trackData.get_tracking(this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_y(tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_y(tracking);
foreach_grapheme(buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask))
continue;
buffer->pos[start].y_advance += advance_to_add;
buffer->pos[start].y_offset += offset_to_add;
}
}
return_trace(true);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && version.major == 1 && horizData.sanitize(c, this, this) &&
vertData.sanitize(c, this, this)));
}
protected:
FixedVersion<> version; /* Version of the tracking table
* (0x00010000u for version 1.0). */
HBUINT16 format; /* Format of the tracking table (set to 0). */
OffsetTo<TrackData> horizData; /* Offset from start of tracking table to TrackData
* for horizontal text (or 0 if none). */
OffsetTo<TrackData> vertData; /* Offset from start of tracking table to TrackData
* for vertical text (or 0 if none). */
HBUINT16 reserved; /* Reserved. Set to 0. */
public:
DEFINE_SIZE_STATIC(12);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_TRAK_TABLE_HH */

View File

@ -0,0 +1,575 @@
/*
* Copyright © 2017 Google, Inc.
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#include "hb-aat-layout.hh"
#include "hb-aat-layout-ankr-table.hh"
#include "hb-aat-layout-feat-table.hh"
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-trak-table.hh"
/*
* hb_aat_apply_context_t
*/
/* Note: This context is used for kerning, even without AAT, hence the condition. */
#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
AAT::hb_aat_apply_context_t::hb_aat_apply_context_t(const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob)
: plan(plan_)
, font(font_)
, face(font->face)
, buffer(buffer_)
, sanitizer()
, ankr_table(&Null(AAT::ankr))
, lookup_index(0)
{
sanitizer.init(blob);
sanitizer.set_num_glyphs(face->get_num_glyphs());
sanitizer.start_processing();
sanitizer.set_max_ops(HB_SANITIZE_MAX_OPS_MAX);
}
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t()
{
sanitizer.end_processing();
}
void AAT::hb_aat_apply_context_t::set_ankr_table(const AAT::ankr *ankr_table_)
{
ankr_table = ankr_table_;
}
#endif
/**
* SECTION:hb-aat-layout
* @title: hb-aat-layout
* @short_description: Apple Advanced Typography Layout
* @include: hb-aat.h
*
* Functions for querying OpenType Layout features in the font face.
**/
#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
/* Table data courtesy of Apple. Converted from mnemonics to integers
* when moving to this file. */
static const hb_aat_feature_mapping_t feature_mappings[] = {
{HB_TAG('a', 'f', 'r', 'c'),
HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
{HB_TAG('c', '2', 'p', 'c'),
HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
{HB_TAG('c', '2', 's', 'c'),
HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
{HB_TAG('c', 'a', 'l', 't'),
HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF},
{HB_TAG('c', 'a', 's', 'e'),
HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF},
{HB_TAG('c', 'l', 'i', 'g'),
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF},
{HB_TAG('c', 'p', 's', 'p'),
HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF},
{HB_TAG('c', 's', 'w', 'h'),
HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF},
{HB_TAG('d', 'l', 'i', 'g'),
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF},
{HB_TAG('e', 'x', 'p', 't'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('f', 'r', 'a', 'c'),
HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
{HB_TAG('f', 'w', 'i', 'd'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('h', 'a', 'l', 't'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('h', 'i', 's', 't'),
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
{HB_TAG('h', 'k', 'n', 'a'),
HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF},
{HB_TAG('h', 'l', 'i', 'g'),
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
{HB_TAG('h', 'n', 'g', 'l'),
HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION},
{HB_TAG('h', 'o', 'j', 'o'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('h', 'w', 'i', 'd'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('i', 't', 'a', 'l'),
HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF},
{HB_TAG('j', 'p', '0', '4'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('j', 'p', '7', '8'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('j', 'p', '8', '3'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('j', 'p', '9', '0'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('l', 'i', 'g', 'a'),
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF},
{HB_TAG('l', 'n', 'u', 'm'),
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS,
(hb_aat_layout_feature_selector_t)2},
{HB_TAG('m', 'g', 'r', 'k'),
HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF},
{HB_TAG('n', 'l', 'c', 'k'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('o', 'n', 'u', 'm'),
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS,
(hb_aat_layout_feature_selector_t)2},
{HB_TAG('o', 'r', 'd', 'n'),
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG('p', 'a', 'l', 't'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('p', 'c', 'a', 'p'),
HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
{HB_TAG('p', 'k', 'n', 'a'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('p', 'n', 'u', 'm'),
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS,
(hb_aat_layout_feature_selector_t)4},
{HB_TAG('p', 'w', 'i', 'd'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('q', 'w', 'i', 'd'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('r', 'u', 'b', 'y'),
HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
{HB_TAG('s', 'i', 'n', 'f'),
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG('s', 'm', 'c', 'p'),
HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
{HB_TAG('s', 'm', 'p', 'l'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('s', 's', '0', '1'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF},
{HB_TAG('s', 's', '0', '2'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF},
{HB_TAG('s', 's', '0', '3'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF},
{HB_TAG('s', 's', '0', '4'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF},
{HB_TAG('s', 's', '0', '5'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF},
{HB_TAG('s', 's', '0', '6'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF},
{HB_TAG('s', 's', '0', '7'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF},
{HB_TAG('s', 's', '0', '8'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF},
{HB_TAG('s', 's', '0', '9'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF},
{HB_TAG('s', 's', '1', '0'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF},
{HB_TAG('s', 's', '1', '1'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF},
{HB_TAG('s', 's', '1', '2'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF},
{HB_TAG('s', 's', '1', '3'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF},
{HB_TAG('s', 's', '1', '4'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF},
{HB_TAG('s', 's', '1', '5'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF},
{HB_TAG('s', 's', '1', '6'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF},
{HB_TAG('s', 's', '1', '7'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF},
{HB_TAG('s', 's', '1', '8'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF},
{HB_TAG('s', 's', '1', '9'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF},
{HB_TAG('s', 's', '2', '0'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF},
{HB_TAG('s', 'u', 'b', 's'),
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG('s', 'u', 'p', 's'),
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG('s', 'w', 's', 'h'),
HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF},
{HB_TAG('t', 'i', 't', 'l'),
HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS},
{HB_TAG('t', 'n', 'a', 'm'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('t', 'n', 'u', 'm'),
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS,
(hb_aat_layout_feature_selector_t)4},
{HB_TAG('t', 'r', 'a', 'd'),
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS,
(hb_aat_layout_feature_selector_t)16},
{HB_TAG('t', 'w', 'i', 'd'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('u', 'n', 'i', 'c'),
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE,
(hb_aat_layout_feature_selector_t)14,
(hb_aat_layout_feature_selector_t)15},
{HB_TAG('v', 'a', 'l', 't'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('v', 'e', 'r', 't'),
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
{HB_TAG('v', 'h', 'a', 'l'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('v', 'k', 'n', 'a'),
HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF},
{HB_TAG('v', 'p', 'a', 'l'),
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT,
(hb_aat_layout_feature_selector_t)7},
{HB_TAG('v', 'r', 't', '2'),
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
{HB_TAG('z', 'e', 'r', 'o'),
HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF},
};
const hb_aat_feature_mapping_t *hb_aat_layout_find_feature_mapping(hb_tag_t tag)
{
return hb_sorted_array(feature_mappings).bsearch(tag);
}
#endif
#ifndef HB_NO_AAT
/*
* mort/morx/kerx/trak
*/
void hb_aat_layout_compile_map(const hb_aat_map_builder_t *mapper, hb_aat_map_t *map)
{
const AAT::morx &morx = *mapper->face->table.morx;
if (morx.has_data()) {
morx.compile_flags(mapper, map);
return;
}
const AAT::mort &mort = *mapper->face->table.mort;
if (mort.has_data()) {
mort.compile_flags(mapper, map);
return;
}
}
/*
* hb_aat_layout_has_substitution:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t hb_aat_layout_has_substitution(hb_face_t *face)
{
return face->table.morx->has_data() || face->table.mort->has_data();
}
void hb_aat_layout_substitute(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer)
{
hb_blob_t *morx_blob = font->face->table.morx.get_blob();
const AAT::morx &morx = *morx_blob->as<AAT::morx>();
if (morx.has_data()) {
AAT::hb_aat_apply_context_t c(plan, font, buffer, morx_blob);
morx.apply(&c);
return;
}
hb_blob_t *mort_blob = font->face->table.mort.get_blob();
const AAT::mort &mort = *mort_blob->as<AAT::mort>();
if (mort.has_data()) {
AAT::hb_aat_apply_context_t c(plan, font, buffer, mort_blob);
mort.apply(&c);
return;
}
}
void hb_aat_layout_zero_width_deleted_glyphs(hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int i = 0; i < count; i++)
if (unlikely(info[i].codepoint == AAT::DELETED_GLYPH))
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
static bool is_deleted_glyph(const hb_glyph_info_t *info)
{
return info->codepoint == AAT::DELETED_GLYPH;
}
void hb_aat_layout_remove_deleted_glyphs(hb_buffer_t *buffer)
{
hb_ot_layout_delete_glyphs_inplace(buffer, is_deleted_glyph);
}
/*
* hb_aat_layout_has_positioning:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t hb_aat_layout_has_positioning(hb_face_t *face)
{
return face->table.kerx->has_data();
}
void hb_aat_layout_position(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer)
{
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob();
const AAT::kerx &kerx = *kerx_blob->as<AAT::kerx>();
AAT::hb_aat_apply_context_t c(plan, font, buffer, kerx_blob);
c.set_ankr_table(font->face->table.ankr.get());
kerx.apply(&c);
}
/*
* hb_aat_layout_has_tracking:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t hb_aat_layout_has_tracking(hb_face_t *face)
{
return face->table.trak->has_data();
}
void hb_aat_layout_track(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer)
{
const AAT::trak &trak = *font->face->table.trak;
AAT::hb_aat_apply_context_t c(plan, font, buffer);
trak.apply(&c);
}
/**
* hb_aat_layout_get_feature_types:
* @face: a face object
* @start_offset: iteration's start offset
* @feature_count:(inout) (allow-none): buffer size as input, filled size as output
* @features: (out caller-allocates) (array length=feature_count): features buffer
*
* Return value: Number of all available feature types.
*
* Since: 2.2.0
*/
unsigned int hb_aat_layout_get_feature_types(hb_face_t *face,
unsigned int start_offset,
unsigned int *feature_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */)
{
return face->table.feat->get_feature_types(start_offset, feature_count, features);
}
/**
* hb_aat_layout_feature_type_get_name_id:
* @face: a face object
* @feature_type: feature id
*
* Return value: Name ID index
*
* Since: 2.2.0
*/
hb_ot_name_id_t hb_aat_layout_feature_type_get_name_id(hb_face_t *face, hb_aat_layout_feature_type_t feature_type)
{
return face->table.feat->get_feature_name_id(feature_type);
}
/**
* hb_aat_layout_feature_type_get_selectors:
* @face: a face object
* @feature_type: feature id
* @start_offset: iteration's start offset
* @selector_count: (inout) (allow-none): buffer size as input, filled size as output
* @selectors: (out caller-allocates) (array length=selector_count): settings buffer
* @default_index: (out) (allow-none): index of default selector if any
*
* If upon return, @default_index is set to #HB_AAT_LAYOUT_NO_SELECTOR_INDEX, then
* the feature type is non-exclusive. Otherwise, @default_index is the index of
* the selector that is selected by default.
*
* Return value: Number of all available feature selectors.
*
* Since: 2.2.0
*/
unsigned int hb_aat_layout_feature_type_get_selector_infos(
hb_face_t *face,
hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selector_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */)
{
return face->table.feat->get_selector_infos(feature_type, start_offset, selector_count, selectors, default_index);
}
#endif

View File

@ -0,0 +1,480 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_H_IN
#error "Include <hb-aat.h> instead."
#endif
#ifndef HB_AAT_LAYOUT_H
#define HB_AAT_LAYOUT_H
#include "hb.h"
#include "hb-ot.h"
HB_BEGIN_DECLS
/**
* hb_aat_layout_feature_type_t:
*
*
* Since: 2.2.0
*/
typedef enum {
HB_AAT_LAYOUT_FEATURE_TYPE_INVALID = 0xFFFF,
HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0,
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1,
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2,
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4,
HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5,
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING = 6,
HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE = 8,
HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE = 9,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION = 10,
HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS = 11,
HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE = 13,
HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS = 14,
HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS = 15,
HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE = 16,
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES = 17,
HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE = 18,
HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS = 19,
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE = 20,
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE = 21,
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING = 22,
HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION = 23,
HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE = 24,
HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE = 25,
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE = 26,
HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE = 27,
HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA = 28,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE = 29,
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE = 30,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE = 31,
HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN = 32,
HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT = 33,
HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA = 34,
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES = 35,
HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES = 36,
HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE = 37,
HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE = 38,
HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103,
_HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_aat_layout_feature_type_t;
/**
* hb_aat_layout_feature_selector_t:
*
*
* Since: 2.2.0
*/
typedef enum {
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID = 0xFFFF,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON = 14,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF = 15,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON = 16,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF = 17,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON = 18,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF = 19,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON = 20,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF = 21,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE = 0, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS = 1, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE = 2, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS = 3, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS = 4, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS = 5, /* deprecated */
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT */
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING */
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF = 9,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS = 4,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF = 11,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF = 11,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS = 6,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES = 0,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1 = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2 = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3 = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4 = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5 = 4,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS = 14,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING */
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT = 6,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE = 9,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATION = 10,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA =
0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA =
1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN =
0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN =
1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON = 14,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF = 15,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON = 16,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF = 17,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON = 18,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF = 19,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON = 20,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF = 21,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON = 22,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF = 23,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON = 24,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF = 25,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON = 26,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF = 27,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON = 28,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF = 29,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON = 30,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF = 31,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON = 32,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF = 33,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON = 34,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF = 35,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON = 36,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF = 37,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON = 38,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF = 39,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON = 40,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF = 41,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3,
_HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_aat_layout_feature_selector_t;
HB_EXTERN unsigned int
hb_aat_layout_get_feature_types(hb_face_t *face,
unsigned int start_offset,
unsigned int *feature_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */);
HB_EXTERN hb_ot_name_id_t hb_aat_layout_feature_type_get_name_id(hb_face_t *face,
hb_aat_layout_feature_type_t feature_type);
typedef struct hb_aat_layout_feature_selector_info_t
{
hb_ot_name_id_t name_id;
hb_aat_layout_feature_selector_t enable;
hb_aat_layout_feature_selector_t disable;
/*< private >*/
unsigned int reserved;
} hb_aat_layout_feature_selector_info_t;
#define HB_AAT_LAYOUT_NO_SELECTOR_INDEX 0xFFFFu
HB_EXTERN unsigned int hb_aat_layout_feature_type_get_selector_infos(
hb_face_t *face,
hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selector_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */);
/*
* morx/mort
*/
HB_EXTERN hb_bool_t hb_aat_layout_has_substitution(hb_face_t *face);
/*
* kerx
*/
HB_EXTERN hb_bool_t hb_aat_layout_has_positioning(hb_face_t *face);
/*
* trak
*/
HB_EXTERN hb_bool_t hb_aat_layout_has_tracking(hb_face_t *face);
HB_END_DECLS
#endif /* HB_AAT_LAYOUT_H */

View File

@ -0,0 +1,61 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_HH
#define HB_AAT_LAYOUT_HH
#include "hb.hh"
#include "hb-ot-shape.hh"
struct hb_aat_feature_mapping_t
{
hb_tag_t otFeatureTag;
hb_aat_layout_feature_type_t aatFeatureType;
hb_aat_layout_feature_selector_t selectorToEnable;
hb_aat_layout_feature_selector_t selectorToDisable;
int cmp(hb_tag_t key) const
{
return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0;
}
};
HB_INTERNAL const hb_aat_feature_mapping_t *hb_aat_layout_find_feature_mapping(hb_tag_t tag);
HB_INTERNAL void hb_aat_layout_compile_map(const hb_aat_map_builder_t *mapper, hb_aat_map_t *map);
HB_INTERNAL void hb_aat_layout_substitute(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
HB_INTERNAL void hb_aat_layout_zero_width_deleted_glyphs(hb_buffer_t *buffer);
HB_INTERNAL void hb_aat_layout_remove_deleted_glyphs(hb_buffer_t *buffer);
HB_INTERNAL void hb_aat_layout_position(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
HB_INTERNAL void hb_aat_layout_track(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
#endif /* HB_AAT_LAYOUT_HH */

View File

@ -0,0 +1,98 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2010,2011,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifndef HB_NO_AAT_SHAPE
#include "hb-aat-map.hh"
#include "hb-aat-layout.hh"
#include "hb-aat-layout-feat-table.hh"
void hb_aat_map_builder_t::add_feature(hb_tag_t tag, unsigned value)
{
if (!face->table.feat->has_data())
return;
if (tag == HB_TAG('a', 'a', 'l', 't')) {
if (!face->table.feat->exposes_feature(HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
return;
feature_info_t *info = features.push();
info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
info->setting = (hb_aat_layout_feature_selector_t)value;
info->seq = features.length;
info->is_exclusive = true;
return;
}
const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping(tag);
if (!mapping)
return;
const AAT::FeatureName *feature = &face->table.feat->get_feature(mapping->aatFeatureType);
if (!feature->has_data()) {
/* Special case: Chain::compile_flags will fall back to the deprecated version of
* small-caps if necessary, so we need to check for that possibility.
* https://github.com/harfbuzz/harfbuzz/issues/2307 */
if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS) {
feature = &face->table.feat->get_feature(HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
if (!feature->has_data())
return;
} else
return;
}
feature_info_t *info = features.push();
info->type = mapping->aatFeatureType;
info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
info->seq = features.length;
info->is_exclusive = feature->is_exclusive();
}
void hb_aat_map_builder_t::compile(hb_aat_map_t &m)
{
/* Sort features and merge duplicates */
if (features.length) {
features.qsort();
unsigned int j = 0;
for (unsigned int i = 1; i < features.length; i++)
if (features[i].type != features[j].type ||
/* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
* respectively, so we mask out the low-order bit when checking for "duplicates"
* (selectors referring to the same feature setting) here. */
(!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
features[++j] = features[i];
features.shrink(j + 1);
}
hb_aat_layout_compile_map(this, &m);
}
#endif

View File

@ -0,0 +1,97 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_MAP_HH
#define HB_AAT_MAP_HH
#include "hb.hh"
struct hb_aat_map_t
{
friend struct hb_aat_map_builder_t;
public:
void init()
{
memset(this, 0, sizeof(*this));
chain_flags.init();
}
void fini()
{
chain_flags.fini();
}
public:
hb_vector_t<hb_mask_t> chain_flags;
};
struct hb_aat_map_builder_t
{
public:
HB_INTERNAL hb_aat_map_builder_t(hb_face_t *face_, const hb_segment_properties_t *props_ HB_UNUSED)
: face(face_)
{
}
HB_INTERNAL void add_feature(hb_tag_t tag, unsigned int value = 1);
HB_INTERNAL void compile(hb_aat_map_t &m);
public:
struct feature_info_t
{
hb_aat_layout_feature_type_t type;
hb_aat_layout_feature_selector_t setting;
bool is_exclusive;
unsigned seq; /* For stable sorting only. */
HB_INTERNAL static int cmp(const void *pa, const void *pb)
{
const feature_info_t *a = (const feature_info_t *)pa;
const feature_info_t *b = (const feature_info_t *)pb;
if (a->type != b->type)
return (a->type < b->type ? -1 : 1);
if (!a->is_exclusive && (a->setting & ~1) != (b->setting & ~1))
return (a->setting < b->setting ? -1 : 1);
return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
}
/* compares type & setting only, not is_exclusive flag or seq number */
int cmp(const feature_info_t &f) const
{
return (f.type != type) ? (f.type < type ? -1 : 1)
: (f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0;
}
};
public:
hb_face_t *face;
public:
hb_sorted_vector_t<feature_info_t> features;
};
#endif /* HB_AAT_MAP_HH */

38
harfbuzz/src/hb-aat.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_H
#define HB_AAT_H
#define HB_AAT_H_IN
#include "hb.h"
#include "hb-aat-layout.h"
HB_BEGIN_DECLS
HB_END_DECLS
#undef HB_AAT_H_IN
#endif /* HB_AAT_H */

1099
harfbuzz/src/hb-algs.hh Normal file

File diff suppressed because it is too large Load Diff

451
harfbuzz/src/hb-array.hh Normal file
View File

@ -0,0 +1,451 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_ARRAY_HH
#define HB_ARRAY_HH
#include "hb.hh"
#include "hb-algs.hh"
#include "hb-iter.hh"
#include "hb-null.hh"
template <typename Type> struct hb_sorted_array_t;
template <typename Type> struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type &>
{
/*
* Constructors.
*/
hb_array_t()
: arrayZ(nullptr)
, length(0)
, backwards_length(0)
{
}
hb_array_t(Type *array_, unsigned int length_)
: arrayZ(array_)
, length(length_)
, backwards_length(0)
{
}
template <unsigned int length_>
hb_array_t(Type (&array_)[length_])
: arrayZ(array_)
, length(length_)
, backwards_length(0)
{
}
template <typename U, hb_enable_if(hb_is_cr_convertible(U, Type))>
hb_array_t(const hb_array_t<U> &o)
: hb_iter_with_fallback_t<hb_array_t, Type &>()
, arrayZ(o.arrayZ)
, length(o.length)
, backwards_length(o.backwards_length)
{
}
template <typename U, hb_enable_if(hb_is_cr_convertible(U, Type))> hb_array_t &operator=(const hb_array_t<U> &o)
{
arrayZ = o.arrayZ;
length = o.length;
backwards_length = o.backwards_length;
return *this;
}
/*
* Iterator implementation.
*/
typedef Type &__item_t__;
static constexpr bool is_random_access_iterator = true;
Type &__item_at__(unsigned i) const
{
if (unlikely(i >= length))
return CrapOrNull(Type);
return arrayZ[i];
}
void __forward__(unsigned n)
{
if (unlikely(n > length))
n = length;
length -= n;
backwards_length += n;
arrayZ += n;
}
void __rewind__(unsigned n)
{
if (unlikely(n > backwards_length))
n = backwards_length;
length += n;
backwards_length -= n;
arrayZ -= n;
}
unsigned __len__() const
{
return length;
}
/* Ouch. The operator== compares the contents of the array. For range-based for loops,
* it's best if we can just compare arrayZ, though comparing contents is still fast,
* but also would require that Type has operator==. As such, we optimize this operator
* for range-based for loop and just compare arrayZ. No need to compare length, as we
* assume we're only compared to .end(). */
bool operator!=(const hb_array_t &o) const
{
return arrayZ != o.arrayZ;
}
/* Extra operators.
*/
Type *operator&() const
{
return arrayZ;
}
operator hb_array_t<const Type>()
{
return hb_array_t<const Type>(arrayZ, length);
}
template <typename T> operator T *() const
{
return arrayZ;
}
HB_INTERNAL bool operator==(const hb_array_t &o) const;
uint32_t hash() const
{
uint32_t current = 0;
for (unsigned int i = 0; i < this->length; i++) {
current = current * 31 + hb_hash(this->arrayZ[i]);
}
return current;
}
/*
* Compare, Sort, and Search.
*/
/* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
int cmp(const hb_array_t &a) const
{
if (length != a.length)
return (int)a.length - (int)length;
return hb_memcmp(a.arrayZ, arrayZ, get_size());
}
HB_INTERNAL static int cmp(const void *pa, const void *pb)
{
hb_array_t *a = (hb_array_t *)pa;
hb_array_t *b = (hb_array_t *)pb;
return b->cmp(*a);
}
template <typename T> Type *lsearch(const T &x, Type *not_found = nullptr)
{
unsigned int count = length;
for (unsigned int i = 0; i < count; i++)
if (!this->arrayZ[i].cmp(x))
return &this->arrayZ[i];
return not_found;
}
template <typename T> const Type *lsearch(const T &x, const Type *not_found = nullptr) const
{
unsigned int count = length;
for (unsigned int i = 0; i < count; i++)
if (!this->arrayZ[i].cmp(x))
return &this->arrayZ[i];
return not_found;
}
hb_sorted_array_t<Type> qsort(int (*cmp_)(const void *, const void *))
{
if (likely(length))
hb_qsort(arrayZ, length, this->get_item_size(), cmp_);
return hb_sorted_array_t<Type>(*this);
}
hb_sorted_array_t<Type> qsort()
{
if (likely(length))
hb_qsort(arrayZ, length, this->get_item_size(), Type::cmp);
return hb_sorted_array_t<Type>(*this);
}
void qsort(unsigned int start, unsigned int end)
{
end = hb_min(end, length);
assert(start <= end);
if (likely(start < end))
hb_qsort(arrayZ + start, end - start, this->get_item_size(), Type::cmp);
}
/*
* Other methods.
*/
unsigned int get_size() const
{
return length * this->get_item_size();
}
/*
* Reverse the order of items in this array in the range [start, end).
*/
void reverse(unsigned start = 0, unsigned end = -1)
{
start = hb_min(start, length);
end = hb_min(end, length);
if (end < start + 2)
return;
for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
Type temp = arrayZ[rhs];
arrayZ[rhs] = arrayZ[lhs];
arrayZ[lhs] = temp;
}
}
hb_array_t sub_array(unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
{
if (!start_offset && !seg_count)
return *this;
unsigned int count = length;
if (unlikely(start_offset > count))
count = 0;
else
count -= start_offset;
if (seg_count)
count = *seg_count = hb_min(count, *seg_count);
return hb_array_t(arrayZ + start_offset, count);
}
hb_array_t sub_array(unsigned int start_offset, unsigned int seg_count) const
{
return sub_array(start_offset, &seg_count);
}
hb_array_t truncate(unsigned length) const
{
return sub_array(0, length);
}
template <typename T, unsigned P = sizeof(Type), hb_enable_if(P == 1)> const T *as() const
{
return length < hb_null_size(T) ? &Null(T) : reinterpret_cast<const T *>(arrayZ);
}
template <typename T, unsigned P = sizeof(Type), hb_enable_if(P == 1)>
bool check_range(const T *p, unsigned int size = T::static_size) const
{
return arrayZ <= ((const char *)p) && ((const char *)p) <= arrayZ + length &&
(unsigned int)(arrayZ + length - (const char *)p) >= size;
}
/* Only call if you allocated the underlying array using malloc() or similar. */
void free()
{
::free((void *)arrayZ);
arrayZ = nullptr;
length = 0;
}
template <typename hb_serialize_context_t> hb_array_t copy(hb_serialize_context_t *c) const
{
TRACE_SERIALIZE(this);
auto *out = c->start_embed(arrayZ);
if (unlikely(!c->extend_size(out, get_size())))
return_trace(hb_array_t());
for (unsigned i = 0; i < length; i++)
out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
return_trace(hb_array_t(out, length));
}
template <typename hb_sanitize_context_t> bool sanitize(hb_sanitize_context_t *c) const
{
return c->check_array(arrayZ, length);
}
/*
* Members
*/
public:
Type *arrayZ;
unsigned int length;
unsigned int backwards_length;
};
template <typename T> inline hb_array_t<T> hb_array(T *array, unsigned int length)
{
return hb_array_t<T>(array, length);
}
template <typename T, unsigned int length_> inline hb_array_t<T> hb_array(T (&array_)[length_])
{
return hb_array_t<T>(array_);
}
enum hb_bfind_not_found_t {
HB_BFIND_NOT_FOUND_DONT_STORE,
HB_BFIND_NOT_FOUND_STORE,
HB_BFIND_NOT_FOUND_STORE_CLOSEST,
};
template <typename Type> struct hb_sorted_array_t : hb_iter_t<hb_sorted_array_t<Type>, Type &>, hb_array_t<Type>
{
typedef hb_iter_t<hb_sorted_array_t, Type &> iter_base_t;
HB_ITER_USING(iter_base_t);
static constexpr bool is_random_access_iterator = true;
static constexpr bool is_sorted_iterator = true;
hb_sorted_array_t()
: hb_array_t<Type>()
{
}
hb_sorted_array_t(Type *array_, unsigned int length_)
: hb_array_t<Type>(array_, length_)
{
}
template <unsigned int length_>
hb_sorted_array_t(Type (&array_)[length_])
: hb_array_t<Type>(array_)
{
}
template <typename U, hb_enable_if(hb_is_cr_convertible(U, Type))>
hb_sorted_array_t(const hb_array_t<U> &o)
: hb_iter_t<hb_sorted_array_t, Type &>()
, hb_array_t<Type>(o)
{
}
template <typename U, hb_enable_if(hb_is_cr_convertible(U, Type))>
hb_sorted_array_t &operator=(const hb_array_t<U> &o)
{
hb_array_t<Type>(*this) = o;
return *this;
}
/* Iterator implementation. */
bool operator!=(const hb_sorted_array_t &o) const
{
return this->arrayZ != o.arrayZ || this->length != o.length;
}
hb_sorted_array_t sub_array(unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
{
return hb_sorted_array_t(((const hb_array_t<Type> *)(this))->sub_array(start_offset, seg_count));
}
hb_sorted_array_t sub_array(unsigned int start_offset, unsigned int seg_count) const
{
return sub_array(start_offset, &seg_count);
}
hb_sorted_array_t truncate(unsigned length) const
{
return sub_array(0, length);
}
template <typename T> Type *bsearch(const T &x, Type *not_found = nullptr)
{
unsigned int i;
return bfind(x, &i) ? &this->arrayZ[i] : not_found;
}
template <typename T> const Type *bsearch(const T &x, const Type *not_found = nullptr) const
{
unsigned int i;
return bfind(x, &i) ? &this->arrayZ[i] : not_found;
}
template <typename T>
bool bfind(const T &x,
unsigned int *i = nullptr,
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int)-1) const
{
unsigned pos;
if (bsearch_impl(x, &pos)) {
if (i)
*i = pos;
return true;
}
if (i) {
switch (not_found) {
case HB_BFIND_NOT_FOUND_DONT_STORE:
break;
case HB_BFIND_NOT_FOUND_STORE:
*i = to_store;
break;
case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
*i = pos;
break;
}
}
return false;
}
template <typename T> bool bsearch_impl(const T &x, unsigned *pos) const
{
return hb_bsearch_impl(pos, x, this->arrayZ, this->length, sizeof(Type), _hb_cmp_method<T, Type>);
}
};
template <typename T> inline hb_sorted_array_t<T> hb_sorted_array(T *array, unsigned int length)
{
return hb_sorted_array_t<T>(array, length);
}
template <typename T, unsigned int length_> inline hb_sorted_array_t<T> hb_sorted_array(T (&array_)[length_])
{
return hb_sorted_array_t<T>(array_);
}
template <typename T> bool hb_array_t<T>::operator==(const hb_array_t<T> &o) const
{
if (o.length != this->length)
return false;
for (unsigned int i = 0; i < this->length; i++) {
if (this->arrayZ[i] != o.arrayZ[i])
return false;
}
return true;
}
/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
template <> inline uint32_t hb_array_t<const char>::hash() const
{
uint32_t current = 0;
for (unsigned int i = 0; i < this->length; i++)
current = current * 31 + (uint32_t)(this->arrayZ[i] * 2654435761u);
return current;
}
template <> inline uint32_t hb_array_t<const unsigned char>::hash() const
{
uint32_t current = 0;
for (unsigned int i = 0; i < this->length; i++)
current = current * 31 + (uint32_t)(this->arrayZ[i] * 2654435761u);
return current;
}
typedef hb_array_t<const char> hb_bytes_t;
typedef hb_array_t<const unsigned char> hb_ubytes_t;
#endif /* HB_ARRAY_HH */

343
harfbuzz/src/hb-atomic.hh Normal file
View File

@ -0,0 +1,343 @@
/*
* Copyright © 2007 Chris Wilson
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_ATOMIC_HH
#define HB_ATOMIC_HH
#include "hb.hh"
#include "hb-meta.hh"
/*
* Atomic integers and pointers.
*/
/* We need external help for these */
#if defined(hb_atomic_int_impl_add) && defined(hb_atomic_ptr_impl_get) && defined(hb_atomic_ptr_impl_cmpexch)
/* Defined externally, i.e. in config.h. */
#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
/* C++11-style GCC primitives. */
#define _hb_memory_barrier() __sync_synchronize()
#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add((AI), (V), __ATOMIC_ACQ_REL)
#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n((AI), (V), __ATOMIC_RELAXED)
#define hb_atomic_int_impl_set(AI, V) __atomic_store_n((AI), (V), __ATOMIC_RELEASE)
#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n((AI), __ATOMIC_RELAXED)
#define hb_atomic_int_impl_get(AI) __atomic_load_n((AI), __ATOMIC_ACQUIRE)
#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n((P), (V), __ATOMIC_RELAXED)
#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n((P), __ATOMIC_RELAXED)
#define hb_atomic_ptr_impl_get(P) __atomic_load_n((P), __ATOMIC_ACQUIRE)
static inline bool _hb_atomic_ptr_impl_cmplexch(const void **P, const void *O_, const void *N)
{
const void *O = O_; // Need lvalue
return __atomic_compare_exchange_n((void **)P, (void **)&O, (void *)N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
}
#define hb_atomic_ptr_impl_cmpexch(P, O, N) _hb_atomic_ptr_impl_cmplexch((const void **)(P), (O), (N))
#elif !defined(HB_NO_MT) && __cplusplus >= 201103L
/* C++11 atomics. */
#include <atomic>
#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel)
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
#define hb_atomic_int_impl_add(AI, V) \
(reinterpret_cast<std::atomic<int> *>(AI)->fetch_add((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) \
(reinterpret_cast<std::atomic<int> *>(AI)->store((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *>(AI)->store((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) \
(reinterpret_cast<std::atomic<int> const *>(AI)->load(std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> const *>(AI)->load(std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) \
(reinterpret_cast<std::atomic<void *> *>(P)->store((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) \
(reinterpret_cast<std::atomic<void *> const *>(P)->load(std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void *> *>(P)->load(std::memory_order_acquire))
static inline bool _hb_atomic_ptr_impl_cmplexch(const void **P, const void *O_, const void *N)
{
const void *O = O_; // Need lvalue
return reinterpret_cast<std::atomic<const void *> *>(P)->compare_exchange_weak(
O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
}
#define hb_atomic_ptr_impl_cmpexch(P, O, N) _hb_atomic_ptr_impl_cmplexch((const void **)(P), (O), (N))
#elif !defined(HB_NO_MT) && defined(_WIN32)
#include <windows.h>
static inline void _hb_memory_barrier()
{
#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
/* MinGW has a convoluted history of supporting MemoryBarrier. */
LONG dummy = 0;
InterlockedExchange(&dummy, 1);
#else
MemoryBarrier();
#endif
}
#define _hb_memory_barrier() _hb_memory_barrier()
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd((LONG *)(AI), (V))
static_assert((sizeof(LONG) == sizeof(int)), "");
#define hb_atomic_ptr_impl_cmpexch(P, O, N) (InterlockedCompareExchangePointer((P), (N), (O)) == (O))
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
#define _hb_memory_barrier() __sync_synchronize()
#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add((AI), (V))
#define hb_atomic_ptr_impl_cmpexch(P, O, N) __sync_bool_compare_and_swap((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
#include <atomic.h>
#include <mbarrier.h>
#define _hb_memory_r_barrier() __machine_r_barrier()
#define _hb_memory_w_barrier() __machine_w_barrier()
#define _hb_memory_barrier() __machine_rw_barrier()
static inline int _hb_fetch_and_add(int *AI, int V)
{
_hb_memory_w_barrier();
int result = atomic_add_int_nv((uint_t *)AI, V) - V;
_hb_memory_r_barrier();
return result;
}
static inline bool _hb_compare_and_swap_ptr(void **P, void *O, void *N)
{
_hb_memory_w_barrier();
bool result = atomic_cas_ptr(P, O, N) == O;
_hb_memory_r_barrier();
return result;
}
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add((AI), (V))
#define hb_atomic_ptr_impl_cmpexch(P, O, N) _hb_compare_and_swap_ptr((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(__APPLE__)
#include <libkern/OSAtomic.h>
#ifdef __MAC_OS_X_MIN_REQUIRED
#include <AvailabilityMacros.h>
#elif defined(__IPHONE_OS_MIN_REQUIRED)
#include <Availability.h>
#endif
#define _hb_memory_barrier() OSMemoryBarrier()
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier((V), (AI)) - (V))
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_impl_cmpexch(P, O, N) OSAtomicCompareAndSwapPtrBarrier((O), (N), (P))
#else
#if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_impl_cmpexch(P, O, N) OSAtomicCompareAndSwap64Barrier((int64_t)(O), (int64_t)(N), (int64_t *)(P))
#else
#define hb_atomic_ptr_impl_cmpexch(P, O, N) OSAtomicCompareAndSwap32Barrier((int32_t)(O), (int32_t)(N), (int32_t *)(P))
#endif
#endif
#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
#include <builtins.h>
#define _hb_memory_barrier() __lwsync()
static inline int _hb_fetch_and_add(int *AI, int V)
{
_hb_memory_barrier();
int result = __fetch_and_add(AI, V);
_hb_memory_barrier();
return result;
}
static inline bool _hb_compare_and_swaplp(long *P, long O, long N)
{
_hb_memory_barrier();
bool result = __compare_and_swaplp(P, &O, N);
_hb_memory_barrier();
return result;
}
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add((AI), (V))
#define hb_atomic_ptr_impl_cmpexch(P, O, N) _hb_compare_and_swaplp((long *)(P), (long)(O), (long)(N))
static_assert((sizeof(long) == sizeof(void *)), "");
#elif defined(HB_NO_MT)
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
#define _hb_memory_barrier() \
do { \
} while (0)
#define hb_atomic_ptr_impl_cmpexch(P, O, N) (*(void **)(P) == (void *)(O) ? (*(void **)(P) = (void *)(N), true) : false)
#else
#error "Could not find any system to define atomic_int macros."
#error "Check hb-atomic.hh for possible resolutions."
#endif
#ifndef _hb_memory_r_barrier
#define _hb_memory_r_barrier() _hb_memory_barrier()
#endif
#ifndef _hb_memory_w_barrier
#define _hb_memory_w_barrier() _hb_memory_barrier()
#endif
#ifndef hb_atomic_int_impl_set_relaxed
#define hb_atomic_int_impl_set_relaxed(AI, V) (*(AI) = (V))
#endif
#ifndef hb_atomic_int_impl_get_relaxed
#define hb_atomic_int_impl_get_relaxed(AI) (*(AI))
#endif
#ifndef hb_atomic_ptr_impl_set_relaxed
#define hb_atomic_ptr_impl_set_relaxed(P, V) (*(P) = (V))
#endif
#ifndef hb_atomic_ptr_impl_get_relaxed
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
#endif
#ifndef hb_atomic_int_impl_set
inline void hb_atomic_int_impl_set(int *AI, int v)
{
_hb_memory_w_barrier();
*AI = v;
}
#endif
#ifndef hb_atomic_int_impl_get
inline int hb_atomic_int_impl_get(const int *AI)
{
int v = *AI;
_hb_memory_r_barrier();
return v;
}
#endif
#ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get(void **const P)
{
void *v = *P;
_hb_memory_r_barrier();
return v;
}
#endif
#define HB_ATOMIC_INT_INIT(V) \
{ \
V \
}
struct hb_atomic_int_t
{
void set_relaxed(int v_)
{
hb_atomic_int_impl_set_relaxed(&v, v_);
}
void set(int v_)
{
hb_atomic_int_impl_set(&v, v_);
}
int get_relaxed() const
{
return hb_atomic_int_impl_get_relaxed(&v);
}
int get() const
{
return hb_atomic_int_impl_get(&v);
}
int inc()
{
return hb_atomic_int_impl_add(&v, 1);
}
int dec()
{
return hb_atomic_int_impl_add(&v, -1);
}
int v;
};
#define HB_ATOMIC_PTR_INIT(V) \
{ \
V \
}
template <typename P> struct hb_atomic_ptr_t
{
typedef hb_remove_pointer<P> T;
void init(T *v_ = nullptr)
{
set_relaxed(v_);
}
void set_relaxed(T *v_)
{
hb_atomic_ptr_impl_set_relaxed(&v, v_);
}
T *get_relaxed() const
{
return (T *)hb_atomic_ptr_impl_get_relaxed(&v);
}
T *get() const
{
return (T *)hb_atomic_ptr_impl_get((void **)&v);
}
bool cmpexch(const T *old, T *new_) const
{
return hb_atomic_ptr_impl_cmpexch((void **)&v, (void *)old, (void *)new_);
}
T *operator->() const
{
return get();
}
template <typename C> operator C *() const
{
return get();
}
T *v;
};
#endif /* HB_ATOMIC_HH */

688
harfbuzz/src/hb-blob.cc Normal file
View File

@ -0,0 +1,688 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#include "hb-blob.hh"
#ifdef HAVE_SYS_MMAN_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <sys/mman.h>
#endif /* HAVE_SYS_MMAN_H */
#include <stdio.h>
#include <stdlib.h>
/**
* SECTION: hb-blob
* @title: hb-blob
* @short_description: Binary data containers
* @include: hb.h
*
* Blobs wrap a chunk of binary data to handle lifecycle management of data
* while it is passed between client and HarfBuzz. Blobs are primarily used
* to create font faces, but also to access font face tables, as well as
* pass around other binary data.
**/
/**
* hb_blob_create: (skip)
* @data: Pointer to blob data.
* @length: Length of @data in bytes.
* @mode: Memory mode for @data.
* @user_data: Data parameter to pass to @destroy.
* @destroy: Callback to call when @data is not needed anymore.
*
* Creates a new "blob" object wrapping @data. The @mode parameter is used
* to negotiate ownership and lifecycle of @data.
*
* Return value: New blob, or the empty blob if something failed or if @length is
* zero. Destroy with hb_blob_destroy().
*
* Since: 0.9.2
**/
hb_blob_t *
hb_blob_create(const char *data, unsigned int length, hb_memory_mode_t mode, void *user_data, hb_destroy_func_t destroy)
{
hb_blob_t *blob;
if (!length || length >= 1u << 31 || !(blob = hb_object_create<hb_blob_t>())) {
if (destroy)
destroy(user_data);
return hb_blob_get_empty();
}
blob->data = data;
blob->length = length;
blob->mode = mode;
blob->user_data = user_data;
blob->destroy = destroy;
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
blob->mode = HB_MEMORY_MODE_READONLY;
if (!blob->try_make_writable()) {
hb_blob_destroy(blob);
return hb_blob_get_empty();
}
}
return blob;
}
static void _hb_blob_destroy(void *data)
{
hb_blob_destroy((hb_blob_t *)data);
}
/**
* hb_blob_create_sub_blob:
* @parent: Parent blob.
* @offset: Start offset of sub-blob within @parent, in bytes.
* @length: Length of sub-blob.
*
* Returns a blob that represents a range of bytes in @parent. The new
* blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
* will never modify data in the parent blob. The parent data is not
* expected to be modified, and will result in undefined behavior if it
* is.
*
* Makes @parent immutable.
*
* Return value: New blob, or the empty blob if something failed or if
* @length is zero or @offset is beyond the end of @parent's data. Destroy
* with hb_blob_destroy().
*
* Since: 0.9.2
**/
hb_blob_t *hb_blob_create_sub_blob(hb_blob_t *parent, unsigned int offset, unsigned int length)
{
hb_blob_t *blob;
if (!length || !parent || offset >= parent->length)
return hb_blob_get_empty();
hb_blob_make_immutable(parent);
blob = hb_blob_create(parent->data + offset,
hb_min(length, parent->length - offset),
HB_MEMORY_MODE_READONLY,
hb_blob_reference(parent),
_hb_blob_destroy);
return blob;
}
/**
* hb_blob_copy_writable_or_fail:
* @blob: A blob.
*
* Makes a writable copy of @blob.
*
* Return value: New blob, or nullptr if allocation failed.
*
* Since: 1.8.0
**/
hb_blob_t *hb_blob_copy_writable_or_fail(hb_blob_t *blob)
{
blob = hb_blob_create(blob->data, blob->length, HB_MEMORY_MODE_DUPLICATE, nullptr, nullptr);
if (unlikely(blob == hb_blob_get_empty()))
blob = nullptr;
return blob;
}
/**
* hb_blob_get_empty:
*
* Returns the singleton empty blob.
*
* See TODO:link object types for more information.
*
* Return value: (transfer full): the empty blob.
*
* Since: 0.9.2
**/
hb_blob_t *hb_blob_get_empty()
{
return const_cast<hb_blob_t *>(&Null(hb_blob_t));
}
/**
* hb_blob_reference: (skip)
* @blob: a blob.
*
* Increases the reference count on @blob.
*
* See TODO:link object types for more information.
*
* Return value: @blob.
*
* Since: 0.9.2
**/
hb_blob_t *hb_blob_reference(hb_blob_t *blob)
{
return hb_object_reference(blob);
}
/**
* hb_blob_destroy: (skip)
* @blob: a blob.
*
* Decreases the reference count on @blob, and if it reaches zero, destroys
* @blob, freeing all memory, possibly calling the destroy-callback the blob
* was created for if it has not been called already.
*
* See TODO:link object types for more information.
*
* Since: 0.9.2
**/
void hb_blob_destroy(hb_blob_t *blob)
{
if (!hb_object_destroy(blob))
return;
blob->fini_shallow();
free(blob);
}
/**
* hb_blob_set_user_data: (skip)
* @blob: a blob.
* @key: key for data to set.
* @data: data to set.
* @destroy: callback to call when @data is not needed anymore.
* @replace: whether to replace an existing data with the same key.
*
* Return value:
*
* Since: 0.9.2
**/
hb_bool_t hb_blob_set_user_data(
hb_blob_t *blob, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace)
{
return hb_object_set_user_data(blob, key, data, destroy, replace);
}
/**
* hb_blob_get_user_data: (skip)
* @blob: a blob.
* @key: key for data to get.
*
*
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
void *hb_blob_get_user_data(hb_blob_t *blob, hb_user_data_key_t *key)
{
return hb_object_get_user_data(blob, key);
}
/**
* hb_blob_make_immutable:
* @blob: a blob.
*
*
*
* Since: 0.9.2
**/
void hb_blob_make_immutable(hb_blob_t *blob)
{
if (hb_object_is_immutable(blob))
return;
hb_object_make_immutable(blob);
}
/**
* hb_blob_is_immutable:
* @blob: a blob.
*
*
*
* Return value: TODO
*
* Since: 0.9.2
**/
hb_bool_t hb_blob_is_immutable(hb_blob_t *blob)
{
return hb_object_is_immutable(blob);
}
/**
* hb_blob_get_length:
* @blob: a blob.
*
*
*
* Return value: the length of blob data in bytes.
*
* Since: 0.9.2
**/
unsigned int hb_blob_get_length(hb_blob_t *blob)
{
return blob->length;
}
/**
* hb_blob_get_data:
* @blob: a blob.
* @length: (out):
*
*
*
* Returns: (transfer none) (array length=length):
*
* Since: 0.9.2
**/
const char *hb_blob_get_data(hb_blob_t *blob, unsigned int *length)
{
if (length)
*length = blob->length;
return blob->data;
}
/**
* hb_blob_get_data_writable:
* @blob: a blob.
* @length: (out): output length of the writable data.
*
* Tries to make blob data writable (possibly copying it) and
* return pointer to data.
*
* Fails if blob has been made immutable, or if memory allocation
* fails.
*
* Returns: (transfer none) (array length=length): Writable blob data,
* or %NULL if failed.
*
* Since: 0.9.2
**/
char *hb_blob_get_data_writable(hb_blob_t *blob, unsigned int *length)
{
if (!blob->try_make_writable()) {
if (length)
*length = 0;
return nullptr;
}
if (length)
*length = blob->length;
return const_cast<char *>(blob->data);
}
bool hb_blob_t::try_make_writable_inplace_unix()
{
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
uintptr_t pagesize = -1, mask, length;
const char *addr;
#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
pagesize = (uintptr_t)sysconf(_SC_PAGE_SIZE);
#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
pagesize = (uintptr_t)sysconf(_SC_PAGESIZE);
#elif defined(HAVE_GETPAGESIZE)
pagesize = (uintptr_t)getpagesize();
#endif
if ((uintptr_t)-1L == pagesize) {
DEBUG_MSG_FUNC(BLOB, this, "failed to get pagesize: %s", strerror(errno));
return false;
}
DEBUG_MSG_FUNC(BLOB, this, "pagesize is %lu", (unsigned long)pagesize);
mask = ~(pagesize - 1);
addr = (const char *)(((uintptr_t)this->data) & mask);
length = (const char *)(((uintptr_t)this->data + this->length + pagesize - 1) & mask) - addr;
DEBUG_MSG_FUNC(BLOB, this, "calling mprotect on [%p..%p] (%lu bytes)", addr, addr + length, (unsigned long)length);
if (-1 == mprotect((void *)addr, length, PROT_READ | PROT_WRITE)) {
DEBUG_MSG_FUNC(BLOB, this, "mprotect failed: %s", strerror(errno));
return false;
}
this->mode = HB_MEMORY_MODE_WRITABLE;
DEBUG_MSG_FUNC(
BLOB, this, "successfully made [%p..%p] (%lu bytes) writable\n", addr, addr + length, (unsigned long)length);
return true;
#else
return false;
#endif
}
bool hb_blob_t::try_make_writable_inplace()
{
DEBUG_MSG_FUNC(BLOB, this, "making writable inplace\n");
if (this->try_make_writable_inplace_unix())
return true;
DEBUG_MSG_FUNC(BLOB, this, "making writable -> FAILED\n");
/* Failed to make writable inplace, mark that */
this->mode = HB_MEMORY_MODE_READONLY;
return false;
}
bool hb_blob_t::try_make_writable()
{
if (hb_object_is_immutable(this))
return false;
if (this->mode == HB_MEMORY_MODE_WRITABLE)
return true;
if (this->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && this->try_make_writable_inplace())
return true;
if (this->mode == HB_MEMORY_MODE_WRITABLE)
return true;
DEBUG_MSG_FUNC(BLOB, this, "current data is -> %p\n", this->data);
char *new_data;
new_data = (char *)malloc(this->length);
if (unlikely(!new_data))
return false;
DEBUG_MSG_FUNC(BLOB, this, "dupped successfully -> %p\n", this->data);
memcpy(new_data, this->data, this->length);
this->destroy_user_data();
this->mode = HB_MEMORY_MODE_WRITABLE;
this->data = new_data;
this->user_data = new_data;
this->destroy = free;
return true;
}
/*
* Mmap
*/
#ifndef HB_NO_OPEN
#ifdef HAVE_MMAP
#if !defined(HB_NO_RESOURCE_FORK) && defined(__APPLE__)
#include <sys/paths.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#ifdef _WIN32
#include <windows.h>
#else
#ifndef O_BINARY
#define O_BINARY 0
#endif
#endif
#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0
#endif
struct hb_mapped_file_t
{
char *contents;
unsigned long length;
#ifdef _WIN32
HANDLE mapping;
#endif
};
#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP)
static void _hb_mapped_file_destroy(void *file_)
{
hb_mapped_file_t *file = (hb_mapped_file_t *)file_;
#ifdef HAVE_MMAP
munmap(file->contents, file->length);
#elif defined(_WIN32)
UnmapViewOfFile(file->contents);
CloseHandle(file->mapping);
#else
assert(0); // If we don't have mmap we shouldn't reach here
#endif
free(file);
}
#endif
#ifdef _PATH_RSRCFORKSPEC
static int _open_resource_fork(const char *file_name, hb_mapped_file_t *file)
{
size_t name_len = strlen(file_name);
size_t len = name_len + sizeof(_PATH_RSRCFORKSPEC);
char *rsrc_name = (char *)malloc(len);
if (unlikely(!rsrc_name))
return -1;
strncpy(rsrc_name, file_name, name_len);
strncpy(rsrc_name + name_len, _PATH_RSRCFORKSPEC, sizeof(_PATH_RSRCFORKSPEC) - 1);
int fd = open(rsrc_name, O_RDONLY | O_BINARY, 0);
free(rsrc_name);
if (fd != -1) {
struct stat st;
if (fstat(fd, &st) != -1)
file->length = (unsigned long)st.st_size;
else {
close(fd);
fd = -1;
}
}
return fd;
}
#endif
/**
* hb_blob_create_from_file:
* @file_name: font filename.
*
* Returns: A hb_blob_t pointer with the content of the file
*
* Since: 1.7.7
**/
hb_blob_t *hb_blob_create_from_file(const char *file_name)
{
/* Adopted from glib's gmappedfile.c with Matthias Clasen and
Allison Lortie permission but changed a lot to suit our need. */
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *)calloc(1, sizeof(hb_mapped_file_t));
if (unlikely(!file))
return hb_blob_get_empty();
int fd = open(file_name, O_RDONLY | O_BINARY, 0);
if (unlikely(fd == -1))
goto fail_without_close;
struct stat st;
if (unlikely(fstat(fd, &st) == -1))
goto fail;
file->length = (unsigned long)st.st_size;
#ifdef _PATH_RSRCFORKSPEC
if (unlikely(file->length == 0)) {
int rfd = _open_resource_fork(file_name, file);
if (rfd != -1) {
close(fd);
fd = rfd;
}
}
#endif
file->contents = (char *)mmap(nullptr, file->length, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
if (unlikely(file->contents == MAP_FAILED))
goto fail;
close(fd);
return hb_blob_create(file->contents,
file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
(void *)file,
(hb_destroy_func_t)_hb_mapped_file_destroy);
fail:
close(fd);
fail_without_close:
free(file);
#elif defined(_WIN32) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *)calloc(1, sizeof(hb_mapped_file_t));
if (unlikely(!file))
return hb_blob_get_empty();
HANDLE fd;
unsigned int size = strlen(file_name) + 1;
wchar_t *wchar_file_name = (wchar_t *)malloc(sizeof(wchar_t) * size);
if (unlikely(!wchar_file_name))
goto fail_without_close;
mbstowcs(wchar_file_name, file_name, size);
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
{
CREATEFILE2_EXTENDED_PARAMETERS ceparams = {0};
ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF;
ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000;
ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000;
ceparams.lpSecurityAttributes = nullptr;
ceparams.hTemplateFile = nullptr;
fd = CreateFile2(wchar_file_name, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &ceparams);
}
#else
fd = CreateFileW(wchar_file_name,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
nullptr);
#endif
free(wchar_file_name);
if (unlikely(fd == INVALID_HANDLE_VALUE))
goto fail_without_close;
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
{
LARGE_INTEGER length;
GetFileSizeEx(fd, &length);
file->length = length.LowPart;
file->mapping = CreateFileMappingFromApp(fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr);
}
#else
file->length = (unsigned long)GetFileSize(fd, nullptr);
file->mapping = CreateFileMapping(fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
#endif
if (unlikely(!file->mapping))
goto fail;
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
file->contents = (char *)MapViewOfFileFromApp(file->mapping, FILE_MAP_READ, 0, 0);
#else
file->contents = (char *)MapViewOfFile(file->mapping, FILE_MAP_READ, 0, 0, 0);
#endif
if (unlikely(!file->contents))
goto fail;
CloseHandle(fd);
return hb_blob_create(file->contents,
file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
(void *)file,
(hb_destroy_func_t)_hb_mapped_file_destroy);
fail:
CloseHandle(fd);
fail_without_close:
free(file);
#endif
/* The following tries to read a file without knowing its size beforehand
It's used as a fallback for systems without mmap or to read from pipes */
unsigned long len = 0, allocated = BUFSIZ * 16;
char *data = (char *)malloc(allocated);
if (unlikely(!data))
return hb_blob_get_empty();
FILE *fp = fopen(file_name, "rb");
if (unlikely(!fp))
goto fread_fail_without_close;
while (!feof(fp)) {
if (allocated - len < BUFSIZ) {
allocated *= 2;
/* Don't allocate and go more than ~536MB, our mmap reader still
can cover files like that but lets limit our fallback reader */
if (unlikely(allocated > (2 << 28)))
goto fread_fail;
char *new_data = (char *)realloc(data, allocated);
if (unlikely(!new_data))
goto fread_fail;
data = new_data;
}
unsigned long addition = fread(data + len, 1, allocated - len, fp);
int err = ferror(fp);
#ifdef EINTR // armcc doesn't have it
if (unlikely(err == EINTR))
continue;
#endif
if (unlikely(err))
goto fread_fail;
len += addition;
}
fclose(fp);
return hb_blob_create(data, len, HB_MEMORY_MODE_WRITABLE, data, (hb_destroy_func_t)free);
fread_fail:
fclose(fp);
fread_fail_without_close:
free(data);
return hb_blob_get_empty();
}
#endif /* !HB_NO_OPEN */

104
harfbuzz/src/hb-blob.h Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright © 2009 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_BLOB_H
#define HB_BLOB_H
#include "hb-common.h"
HB_BEGIN_DECLS
/*
* Note re various memory-modes:
*
* - In no case shall the HarfBuzz client modify memory
* that is passed to HarfBuzz in a blob. If there is
* any such possibility, MODE_DUPLICATE should be used
* such that HarfBuzz makes a copy immediately,
*
* - Use MODE_READONLY otherwise, unless you really really
* really know what you are doing,
*
* - MODE_WRITABLE is appropriate if you really made a
* copy of data solely for the purpose of passing to
* HarfBuzz and doing that just once (no reuse!),
*
* - If the font is mmap()ed, it's ok to use
* READONLY_MAY_MAKE_WRITABLE, however, using that mode
* correctly is very tricky. Use MODE_READONLY instead.
*/
typedef enum {
HB_MEMORY_MODE_DUPLICATE,
HB_MEMORY_MODE_READONLY,
HB_MEMORY_MODE_WRITABLE,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
} hb_memory_mode_t;
typedef struct hb_blob_t hb_blob_t;
HB_EXTERN hb_blob_t *hb_blob_create(
const char *data, unsigned int length, hb_memory_mode_t mode, void *user_data, hb_destroy_func_t destroy);
HB_EXTERN hb_blob_t *hb_blob_create_from_file(const char *file_name);
/* Always creates with MEMORY_MODE_READONLY.
* Even if the parent blob is writable, we don't
* want the user of the sub-blob to be able to
* modify the parent data as that data may be
* shared among multiple sub-blobs.
*/
HB_EXTERN hb_blob_t *hb_blob_create_sub_blob(hb_blob_t *parent, unsigned int offset, unsigned int length);
HB_EXTERN hb_blob_t *hb_blob_copy_writable_or_fail(hb_blob_t *blob);
HB_EXTERN hb_blob_t *hb_blob_get_empty(void);
HB_EXTERN hb_blob_t *hb_blob_reference(hb_blob_t *blob);
HB_EXTERN void hb_blob_destroy(hb_blob_t *blob);
HB_EXTERN hb_bool_t hb_blob_set_user_data(
hb_blob_t *blob, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
HB_EXTERN void *hb_blob_get_user_data(hb_blob_t *blob, hb_user_data_key_t *key);
HB_EXTERN void hb_blob_make_immutable(hb_blob_t *blob);
HB_EXTERN hb_bool_t hb_blob_is_immutable(hb_blob_t *blob);
HB_EXTERN unsigned int hb_blob_get_length(hb_blob_t *blob);
HB_EXTERN const char *hb_blob_get_data(hb_blob_t *blob, unsigned int *length);
HB_EXTERN char *hb_blob_get_data_writable(hb_blob_t *blob, unsigned int *length);
HB_END_DECLS
#endif /* HB_BLOB_H */

131
harfbuzz/src/hb-blob.hh Normal file
View File

@ -0,0 +1,131 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BLOB_HH
#define HB_BLOB_HH
#include "hb.hh"
/*
* hb_blob_t
*/
struct hb_blob_t
{
void fini_shallow()
{
destroy_user_data();
}
void destroy_user_data()
{
if (destroy) {
destroy(user_data);
user_data = nullptr;
destroy = nullptr;
}
}
HB_INTERNAL bool try_make_writable();
HB_INTERNAL bool try_make_writable_inplace();
HB_INTERNAL bool try_make_writable_inplace_unix();
hb_bytes_t as_bytes() const
{
return hb_bytes_t(data, length);
}
template <typename Type> const Type *as() const
{
return as_bytes().as<Type>();
}
public:
hb_object_header_t header;
const char *data;
unsigned int length;
hb_memory_mode_t mode;
void *user_data;
hb_destroy_func_t destroy;
};
/*
* hb_blob_ptr_t
*/
template <typename P> struct hb_blob_ptr_t
{
typedef hb_remove_pointer<P> T;
hb_blob_ptr_t(hb_blob_t *b_ = nullptr)
: b(b_)
{
}
hb_blob_t *operator=(hb_blob_t *b_)
{
return b = b_;
}
const T *operator->() const
{
return get();
}
const T &operator*() const
{
return *get();
}
template <typename C> operator const C *() const
{
return get();
}
operator const char *() const
{
return (const char *)get();
}
const T *get() const
{
return b->as<T>();
}
hb_blob_t *get_blob() const
{
return b.get_raw();
}
unsigned int get_length() const
{
return b.get()->length;
}
void destroy()
{
hb_blob_destroy(b.get());
b = nullptr;
}
hb_nonnull_ptr_t<hb_blob_t> b;
};
#endif /* HB_BLOB_HH */

View File

@ -0,0 +1,368 @@
/*
* Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifndef HB_NO_BUFFER_SERIALIZE
#include "hb-buffer.hh"
static const char *serialize_formats[] = {"text", "json", nullptr};
/**
* hb_buffer_serialize_list_formats:
*
* Returns a list of supported buffer serialization formats.
*
* Return value: (transfer none):
* A string array of buffer serialization formats. Should not be freed.
*
* Since: 0.9.7
**/
const char **hb_buffer_serialize_list_formats()
{
return serialize_formats;
}
/**
* hb_buffer_serialize_format_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
* @len: length of @str, or -1 if string is %NULL terminated
*
* Parses a string into an #hb_buffer_serialize_format_t. Does not check if
* @str is a valid buffer serialization format, use
* hb_buffer_serialize_list_formats() to get the list of supported formats.
*
* Return value:
* The parsed #hb_buffer_serialize_format_t.
*
* Since: 0.9.7
**/
hb_buffer_serialize_format_t hb_buffer_serialize_format_from_string(const char *str, int len)
{
/* Upper-case it. */
return (hb_buffer_serialize_format_t)(hb_tag_from_string(str, len) & ~0x20202020u);
}
/**
* hb_buffer_serialize_format_to_string:
* @format: an #hb_buffer_serialize_format_t to convert.
*
* Converts @format to the string corresponding it, or %NULL if it is not a valid
* #hb_buffer_serialize_format_t.
*
* Return value: (transfer none):
* A %NULL terminated string corresponding to @format. Should not be freed.
*
* Since: 0.9.7
**/
const char *hb_buffer_serialize_format_to_string(hb_buffer_serialize_format_t format)
{
switch ((unsigned)format) {
case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return serialize_formats[0];
case HB_BUFFER_SERIALIZE_FORMAT_JSON:
return serialize_formats[1];
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
return nullptr;
}
}
static unsigned int _hb_buffer_serialize_glyphs_json(hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, nullptr);
hb_glyph_position_t *pos =
(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? nullptr : hb_buffer_get_glyph_positions(buffer, nullptr);
*buf_consumed = 0;
hb_position_t x = 0, y = 0;
for (unsigned int i = start; i < end; i++) {
char b[1024];
char *p = b;
/* In the following code, we know b is large enough that no overflow can happen. */
#define APPEND(s) \
HB_STMT_START \
{ \
strcpy(p, s); \
p += strlen(s); \
} \
HB_STMT_END
if (i)
*p++ = ',';
*p++ = '{';
APPEND("\"g\":");
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) {
char g[128];
hb_font_glyph_to_string(font, info[i].codepoint, g, sizeof(g));
*p++ = '"';
for (char *q = g; *q; q++) {
if (*q == '"')
*p++ = '\\';
*p++ = *q;
}
*p++ = '"';
} else
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), "%u", info[i].codepoint));
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), ",\"cl\":%u", info[i].cluster));
}
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) {
p += hb_max(
0,
snprintf(
p, ARRAY_LENGTH(b) - (p - b), ",\"dx\":%d,\"dy\":%d", x + pos[i].x_offset, y + pos[i].y_offset));
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
p += hb_max(
0,
snprintf(p, ARRAY_LENGTH(b) - (p - b), ",\"ax\":%d,\"ay\":%d", pos[i].x_advance, pos[i].y_advance));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) {
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
p += hb_max(0,
snprintf(p, ARRAY_LENGTH(b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) {
hb_glyph_extents_t extents;
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += hb_max(
0,
snprintf(p, ARRAY_LENGTH(b) - (p - b), ",\"xb\":%d,\"yb\":%d", extents.x_bearing, extents.y_bearing));
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), ",\"w\":%d,\"h\":%d", extents.width, extents.height));
}
*p++ = '}';
unsigned int l = p - b;
if (buf_size > l) {
memcpy(buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
*buf = '\0';
} else
return i - start;
if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) {
x += pos[i].x_advance;
y += pos[i].y_advance;
}
}
return end - start;
}
static unsigned int _hb_buffer_serialize_glyphs_text(hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, nullptr);
hb_glyph_position_t *pos =
(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? nullptr : hb_buffer_get_glyph_positions(buffer, nullptr);
*buf_consumed = 0;
hb_position_t x = 0, y = 0;
for (unsigned int i = start; i < end; i++) {
char b[1024];
char *p = b;
/* In the following code, we know b is large enough that no overflow can happen. */
if (i)
*p++ = '|';
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) {
hb_font_glyph_to_string(font, info[i].codepoint, p, 128);
p += strlen(p);
} else
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), "%u", info[i].codepoint));
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), "=%u", info[i].cluster));
}
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) {
if (x + pos[i].x_offset || y + pos[i].y_offset)
p += hb_max(0,
snprintf(p, ARRAY_LENGTH(b) - (p - b), "@%d,%d", x + pos[i].x_offset, y + pos[i].y_offset));
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) {
*p++ = '+';
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), "%d", pos[i].x_advance));
if (pos[i].y_advance)
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), ",%d", pos[i].y_advance));
}
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) {
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
p += hb_max(0, snprintf(p, ARRAY_LENGTH(b) - (p - b), "#%X", info[i].mask & HB_GLYPH_FLAG_DEFINED));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) {
hb_glyph_extents_t extents;
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += hb_max(0,
snprintf(p,
ARRAY_LENGTH(b) - (p - b),
"<%d,%d,%d,%d>",
extents.x_bearing,
extents.y_bearing,
extents.width,
extents.height));
}
unsigned int l = p - b;
if (buf_size > l) {
memcpy(buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
*buf = '\0';
} else
return i - start;
if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) {
x += pos[i].x_advance;
y += pos[i].y_advance;
}
}
return end - start;
}
/**
* hb_buffer_serialize_glyphs:
* @buffer: an #hb_buffer_t buffer.
* @start: the first item in @buffer to serialize.
* @end: the last item in @buffer to serialize.
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
* @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
* @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
* read glyph names and extents. If %NULL, and empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
* to serialize.
*
* Serializes @buffer into a textual representation of its glyph content,
* useful for showing the contents of the buffer, for example during debugging.
* There are currently two supported serialization formats:
*
* ## text
* A human-readable, plain text format.
* The serialized glyphs will look something like:
*
* ```
* [uni0651=0@518,0+0|uni0628=0+1897]
* ```
* - The serialized glyphs are delimited with `[` and `]`.
* - Glyphs are separated with `|`
* - Each glyph starts with glyph name, or glyph index if
* #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
* - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
* - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
* - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
* - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
* - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
* #hb_glyph_extents_t in the format
* `&lt;x_bearing,y_bearing,width,height&gt;`
*
* ## json
* TODO.
*
* Return value:
* The number of serialized items.
*
* Since: 0.9.7
**/
unsigned int hb_buffer_serialize_glyphs(hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags)
{
assert(start <= end && end <= buffer->len);
unsigned int sconsumed;
if (!buf_consumed)
buf_consumed = &sconsumed;
*buf_consumed = 0;
if (buf_size)
*buf = '\0';
assert((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
if (!buffer->have_positions)
flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
if (unlikely(start == end))
return 0;
if (!font)
font = hb_font_get_empty();
switch (format) {
case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return _hb_buffer_serialize_glyphs_text(buffer, start, end, buf, buf_size, buf_consumed, font, flags);
case HB_BUFFER_SERIALIZE_FORMAT_JSON:
return _hb_buffer_serialize_glyphs_json(buffer, start, end, buf, buf_size, buf_consumed, font, flags);
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
return 0;
}
}
#endif

1730
harfbuzz/src/hb-buffer.cc Normal file

File diff suppressed because it is too large Load Diff

458
harfbuzz/src/hb-buffer.h Normal file
View File

@ -0,0 +1,458 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Owen Taylor, Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_BUFFER_H
#define HB_BUFFER_H
#include "hb-common.h"
#include "hb-unicode.h"
#include "hb-font.h"
HB_BEGIN_DECLS
/**
* hb_glyph_info_t:
* @codepoint: either a Unicode code point (before shaping) or a glyph index
* (after shaping).
* @cluster: the index of the character in the original text that corresponds
* to this #hb_glyph_info_t, or whatever the client passes to
* hb_buffer_add(). More than one #hb_glyph_info_t can have the same
* @cluster value, if they resulted from the same character (e.g. one
* to many glyph substitution), and when more than one character gets
* merged in the same glyph (e.g. many to one glyph substitution) the
* #hb_glyph_info_t will have the smallest cluster value of them.
* By default some characters are merged into the same cluster
* (e.g. combining marks have the same cluster as their bases)
* even if they are separate glyphs, hb_buffer_set_cluster_level()
* allow selecting more fine-grained cluster handling.
*
* The #hb_glyph_info_t is the structure that holds information about the
* glyphs and their relation to input text.
*/
typedef struct hb_glyph_info_t
{
hb_codepoint_t codepoint;
/*< private >*/
hb_mask_t mask;
/*< public >*/
uint32_t cluster;
/*< private >*/
hb_var_int_t var1;
hb_var_int_t var2;
} hb_glyph_info_t;
/**
* hb_glyph_flags_t:
* @HB_GLYPH_FLAG_UNSAFE_TO_BREAK: Indicates that if input text is broken at the
* beginning of the cluster this glyph is part of,
* then both sides need to be re-shaped, as the
* result might be different. On the flip side,
* it means that when this flag is not present,
* then it's safe to break the glyph-run at the
* beginning of this cluster, and the two sides
* represent the exact same result one would get
* if breaking input text at the beginning of
* this cluster and shaping the two sides
* separately. This can be used to optimize
* paragraph layout, by avoiding re-shaping
* of each line after line-breaking, or limiting
* the reshaping to a small piece around the
* breaking point only.
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
* Since: 1.5.0
*/
typedef enum { /*< flags >*/
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */
} hb_glyph_flags_t;
HB_EXTERN hb_glyph_flags_t hb_glyph_info_get_glyph_flags(const hb_glyph_info_t *info);
#define hb_glyph_info_get_glyph_flags(info) ((hb_glyph_flags_t)((unsigned int)(info)->mask & HB_GLYPH_FLAG_DEFINED))
/**
* hb_glyph_position_t:
* @x_advance: how much the line advances after drawing this glyph when setting
* text in horizontal direction.
* @y_advance: how much the line advances after drawing this glyph when setting
* text in vertical direction.
* @x_offset: how much the glyph moves on the X-axis before drawing it, this
* should not affect how much the line advances.
* @y_offset: how much the glyph moves on the Y-axis before drawing it, this
* should not affect how much the line advances.
*
* The #hb_glyph_position_t is the structure that holds the positions of the
* glyph in both horizontal and vertical directions. All positions in
* #hb_glyph_position_t are relative to the current point.
*
*/
typedef struct hb_glyph_position_t
{
hb_position_t x_advance;
hb_position_t y_advance;
hb_position_t x_offset;
hb_position_t y_offset;
/*< private >*/
hb_var_int_t var;
} hb_glyph_position_t;
/**
* hb_segment_properties_t:
* @direction: the #hb_direction_t of the buffer, see hb_buffer_set_direction().
* @script: the #hb_script_t of the buffer, see hb_buffer_set_script().
* @language: the #hb_language_t of the buffer, see hb_buffer_set_language().
*
* The structure that holds various text properties of an #hb_buffer_t. Can be
* set and retrieved using hb_buffer_set_segment_properties() and
* hb_buffer_get_segment_properties(), respectively.
*/
typedef struct hb_segment_properties_t
{
hb_direction_t direction;
hb_script_t script;
hb_language_t language;
/*< private >*/
void *reserved1;
void *reserved2;
} hb_segment_properties_t;
#define HB_SEGMENT_PROPERTIES_DEFAULT \
{ \
HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID, (void *)0, (void *)0 \
}
HB_EXTERN hb_bool_t hb_segment_properties_equal(const hb_segment_properties_t *a, const hb_segment_properties_t *b);
HB_EXTERN unsigned int hb_segment_properties_hash(const hb_segment_properties_t *p);
/**
* hb_buffer_t:
*
* The main structure holding the input text and its properties before shaping,
* and output glyphs and their information after shaping.
*/
typedef struct hb_buffer_t hb_buffer_t;
HB_EXTERN hb_buffer_t *hb_buffer_create(void);
HB_EXTERN hb_buffer_t *hb_buffer_get_empty(void);
HB_EXTERN hb_buffer_t *hb_buffer_reference(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_destroy(hb_buffer_t *buffer);
HB_EXTERN hb_bool_t hb_buffer_set_user_data(
hb_buffer_t *buffer, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
HB_EXTERN void *hb_buffer_get_user_data(hb_buffer_t *buffer, hb_user_data_key_t *key);
/**
* hb_buffer_content_type_t:
* @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
* @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
* @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
*/
typedef enum {
HB_BUFFER_CONTENT_TYPE_INVALID = 0,
HB_BUFFER_CONTENT_TYPE_UNICODE,
HB_BUFFER_CONTENT_TYPE_GLYPHS
} hb_buffer_content_type_t;
HB_EXTERN void hb_buffer_set_content_type(hb_buffer_t *buffer, hb_buffer_content_type_t content_type);
HB_EXTERN hb_buffer_content_type_t hb_buffer_get_content_type(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_set_unicode_funcs(hb_buffer_t *buffer, hb_unicode_funcs_t *unicode_funcs);
HB_EXTERN hb_unicode_funcs_t *hb_buffer_get_unicode_funcs(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_set_direction(hb_buffer_t *buffer, hb_direction_t direction);
HB_EXTERN hb_direction_t hb_buffer_get_direction(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_set_script(hb_buffer_t *buffer, hb_script_t script);
HB_EXTERN hb_script_t hb_buffer_get_script(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_set_language(hb_buffer_t *buffer, hb_language_t language);
HB_EXTERN hb_language_t hb_buffer_get_language(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_set_segment_properties(hb_buffer_t *buffer, const hb_segment_properties_t *props);
HB_EXTERN void hb_buffer_get_segment_properties(hb_buffer_t *buffer, hb_segment_properties_t *props);
HB_EXTERN void hb_buffer_guess_segment_properties(hb_buffer_t *buffer);
/**
* hb_buffer_flags_t:
* @HB_BUFFER_FLAG_DEFAULT: the default buffer flag.
* @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning
* of text paragraph can be applied to this buffer. Should usually
* be set, unless you are passing to the buffer only part
* of the text without the full context.
* @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
* paragraph can be applied to this buffer, similar to
* @HB_BUFFER_FLAG_BOT.
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
* flag indication that character with Default_Ignorable
* Unicode property should use the corresponding glyph
* from the font, instead of hiding them (done by
* replacing them with the space glyph and zeroing the
* advance width.) This flag takes precedence over
* @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES.
* @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES:
* flag indication that character with Default_Ignorable
* Unicode property should be removed from glyph string
* instead of hiding them (done by replacing them with the
* space glyph and zeroing the advance width.)
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
* precedence over this flag. Since: 1.8.0
* @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
* flag indicating that a dotted circle should
* not be inserted in the rendering of incorrect
* character sequences (such at <0905 093E>). Since: 2.4
*
* Since: 0.9.20
*/
typedef enum { /*< flags >*/
HB_BUFFER_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
} hb_buffer_flags_t;
HB_EXTERN void hb_buffer_set_flags(hb_buffer_t *buffer, hb_buffer_flags_t flags);
HB_EXTERN hb_buffer_flags_t hb_buffer_get_flags(hb_buffer_t *buffer);
/**
* hb_buffer_cluster_level_t:
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: Return cluster values grouped by graphemes into
* monotone order.
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: Return cluster values grouped into monotone order.
* @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
* @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
* equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
*
* Since: 0.9.42
*/
typedef enum {
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0,
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1,
HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
} hb_buffer_cluster_level_t;
HB_EXTERN void hb_buffer_set_cluster_level(hb_buffer_t *buffer, hb_buffer_cluster_level_t cluster_level);
HB_EXTERN hb_buffer_cluster_level_t hb_buffer_get_cluster_level(hb_buffer_t *buffer);
/**
* HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
*
* The default code point for replacing invalid characters in a given encoding.
* Set to U+FFFD REPLACEMENT CHARACTER.
*
* Since: 0.9.31
*/
#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
HB_EXTERN void hb_buffer_set_replacement_codepoint(hb_buffer_t *buffer, hb_codepoint_t replacement);
HB_EXTERN hb_codepoint_t hb_buffer_get_replacement_codepoint(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_set_invisible_glyph(hb_buffer_t *buffer, hb_codepoint_t invisible);
HB_EXTERN hb_codepoint_t hb_buffer_get_invisible_glyph(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_reset(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_clear_contents(hb_buffer_t *buffer);
HB_EXTERN hb_bool_t hb_buffer_pre_allocate(hb_buffer_t *buffer, unsigned int size);
HB_EXTERN hb_bool_t hb_buffer_allocation_successful(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_reverse(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_reverse_range(hb_buffer_t *buffer, unsigned int start, unsigned int end);
HB_EXTERN void hb_buffer_reverse_clusters(hb_buffer_t *buffer);
HB_EXTERN void hb_buffer_reset_clusters(hb_buffer_t *buffer);
/* Filling the buffer in */
HB_EXTERN void hb_buffer_add(hb_buffer_t *buffer, hb_codepoint_t codepoint, unsigned int cluster);
HB_EXTERN void
hb_buffer_add_utf8(hb_buffer_t *buffer, const char *text, int text_length, unsigned int item_offset, int item_length);
HB_EXTERN void hb_buffer_append(hb_buffer_t *buffer, hb_buffer_t *source, unsigned int start, unsigned int end);
HB_EXTERN hb_bool_t hb_buffer_set_length(hb_buffer_t *buffer, unsigned int length);
HB_EXTERN unsigned int hb_buffer_get_length(hb_buffer_t *buffer);
/* Getting glyphs out of the buffer */
HB_EXTERN hb_glyph_info_t *hb_buffer_get_glyph_infos(hb_buffer_t *buffer, unsigned int *length);
HB_EXTERN hb_glyph_position_t *hb_buffer_get_glyph_positions(hb_buffer_t *buffer, unsigned int *length);
HB_EXTERN void hb_buffer_normalize_glyphs(hb_buffer_t *buffer);
/*
* Serialize
*/
/**
* hb_buffer_serialize_flags_t:
* @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions.
* @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster.
* @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
* @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0
* @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances,
* glyph offsets will reflect absolute glyph positions. Since: 1.8.0
*
* Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
*
* Since: 0.9.20
*/
typedef enum { /*< flags >*/
HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u,
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u,
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS = 0x00000010u,
HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES = 0x00000020u
} hb_buffer_serialize_flags_t;
/**
* hb_buffer_serialize_format_t:
* @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format.
* @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format.
* @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format.
*
* The buffer serialization and de-serialization format used in
* hb_buffer_serialize_glyphs() and hb_buffer_deserialize_glyphs().
*
* Since: 0.9.2
*/
typedef enum {
HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T', 'E', 'X', 'T'),
HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J', 'S', 'O', 'N'),
HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE
} hb_buffer_serialize_format_t;
HB_EXTERN hb_buffer_serialize_format_t hb_buffer_serialize_format_from_string(const char *str, int len);
HB_EXTERN const char *hb_buffer_serialize_format_to_string(hb_buffer_serialize_format_t format);
HB_EXTERN const char **hb_buffer_serialize_list_formats(void);
HB_EXTERN unsigned int hb_buffer_serialize_glyphs(hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags);
/*
* Compare buffers
*/
typedef enum { /*< flags >*/
HB_BUFFER_DIFF_FLAG_EQUAL = 0x0000,
/* Buffers with different content_type cannot be meaningfully compared
* in any further detail. */
HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH = 0x0001,
/* For buffers with differing length, the per-glyph comparison is not
* attempted, though we do still scan reference for dottedcircle / .notdef
* glyphs. */
HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH = 0x0002,
/* We want to know if dottedcircle / .notdef glyphs are present in the
* reference, as we may not care so much about other differences in this
* case. */
HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT = 0x0004,
HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT = 0x0008,
/* If the buffers have the same length, we compare them glyph-by-glyph
* and report which aspect(s) of the glyph info/position are different. */
HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH = 0x0010,
HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH = 0x0020,
HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH = 0x0040,
HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH = 0x0080
} hb_buffer_diff_flags_t;
/* Compare the contents of two buffers, report types of differences. */
HB_EXTERN hb_buffer_diff_flags_t hb_buffer_diff(hb_buffer_t *buffer,
hb_buffer_t *reference,
hb_codepoint_t dottedcircle_glyph,
unsigned int position_fuzz);
/*
* Debugging.
*/
typedef hb_bool_t (*hb_buffer_message_func_t)(hb_buffer_t *buffer,
hb_font_t *font,
const char *message,
void *user_data);
HB_EXTERN void hb_buffer_set_message_func(hb_buffer_t *buffer,
hb_buffer_message_func_t func,
void *user_data,
hb_destroy_func_t destroy);
HB_END_DECLS
#endif /* HB_BUFFER_H */

474
harfbuzz/src/hb-buffer.hh Normal file
View File

@ -0,0 +1,474 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Owen Taylor, Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_HH
#define HB_BUFFER_HH
#include "hb.hh"
#include "hb-unicode.hh"
#ifndef HB_BUFFER_MAX_LEN_FACTOR
#define HB_BUFFER_MAX_LEN_FACTOR 32
#endif
#ifndef HB_BUFFER_MAX_LEN_MIN
#define HB_BUFFER_MAX_LEN_MIN 8192
#endif
#ifndef HB_BUFFER_MAX_LEN_DEFAULT
#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
#endif
#ifndef HB_BUFFER_MAX_OPS_FACTOR
#define HB_BUFFER_MAX_OPS_FACTOR 64
#endif
#ifndef HB_BUFFER_MAX_OPS_MIN
#define HB_BUFFER_MAX_OPS_MIN 1024
#endif
#ifndef HB_BUFFER_MAX_OPS_DEFAULT
#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
#endif
static_assert((sizeof(hb_glyph_info_t) == 20), "");
static_assert((sizeof(hb_glyph_info_t) == sizeof(hb_glyph_position_t)), "");
HB_MARK_AS_FLAG_T(hb_buffer_flags_t);
HB_MARK_AS_FLAG_T(hb_buffer_serialize_flags_t);
HB_MARK_AS_FLAG_T(hb_buffer_diff_flags_t);
enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u,
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000020u,
/* Reserved for complex shapers' internal use. */
HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u,
};
HB_MARK_AS_FLAG_T(hb_buffer_scratch_flags_t);
/*
* hb_buffer_t
*/
struct hb_buffer_t
{
hb_object_header_t header;
/* Information about how the text in the buffer should be treated */
hb_unicode_funcs_t *unicode; /* Unicode functions */
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_codepoint_t invisible; /* 0 or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
/* Buffer contents */
hb_buffer_content_type_t content_type;
hb_segment_properties_t props; /* Script, language, direction */
bool successful; /* Allocations successful */
bool have_output; /* Whether we have an output buffer going on */
bool have_positions; /* Whether we have positions */
unsigned int idx; /* Cursor into ->info and ->pos arrays */
unsigned int len; /* Length of ->info and ->pos arrays */
unsigned int out_len; /* Length of ->out array if have_output */
unsigned int allocated; /* Length of allocated arrays */
hb_glyph_info_t *info;
hb_glyph_info_t *out_info;
hb_glyph_position_t *pos;
unsigned int serial;
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
static constexpr unsigned CONTEXT_LENGTH = 5u;
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
/* Debugging API */
#ifndef HB_NO_BUFFER_MESSAGE
hb_buffer_message_func_t message_func;
void *message_data;
hb_destroy_func_t message_destroy;
#endif
/* Internal debugging. */
/* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
#ifndef HB_NDEBUG
uint8_t allocated_var_bits;
#endif
/* Methods */
bool in_error() const
{
return !successful;
}
void allocate_var(unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert(end <= 8);
unsigned int bits = (1u << end) - (1u << start);
assert(0 == (allocated_var_bits & bits));
allocated_var_bits |= bits;
#endif
}
void deallocate_var(unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert(end <= 8);
unsigned int bits = (1u << end) - (1u << start);
assert(bits == (allocated_var_bits & bits));
allocated_var_bits &= ~bits;
#endif
}
void assert_var(unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert(end <= 8);
unsigned int bits = (1u << end) - (1u << start);
assert(bits == (allocated_var_bits & bits));
#endif
}
void deallocate_var_all()
{
#ifndef HB_NDEBUG
allocated_var_bits = 0;
#endif
}
hb_glyph_info_t &cur(unsigned int i = 0)
{
return info[idx + i];
}
hb_glyph_info_t cur(unsigned int i = 0) const
{
return info[idx + i];
}
hb_glyph_position_t &cur_pos(unsigned int i = 0)
{
return pos[idx + i];
}
hb_glyph_position_t cur_pos(unsigned int i = 0) const
{
return pos[idx + i];
}
hb_glyph_info_t &prev()
{
return out_info[out_len ? out_len - 1 : 0];
}
hb_glyph_info_t prev() const
{
return out_info[out_len ? out_len - 1 : 0];
}
bool has_separate_output() const
{
return info != out_info;
}
HB_INTERNAL void reset();
HB_INTERNAL void clear();
unsigned int backtrack_len() const
{
return have_output ? out_len : idx;
}
unsigned int lookahead_len() const
{
return len - idx;
}
unsigned int next_serial()
{
return serial++;
}
HB_INTERNAL void add(hb_codepoint_t codepoint, unsigned int cluster);
HB_INTERNAL void add_info(const hb_glyph_info_t &glyph_info);
HB_INTERNAL void reverse_range(unsigned int start, unsigned int end);
HB_INTERNAL void reverse();
HB_INTERNAL void reverse_clusters();
HB_INTERNAL void guess_segment_properties();
HB_INTERNAL void swap_buffers();
HB_INTERNAL void remove_output();
HB_INTERNAL void clear_output();
HB_INTERNAL void clear_positions();
HB_INTERNAL void replace_glyphs(unsigned int num_in, unsigned int num_out, const hb_codepoint_t *glyph_data);
void replace_glyph(hb_codepoint_t glyph_index)
{
if (unlikely(out_info != info || out_len != idx)) {
if (unlikely(!make_room_for(1, 1)))
return;
out_info[out_len] = info[idx];
}
out_info[out_len].codepoint = glyph_index;
idx++;
out_len++;
}
/* Makes a copy of the glyph at idx to output and replace glyph_index */
hb_glyph_info_t &output_glyph(hb_codepoint_t glyph_index)
{
if (unlikely(!make_room_for(0, 1)))
return Crap(hb_glyph_info_t);
if (unlikely(idx == len && !out_len))
return Crap(hb_glyph_info_t);
out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
out_info[out_len].codepoint = glyph_index;
out_len++;
return out_info[out_len - 1];
}
void output_info(const hb_glyph_info_t &glyph_info)
{
if (unlikely(!make_room_for(0, 1)))
return;
out_info[out_len] = glyph_info;
out_len++;
}
/* Copies glyph at idx to output but doesn't advance idx */
void copy_glyph()
{
if (unlikely(!make_room_for(0, 1)))
return;
out_info[out_len] = info[idx];
out_len++;
}
/* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */
void next_glyph()
{
if (have_output) {
if (out_info != info || out_len != idx) {
if (unlikely(!make_room_for(1, 1)))
return;
out_info[out_len] = info[idx];
}
out_len++;
}
idx++;
}
/* Copies n glyphs at idx to output and advance idx.
* If there's no output, just advance idx. */
void next_glyphs(unsigned int n)
{
if (have_output) {
if (out_info != info || out_len != idx) {
if (unlikely(!make_room_for(n, n)))
return;
memmove(out_info + out_len, info + idx, n * sizeof(out_info[0]));
}
out_len += n;
}
idx += n;
}
/* Advance idx without copying to output. */
void skip_glyph()
{
idx++;
}
void reset_masks(hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask = mask;
}
void add_masks(hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask |= mask;
}
HB_INTERNAL void set_masks(hb_mask_t value, hb_mask_t mask, unsigned int cluster_start, unsigned int cluster_end);
void merge_clusters(unsigned int start, unsigned int end)
{
if (end - start < 2)
return;
merge_clusters_impl(start, end);
}
HB_INTERNAL void merge_clusters_impl(unsigned int start, unsigned int end);
HB_INTERNAL void merge_out_clusters(unsigned int start, unsigned int end);
/* Merge clusters for deleting current glyph, and skip it. */
HB_INTERNAL void delete_glyph();
void unsafe_to_break(unsigned int start, unsigned int end)
{
if (end - start < 2)
return;
unsafe_to_break_impl(start, end);
}
HB_INTERNAL void unsafe_to_break_impl(unsigned int start, unsigned int end);
HB_INTERNAL void unsafe_to_break_from_outbuffer(unsigned int start, unsigned int end);
/* Internal methods */
HB_INTERNAL bool move_to(unsigned int i); /* i is output-buffer index. */
HB_INTERNAL bool enlarge(unsigned int size);
bool ensure(unsigned int size)
{
return likely(!size || size < allocated) ? true : enlarge(size);
}
bool ensure_inplace(unsigned int size)
{
return likely(!size || size < allocated);
}
HB_INTERNAL bool make_room_for(unsigned int num_in, unsigned int num_out);
HB_INTERNAL bool shift_forward(unsigned int count);
typedef long scratch_buffer_t;
HB_INTERNAL scratch_buffer_t *get_scratch_buffer(unsigned int *size);
void clear_context(unsigned int side)
{
context_len[side] = 0;
}
HB_INTERNAL void
sort(unsigned int start, unsigned int end, int (*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
bool messaging()
{
#ifdef HB_NO_BUFFER_MESSAGE
return false;
#else
return unlikely(message_func);
#endif
}
bool message(hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{
#ifdef HB_NO_BUFFER_MESSAGE
return true;
#else
if (!messaging())
return true;
va_list ap;
va_start(ap, fmt);
bool ret = message_impl(font, fmt, ap);
va_end(ap);
return ret;
#endif
}
HB_INTERNAL bool message_impl(hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
static void set_cluster(hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
{
if (inf.cluster != cluster) {
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
else
inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
inf.cluster = cluster;
}
unsigned int _unsafe_to_break_find_min_cluster(const hb_glyph_info_t *infos,
unsigned int start,
unsigned int end,
unsigned int cluster) const
{
for (unsigned int i = start; i < end; i++)
cluster = hb_min(cluster, infos[i].cluster);
return cluster;
}
void _unsafe_to_break_set_mask(hb_glyph_info_t *infos, unsigned int start, unsigned int end, unsigned int cluster)
{
for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster) {
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
}
void unsafe_to_break_all()
{
unsafe_to_break_impl(0, len);
}
void safe_to_break_all()
{
for (unsigned int i = 0; i < len; i++)
info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
};
DECLARE_NULL_INSTANCE(hb_buffer_t);
/* Loop over clusters. Duplicated in foreach_syllable(). */
#define foreach_cluster(buffer, start, end) \
for (unsigned int _count = buffer->len, start = 0, end = _count ? _next_cluster(buffer, 0) : 0; start < _count; \
start = end, end = _next_cluster(buffer, start))
static inline unsigned int _next_cluster(hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
unsigned int cluster = info[start].cluster;
while (++start < count && cluster == info[start].cluster)
;
return start;
}
#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
b->func(offsetof(hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), sizeof(b->info[0].var))
#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR(b, allocate_var, var())
#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR(b, deallocate_var, var())
#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR(b, assert_var, var())
#endif /* HB_BUFFER_HH */

80
harfbuzz/src/hb-cache.hh Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_CACHE_HH
#define HB_CACHE_HH
#include "hb.hh"
/* Implements a lock-free cache for int->int functions. */
template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits> struct hb_cache_t
{
static_assert((key_bits >= cache_bits), "");
static_assert((key_bits + value_bits - cache_bits <= 8 * sizeof(hb_atomic_int_t)), "");
static_assert(sizeof(hb_atomic_int_t) == sizeof(unsigned int), "");
void init()
{
clear();
}
void fini() {}
void clear()
{
for (unsigned i = 0; i < ARRAY_LENGTH(values); i++)
values[i].set_relaxed(-1);
}
bool get(unsigned int key, unsigned int *value) const
{
unsigned int k = key & ((1u << cache_bits) - 1);
unsigned int v = values[k].get_relaxed();
if ((key_bits + value_bits - cache_bits == 8 * sizeof(hb_atomic_int_t) && v == (unsigned int)-1) ||
(v >> value_bits) != (key >> cache_bits))
return false;
*value = v & ((1u << value_bits) - 1);
return true;
}
bool set(unsigned int key, unsigned int value)
{
if (unlikely((key >> key_bits) || (value >> value_bits)))
return false; /* Overflows */
unsigned int k = key & ((1u << cache_bits) - 1);
unsigned int v = ((key >> cache_bits) << value_bits) | value;
values[k].set_relaxed(v);
return true;
}
private:
hb_atomic_int_t values[1u << cache_bits];
};
typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
#endif /* HB_CACHE_HH */

View File

@ -0,0 +1,777 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF_INTERP_COMMON_HH
#define HB_CFF_INTERP_COMMON_HH
namespace CFF {
using namespace OT;
typedef unsigned int op_code_t;
/* === Dict operators === */
/* One byte operators (0-31) */
#define OpCode_version 0 /* CFF Top */
#define OpCode_Notice 1 /* CFF Top */
#define OpCode_FullName 2 /* CFF Top */
#define OpCode_FamilyName 3 /* CFF Top */
#define OpCode_Weight 4 /* CFF Top */
#define OpCode_FontBBox 5 /* CFF Top */
#define OpCode_BlueValues 6 /* CFF Private, CFF2 Private */
#define OpCode_OtherBlues 7 /* CFF Private, CFF2 Private */
#define OpCode_FamilyBlues 8 /* CFF Private, CFF2 Private */
#define OpCode_FamilyOtherBlues 9 /* CFF Private, CFF2 Private */
#define OpCode_StdHW 10 /* CFF Private, CFF2 Private */
#define OpCode_StdVW 11 /* CFF Private, CFF2 Private */
#define OpCode_escape 12 /* All. Shared with CS */
#define OpCode_UniqueID 13 /* CFF Top */
#define OpCode_XUID 14 /* CFF Top */
#define OpCode_charset 15 /* CFF Top (0) */
#define OpCode_Encoding 16 /* CFF Top (0) */
#define OpCode_CharStrings 17 /* CFF Top, CFF2 Top */
#define OpCode_Private 18 /* CFF Top, CFF2 FD */
#define OpCode_Subrs 19 /* CFF Private, CFF2 Private */
#define OpCode_defaultWidthX 20 /* CFF Private (0) */
#define OpCode_nominalWidthX 21 /* CFF Private (0) */
#define OpCode_vsindexdict 22 /* CFF2 Private/CS */
#define OpCode_blenddict 23 /* CFF2 Private/CS */
#define OpCode_vstore 24 /* CFF2 Top */
#define OpCode_reserved25 25
#define OpCode_reserved26 26
#define OpCode_reserved27 27
/* Numbers */
#define OpCode_shortint 28 /* 16-bit integer, All */
#define OpCode_longintdict 29 /* 32-bit integer, All */
#define OpCode_BCD 30 /* Real number, CFF2 Top/FD */
#define OpCode_reserved31 31
/* 1-byte integers */
#define OpCode_OneByteIntFirst 32 /* All. beginning of the range of first byte ints */
#define OpCode_OneByteIntLast 246 /* All. ending of the range of first byte int */
/* 2-byte integers */
#define OpCode_TwoBytePosInt0 247 /* All. first byte of two byte positive int (+108 to +1131) */
#define OpCode_TwoBytePosInt1 248
#define OpCode_TwoBytePosInt2 249
#define OpCode_TwoBytePosInt3 250
#define OpCode_TwoByteNegInt0 251 /* All. first byte of two byte negative int (-1131 to -108) */
#define OpCode_TwoByteNegInt1 252
#define OpCode_TwoByteNegInt2 253
#define OpCode_TwoByteNegInt3 254
/* Two byte escape operators 12, (0-41) */
#define OpCode_ESC_Base 256
#define Make_OpCode_ESC(byte2) ((op_code_t)(OpCode_ESC_Base + (byte2)))
inline op_code_t Unmake_OpCode_ESC(op_code_t op)
{
return (op_code_t)(op - OpCode_ESC_Base);
}
inline bool Is_OpCode_ESC(op_code_t op)
{
return op >= OpCode_ESC_Base;
}
inline unsigned int OpCode_Size(op_code_t op)
{
return Is_OpCode_ESC(op) ? 2 : 1;
}
#define OpCode_Copyright Make_OpCode_ESC(0) /* CFF Top */
#define OpCode_isFixedPitch Make_OpCode_ESC(1) /* CFF Top (false) */
#define OpCode_ItalicAngle Make_OpCode_ESC(2) /* CFF Top (0) */
#define OpCode_UnderlinePosition Make_OpCode_ESC(3) /* CFF Top (-100) */
#define OpCode_UnderlineThickness Make_OpCode_ESC(4) /* CFF Top (50) */
#define OpCode_PaintType Make_OpCode_ESC(5) /* CFF Top (0) */
#define OpCode_CharstringType Make_OpCode_ESC(6) /* CFF Top (2) */
#define OpCode_FontMatrix Make_OpCode_ESC(7) /* CFF Top, CFF2 Top (.001 0 0 .001 0 0)*/
#define OpCode_StrokeWidth Make_OpCode_ESC(8) /* CFF Top (0) */
#define OpCode_BlueScale Make_OpCode_ESC(9) /* CFF Private, CFF2 Private (0.039625) */
#define OpCode_BlueShift Make_OpCode_ESC(10) /* CFF Private, CFF2 Private (7) */
#define OpCode_BlueFuzz Make_OpCode_ESC(11) /* CFF Private, CFF2 Private (1) */
#define OpCode_StemSnapH Make_OpCode_ESC(12) /* CFF Private, CFF2 Private */
#define OpCode_StemSnapV Make_OpCode_ESC(13) /* CFF Private, CFF2 Private */
#define OpCode_ForceBold Make_OpCode_ESC(14) /* CFF Private (false) */
#define OpCode_reservedESC15 Make_OpCode_ESC(15)
#define OpCode_reservedESC16 Make_OpCode_ESC(16)
#define OpCode_LanguageGroup Make_OpCode_ESC(17) /* CFF Private, CFF2 Private (0) */
#define OpCode_ExpansionFactor Make_OpCode_ESC(18) /* CFF Private, CFF2 Private (0.06) */
#define OpCode_initialRandomSeed Make_OpCode_ESC(19) /* CFF Private (0) */
#define OpCode_SyntheticBase Make_OpCode_ESC(20) /* CFF Top */
#define OpCode_PostScript Make_OpCode_ESC(21) /* CFF Top */
#define OpCode_BaseFontName Make_OpCode_ESC(22) /* CFF Top */
#define OpCode_BaseFontBlend Make_OpCode_ESC(23) /* CFF Top */
#define OpCode_reservedESC24 Make_OpCode_ESC(24)
#define OpCode_reservedESC25 Make_OpCode_ESC(25)
#define OpCode_reservedESC26 Make_OpCode_ESC(26)
#define OpCode_reservedESC27 Make_OpCode_ESC(27)
#define OpCode_reservedESC28 Make_OpCode_ESC(28)
#define OpCode_reservedESC29 Make_OpCode_ESC(29)
#define OpCode_ROS Make_OpCode_ESC(30) /* CFF Top_CID */
#define OpCode_CIDFontVersion Make_OpCode_ESC(31) /* CFF Top_CID (0) */
#define OpCode_CIDFontRevision Make_OpCode_ESC(32) /* CFF Top_CID (0) */
#define OpCode_CIDFontType Make_OpCode_ESC(33) /* CFF Top_CID (0) */
#define OpCode_CIDCount Make_OpCode_ESC(34) /* CFF Top_CID (8720) */
#define OpCode_UIDBase Make_OpCode_ESC(35) /* CFF Top_CID */
#define OpCode_FDArray Make_OpCode_ESC(36) /* CFF Top_CID, CFF2 Top */
#define OpCode_FDSelect Make_OpCode_ESC(37) /* CFF Top_CID, CFF2 Top */
#define OpCode_FontName Make_OpCode_ESC(38) /* CFF Top_CID */
/* === CharString operators === */
#define OpCode_hstem 1 /* CFF, CFF2 */
#define OpCode_Reserved2 2
#define OpCode_vstem 3 /* CFF, CFF2 */
#define OpCode_vmoveto 4 /* CFF, CFF2 */
#define OpCode_rlineto 5 /* CFF, CFF2 */
#define OpCode_hlineto 6 /* CFF, CFF2 */
#define OpCode_vlineto 7 /* CFF, CFF2 */
#define OpCode_rrcurveto 8 /* CFF, CFF2 */
#define OpCode_Reserved9 9
#define OpCode_callsubr 10 /* CFF, CFF2 */
#define OpCode_return 11 /* CFF */
//#define OpCode_escape 12 /* CFF, CFF2 */
#define OpCode_Reserved13 13
#define OpCode_endchar 14 /* CFF */
#define OpCode_vsindexcs 15 /* CFF2 */
#define OpCode_blendcs 16 /* CFF2 */
#define OpCode_Reserved17 17
#define OpCode_hstemhm 18 /* CFF, CFF2 */
#define OpCode_hintmask 19 /* CFF, CFF2 */
#define OpCode_cntrmask 20 /* CFF, CFF2 */
#define OpCode_rmoveto 21 /* CFF, CFF2 */
#define OpCode_hmoveto 22 /* CFF, CFF2 */
#define OpCode_vstemhm 23 /* CFF, CFF2 */
#define OpCode_rcurveline 24 /* CFF, CFF2 */
#define OpCode_rlinecurve 25 /* CFF, CFF2 */
#define OpCode_vvcurveto 26 /* CFF, CFF2 */
#define OpCode_hhcurveto 27 /* CFF, CFF2 */
//#define OpCode_shortint 28 /* CFF, CFF2 */
#define OpCode_callgsubr 29 /* CFF, CFF2 */
#define OpCode_vhcurveto 30 /* CFF, CFF2 */
#define OpCode_hvcurveto 31 /* CFF, CFF2 */
#define OpCode_fixedcs 255 /* 32-bit fixed */
/* Two byte escape operators 12, (0-41) */
#define OpCode_dotsection Make_OpCode_ESC(0) /* CFF (obsoleted) */
#define OpCode_ReservedESC1 Make_OpCode_ESC(1)
#define OpCode_ReservedESC2 Make_OpCode_ESC(2)
#define OpCode_and Make_OpCode_ESC(3) /* CFF */
#define OpCode_or Make_OpCode_ESC(4) /* CFF */
#define OpCode_not Make_OpCode_ESC(5) /* CFF */
#define OpCode_ReservedESC6 Make_OpCode_ESC(6)
#define OpCode_ReservedESC7 Make_OpCode_ESC(7)
#define OpCode_ReservedESC8 Make_OpCode_ESC(8)
#define OpCode_abs Make_OpCode_ESC(9) /* CFF */
#define OpCode_add Make_OpCode_ESC(10) /* CFF */
#define OpCode_sub Make_OpCode_ESC(11) /* CFF */
#define OpCode_div Make_OpCode_ESC(12) /* CFF */
#define OpCode_ReservedESC13 Make_OpCode_ESC(13)
#define OpCode_neg Make_OpCode_ESC(14) /* CFF */
#define OpCode_eq Make_OpCode_ESC(15) /* CFF */
#define OpCode_ReservedESC16 Make_OpCode_ESC(16)
#define OpCode_ReservedESC17 Make_OpCode_ESC(17)
#define OpCode_drop Make_OpCode_ESC(18) /* CFF */
#define OpCode_ReservedESC19 Make_OpCode_ESC(19)
#define OpCode_put Make_OpCode_ESC(20) /* CFF */
#define OpCode_get Make_OpCode_ESC(21) /* CFF */
#define OpCode_ifelse Make_OpCode_ESC(22) /* CFF */
#define OpCode_random Make_OpCode_ESC(23) /* CFF */
#define OpCode_mul Make_OpCode_ESC(24) /* CFF */
//#define OpCode_reservedESC25 Make_OpCode_ESC(25)
#define OpCode_sqrt Make_OpCode_ESC(26) /* CFF */
#define OpCode_dup Make_OpCode_ESC(27) /* CFF */
#define OpCode_exch Make_OpCode_ESC(28) /* CFF */
#define OpCode_index Make_OpCode_ESC(29) /* CFF */
#define OpCode_roll Make_OpCode_ESC(30) /* CFF */
#define OpCode_reservedESC31 Make_OpCode_ESC(31)
#define OpCode_reservedESC32 Make_OpCode_ESC(32)
#define OpCode_reservedESC33 Make_OpCode_ESC(33)
#define OpCode_hflex Make_OpCode_ESC(34) /* CFF, CFF2 */
#define OpCode_flex Make_OpCode_ESC(35) /* CFF, CFF2 */
#define OpCode_hflex1 Make_OpCode_ESC(36) /* CFF, CFF2 */
#define OpCode_flex1 Make_OpCode_ESC(37) /* CFF, CFF2 */
#define OpCode_Invalid 0xFFFFu
struct number_t
{
void init()
{
set_real(0.0);
}
void fini() {}
void set_int(int v)
{
value = v;
}
int to_int() const
{
return value;
}
void set_fixed(int32_t v)
{
value = v / 65536.0;
}
int32_t to_fixed() const
{
return value * 65536.0;
}
void set_real(double v)
{
value = v;
}
double to_real() const
{
return value;
}
bool in_int_range() const
{
return ((double)(int16_t)to_int() == value);
}
bool operator>(const number_t &n) const
{
return value > n.to_real();
}
bool operator<(const number_t &n) const
{
return n > *this;
}
bool operator>=(const number_t &n) const
{
return !(*this < n);
}
bool operator<=(const number_t &n) const
{
return !(*this > n);
}
const number_t &operator+=(const number_t &n)
{
set_real(to_real() + n.to_real());
return *this;
}
protected:
double value;
};
/* byte string */
struct UnsizedByteStr : UnsizedArrayOf<HBUINT8>
{
/* Defining null_size allows a Null object may be created. Should be safe because:
* A descendent struct Dict uses a Null pointer to indicate a missing table,
* checked before access.
* byte_str_t, a wrapper struct pairing a byte pointer along with its length, always
* checks the length before access. A Null pointer is used as the initial pointer
* along with zero length by the default ctor.
*/
DEFINE_SIZE_MIN(0);
};
/* Holder of a section of byte string within a CFFIndex entry */
struct byte_str_t : hb_ubytes_t
{
byte_str_t()
: hb_ubytes_t()
{
}
byte_str_t(const UnsizedByteStr &s, unsigned int l)
: hb_ubytes_t((const unsigned char *)&s, l)
{
}
byte_str_t(const unsigned char *s, unsigned int l)
: hb_ubytes_t(s, l)
{
}
byte_str_t(const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */
: hb_ubytes_t(ub)
{
}
/* sub-string */
byte_str_t sub_str(unsigned int offset, unsigned int len_) const
{
return byte_str_t(hb_ubytes_t::sub_array(offset, len_));
}
bool check_limit(unsigned int offset, unsigned int count) const
{
return (offset + count <= length);
}
};
/* A byte string associated with the current offset and an error condition */
struct byte_str_ref_t
{
byte_str_ref_t()
{
init();
}
void init()
{
str = byte_str_t();
offset = 0;
error = false;
}
void fini() {}
byte_str_ref_t(const byte_str_t &str_, unsigned int offset_ = 0)
: str(str_)
, offset(offset_)
, error(false)
{
}
void reset(const byte_str_t &str_, unsigned int offset_ = 0)
{
str = str_;
offset = offset_;
error = false;
}
const unsigned char &operator[](int i)
{
if (unlikely((unsigned int)(offset + i) >= str.length)) {
set_error();
return Null(unsigned char);
}
return str[offset + i];
}
/* Conversion to byte_str_t */
operator byte_str_t() const
{
return str.sub_str(offset, str.length - offset);
}
byte_str_t sub_str(unsigned int offset_, unsigned int len_) const
{
return str.sub_str(offset_, len_);
}
bool avail(unsigned int count = 1) const
{
return (!in_error() && str.check_limit(offset, count));
}
void inc(unsigned int count = 1)
{
if (likely(!in_error() && (offset <= str.length) && (offset + count <= str.length))) {
offset += count;
} else {
offset = str.length;
set_error();
}
}
void set_error()
{
error = true;
}
bool in_error() const
{
return error;
}
byte_str_t str;
unsigned int offset; /* beginning of the sub-string within str */
protected:
bool error;
};
typedef hb_vector_t<byte_str_t> byte_str_array_t;
/* stack */
template <typename ELEM, int LIMIT> struct cff_stack_t
{
void init()
{
error = false;
count = 0;
elements.init();
elements.resize(kSizeLimit);
for (unsigned int i = 0; i < elements.length; i++)
elements[i].init();
}
void fini()
{
elements.fini_deep();
}
ELEM &operator[](unsigned int i)
{
if (unlikely(i >= count))
set_error();
return elements[i];
}
void push(const ELEM &v)
{
if (likely(count < elements.length))
elements[count++] = v;
else
set_error();
}
ELEM &push()
{
if (likely(count < elements.length))
return elements[count++];
else {
set_error();
return Crap(ELEM);
}
}
ELEM &pop()
{
if (likely(count > 0))
return elements[--count];
else {
set_error();
return Crap(ELEM);
}
}
void pop(unsigned int n)
{
if (likely(count >= n))
count -= n;
else
set_error();
}
const ELEM &peek()
{
if (unlikely(count < 0)) {
set_error();
return Null(ELEM);
}
return elements[count - 1];
}
void unpop()
{
if (likely(count < elements.length))
count++;
else
set_error();
}
void clear()
{
count = 0;
}
bool in_error() const
{
return (error || elements.in_error());
}
void set_error()
{
error = true;
}
unsigned int get_count() const
{
return count;
}
bool is_empty() const
{
return !count;
}
static constexpr unsigned kSizeLimit = LIMIT;
protected:
bool error;
unsigned int count;
hb_vector_t<ELEM> elements;
};
/* argument stack */
template <typename ARG = number_t> struct arg_stack_t : cff_stack_t<ARG, 513>
{
void push_int(int v)
{
ARG &n = S::push();
n.set_int(v);
}
void push_fixed(int32_t v)
{
ARG &n = S::push();
n.set_fixed(v);
}
void push_real(double v)
{
ARG &n = S::push();
n.set_real(v);
}
ARG &pop_num()
{
return this->pop();
}
int pop_int()
{
return this->pop().to_int();
}
unsigned int pop_uint()
{
int i = pop_int();
if (unlikely(i < 0)) {
i = 0;
S::set_error();
}
return (unsigned)i;
}
void push_longint_from_substr(byte_str_ref_t &str_ref)
{
push_int((str_ref[0] << 24) | (str_ref[1] << 16) | (str_ref[2] << 8) | (str_ref[3]));
str_ref.inc(4);
}
bool push_fixed_from_substr(byte_str_ref_t &str_ref)
{
if (unlikely(!str_ref.avail(4)))
return false;
push_fixed((int32_t) * (const HBUINT32 *)&str_ref[0]);
str_ref.inc(4);
return true;
}
hb_array_t<const ARG> get_subarray(unsigned int start) const
{
return S::elements.sub_array(start);
}
private:
typedef cff_stack_t<ARG, 513> S;
};
/* an operator prefixed by its operands in a byte string */
struct op_str_t
{
void init() {}
void fini() {}
op_code_t op;
byte_str_t str;
};
template <typename VAL> struct parsed_values_t
{
void init()
{
opStart = 0;
values.init();
}
void fini()
{
values.fini_deep();
}
void add_op(op_code_t op, const byte_str_ref_t &str_ref = byte_str_ref_t())
{
VAL *val = values.push();
val->op = op;
val->str = str_ref.str.sub_str(opStart, str_ref.offset - opStart);
opStart = str_ref.offset;
}
void add_op(op_code_t op, const byte_str_ref_t &str_ref, const VAL &v)
{
VAL *val = values.push(v);
val->op = op;
val->str = str_ref.sub_str(opStart, str_ref.offset - opStart);
opStart = str_ref.offset;
}
bool has_op(op_code_t op) const
{
for (unsigned int i = 0; i < get_count(); i++)
if (get_value(i).op == op)
return true;
return false;
}
unsigned get_count() const
{
return values.length;
}
const VAL &get_value(unsigned int i) const
{
return values[i];
}
const VAL &operator[](unsigned int i) const
{
return get_value(i);
}
unsigned int opStart;
hb_vector_t<VAL> values;
};
template <typename ARG = number_t> struct interp_env_t
{
void init(const byte_str_t &str_)
{
str_ref.reset(str_);
argStack.init();
error = false;
}
void fini()
{
argStack.fini();
}
bool in_error() const
{
return error || str_ref.in_error() || argStack.in_error();
}
void set_error()
{
error = true;
}
op_code_t fetch_op()
{
op_code_t op = OpCode_Invalid;
if (unlikely(!str_ref.avail()))
return OpCode_Invalid;
op = (op_code_t)(unsigned char)str_ref[0];
if (op == OpCode_escape) {
if (unlikely(!str_ref.avail()))
return OpCode_Invalid;
op = Make_OpCode_ESC(str_ref[1]);
str_ref.inc();
}
str_ref.inc();
return op;
}
const ARG &eval_arg(unsigned int i)
{
return argStack[i];
}
ARG &pop_arg()
{
return argStack.pop();
}
void pop_n_args(unsigned int n)
{
argStack.pop(n);
}
void clear_args()
{
pop_n_args(argStack.get_count());
}
byte_str_ref_t str_ref;
arg_stack_t<ARG> argStack;
protected:
bool error;
};
typedef interp_env_t<> num_interp_env_t;
template <typename ARG = number_t> struct opset_t
{
static void process_op(op_code_t op, interp_env_t<ARG> &env)
{
switch (op) {
case OpCode_shortint:
env.argStack.push_int((int16_t)((env.str_ref[0] << 8) | env.str_ref[1]));
env.str_ref.inc(2);
break;
case OpCode_TwoBytePosInt0:
case OpCode_TwoBytePosInt1:
case OpCode_TwoBytePosInt2:
case OpCode_TwoBytePosInt3:
env.argStack.push_int((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.str_ref[0] + 108));
env.str_ref.inc();
break;
case OpCode_TwoByteNegInt0:
case OpCode_TwoByteNegInt1:
case OpCode_TwoByteNegInt2:
case OpCode_TwoByteNegInt3:
env.argStack.push_int((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
env.str_ref.inc();
break;
default:
/* 1-byte integer */
if (likely((OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast))) {
env.argStack.push_int((int)op - 139);
} else {
/* invalid unknown operator */
env.clear_args();
env.set_error();
}
break;
}
}
};
template <typename ENV> struct interpreter_t
{
~interpreter_t()
{
fini();
}
void fini()
{
env.fini();
}
ENV env;
};
} /* namespace CFF */
#endif /* HB_CFF_INTERP_COMMON_HH */

View File

@ -0,0 +1,919 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF_INTERP_CS_COMMON_HH
#define HB_CFF_INTERP_CS_COMMON_HH
#include "hb.hh"
#include "hb-cff-interp-common.hh"
namespace CFF {
using namespace OT;
enum cs_type_t { CSType_CharString, CSType_GlobalSubr, CSType_LocalSubr };
struct call_context_t
{
void init(const byte_str_ref_t substr_ = byte_str_ref_t(),
cs_type_t type_ = CSType_CharString,
unsigned int subr_num_ = 0)
{
str_ref = substr_;
type = type_;
subr_num = subr_num_;
}
void fini() {}
byte_str_ref_t str_ref;
cs_type_t type;
unsigned int subr_num;
};
/* call stack */
const unsigned int kMaxCallLimit = 10;
struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit>
{
};
template <typename SUBRS> struct biased_subrs_t
{
void init(const SUBRS *subrs_)
{
subrs = subrs_;
unsigned int nSubrs = get_count();
if (nSubrs < 1240)
bias = 107;
else if (nSubrs < 33900)
bias = 1131;
else
bias = 32768;
}
void fini() {}
unsigned int get_count() const
{
return subrs ? subrs->count : 0;
}
unsigned int get_bias() const
{
return bias;
}
byte_str_t operator[](unsigned int index) const
{
if (unlikely(!subrs || index >= subrs->count))
return Null(byte_str_t);
else
return (*subrs)[index];
}
protected:
unsigned int bias;
const SUBRS *subrs;
};
struct point_t
{
void init()
{
x.init();
y.init();
}
void set_int(int _x, int _y)
{
x.set_int(_x);
y.set_int(_y);
}
void move_x(const number_t &dx)
{
x += dx;
}
void move_y(const number_t &dy)
{
y += dy;
}
void move(const number_t &dx, const number_t &dy)
{
move_x(dx);
move_y(dy);
}
void move(const point_t &d)
{
move_x(d.x);
move_y(d.y);
}
number_t x;
number_t y;
};
template <typename ARG, typename SUBRS> struct cs_interp_env_t : interp_env_t<ARG>
{
void init(const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
{
interp_env_t<ARG>::init(str);
context.init(str, CSType_CharString);
seen_moveto = true;
seen_hintmask = false;
hstem_count = 0;
vstem_count = 0;
hintmask_size = 0;
pt.init();
callStack.init();
globalSubrs.init(globalSubrs_);
localSubrs.init(localSubrs_);
}
void fini()
{
interp_env_t<ARG>::fini();
callStack.fini();
globalSubrs.fini();
localSubrs.fini();
}
bool in_error() const
{
return callStack.in_error() || SUPER::in_error();
}
bool pop_subr_num(const biased_subrs_t<SUBRS> &biasedSubrs, unsigned int &subr_num)
{
subr_num = 0;
int n = SUPER::argStack.pop_int();
n += biasedSubrs.get_bias();
if (unlikely((n < 0) || ((unsigned int)n >= biasedSubrs.get_count())))
return false;
subr_num = (unsigned int)n;
return true;
}
void call_subr(const biased_subrs_t<SUBRS> &biasedSubrs, cs_type_t type)
{
unsigned int subr_num = 0;
if (unlikely(!pop_subr_num(biasedSubrs, subr_num) || callStack.get_count() >= kMaxCallLimit)) {
SUPER::set_error();
return;
}
context.str_ref = SUPER::str_ref;
callStack.push(context);
context.init(biasedSubrs[subr_num], type, subr_num);
SUPER::str_ref = context.str_ref;
}
void return_from_subr()
{
if (unlikely(SUPER::str_ref.in_error()))
SUPER::set_error();
context = callStack.pop();
SUPER::str_ref = context.str_ref;
}
void determine_hintmask_size()
{
if (!seen_hintmask) {
vstem_count += SUPER::argStack.get_count() / 2;
hintmask_size = (hstem_count + vstem_count + 7) >> 3;
seen_hintmask = true;
}
}
void set_endchar(bool endchar_flag_)
{
endchar_flag = endchar_flag_;
}
bool is_endchar() const
{
return endchar_flag;
}
const number_t &get_x() const
{
return pt.x;
}
const number_t &get_y() const
{
return pt.y;
}
const point_t &get_pt() const
{
return pt;
}
void moveto(const point_t &pt_)
{
pt = pt_;
}
public:
call_context_t context;
bool endchar_flag;
bool seen_moveto;
bool seen_hintmask;
unsigned int hstem_count;
unsigned int vstem_count;
unsigned int hintmask_size;
call_stack_t callStack;
biased_subrs_t<SUBRS> globalSubrs;
biased_subrs_t<SUBRS> localSubrs;
private:
point_t pt;
typedef interp_env_t<ARG> SUPER;
};
template <typename ENV, typename PARAM> struct path_procs_null_t
{
static void rmoveto(ENV &env, PARAM &param) {}
static void hmoveto(ENV &env, PARAM &param) {}
static void vmoveto(ENV &env, PARAM &param) {}
static void rlineto(ENV &env, PARAM &param) {}
static void hlineto(ENV &env, PARAM &param) {}
static void vlineto(ENV &env, PARAM &param) {}
static void rrcurveto(ENV &env, PARAM &param) {}
static void rcurveline(ENV &env, PARAM &param) {}
static void rlinecurve(ENV &env, PARAM &param) {}
static void vvcurveto(ENV &env, PARAM &param) {}
static void hhcurveto(ENV &env, PARAM &param) {}
static void vhcurveto(ENV &env, PARAM &param) {}
static void hvcurveto(ENV &env, PARAM &param) {}
static void moveto(ENV &env, PARAM &param, const point_t &pt) {}
static void line(ENV &env, PARAM &param, const point_t &pt1) {}
static void curve(ENV &env, PARAM &param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
static void hflex(ENV &env, PARAM &param) {}
static void flex(ENV &env, PARAM &param) {}
static void hflex1(ENV &env, PARAM &param) {}
static void flex1(ENV &env, PARAM &param) {}
};
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH = path_procs_null_t<ENV, PARAM>>
struct cs_opset_t : opset_t<ARG>
{
static void process_op(op_code_t op, ENV &env, PARAM &param)
{
switch (op) {
case OpCode_return:
env.return_from_subr();
break;
case OpCode_endchar:
OPSET::check_width(op, env, param);
env.set_endchar(true);
OPSET::flush_args_and_op(op, env, param);
break;
case OpCode_fixedcs:
env.argStack.push_fixed_from_substr(env.str_ref);
break;
case OpCode_callsubr:
env.call_subr(env.localSubrs, CSType_LocalSubr);
break;
case OpCode_callgsubr:
env.call_subr(env.globalSubrs, CSType_GlobalSubr);
break;
case OpCode_hstem:
case OpCode_hstemhm:
OPSET::check_width(op, env, param);
OPSET::process_hstem(op, env, param);
break;
case OpCode_vstem:
case OpCode_vstemhm:
OPSET::check_width(op, env, param);
OPSET::process_vstem(op, env, param);
break;
case OpCode_hintmask:
case OpCode_cntrmask:
OPSET::check_width(op, env, param);
OPSET::process_hintmask(op, env, param);
break;
case OpCode_rmoveto:
OPSET::check_width(op, env, param);
PATH::rmoveto(env, param);
OPSET::process_post_move(op, env, param);
break;
case OpCode_hmoveto:
OPSET::check_width(op, env, param);
PATH::hmoveto(env, param);
OPSET::process_post_move(op, env, param);
break;
case OpCode_vmoveto:
OPSET::check_width(op, env, param);
PATH::vmoveto(env, param);
OPSET::process_post_move(op, env, param);
break;
case OpCode_rlineto:
PATH::rlineto(env, param);
process_post_path(op, env, param);
break;
case OpCode_hlineto:
PATH::hlineto(env, param);
process_post_path(op, env, param);
break;
case OpCode_vlineto:
PATH::vlineto(env, param);
process_post_path(op, env, param);
break;
case OpCode_rrcurveto:
PATH::rrcurveto(env, param);
process_post_path(op, env, param);
break;
case OpCode_rcurveline:
PATH::rcurveline(env, param);
process_post_path(op, env, param);
break;
case OpCode_rlinecurve:
PATH::rlinecurve(env, param);
process_post_path(op, env, param);
break;
case OpCode_vvcurveto:
PATH::vvcurveto(env, param);
process_post_path(op, env, param);
break;
case OpCode_hhcurveto:
PATH::hhcurveto(env, param);
process_post_path(op, env, param);
break;
case OpCode_vhcurveto:
PATH::vhcurveto(env, param);
process_post_path(op, env, param);
break;
case OpCode_hvcurveto:
PATH::hvcurveto(env, param);
process_post_path(op, env, param);
break;
case OpCode_hflex:
PATH::hflex(env, param);
OPSET::process_post_flex(op, env, param);
break;
case OpCode_flex:
PATH::flex(env, param);
OPSET::process_post_flex(op, env, param);
break;
case OpCode_hflex1:
PATH::hflex1(env, param);
OPSET::process_post_flex(op, env, param);
break;
case OpCode_flex1:
PATH::flex1(env, param);
OPSET::process_post_flex(op, env, param);
break;
default:
SUPER::process_op(op, env);
break;
}
}
static void process_hstem(op_code_t op, ENV &env, PARAM &param)
{
env.hstem_count += env.argStack.get_count() / 2;
OPSET::flush_args_and_op(op, env, param);
}
static void process_vstem(op_code_t op, ENV &env, PARAM &param)
{
env.vstem_count += env.argStack.get_count() / 2;
OPSET::flush_args_and_op(op, env, param);
}
static void process_hintmask(op_code_t op, ENV &env, PARAM &param)
{
env.determine_hintmask_size();
if (likely(env.str_ref.avail(env.hintmask_size))) {
OPSET::flush_hintmask(op, env, param);
env.str_ref.inc(env.hintmask_size);
}
}
static void process_post_flex(op_code_t op, ENV &env, PARAM &param)
{
OPSET::flush_args_and_op(op, env, param);
}
static void check_width(op_code_t op, ENV &env, PARAM &param) {}
static void process_post_move(op_code_t op, ENV &env, PARAM &param)
{
if (!env.seen_moveto) {
env.determine_hintmask_size();
env.seen_moveto = true;
}
OPSET::flush_args_and_op(op, env, param);
}
static void process_post_path(op_code_t op, ENV &env, PARAM &param)
{
OPSET::flush_args_and_op(op, env, param);
}
static void flush_args_and_op(op_code_t op, ENV &env, PARAM &param)
{
OPSET::flush_args(env, param);
OPSET::flush_op(op, env, param);
}
static void flush_args(ENV &env, PARAM &param)
{
env.pop_n_args(env.argStack.get_count());
}
static void flush_op(op_code_t op, ENV &env, PARAM &param) {}
static void flush_hintmask(op_code_t op, ENV &env, PARAM &param)
{
OPSET::flush_args_and_op(op, env, param);
}
static bool is_number_op(op_code_t op)
{
switch (op) {
case OpCode_shortint:
case OpCode_fixedcs:
case OpCode_TwoBytePosInt0:
case OpCode_TwoBytePosInt1:
case OpCode_TwoBytePosInt2:
case OpCode_TwoBytePosInt3:
case OpCode_TwoByteNegInt0:
case OpCode_TwoByteNegInt1:
case OpCode_TwoByteNegInt2:
case OpCode_TwoByteNegInt3:
return true;
default:
/* 1-byte integer */
return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
}
}
protected:
typedef opset_t<ARG> SUPER;
};
template <typename PATH, typename ENV, typename PARAM> struct path_procs_t
{
static void rmoveto(ENV &env, PARAM &param)
{
point_t pt1 = env.get_pt();
const number_t &dy = env.pop_arg();
const number_t &dx = env.pop_arg();
pt1.move(dx, dy);
PATH::moveto(env, param, pt1);
}
static void hmoveto(ENV &env, PARAM &param)
{
point_t pt1 = env.get_pt();
pt1.move_x(env.pop_arg());
PATH::moveto(env, param, pt1);
}
static void vmoveto(ENV &env, PARAM &param)
{
point_t pt1 = env.get_pt();
pt1.move_y(env.pop_arg());
PATH::moveto(env, param, pt1);
}
static void rlineto(ENV &env, PARAM &param)
{
for (unsigned int i = 0; i + 2 <= env.argStack.get_count(); i += 2) {
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(i), env.eval_arg(i + 1));
PATH::line(env, param, pt1);
}
}
static void hlineto(ENV &env, PARAM &param)
{
point_t pt1;
unsigned int i = 0;
for (; i + 2 <= env.argStack.get_count(); i += 2) {
pt1 = env.get_pt();
pt1.move_x(env.eval_arg(i));
PATH::line(env, param, pt1);
pt1.move_y(env.eval_arg(i + 1));
PATH::line(env, param, pt1);
}
if (i < env.argStack.get_count()) {
pt1 = env.get_pt();
pt1.move_x(env.eval_arg(i));
PATH::line(env, param, pt1);
}
}
static void vlineto(ENV &env, PARAM &param)
{
point_t pt1;
unsigned int i = 0;
for (; i + 2 <= env.argStack.get_count(); i += 2) {
pt1 = env.get_pt();
pt1.move_y(env.eval_arg(i));
PATH::line(env, param, pt1);
pt1.move_x(env.eval_arg(i + 1));
PATH::line(env, param, pt1);
}
if (i < env.argStack.get_count()) {
pt1 = env.get_pt();
pt1.move_y(env.eval_arg(i));
PATH::line(env, param, pt1);
}
}
static void rrcurveto(ENV &env, PARAM &param)
{
for (unsigned int i = 0; i + 6 <= env.argStack.get_count(); i += 6) {
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(i), env.eval_arg(i + 1));
point_t pt2 = pt1;
pt2.move(env.eval_arg(i + 2), env.eval_arg(i + 3));
point_t pt3 = pt2;
pt3.move(env.eval_arg(i + 4), env.eval_arg(i + 5));
PATH::curve(env, param, pt1, pt2, pt3);
}
}
static void rcurveline(ENV &env, PARAM &param)
{
unsigned int arg_count = env.argStack.get_count();
if (unlikely(arg_count < 8))
return;
unsigned int i = 0;
unsigned int curve_limit = arg_count - 2;
for (; i + 6 <= curve_limit; i += 6) {
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(i), env.eval_arg(i + 1));
point_t pt2 = pt1;
pt2.move(env.eval_arg(i + 2), env.eval_arg(i + 3));
point_t pt3 = pt2;
pt3.move(env.eval_arg(i + 4), env.eval_arg(i + 5));
PATH::curve(env, param, pt1, pt2, pt3);
}
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(i), env.eval_arg(i + 1));
PATH::line(env, param, pt1);
}
static void rlinecurve(ENV &env, PARAM &param)
{
unsigned int arg_count = env.argStack.get_count();
if (unlikely(arg_count < 8))
return;
unsigned int i = 0;
unsigned int line_limit = arg_count - 6;
for (; i + 2 <= line_limit; i += 2) {
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(i), env.eval_arg(i + 1));
PATH::line(env, param, pt1);
}
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(i), env.eval_arg(i + 1));
point_t pt2 = pt1;
pt2.move(env.eval_arg(i + 2), env.eval_arg(i + 3));
point_t pt3 = pt2;
pt3.move(env.eval_arg(i + 4), env.eval_arg(i + 5));
PATH::curve(env, param, pt1, pt2, pt3);
}
static void vvcurveto(ENV &env, PARAM &param)
{
unsigned int i = 0;
point_t pt1 = env.get_pt();
if ((env.argStack.get_count() & 1) != 0)
pt1.move_x(env.eval_arg(i++));
for (; i + 4 <= env.argStack.get_count(); i += 4) {
pt1.move_y(env.eval_arg(i));
point_t pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
point_t pt3 = pt2;
pt3.move_y(env.eval_arg(i + 3));
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = env.get_pt();
}
}
static void hhcurveto(ENV &env, PARAM &param)
{
unsigned int i = 0;
point_t pt1 = env.get_pt();
if ((env.argStack.get_count() & 1) != 0)
pt1.move_y(env.eval_arg(i++));
for (; i + 4 <= env.argStack.get_count(); i += 4) {
pt1.move_x(env.eval_arg(i));
point_t pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
point_t pt3 = pt2;
pt3.move_x(env.eval_arg(i + 3));
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = env.get_pt();
}
}
static void vhcurveto(ENV &env, PARAM &param)
{
point_t pt1, pt2, pt3;
unsigned int i = 0;
if ((env.argStack.get_count() % 8) >= 4) {
point_t pt1 = env.get_pt();
pt1.move_y(env.eval_arg(i));
point_t pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
point_t pt3 = pt2;
pt3.move_x(env.eval_arg(i + 3));
i += 4;
for (; i + 8 <= env.argStack.get_count(); i += 8) {
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = env.get_pt();
pt1.move_x(env.eval_arg(i));
pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
pt3 = pt2;
pt3.move_y(env.eval_arg(i + 3));
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_y(env.eval_arg(i + 4));
pt2 = pt1;
pt2.move(env.eval_arg(i + 5), env.eval_arg(i + 6));
pt3 = pt2;
pt3.move_x(env.eval_arg(i + 7));
}
if (i < env.argStack.get_count())
pt3.move_y(env.eval_arg(i));
PATH::curve(env, param, pt1, pt2, pt3);
} else {
for (; i + 8 <= env.argStack.get_count(); i += 8) {
pt1 = env.get_pt();
pt1.move_y(env.eval_arg(i));
pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
pt3 = pt2;
pt3.move_x(env.eval_arg(i + 3));
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_x(env.eval_arg(i + 4));
pt2 = pt1;
pt2.move(env.eval_arg(i + 5), env.eval_arg(i + 6));
pt3 = pt2;
pt3.move_y(env.eval_arg(i + 7));
if ((env.argStack.get_count() - i < 16) && ((env.argStack.get_count() & 1) != 0))
pt3.move_x(env.eval_arg(i + 8));
PATH::curve(env, param, pt1, pt2, pt3);
}
}
}
static void hvcurveto(ENV &env, PARAM &param)
{
point_t pt1, pt2, pt3;
unsigned int i = 0;
if ((env.argStack.get_count() % 8) >= 4) {
point_t pt1 = env.get_pt();
pt1.move_x(env.eval_arg(i));
point_t pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
point_t pt3 = pt2;
pt3.move_y(env.eval_arg(i + 3));
i += 4;
for (; i + 8 <= env.argStack.get_count(); i += 8) {
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = env.get_pt();
pt1.move_y(env.eval_arg(i));
pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
pt3 = pt2;
pt3.move_x(env.eval_arg(i + 3));
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_x(env.eval_arg(i + 4));
pt2 = pt1;
pt2.move(env.eval_arg(i + 5), env.eval_arg(i + 6));
pt3 = pt2;
pt3.move_y(env.eval_arg(i + 7));
}
if (i < env.argStack.get_count())
pt3.move_x(env.eval_arg(i));
PATH::curve(env, param, pt1, pt2, pt3);
} else {
for (; i + 8 <= env.argStack.get_count(); i += 8) {
pt1 = env.get_pt();
pt1.move_x(env.eval_arg(i));
pt2 = pt1;
pt2.move(env.eval_arg(i + 1), env.eval_arg(i + 2));
pt3 = pt2;
pt3.move_y(env.eval_arg(i + 3));
PATH::curve(env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_y(env.eval_arg(i + 4));
pt2 = pt1;
pt2.move(env.eval_arg(i + 5), env.eval_arg(i + 6));
pt3 = pt2;
pt3.move_x(env.eval_arg(i + 7));
if ((env.argStack.get_count() - i < 16) && ((env.argStack.get_count() & 1) != 0))
pt3.move_y(env.eval_arg(i + 8));
PATH::curve(env, param, pt1, pt2, pt3);
}
}
}
/* default actions to be overridden */
static void moveto(ENV &env, PARAM &param, const point_t &pt)
{
env.moveto(pt);
}
static void line(ENV &env, PARAM &param, const point_t &pt1)
{
PATH::moveto(env, param, pt1);
}
static void curve(ENV &env, PARAM &param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
{
PATH::moveto(env, param, pt3);
}
static void hflex(ENV &env, PARAM &param)
{
if (likely(env.argStack.get_count() == 7)) {
point_t pt1 = env.get_pt();
pt1.move_x(env.eval_arg(0));
point_t pt2 = pt1;
pt2.move(env.eval_arg(1), env.eval_arg(2));
point_t pt3 = pt2;
pt3.move_x(env.eval_arg(3));
point_t pt4 = pt3;
pt4.move_x(env.eval_arg(4));
point_t pt5 = pt4;
pt5.move_x(env.eval_arg(5));
pt5.y = pt1.y;
point_t pt6 = pt5;
pt6.move_x(env.eval_arg(6));
curve2(env, param, pt1, pt2, pt3, pt4, pt5, pt6);
} else
env.set_error();
}
static void flex(ENV &env, PARAM &param)
{
if (likely(env.argStack.get_count() == 13)) {
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(0), env.eval_arg(1));
point_t pt2 = pt1;
pt2.move(env.eval_arg(2), env.eval_arg(3));
point_t pt3 = pt2;
pt3.move(env.eval_arg(4), env.eval_arg(5));
point_t pt4 = pt3;
pt4.move(env.eval_arg(6), env.eval_arg(7));
point_t pt5 = pt4;
pt5.move(env.eval_arg(8), env.eval_arg(9));
point_t pt6 = pt5;
pt6.move(env.eval_arg(10), env.eval_arg(11));
curve2(env, param, pt1, pt2, pt3, pt4, pt5, pt6);
} else
env.set_error();
}
static void hflex1(ENV &env, PARAM &param)
{
if (likely(env.argStack.get_count() == 9)) {
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(0), env.eval_arg(1));
point_t pt2 = pt1;
pt2.move(env.eval_arg(2), env.eval_arg(3));
point_t pt3 = pt2;
pt3.move_x(env.eval_arg(4));
point_t pt4 = pt3;
pt4.move_x(env.eval_arg(5));
point_t pt5 = pt4;
pt5.move(env.eval_arg(6), env.eval_arg(7));
point_t pt6 = pt5;
pt6.move_x(env.eval_arg(8));
pt6.y = env.get_pt().y;
curve2(env, param, pt1, pt2, pt3, pt4, pt5, pt6);
} else
env.set_error();
}
static void flex1(ENV &env, PARAM &param)
{
if (likely(env.argStack.get_count() == 11)) {
point_t d;
d.init();
for (unsigned int i = 0; i < 10; i += 2)
d.move(env.eval_arg(i), env.eval_arg(i + 1));
point_t pt1 = env.get_pt();
pt1.move(env.eval_arg(0), env.eval_arg(1));
point_t pt2 = pt1;
pt2.move(env.eval_arg(2), env.eval_arg(3));
point_t pt3 = pt2;
pt3.move(env.eval_arg(4), env.eval_arg(5));
point_t pt4 = pt3;
pt4.move(env.eval_arg(6), env.eval_arg(7));
point_t pt5 = pt4;
pt5.move(env.eval_arg(8), env.eval_arg(9));
point_t pt6 = pt5;
if (fabs(d.x.to_real()) > fabs(d.y.to_real())) {
pt6.move_x(env.eval_arg(10));
pt6.y = env.get_pt().y;
} else {
pt6.x = env.get_pt().x;
pt6.move_y(env.eval_arg(10));
}
curve2(env, param, pt1, pt2, pt3, pt4, pt5, pt6);
} else
env.set_error();
}
protected:
static void curve2(ENV &env,
PARAM &param,
const point_t &pt1,
const point_t &pt2,
const point_t &pt3,
const point_t &pt4,
const point_t &pt5,
const point_t &pt6)
{
PATH::curve(env, param, pt1, pt2, pt3);
PATH::curve(env, param, pt4, pt5, pt6);
}
};
template <typename ENV, typename OPSET, typename PARAM> struct cs_interpreter_t : interpreter_t<ENV>
{
bool interpret(PARAM &param)
{
SUPER::env.set_endchar(false);
for (;;) {
OPSET::process_op(SUPER::env.fetch_op(), SUPER::env, param);
if (unlikely(SUPER::env.in_error()))
return false;
if (SUPER::env.is_endchar())
break;
}
return true;
}
private:
typedef interpreter_t<ENV> SUPER;
};
} /* namespace CFF */
#endif /* HB_CFF_INTERP_CS_COMMON_HH */

View File

@ -0,0 +1,202 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF_INTERP_DICT_COMMON_HH
#define HB_CFF_INTERP_DICT_COMMON_HH
#include "hb-cff-interp-common.hh"
namespace CFF {
using namespace OT;
/* an opstr and the parsed out dict value(s) */
struct dict_val_t : op_str_t
{
void init()
{
single_val.set_int(0);
}
void fini() {}
number_t single_val;
};
typedef dict_val_t num_dict_val_t;
template <typename VAL> struct dict_values_t : parsed_values_t<VAL>
{
};
template <typename OPSTR = op_str_t> struct top_dict_values_t : dict_values_t<OPSTR>
{
void init()
{
dict_values_t<OPSTR>::init();
charStringsOffset = 0;
FDArrayOffset = 0;
}
void fini()
{
dict_values_t<OPSTR>::fini();
}
unsigned int charStringsOffset;
unsigned int FDArrayOffset;
};
struct dict_opset_t : opset_t<number_t>
{
static void process_op(op_code_t op, interp_env_t<number_t> &env)
{
switch (op) {
case OpCode_longintdict: /* 5-byte integer */
env.argStack.push_longint_from_substr(env.str_ref);
break;
case OpCode_BCD: /* real number */
env.argStack.push_real(parse_bcd(env.str_ref));
break;
default:
opset_t<number_t>::process_op(op, env);
break;
}
}
/* Turns CFF's BCD format into strtod understandable string */
static double parse_bcd(byte_str_ref_t &str_ref)
{
if (unlikely(str_ref.in_error()))
return .0;
enum Nibble { DECIMAL = 10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
char buf[32];
unsigned char byte = 0;
for (unsigned i = 0, count = 0; count < ARRAY_LENGTH(buf); ++i, ++count) {
unsigned nibble;
if (!(i & 1)) {
if (unlikely(!str_ref.avail()))
break;
byte = str_ref[0];
str_ref.inc();
nibble = byte >> 4;
} else
nibble = byte & 0x0F;
if (unlikely(nibble == RESERVED))
break;
else if (nibble == END) {
const char *p = buf;
double pv;
if (unlikely(!hb_parse_double(&p, p + count, &pv, true /* whole buffer */)))
break;
return pv;
} else {
buf[count] = "0123456789.EE?-?"[nibble];
if (nibble == EXP_NEG) {
++count;
if (unlikely(count == ARRAY_LENGTH(buf)))
break;
buf[count] = '-';
}
}
}
str_ref.set_error();
return .0;
}
static bool is_hint_op(op_code_t op)
{
switch (op) {
case OpCode_BlueValues:
case OpCode_OtherBlues:
case OpCode_FamilyBlues:
case OpCode_FamilyOtherBlues:
case OpCode_StemSnapH:
case OpCode_StemSnapV:
case OpCode_StdHW:
case OpCode_StdVW:
case OpCode_BlueScale:
case OpCode_BlueShift:
case OpCode_BlueFuzz:
case OpCode_ForceBold:
case OpCode_LanguageGroup:
case OpCode_ExpansionFactor:
return true;
default:
return false;
}
}
};
template <typename VAL = op_str_t> struct top_dict_opset_t : dict_opset_t
{
static void process_op(op_code_t op, interp_env_t<number_t> &env, top_dict_values_t<VAL> &dictval)
{
switch (op) {
case OpCode_CharStrings:
dictval.charStringsOffset = env.argStack.pop_uint();
env.clear_args();
break;
case OpCode_FDArray:
dictval.FDArrayOffset = env.argStack.pop_uint();
env.clear_args();
break;
case OpCode_FontMatrix:
env.clear_args();
break;
default:
dict_opset_t::process_op(op, env);
break;
}
}
};
template <typename OPSET, typename PARAM, typename ENV = num_interp_env_t>
struct dict_interpreter_t : interpreter_t<ENV>
{
bool interpret(PARAM &param)
{
param.init();
while (SUPER::env.str_ref.avail()) {
OPSET::process_op(SUPER::env.fetch_op(), SUPER::env, param);
if (unlikely(SUPER::env.in_error()))
return false;
}
return true;
}
private:
typedef interpreter_t<ENV> SUPER;
};
} /* namespace CFF */
#endif /* HB_CFF_INTERP_DICT_COMMON_HH */

View File

@ -0,0 +1,161 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF1_INTERP_CS_HH
#define HB_CFF1_INTERP_CS_HH
#include "hb.hh"
#include "hb-cff-interp-cs-common.hh"
namespace CFF {
using namespace OT;
typedef biased_subrs_t<CFF1Subrs> cff1_biased_subrs_t;
struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
{
template <typename ACC> void init(const byte_str_t &str, ACC &acc, unsigned int fd)
{
SUPER::init(str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
processed_width = false;
has_width = false;
arg_start = 0;
in_seac = false;
}
void fini()
{
SUPER::fini();
}
void set_width(bool has_width_)
{
if (likely(!processed_width && (SUPER::argStack.get_count() > 0))) {
if (has_width_) {
width = SUPER::argStack[0];
has_width = true;
arg_start = 1;
}
}
processed_width = true;
}
void clear_args()
{
arg_start = 0;
SUPER::clear_args();
}
void set_in_seac(bool _in_seac)
{
in_seac = _in_seac;
}
bool processed_width;
bool has_width;
unsigned int arg_start;
number_t width;
bool in_seac;
private:
typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER;
};
template <typename OPSET, typename PARAM, typename PATH = path_procs_null_t<cff1_cs_interp_env_t, PARAM>>
struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>
{
/* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
/* Type 1-originated deprecated opcodes, seac behavior of endchar and dotsection are supported */
static void process_op(op_code_t op, cff1_cs_interp_env_t &env, PARAM &param)
{
switch (op) {
case OpCode_dotsection:
SUPER::flush_args_and_op(op, env, param);
break;
case OpCode_endchar:
OPSET::check_width(op, env, param);
if (env.argStack.get_count() >= 4) {
OPSET::process_seac(env, param);
}
OPSET::flush_args_and_op(op, env, param);
env.set_endchar(true);
break;
default:
SUPER::process_op(op, env, param);
}
}
static void check_width(op_code_t op, cff1_cs_interp_env_t &env, PARAM &param)
{
if (!env.processed_width) {
bool has_width = false;
switch (op) {
case OpCode_endchar:
case OpCode_hstem:
case OpCode_hstemhm:
case OpCode_vstem:
case OpCode_vstemhm:
case OpCode_hintmask:
case OpCode_cntrmask:
has_width = ((env.argStack.get_count() & 1) != 0);
break;
case OpCode_hmoveto:
case OpCode_vmoveto:
has_width = (env.argStack.get_count() > 1);
break;
case OpCode_rmoveto:
has_width = (env.argStack.get_count() > 2);
break;
default:
return;
}
env.set_width(has_width);
}
}
static void process_seac(cff1_cs_interp_env_t &env, PARAM &param) {}
static void flush_args(cff1_cs_interp_env_t &env, PARAM &param)
{
SUPER::flush_args(env, param);
env.clear_args(); /* pop off width */
}
private:
typedef cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH> SUPER;
};
template <typename OPSET, typename PARAM>
struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM>
{
};
} /* namespace CFF */
#endif /* HB_CFF1_INTERP_CS_HH */

View File

@ -0,0 +1,291 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF2_INTERP_CS_HH
#define HB_CFF2_INTERP_CS_HH
#include "hb.hh"
#include "hb-cff-interp-cs-common.hh"
namespace CFF {
using namespace OT;
struct blend_arg_t : number_t
{
void init()
{
number_t::init();
deltas.init();
}
void fini()
{
number_t::fini();
deltas.fini_deep();
}
void set_int(int v)
{
reset_blends();
number_t::set_int(v);
}
void set_fixed(int32_t v)
{
reset_blends();
number_t::set_fixed(v);
}
void set_real(double v)
{
reset_blends();
number_t::set_real(v);
}
void set_blends(unsigned int numValues_,
unsigned int valueIndex_,
unsigned int numBlends,
hb_array_t<const blend_arg_t> blends_)
{
numValues = numValues_;
valueIndex = valueIndex_;
deltas.resize(numBlends);
for (unsigned int i = 0; i < numBlends; i++)
deltas[i] = blends_[i];
}
bool blending() const
{
return deltas.length > 0;
}
void reset_blends()
{
numValues = valueIndex = 0;
deltas.resize(0);
}
unsigned int numValues;
unsigned int valueIndex;
hb_vector_t<number_t> deltas;
};
typedef interp_env_t<blend_arg_t> BlendInterpEnv;
typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
{
template <typename ACC>
void
init(const byte_str_t &str, ACC &acc, unsigned int fd, const int *coords_ = nullptr, unsigned int num_coords_ = 0)
{
SUPER::init(str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
coords = coords_;
num_coords = num_coords_;
varStore = acc.varStore;
seen_blend = false;
seen_vsindex_ = false;
scalars.init();
do_blend = num_coords && coords && varStore->size;
set_ivs(acc.privateDicts[fd].ivs);
}
void fini()
{
scalars.fini();
SUPER::fini();
}
op_code_t fetch_op()
{
if (this->str_ref.avail())
return SUPER::fetch_op();
/* make up return or endchar op */
if (this->callStack.is_empty())
return OpCode_endchar;
else
return OpCode_return;
}
const blend_arg_t &eval_arg(unsigned int i)
{
blend_arg_t &arg = argStack[i];
blend_arg(arg);
return arg;
}
const blend_arg_t &pop_arg()
{
blend_arg_t &arg = argStack.pop();
blend_arg(arg);
return arg;
}
void process_blend()
{
if (!seen_blend) {
region_count = varStore->varStore.get_region_index_count(get_ivs());
if (do_blend) {
scalars.resize(region_count);
varStore->varStore.get_scalars(get_ivs(), coords, num_coords, &scalars[0], region_count);
}
seen_blend = true;
}
}
void process_vsindex()
{
unsigned int index = argStack.pop_uint();
if (unlikely(seen_vsindex() || seen_blend)) {
set_error();
} else {
set_ivs(index);
}
seen_vsindex_ = true;
}
unsigned int get_region_count() const
{
return region_count;
}
void set_region_count(unsigned int region_count_)
{
region_count = region_count_;
}
unsigned int get_ivs() const
{
return ivs;
}
void set_ivs(unsigned int ivs_)
{
ivs = ivs_;
}
bool seen_vsindex() const
{
return seen_vsindex_;
}
protected:
void blend_arg(blend_arg_t &arg)
{
if (do_blend && arg.blending()) {
if (likely(scalars.length == arg.deltas.length)) {
double v = arg.to_real();
for (unsigned int i = 0; i < scalars.length; i++) {
v += (double)scalars[i] * arg.deltas[i].to_real();
}
arg.set_real(v);
arg.deltas.resize(0);
}
}
}
protected:
const int *coords;
unsigned int num_coords;
const CFF2VariationStore *varStore;
unsigned int region_count;
unsigned int ivs;
hb_vector_t<float> scalars;
bool do_blend;
bool seen_vsindex_;
bool seen_blend;
typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
};
template <typename OPSET, typename PARAM, typename PATH = path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
{
static void process_op(op_code_t op, cff2_cs_interp_env_t &env, PARAM &param)
{
switch (op) {
case OpCode_callsubr:
case OpCode_callgsubr:
/* a subroutine number shoudln't be a blended value */
if (unlikely(env.argStack.peek().blending())) {
env.set_error();
break;
}
SUPER::process_op(op, env, param);
break;
case OpCode_blendcs:
OPSET::process_blend(env, param);
break;
case OpCode_vsindexcs:
if (unlikely(env.argStack.peek().blending())) {
env.set_error();
break;
}
OPSET::process_vsindex(env, param);
break;
default:
SUPER::process_op(op, env, param);
}
}
static void process_blend(cff2_cs_interp_env_t &env, PARAM &param)
{
unsigned int n, k;
env.process_blend();
k = env.get_region_count();
n = env.argStack.pop_uint();
/* copy the blend values into blend array of the default values */
unsigned int start = env.argStack.get_count() - ((k + 1) * n);
/* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
if (unlikely(start > env.argStack.get_count())) {
env.set_error();
return;
}
for (unsigned int i = 0; i < n; i++) {
const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray(start + n + (i * k));
env.argStack[start + i].set_blends(n, i, k, blends);
}
/* pop off blend values leaving default values now adorned with blend values */
env.argStack.pop(k * n);
}
static void process_vsindex(cff2_cs_interp_env_t &env, PARAM &param)
{
env.process_vsindex();
env.clear_args();
}
private:
typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER;
};
template <typename OPSET, typename PARAM>
struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM>
{
};
} /* namespace CFF */
#endif /* HB_CFF2_INTERP_CS_HH */

967
harfbuzz/src/hb-common.cc Normal file
View File

@ -0,0 +1,967 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#include "hb-machinery.hh"
#include <locale.h>
#ifdef HB_NO_SETLOCALE
#define setlocale(Category, Locale) "C"
#endif
/**
* SECTION:hb-common
* @title: hb-common
* @short_description: Common data types
* @include: hb.h
*
* Common data types used across HarfBuzz are defined here.
**/
/* hb_options_t */
hb_atomic_int_t _hb_options;
void _hb_options_init()
{
hb_options_union_t u;
u.i = 0;
u.opts.initialized = true;
const char *c = getenv("HB_OPTIONS");
if (c) {
while (*c) {
const char *p = strchr(c, ':');
if (!p)
p = c + strlen(c);
#define OPTION(name, symbol) \
if (0 == strncmp(c, name, p - c) && strlen(name) == static_cast<size_t>(p - c)) \
do { \
u.opts.symbol = true; \
} while (0)
OPTION("uniscribe-bug-compatible", uniscribe_bug_compatible);
#undef OPTION
c = *p ? p + 1 : p;
}
}
/* This is idempotent and threadsafe. */
_hb_options.set_relaxed(u.i);
}
/* hb_tag_t */
/**
* hb_tag_from_string:
* @str: (array length=len) (element-type uint8_t):
* @len:
*
*
*
* Return value:
*
* Since: 0.9.2
**/
hb_tag_t hb_tag_from_string(const char *str, int len)
{
char tag[4];
unsigned int i;
if (!str || !len || !*str)
return HB_TAG_NONE;
if (len < 0 || len > 4)
len = 4;
for (i = 0; i < (unsigned)len && str[i]; i++)
tag[i] = str[i];
for (; i < 4; i++)
tag[i] = ' ';
return HB_TAG(tag[0], tag[1], tag[2], tag[3]);
}
/**
* hb_tag_to_string:
* @tag:
* @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
*
*
*
* Since: 0.9.5
**/
void hb_tag_to_string(hb_tag_t tag, char *buf)
{
buf[0] = (char)(uint8_t)(tag >> 24);
buf[1] = (char)(uint8_t)(tag >> 16);
buf[2] = (char)(uint8_t)(tag >> 8);
buf[3] = (char)(uint8_t)(tag >> 0);
}
/* hb_direction_t */
const char direction_strings[][4] = {"ltr", "rtl", "ttb", "btt"};
/**
* hb_direction_from_string:
* @str: (array length=len) (element-type uint8_t):
* @len:
*
*
*
* Return value:
*
* Since: 0.9.2
**/
hb_direction_t hb_direction_from_string(const char *str, int len)
{
if (unlikely(!str || !len || !*str))
return HB_DIRECTION_INVALID;
/* Lets match loosely: just match the first letter, such that
* all of "ltr", "left-to-right", etc work!
*/
char c = TOLOWER(str[0]);
for (unsigned int i = 0; i < ARRAY_LENGTH(direction_strings); i++)
if (c == direction_strings[i][0])
return (hb_direction_t)(HB_DIRECTION_LTR + i);
return HB_DIRECTION_INVALID;
}
/**
* hb_direction_to_string:
* @direction:
*
*
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
const char *hb_direction_to_string(hb_direction_t direction)
{
if (likely((unsigned int)(direction - HB_DIRECTION_LTR) < ARRAY_LENGTH(direction_strings)))
return direction_strings[direction - HB_DIRECTION_LTR];
return "invalid";
}
/* hb_language_t */
struct hb_language_impl_t
{
const char s[1];
};
static const char canon_map[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, '-', 0, 0, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, 0, 'a',
'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0, 0, 0, 0, '-', 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0};
static bool lang_equal(hb_language_t v1, const void *v2)
{
const unsigned char *p1 = (const unsigned char *)v1;
const unsigned char *p2 = (const unsigned char *)v2;
while (*p1 && *p1 == canon_map[*p2]) {
p1++;
p2++;
}
return *p1 == canon_map[*p2];
}
#if 0
static unsigned int
lang_hash (const void *key)
{
const unsigned char *p = key;
unsigned int h = 0;
while (canon_map[*p])
{
h = (h << 5) - h + canon_map[*p];
p++;
}
return h;
}
#endif
struct hb_language_item_t
{
struct hb_language_item_t *next;
hb_language_t lang;
bool operator==(const char *s) const
{
return lang_equal(lang, s);
}
hb_language_item_t &operator=(const char *s)
{
/* If a custom allocated is used calling strdup() pairs
badly with a call to the custom free() in fini() below.
Therefore don't call strdup(), implement its behavior.
*/
size_t len = strlen(s) + 1;
lang = (hb_language_t)malloc(len);
if (likely(lang)) {
memcpy((unsigned char *)lang, s, len);
for (unsigned char *p = (unsigned char *)lang; *p; p++)
*p = canon_map[*p];
}
return *this;
}
void fini()
{
free((void *)lang);
}
};
/* Thread-safe lock-free language list */
static hb_atomic_ptr_t<hb_language_item_t> langs;
#if HB_USE_ATEXIT
static void free_langs()
{
retry:
hb_language_item_t *first_lang = langs;
if (unlikely(!langs.cmpexch(first_lang, nullptr)))
goto retry;
while (first_lang) {
hb_language_item_t *next = first_lang->next;
first_lang->fini();
free(first_lang);
first_lang = next;
}
}
#endif
static hb_language_item_t *lang_find_or_insert(const char *key)
{
retry:
hb_language_item_t *first_lang = langs;
for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
if (*lang == key)
return lang;
/* Not found; allocate one. */
hb_language_item_t *lang = (hb_language_item_t *)calloc(1, sizeof(hb_language_item_t));
if (unlikely(!lang))
return nullptr;
lang->next = first_lang;
*lang = key;
if (unlikely(!lang->lang)) {
free(lang);
return nullptr;
}
if (unlikely(!langs.cmpexch(first_lang, lang))) {
lang->fini();
free(lang);
goto retry;
}
#if HB_USE_ATEXIT
if (!first_lang)
atexit(free_langs); /* First person registers atexit() callback. */
#endif
return lang;
}
/**
* hb_language_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing
* a BCP 47 language tag
* @len: length of the @str, or -1 if it is %NULL-terminated.
*
* Converts @str representing a BCP 47 language tag to the corresponding
* #hb_language_t.
*
* Return value: (transfer none):
* The #hb_language_t corresponding to the BCP 47 language tag.
*
* Since: 0.9.2
**/
hb_language_t hb_language_from_string(const char *str, int len)
{
if (!str || !len || !*str)
return HB_LANGUAGE_INVALID;
hb_language_item_t *item = nullptr;
if (len >= 0) {
/* NUL-terminate it. */
char strbuf[64];
len = hb_min(len, (int)sizeof(strbuf) - 1);
memcpy(strbuf, str, len);
strbuf[len] = '\0';
item = lang_find_or_insert(strbuf);
} else
item = lang_find_or_insert(str);
return likely(item) ? item->lang : HB_LANGUAGE_INVALID;
}
/**
* hb_language_to_string:
* @language: an #hb_language_t to convert.
*
* See hb_language_from_string().
*
* Return value: (transfer none):
* A %NULL-terminated string representing the @language. Must not be freed by
* the caller.
*
* Since: 0.9.2
**/
const char *hb_language_to_string(hb_language_t language)
{
if (unlikely(!language))
return nullptr;
return language->s;
}
/**
* hb_language_get_default:
*
* Get default language from current locale.
*
* Note that the first time this function is called, it calls
* "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
* setlocale function is, in many implementations, NOT threadsafe. To avoid
* problems, call this function once before multiple threads can call it.
* This function is only used from hb_buffer_guess_segment_properties() by
* HarfBuzz itself.
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
hb_language_t hb_language_get_default()
{
static hb_atomic_ptr_t<hb_language_t> default_language;
hb_language_t language = default_language;
if (unlikely(language == HB_LANGUAGE_INVALID)) {
language = hb_language_from_string(setlocale(LC_CTYPE, nullptr), -1);
(void)default_language.cmpexch(HB_LANGUAGE_INVALID, language);
}
return language;
}
/* hb_script_t */
/**
* hb_script_from_iso15924_tag:
* @tag: an #hb_tag_t representing an ISO 15924 tag.
*
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
*
* Return value:
* An #hb_script_t corresponding to the ISO 15924 tag.
*
* Since: 0.9.2
**/
hb_script_t hb_script_from_iso15924_tag(hb_tag_t tag)
{
if (unlikely(tag == HB_TAG_NONE))
return HB_SCRIPT_INVALID;
/* Be lenient, adjust case (one capital letter followed by three small letters) */
tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
switch (tag) {
/* These graduated from the 'Q' private-area codes, but
* the old code is still aliased by Unicode, and the Qaai
* one in use by ICU. */
case HB_TAG('Q', 'a', 'a', 'i'):
return HB_SCRIPT_INHERITED;
case HB_TAG('Q', 'a', 'a', 'c'):
return HB_SCRIPT_COPTIC;
/* Script variants from https://unicode.org/iso15924/ */
case HB_TAG('C', 'y', 'r', 's'):
return HB_SCRIPT_CYRILLIC;
case HB_TAG('L', 'a', 't', 'f'):
return HB_SCRIPT_LATIN;
case HB_TAG('L', 'a', 't', 'g'):
return HB_SCRIPT_LATIN;
case HB_TAG('S', 'y', 'r', 'e'):
return HB_SCRIPT_SYRIAC;
case HB_TAG('S', 'y', 'r', 'j'):
return HB_SCRIPT_SYRIAC;
case HB_TAG('S', 'y', 'r', 'n'):
return HB_SCRIPT_SYRIAC;
}
/* If it looks right, just use the tag as a script */
if (((uint32_t)tag & 0xE0E0E0E0u) == 0x40606060u)
return (hb_script_t)tag;
/* Otherwise, return unknown */
return HB_SCRIPT_UNKNOWN;
}
/**
* hb_script_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing an
* ISO 15924 tag.
* @len: length of the @str, or -1 if it is %NULL-terminated.
*
* Converts a string @str representing an ISO 15924 script tag to a
* corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
* hb_script_from_iso15924_tag().
*
* Return value:
* An #hb_script_t corresponding to the ISO 15924 tag.
*
* Since: 0.9.2
**/
hb_script_t hb_script_from_string(const char *str, int len)
{
return hb_script_from_iso15924_tag(hb_tag_from_string(str, len));
}
/**
* hb_script_to_iso15924_tag:
* @script: an #hb_script_t to convert.
*
* See hb_script_from_iso15924_tag().
*
* Return value:
* An #hb_tag_t representing an ISO 15924 script tag.
*
* Since: 0.9.2
**/
hb_tag_t hb_script_to_iso15924_tag(hb_script_t script)
{
return (hb_tag_t)script;
}
/**
* hb_script_get_horizontal_direction:
* @script:
*
*
*
* Return value:
*
* Since: 0.9.2
**/
hb_direction_t hb_script_get_horizontal_direction(hb_script_t script)
{
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
switch ((hb_tag_t)script) {
/* Unicode-1.1 additions */
case HB_SCRIPT_ARABIC:
case HB_SCRIPT_HEBREW:
/* Unicode-3.0 additions */
case HB_SCRIPT_SYRIAC:
case HB_SCRIPT_THAANA:
/* Unicode-4.0 additions */
case HB_SCRIPT_CYPRIOT:
/* Unicode-4.1 additions */
case HB_SCRIPT_KHAROSHTHI:
/* Unicode-5.0 additions */
case HB_SCRIPT_PHOENICIAN:
case HB_SCRIPT_NKO:
/* Unicode-5.1 additions */
case HB_SCRIPT_LYDIAN:
/* Unicode-5.2 additions */
case HB_SCRIPT_AVESTAN:
case HB_SCRIPT_IMPERIAL_ARAMAIC:
case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
case HB_SCRIPT_OLD_SOUTH_ARABIAN:
case HB_SCRIPT_OLD_TURKIC:
case HB_SCRIPT_SAMARITAN:
/* Unicode-6.0 additions */
case HB_SCRIPT_MANDAIC:
/* Unicode-6.1 additions */
case HB_SCRIPT_MEROITIC_CURSIVE:
case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
/* Unicode-7.0 additions */
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_MENDE_KIKAKUI:
case HB_SCRIPT_NABATAEAN:
case HB_SCRIPT_OLD_NORTH_ARABIAN:
case HB_SCRIPT_PALMYRENE:
case HB_SCRIPT_PSALTER_PAHLAVI:
/* Unicode-8.0 additions */
case HB_SCRIPT_HATRAN:
/* Unicode-9.0 additions */
case HB_SCRIPT_ADLAM:
/* Unicode-11.0 additions */
case HB_SCRIPT_HANIFI_ROHINGYA:
case HB_SCRIPT_OLD_SOGDIAN:
case HB_SCRIPT_SOGDIAN:
/* Unicode-12.0 additions */
case HB_SCRIPT_ELYMAIC:
/* Unicode-13.0 additions */
case HB_SCRIPT_CHORASMIAN:
case HB_SCRIPT_YEZIDI:
return HB_DIRECTION_RTL;
/* https://github.com/harfbuzz/harfbuzz/issues/1000 */
case HB_SCRIPT_OLD_HUNGARIAN:
case HB_SCRIPT_OLD_ITALIC:
case HB_SCRIPT_RUNIC:
return HB_DIRECTION_INVALID;
}
return HB_DIRECTION_LTR;
}
/* hb_feature_t and hb_variation_t */
static bool parse_space(const char **pp, const char *end)
{
while (*pp < end && ISSPACE(**pp))
(*pp)++;
return true;
}
static bool parse_char(const char **pp, const char *end, char c)
{
parse_space(pp, end);
if (*pp == end || **pp != c)
return false;
(*pp)++;
return true;
}
static bool parse_uint(const char **pp, const char *end, unsigned int *pv)
{
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
* such that -1 turns into "big number"... */
int v;
if (unlikely(!hb_parse_int(pp, end, &v)))
return false;
*pv = v;
return true;
}
static bool parse_uint32(const char **pp, const char *end, uint32_t *pv)
{
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
* such that -1 turns into "big number"... */
int v;
if (unlikely(!hb_parse_int(pp, end, &v)))
return false;
*pv = v;
return true;
}
static bool parse_bool(const char **pp, const char *end, uint32_t *pv)
{
parse_space(pp, end);
const char *p = *pp;
while (*pp < end && ISALPHA(**pp))
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 && TOLOWER(p[0]) == 'o' && TOLOWER(p[1]) == 'n')
*pv = 1;
else if (*pp - p == 3 && TOLOWER(p[0]) == 'o' && TOLOWER(p[1]) == 'f' && TOLOWER(p[2]) == 'f')
*pv = 0;
else
return false;
return true;
}
/* hb_feature_t */
static bool parse_feature_value_prefix(const char **pp, const char *end, hb_feature_t *feature)
{
if (parse_char(pp, end, '-'))
feature->value = 0;
else {
parse_char(pp, end, '+');
feature->value = 1;
}
return true;
}
static bool parse_tag(const char **pp, const char *end, hb_tag_t *tag)
{
parse_space(pp, end);
char quote = 0;
if (*pp < end && (**pp == '\'' || **pp == '"')) {
quote = **pp;
(*pp)++;
}
const char *p = *pp;
while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
(*pp)++;
if (p == *pp || *pp - p > 4)
return false;
*tag = hb_tag_from_string(p, *pp - p);
if (quote) {
/* CSS expects exactly four bytes. And we only allow quotations for
* CSS compatibility. So, enforce the length. */
if (*pp - p != 4)
return false;
if (*pp == end || **pp != quote)
return false;
(*pp)++;
}
return true;
}
static bool parse_feature_indices(const char **pp, const char *end, hb_feature_t *feature)
{
parse_space(pp, end);
bool has_start;
feature->start = HB_FEATURE_GLOBAL_START;
feature->end = HB_FEATURE_GLOBAL_END;
if (!parse_char(pp, end, '['))
return true;
has_start = parse_uint(pp, end, &feature->start);
if (parse_char(pp, end, ':') || parse_char(pp, end, ';')) {
parse_uint(pp, end, &feature->end);
} else {
if (has_start)
feature->end = feature->start + 1;
}
return parse_char(pp, end, ']');
}
static bool parse_feature_value_postfix(const char **pp, const char *end, hb_feature_t *feature)
{
bool had_equal = parse_char(pp, end, '=');
bool had_value = parse_uint32(pp, end, &feature->value) || parse_bool(pp, end, &feature->value);
/* CSS doesn't use equal-sign between tag and value.
* If there was an equal-sign, then there *must* be a value.
* A value without an equal-sign is ok, but not required. */
return !had_equal || had_value;
}
static bool parse_one_feature(const char **pp, const char *end, hb_feature_t *feature)
{
return parse_feature_value_prefix(pp, end, feature) && parse_tag(pp, end, &feature->tag) &&
parse_feature_indices(pp, end, feature) && parse_feature_value_postfix(pp, end, feature) &&
parse_space(pp, end) && *pp == end;
}
/**
* hb_feature_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
* @len: length of @str, or -1 if string is %NULL terminated
* @feature: (out): the #hb_feature_t to initialize with the parsed values
*
* Parses a string into a #hb_feature_t.
*
* The format for specifying feature strings follows. All valid CSS
* font-feature-settings values other than 'normal' and the global values are
* also accepted, though not documented below. CSS string escapes are not
* supported.
*
* The range indices refer to the positions between Unicode characters. The
* position before the first character is always 0.
*
* The format is Python-esque. Here is how it all works:
*
* <informaltable pgwide='1' align='left' frame='none'>
* <tgroup cols='5'>
* <thead>
* <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
* </thead>
* <tbody>
* <row><entry>Setting value:</entry></row>
* <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature
*on</entry></row> <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn
*feature on</entry></row> <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry></entry>
*<entry>Turn feature off</entry></row> <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry>
*<entry></entry> <entry>Turn feature off</entry></row> <row><entry>kern=1</entry> <entry>1</entry>
*<entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row> <row><entry>aalt=2</entry>
*<entry>2</entry> <entry>0</entry> <entry></entry> <entry>Choose 2nd alternate</entry></row>
* <row><entry>Setting index:</entry></row>
* <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature
*on</entry></row> <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn
*feature on</entry></row> <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry></entry>
*<entry>Turn feature on, partial</entry></row> <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry>
*<entry>5</entry> <entry>Turn feature on, partial</entry></row> <row><entry>kern[3:5]</entry> <entry>1</entry>
*<entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row> <row><entry>kern[3]</entry>
*<entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
* <row><entry>Mixing it all:</entry></row>
* <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate
*on for range</entry></row>
* </tbody>
* </tgroup>
* </informaltable>
*
* Return value:
* %true if @str is successfully parsed, %false otherwise.
*
* Since: 0.9.5
**/
hb_bool_t hb_feature_from_string(const char *str, int len, hb_feature_t *feature)
{
hb_feature_t feat;
if (len < 0)
len = strlen(str);
if (likely(parse_one_feature(&str, str + len, &feat))) {
if (feature)
*feature = feat;
return true;
}
if (feature)
memset(feature, 0, sizeof(*feature));
return false;
}
/**
* hb_feature_to_string:
* @feature: an #hb_feature_t to convert
* @buf: (array length=size) (out): output string
* @size: the allocated size of @buf
*
* Converts a #hb_feature_t into a %NULL-terminated string in the format
* understood by hb_feature_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Since: 0.9.5
**/
void hb_feature_to_string(hb_feature_t *feature, char *buf, unsigned int size)
{
if (unlikely(!size))
return;
char s[128];
unsigned int len = 0;
if (feature->value == 0)
s[len++] = '-';
hb_tag_to_string(feature->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END) {
s[len++] = '[';
if (feature->start)
len += hb_max(0, snprintf(s + len, ARRAY_LENGTH(s) - len, "%u", feature->start));
if (feature->end != feature->start + 1) {
s[len++] = ':';
if (feature->end != HB_FEATURE_GLOBAL_END)
len += hb_max(0, snprintf(s + len, ARRAY_LENGTH(s) - len, "%u", feature->end));
}
s[len++] = ']';
}
if (feature->value > 1) {
s[len++] = '=';
len += hb_max(0, snprintf(s + len, ARRAY_LENGTH(s) - len, "%u", feature->value));
}
assert(len < ARRAY_LENGTH(s));
len = hb_min(len, size - 1);
memcpy(buf, s, len);
buf[len] = '\0';
}
/* hb_variation_t */
static bool parse_variation_value(const char **pp, const char *end, hb_variation_t *variation)
{
parse_char(pp, end, '='); /* Optional. */
double v;
if (unlikely(!hb_parse_double(pp, end, &v)))
return false;
variation->value = v;
return true;
}
static bool parse_one_variation(const char **pp, const char *end, hb_variation_t *variation)
{
return parse_tag(pp, end, &variation->tag) && parse_variation_value(pp, end, variation) && parse_space(pp, end) &&
*pp == end;
}
/**
* hb_variation_from_string:
*
* Since: 1.4.2
*/
hb_bool_t hb_variation_from_string(const char *str, int len, hb_variation_t *variation)
{
hb_variation_t var;
if (len < 0)
len = strlen(str);
if (likely(parse_one_variation(&str, str + len, &var))) {
if (variation)
*variation = var;
return true;
}
if (variation)
memset(variation, 0, sizeof(*variation));
return false;
}
/**
* hb_variation_to_string:
*
* Since: 1.4.2
*/
void hb_variation_to_string(hb_variation_t *variation, char *buf, unsigned int size)
{
if (unlikely(!size))
return;
char s[128];
unsigned int len = 0;
hb_tag_to_string(variation->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
len += hb_max(0, snprintf(s + len, ARRAY_LENGTH(s) - len, "%g", (double)variation->value));
assert(len < ARRAY_LENGTH(s));
len = hb_min(len, size - 1);
memcpy(buf, s, len);
buf[len] = '\0';
}
/**
* hb_color_get_alpha:
* color: a #hb_color_t we are interested in its channels.
*
* Return value: Alpha channel value of the given color
*
* Since: 2.1.0
*/
uint8_t(hb_color_get_alpha)(hb_color_t color)
{
return hb_color_get_alpha(color);
}
/**
* hb_color_get_red:
* color: a #hb_color_t we are interested in its channels.
*
* Return value: Red channel value of the given color
*
* Since: 2.1.0
*/
uint8_t(hb_color_get_red)(hb_color_t color)
{
return hb_color_get_red(color);
}
/**
* hb_color_get_green:
* color: a #hb_color_t we are interested in its channels.
*
* Return value: Green channel value of the given color
*
* Since: 2.1.0
*/
uint8_t(hb_color_get_green)(hb_color_t color)
{
return hb_color_get_green(color);
}
/**
* hb_color_get_blue:
* color: a #hb_color_t we are interested in its channels.
*
* Return value: Blue channel value of the given color
*
* Since: 2.1.0
*/
uint8_t(hb_color_get_blue)(hb_color_t color)
{
return hb_color_get_blue(color);
}
/* If there is no visibility control, then hb-static.cc will NOT
* define anything. Instead, we get it to define one set in here
* only, so only libharfbuzz.so defines them, not other libs. */
#ifdef HB_NO_VISIBILITY
#undef HB_NO_VISIBILITY
#include "hb-static.cc"
#define HB_NO_VISIBILITY 1
#endif

486
harfbuzz/src/hb-common.h Normal file
View File

@ -0,0 +1,486 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_COMMON_H
#define HB_COMMON_H
#ifndef HB_EXTERN
#define HB_EXTERN extern
#endif
#ifndef HB_BEGIN_DECLS
#ifdef __cplusplus
#define HB_BEGIN_DECLS extern "C" {
#define HB_END_DECLS }
#else /* !__cplusplus */
#define HB_BEGIN_DECLS
#define HB_END_DECLS
#endif /* !__cplusplus */
#endif
#if defined(_SVR4) || defined(SVR4) || defined(__OpenBSD__) || defined(_sgi) || defined(__sun) || defined(sun) || \
defined(__digital__) || defined(__HP_cc)
#include <inttypes.h>
#elif defined(_AIX)
#include <sys/inttypes.h>
#elif defined(_MSC_VER) && _MSC_VER < 1600
/* VS 2010 (_MSC_VER 1600) has stdint.h */
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#elif defined(__KERNEL__)
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define HB_DEPRECATED __attribute__((__deprecated__))
#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
#define HB_DEPRECATED __declspec(deprecated)
#else
#define HB_DEPRECATED
#endif
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead")))
#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead"))
#else
#define HB_DEPRECATED_FOR(f) HB_DEPRECATED
#endif
HB_BEGIN_DECLS
typedef int hb_bool_t;
typedef uint32_t hb_codepoint_t;
typedef int32_t hb_position_t;
typedef uint32_t hb_mask_t;
typedef union _hb_var_int_t {
uint32_t u32;
int32_t i32;
uint16_t u16[2];
int16_t i16[2];
uint8_t u8[4];
int8_t i8[4];
} hb_var_int_t;
/* hb_tag_t */
typedef uint32_t hb_tag_t;
#define HB_TAG(c1, c2, c3, c4) \
((hb_tag_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | \
((uint32_t)(c4)&0xFF)))
#define HB_UNTAG(tag) \
(uint8_t)(((tag) >> 24) & 0xFF), (uint8_t)(((tag) >> 16) & 0xFF), (uint8_t)(((tag) >> 8) & 0xFF), \
(uint8_t)((tag)&0xFF)
#define HB_TAG_NONE HB_TAG(0, 0, 0, 0)
#define HB_TAG_MAX HB_TAG(0xff, 0xff, 0xff, 0xff)
#define HB_TAG_MAX_SIGNED HB_TAG(0x7f, 0xff, 0xff, 0xff)
/* len=-1 means str is NUL-terminated. */
HB_EXTERN hb_tag_t hb_tag_from_string(const char *str, int len);
/* buf should have 4 bytes. */
HB_EXTERN void hb_tag_to_string(hb_tag_t tag, char *buf);
/**
* hb_direction_t:
* @HB_DIRECTION_INVALID: Initial, unset direction.
* @HB_DIRECTION_LTR: Text is set horizontally from left to right.
* @HB_DIRECTION_RTL: Text is set horizontally from right to left.
* @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
* @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
*/
typedef enum {
HB_DIRECTION_INVALID = 0,
HB_DIRECTION_LTR = 4,
HB_DIRECTION_RTL,
HB_DIRECTION_TTB,
HB_DIRECTION_BTT
} hb_direction_t;
/* len=-1 means str is NUL-terminated */
HB_EXTERN hb_direction_t hb_direction_from_string(const char *str, int len);
HB_EXTERN const char *hb_direction_to_string(hb_direction_t direction);
#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int)(dir)) & ~3U) == 4)
/* Direction must be valid for the following */
#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int)(dir)) & ~1U) == 4)
#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int)(dir)) & ~1U) == 6)
#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int)(dir)) & ~2U) == 4)
#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int)(dir)) & ~2U) == 5)
#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t)(((unsigned int)(dir)) ^ 1))
/* hb_language_t */
typedef const struct hb_language_impl_t *hb_language_t;
HB_EXTERN hb_language_t hb_language_from_string(const char *str, int len);
HB_EXTERN const char *hb_language_to_string(hb_language_t language);
#define HB_LANGUAGE_INVALID ((hb_language_t)0)
HB_EXTERN hb_language_t hb_language_get_default(void);
/* hb_script_t */
/* https://unicode.org/iso15924/ */
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
/* Unicode Character Database property: Script (sc) */
typedef enum {
/*1.1*/ HB_SCRIPT_COMMON = HB_TAG('Z', 'y', 'y', 'y'),
/*1.1*/ HB_SCRIPT_INHERITED = HB_TAG('Z', 'i', 'n', 'h'),
/*5.0*/ HB_SCRIPT_UNKNOWN = HB_TAG('Z', 'z', 'z', 'z'),
/*1.1*/ HB_SCRIPT_ARABIC = HB_TAG('A', 'r', 'a', 'b'),
/*1.1*/ HB_SCRIPT_ARMENIAN = HB_TAG('A', 'r', 'm', 'n'),
/*1.1*/ HB_SCRIPT_BENGALI = HB_TAG('B', 'e', 'n', 'g'),
/*1.1*/ HB_SCRIPT_CYRILLIC = HB_TAG('C', 'y', 'r', 'l'),
/*1.1*/ HB_SCRIPT_DEVANAGARI = HB_TAG('D', 'e', 'v', 'a'),
/*1.1*/ HB_SCRIPT_GEORGIAN = HB_TAG('G', 'e', 'o', 'r'),
/*1.1*/ HB_SCRIPT_GREEK = HB_TAG('G', 'r', 'e', 'k'),
/*1.1*/ HB_SCRIPT_GUJARATI = HB_TAG('G', 'u', 'j', 'r'),
/*1.1*/ HB_SCRIPT_GURMUKHI = HB_TAG('G', 'u', 'r', 'u'),
/*1.1*/ HB_SCRIPT_HANGUL = HB_TAG('H', 'a', 'n', 'g'),
/*1.1*/ HB_SCRIPT_HAN = HB_TAG('H', 'a', 'n', 'i'),
/*1.1*/ HB_SCRIPT_HEBREW = HB_TAG('H', 'e', 'b', 'r'),
/*1.1*/ HB_SCRIPT_HIRAGANA = HB_TAG('H', 'i', 'r', 'a'),
/*1.1*/ HB_SCRIPT_KANNADA = HB_TAG('K', 'n', 'd', 'a'),
/*1.1*/ HB_SCRIPT_KATAKANA = HB_TAG('K', 'a', 'n', 'a'),
/*1.1*/ HB_SCRIPT_LAO = HB_TAG('L', 'a', 'o', 'o'),
/*1.1*/ HB_SCRIPT_LATIN = HB_TAG('L', 'a', 't', 'n'),
/*1.1*/ HB_SCRIPT_MALAYALAM = HB_TAG('M', 'l', 'y', 'm'),
/*1.1*/ HB_SCRIPT_ORIYA = HB_TAG('O', 'r', 'y', 'a'),
/*1.1*/ HB_SCRIPT_TAMIL = HB_TAG('T', 'a', 'm', 'l'),
/*1.1*/ HB_SCRIPT_TELUGU = HB_TAG('T', 'e', 'l', 'u'),
/*1.1*/ HB_SCRIPT_THAI = HB_TAG('T', 'h', 'a', 'i'),
/*2.0*/ HB_SCRIPT_TIBETAN = HB_TAG('T', 'i', 'b', 't'),
/*3.0*/ HB_SCRIPT_BOPOMOFO = HB_TAG('B', 'o', 'p', 'o'),
/*3.0*/ HB_SCRIPT_BRAILLE = HB_TAG('B', 'r', 'a', 'i'),
/*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG('C', 'a', 'n', 's'),
/*3.0*/ HB_SCRIPT_CHEROKEE = HB_TAG('C', 'h', 'e', 'r'),
/*3.0*/ HB_SCRIPT_ETHIOPIC = HB_TAG('E', 't', 'h', 'i'),
/*3.0*/ HB_SCRIPT_KHMER = HB_TAG('K', 'h', 'm', 'r'),
/*3.0*/ HB_SCRIPT_MONGOLIAN = HB_TAG('M', 'o', 'n', 'g'),
/*3.0*/ HB_SCRIPT_MYANMAR = HB_TAG('M', 'y', 'm', 'r'),
/*3.0*/ HB_SCRIPT_OGHAM = HB_TAG('O', 'g', 'a', 'm'),
/*3.0*/ HB_SCRIPT_RUNIC = HB_TAG('R', 'u', 'n', 'r'),
/*3.0*/ HB_SCRIPT_SINHALA = HB_TAG('S', 'i', 'n', 'h'),
/*3.0*/ HB_SCRIPT_SYRIAC = HB_TAG('S', 'y', 'r', 'c'),
/*3.0*/ HB_SCRIPT_THAANA = HB_TAG('T', 'h', 'a', 'a'),
/*3.0*/ HB_SCRIPT_YI = HB_TAG('Y', 'i', 'i', 'i'),
/*3.1*/ HB_SCRIPT_DESERET = HB_TAG('D', 's', 'r', 't'),
/*3.1*/ HB_SCRIPT_GOTHIC = HB_TAG('G', 'o', 't', 'h'),
/*3.1*/ HB_SCRIPT_OLD_ITALIC = HB_TAG('I', 't', 'a', 'l'),
/*3.2*/ HB_SCRIPT_BUHID = HB_TAG('B', 'u', 'h', 'd'),
/*3.2*/ HB_SCRIPT_HANUNOO = HB_TAG('H', 'a', 'n', 'o'),
/*3.2*/ HB_SCRIPT_TAGALOG = HB_TAG('T', 'g', 'l', 'g'),
/*3.2*/ HB_SCRIPT_TAGBANWA = HB_TAG('T', 'a', 'g', 'b'),
/*4.0*/ HB_SCRIPT_CYPRIOT = HB_TAG('C', 'p', 'r', 't'),
/*4.0*/ HB_SCRIPT_LIMBU = HB_TAG('L', 'i', 'm', 'b'),
/*4.0*/ HB_SCRIPT_LINEAR_B = HB_TAG('L', 'i', 'n', 'b'),
/*4.0*/ HB_SCRIPT_OSMANYA = HB_TAG('O', 's', 'm', 'a'),
/*4.0*/ HB_SCRIPT_SHAVIAN = HB_TAG('S', 'h', 'a', 'w'),
/*4.0*/ HB_SCRIPT_TAI_LE = HB_TAG('T', 'a', 'l', 'e'),
/*4.0*/ HB_SCRIPT_UGARITIC = HB_TAG('U', 'g', 'a', 'r'),
/*4.1*/ HB_SCRIPT_BUGINESE = HB_TAG('B', 'u', 'g', 'i'),
/*4.1*/ HB_SCRIPT_COPTIC = HB_TAG('C', 'o', 'p', 't'),
/*4.1*/ HB_SCRIPT_GLAGOLITIC = HB_TAG('G', 'l', 'a', 'g'),
/*4.1*/ HB_SCRIPT_KHAROSHTHI = HB_TAG('K', 'h', 'a', 'r'),
/*4.1*/ HB_SCRIPT_NEW_TAI_LUE = HB_TAG('T', 'a', 'l', 'u'),
/*4.1*/ HB_SCRIPT_OLD_PERSIAN = HB_TAG('X', 'p', 'e', 'o'),
/*4.1*/ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG('S', 'y', 'l', 'o'),
/*4.1*/ HB_SCRIPT_TIFINAGH = HB_TAG('T', 'f', 'n', 'g'),
/*5.0*/ HB_SCRIPT_BALINESE = HB_TAG('B', 'a', 'l', 'i'),
/*5.0*/ HB_SCRIPT_CUNEIFORM = HB_TAG('X', 's', 'u', 'x'),
/*5.0*/ HB_SCRIPT_NKO = HB_TAG('N', 'k', 'o', 'o'),
/*5.0*/ HB_SCRIPT_PHAGS_PA = HB_TAG('P', 'h', 'a', 'g'),
/*5.0*/ HB_SCRIPT_PHOENICIAN = HB_TAG('P', 'h', 'n', 'x'),
/*5.1*/ HB_SCRIPT_CARIAN = HB_TAG('C', 'a', 'r', 'i'),
/*5.1*/ HB_SCRIPT_CHAM = HB_TAG('C', 'h', 'a', 'm'),
/*5.1*/ HB_SCRIPT_KAYAH_LI = HB_TAG('K', 'a', 'l', 'i'),
/*5.1*/ HB_SCRIPT_LEPCHA = HB_TAG('L', 'e', 'p', 'c'),
/*5.1*/ HB_SCRIPT_LYCIAN = HB_TAG('L', 'y', 'c', 'i'),
/*5.1*/ HB_SCRIPT_LYDIAN = HB_TAG('L', 'y', 'd', 'i'),
/*5.1*/ HB_SCRIPT_OL_CHIKI = HB_TAG('O', 'l', 'c', 'k'),
/*5.1*/ HB_SCRIPT_REJANG = HB_TAG('R', 'j', 'n', 'g'),
/*5.1*/ HB_SCRIPT_SAURASHTRA = HB_TAG('S', 'a', 'u', 'r'),
/*5.1*/ HB_SCRIPT_SUNDANESE = HB_TAG('S', 'u', 'n', 'd'),
/*5.1*/ HB_SCRIPT_VAI = HB_TAG('V', 'a', 'i', 'i'),
/*5.2*/ HB_SCRIPT_AVESTAN = HB_TAG('A', 'v', 's', 't'),
/*5.2*/ HB_SCRIPT_BAMUM = HB_TAG('B', 'a', 'm', 'u'),
/*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG('E', 'g', 'y', 'p'),
/*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG('A', 'r', 'm', 'i'),
/*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG('P', 'h', 'l', 'i'),
/*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG('P', 'r', 't', 'i'),
/*5.2*/ HB_SCRIPT_JAVANESE = HB_TAG('J', 'a', 'v', 'a'),
/*5.2*/ HB_SCRIPT_KAITHI = HB_TAG('K', 't', 'h', 'i'),
/*5.2*/ HB_SCRIPT_LISU = HB_TAG('L', 'i', 's', 'u'),
/*5.2*/ HB_SCRIPT_MEETEI_MAYEK = HB_TAG('M', 't', 'e', 'i'),
/*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG('S', 'a', 'r', 'b'),
/*5.2*/ HB_SCRIPT_OLD_TURKIC = HB_TAG('O', 'r', 'k', 'h'),
/*5.2*/ HB_SCRIPT_SAMARITAN = HB_TAG('S', 'a', 'm', 'r'),
/*5.2*/ HB_SCRIPT_TAI_THAM = HB_TAG('L', 'a', 'n', 'a'),
/*5.2*/ HB_SCRIPT_TAI_VIET = HB_TAG('T', 'a', 'v', 't'),
/*6.0*/ HB_SCRIPT_BATAK = HB_TAG('B', 'a', 't', 'k'),
/*6.0*/ HB_SCRIPT_BRAHMI = HB_TAG('B', 'r', 'a', 'h'),
/*6.0*/ HB_SCRIPT_MANDAIC = HB_TAG('M', 'a', 'n', 'd'),
/*6.1*/ HB_SCRIPT_CHAKMA = HB_TAG('C', 'a', 'k', 'm'),
/*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG('M', 'e', 'r', 'c'),
/*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG('M', 'e', 'r', 'o'),
/*6.1*/ HB_SCRIPT_MIAO = HB_TAG('P', 'l', 'r', 'd'),
/*6.1*/ HB_SCRIPT_SHARADA = HB_TAG('S', 'h', 'r', 'd'),
/*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG('S', 'o', 'r', 'a'),
/*6.1*/ HB_SCRIPT_TAKRI = HB_TAG('T', 'a', 'k', 'r'),
/*
* Since: 0.9.30
*/
/*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG('B', 'a', 's', 's'),
/*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG('A', 'g', 'h', 'b'),
/*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG('D', 'u', 'p', 'l'),
/*7.0*/ HB_SCRIPT_ELBASAN = HB_TAG('E', 'l', 'b', 'a'),
/*7.0*/ HB_SCRIPT_GRANTHA = HB_TAG('G', 'r', 'a', 'n'),
/*7.0*/ HB_SCRIPT_KHOJKI = HB_TAG('K', 'h', 'o', 'j'),
/*7.0*/ HB_SCRIPT_KHUDAWADI = HB_TAG('S', 'i', 'n', 'd'),
/*7.0*/ HB_SCRIPT_LINEAR_A = HB_TAG('L', 'i', 'n', 'a'),
/*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG('M', 'a', 'h', 'j'),
/*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG('M', 'a', 'n', 'i'),
/*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG('M', 'e', 'n', 'd'),
/*7.0*/ HB_SCRIPT_MODI = HB_TAG('M', 'o', 'd', 'i'),
/*7.0*/ HB_SCRIPT_MRO = HB_TAG('M', 'r', 'o', 'o'),
/*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG('N', 'b', 'a', 't'),
/*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG('N', 'a', 'r', 'b'),
/*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG('P', 'e', 'r', 'm'),
/*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG('H', 'm', 'n', 'g'),
/*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG('P', 'a', 'l', 'm'),
/*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG('P', 'a', 'u', 'c'),
/*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG('P', 'h', 'l', 'p'),
/*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG('S', 'i', 'd', 'd'),
/*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG('T', 'i', 'r', 'h'),
/*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG('W', 'a', 'r', 'a'),
/*8.0*/ HB_SCRIPT_AHOM = HB_TAG('A', 'h', 'o', 'm'),
/*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG('H', 'l', 'u', 'w'),
/*8.0*/ HB_SCRIPT_HATRAN = HB_TAG('H', 'a', 't', 'r'),
/*8.0*/ HB_SCRIPT_MULTANI = HB_TAG('M', 'u', 'l', 't'),
/*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG('H', 'u', 'n', 'g'),
/*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG('S', 'g', 'n', 'w'),
/*
* Since 1.3.0
*/
/*9.0*/ HB_SCRIPT_ADLAM = HB_TAG('A', 'd', 'l', 'm'),
/*9.0*/ HB_SCRIPT_BHAIKSUKI = HB_TAG('B', 'h', 'k', 's'),
/*9.0*/ HB_SCRIPT_MARCHEN = HB_TAG('M', 'a', 'r', 'c'),
/*9.0*/ HB_SCRIPT_OSAGE = HB_TAG('O', 's', 'g', 'e'),
/*9.0*/ HB_SCRIPT_TANGUT = HB_TAG('T', 'a', 'n', 'g'),
/*9.0*/ HB_SCRIPT_NEWA = HB_TAG('N', 'e', 'w', 'a'),
/*
* Since 1.6.0
*/
/*10.0*/ HB_SCRIPT_MASARAM_GONDI = HB_TAG('G', 'o', 'n', 'm'),
/*10.0*/ HB_SCRIPT_NUSHU = HB_TAG('N', 's', 'h', 'u'),
/*10.0*/ HB_SCRIPT_SOYOMBO = HB_TAG('S', 'o', 'y', 'o'),
/*10.0*/ HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG('Z', 'a', 'n', 'b'),
/*
* Since 1.8.0
*/
/*11.0*/ HB_SCRIPT_DOGRA = HB_TAG('D', 'o', 'g', 'r'),
/*11.0*/ HB_SCRIPT_GUNJALA_GONDI = HB_TAG('G', 'o', 'n', 'g'),
/*11.0*/ HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG('R', 'o', 'h', 'g'),
/*11.0*/ HB_SCRIPT_MAKASAR = HB_TAG('M', 'a', 'k', 'a'),
/*11.0*/ HB_SCRIPT_MEDEFAIDRIN = HB_TAG('M', 'e', 'd', 'f'),
/*11.0*/ HB_SCRIPT_OLD_SOGDIAN = HB_TAG('S', 'o', 'g', 'o'),
/*11.0*/ HB_SCRIPT_SOGDIAN = HB_TAG('S', 'o', 'g', 'd'),
/*
* Since 2.4.0
*/
/*12.0*/ HB_SCRIPT_ELYMAIC = HB_TAG('E', 'l', 'y', 'm'),
/*12.0*/ HB_SCRIPT_NANDINAGARI = HB_TAG('N', 'a', 'n', 'd'),
/*12.0*/ HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG('H', 'm', 'n', 'p'),
/*12.0*/ HB_SCRIPT_WANCHO = HB_TAG('W', 'c', 'h', 'o'),
/*
* Since 2.6.7
*/
/*13.0*/ HB_SCRIPT_CHORASMIAN = HB_TAG('C', 'h', 'r', 's'),
/*13.0*/ HB_SCRIPT_DIVES_AKURU = HB_TAG('D', 'i', 'a', 'k'),
/*13.0*/ HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG('K', 'i', 't', 's'),
/*13.0*/ HB_SCRIPT_YEZIDI = HB_TAG('Y', 'e', 'z', 'i'),
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. We have two, for historical reasons.
* HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
* to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
*
* See this thread for technicalities:
*
* https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
*/
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_script_t;
/* Script functions */
HB_EXTERN hb_script_t hb_script_from_iso15924_tag(hb_tag_t tag);
HB_EXTERN hb_script_t hb_script_from_string(const char *str, int len);
HB_EXTERN hb_tag_t hb_script_to_iso15924_tag(hb_script_t script);
HB_EXTERN hb_direction_t hb_script_get_horizontal_direction(hb_script_t script);
/* User data */
typedef struct hb_user_data_key_t
{
/*< private >*/
char unused;
} hb_user_data_key_t;
typedef void (*hb_destroy_func_t)(void *user_data);
/* Font features and variations. */
/**
* HB_FEATURE_GLOBAL_START
*
* Since: 2.0.0
*/
#define HB_FEATURE_GLOBAL_START 0
/**
* HB_FEATURE_GLOBAL_END
*
* Since: 2.0.0
*/
#define HB_FEATURE_GLOBAL_END ((unsigned int)-1)
/**
* hb_feature_t:
* @tag: a feature tag
* @value: 0 disables the feature, non-zero (usually 1) enables the feature.
* For features implemented as lookup type 3 (like 'salt') the @value is a one
* based index into the alternates.
* @start: the cluster to start applying this feature setting (inclusive).
* @end: the cluster to end applying this feature setting (exclusive).
*
* The #hb_feature_t is the structure that holds information about requested
* feature application. The feature will be applied with the given value to all
* glyphs which are in clusters between @start (inclusive) and @end (exclusive).
* Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
* specifies that the feature always applies to the entire buffer.
*/
typedef struct hb_feature_t
{
hb_tag_t tag;
uint32_t value;
unsigned int start;
unsigned int end;
} hb_feature_t;
HB_EXTERN hb_bool_t hb_feature_from_string(const char *str, int len, hb_feature_t *feature);
HB_EXTERN void hb_feature_to_string(hb_feature_t *feature, char *buf, unsigned int size);
/**
* hb_variation_t:
*
* Since: 1.4.2
*/
typedef struct hb_variation_t
{
hb_tag_t tag;
float value;
} hb_variation_t;
HB_EXTERN hb_bool_t hb_variation_from_string(const char *str, int len, hb_variation_t *variation);
HB_EXTERN void hb_variation_to_string(hb_variation_t *variation, char *buf, unsigned int size);
/**
* hb_color_t:
*
* Data type for holding color values.
*
* Since: 2.1.0
*/
typedef uint32_t hb_color_t;
#define HB_COLOR(b, g, r, a) ((hb_color_t)HB_TAG((b), (g), (r), (a)))
HB_EXTERN uint8_t hb_color_get_alpha(hb_color_t color);
#define hb_color_get_alpha(color) ((color)&0xFF)
HB_EXTERN uint8_t hb_color_get_red(hb_color_t color);
#define hb_color_get_red(color) (((color) >> 8) & 0xFF)
HB_EXTERN uint8_t hb_color_get_green(hb_color_t color);
#define hb_color_get_green(color) (((color) >> 16) & 0xFF)
HB_EXTERN uint8_t hb_color_get_blue(hb_color_t color);
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
HB_END_DECLS
#endif /* HB_COMMON_H */

158
harfbuzz/src/hb-config.hh Normal file
View File

@ -0,0 +1,158 @@
/*
* Copyright © 2019 Facebook, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Facebook Author(s): Behdad Esfahbod
*/
#ifndef HB_CONFIG_HH
#define HB_CONFIG_HH
#if 0 /* Make test happy. */
#include "hb.hh"
#endif
#include "config.h"
#ifdef HB_TINY
#define HB_LEAN
#define HB_MINI
#define HB_NO_MT
#define HB_NO_UCD_UNASSIGNED
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef __OPTIMIZE_SIZE__
#define __OPTIMIZE_SIZE__
#endif
#endif
#ifdef HB_LEAN
#define HB_DISABLE_DEPRECATED
#define HB_NDEBUG
#define HB_NO_ATEXIT
#define HB_NO_BUFFER_MESSAGE
#define HB_NO_BUFFER_SERIALIZE
#define HB_NO_BITMAP
#define HB_NO_CFF
#define HB_NO_COLOR
#define HB_NO_DRAW
#define HB_NO_ERRNO
#define HB_NO_FACE_COLLECT_UNICODES
#define HB_NO_GETENV
#define HB_NO_HINTING
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
#define HB_NO_LAYOUT_FEATURE_PARAMS
#define HB_NO_LAYOUT_COLLECT_GLYPHS
#define HB_NO_LAYOUT_UNUSED
#define HB_NO_MATH
#define HB_NO_METRICS
#define HB_NO_MMAP
#define HB_NO_OPEN
#define HB_NO_SETLOCALE
#define HB_NO_OT_FONT_GLYPH_NAMES
#define HB_NO_OT_SHAPE_FRACTIONS
#define HB_NO_STYLE
#define HB_NO_SUBSET_LAYOUT
#define HB_NO_VAR
#endif
#ifdef HB_MINI
#define HB_NO_AAT
#define HB_NO_LEGACY
#endif
/* Closure of options. */
#define HB_DISABLE_DEPRECATED
#ifdef HB_DISABLE_DEPRECATED
#define HB_IF_NOT_DEPRECATED(x)
#else
#define HB_IF_NOT_DEPRECATED(x) x
#endif
#ifdef HB_NO_AAT
#define HB_NO_OT_NAME_LANGUAGE_AAT
#define HB_NO_AAT_SHAPE
#endif
#ifdef HB_NO_BITMAP
#define HB_NO_OT_FONT_BITMAP
#endif
#ifdef HB_NO_CFF
#define HB_NO_OT_FONT_CFF
#define HB_NO_SUBSET_CFF
#endif
#ifdef HB_NO_GETENV
#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
#endif
#ifdef HB_NO_LEGACY
#define HB_NO_CMAP_LEGACY_SUBTABLES
#define HB_NO_FALLBACK_SHAPE
#define HB_NO_OT_KERN
#define HB_NO_OT_LAYOUT_BLACKLIST
#define HB_NO_OT_SHAPE_FALLBACK
#endif
#ifdef HB_NO_NAME
#define HB_NO_OT_NAME_LANGUAGE
#endif
#ifdef HB_NO_OT
#define HB_NO_OT_FONT
#define HB_NO_OT_LAYOUT
#define HB_NO_OT_TAG
#define HB_NO_OT_SHAPE
#endif
#ifdef HB_NO_OT_SHAPE
#define HB_NO_AAT_SHAPE
#endif
#ifdef HB_NO_OT_SHAPE_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
#endif
#ifdef NDEBUG
#ifndef HB_NDEBUG
#define HB_NDEBUG
#endif
#endif
#ifdef __OPTIMIZE_SIZE__
#ifndef HB_OPTIMIZE_SIZE
#define HB_OPTIMIZE_SIZE
#endif
#endif
#ifdef HAVE_CONFIG_OVERRIDE_H
#include "config-override.h"
#endif
#endif /* HB_CONFIG_HH */

453
harfbuzz/src/hb-debug.hh Normal file
View File

@ -0,0 +1,453 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_DEBUG_HH
#define HB_DEBUG_HH
#include "hb.hh"
#include "hb-atomic.hh"
#include "hb-algs.hh"
#ifndef HB_DEBUG
#define HB_DEBUG 0
#endif
/*
* Global runtime options.
*/
struct hb_options_t
{
bool unused : 1; /* In-case sign bit is here. */
bool initialized : 1;
bool uniscribe_bug_compatible : 1;
};
union hb_options_union_t {
int i;
hb_options_t opts;
};
static_assert((sizeof(hb_atomic_int_t) >= sizeof(hb_options_union_t)), "");
HB_INTERNAL void _hb_options_init();
extern HB_INTERNAL hb_atomic_int_t _hb_options;
static inline hb_options_t hb_options()
{
#ifdef HB_NO_GETENV
return hb_options_t();
#endif
/* Make a local copy, so we can access bitfield threadsafely. */
hb_options_union_t u;
u.i = _hb_options.get_relaxed();
if (unlikely(!u.i)) {
_hb_options_init();
u.i = _hb_options.get_relaxed();
}
return u.opts;
}
/*
* Debug output (needs enabling at compile time.)
*/
static inline bool _hb_debug(unsigned int level, unsigned int max_level)
{
return level < max_level;
}
#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug((LEVEL), HB_DEBUG_##WHAT))
#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED(WHAT, 0))
static inline void _hb_print_func(const char *func)
{
if (func) {
unsigned int func_len = strlen(func);
/* Skip "static" */
if (0 == strncmp(func, "static ", 7))
func += 7;
/* Skip "typename" */
if (0 == strncmp(func, "typename ", 9))
func += 9;
/* Skip return type */
const char *space = strchr(func, ' ');
if (space)
func = space + 1;
/* Skip parameter list */
const char *paren = strchr(func, '(');
if (paren)
func_len = paren - func;
fprintf(stderr, "%.*s", func_len, func);
}
}
template <int max_level>
static inline void _hb_debug_msg_va(const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
va_list ap) HB_PRINTF_FUNC(7, 0);
template <int max_level>
static inline void _hb_debug_msg_va(const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
va_list ap)
{
if (!_hb_debug(level, max_level))
return;
fprintf(stderr, "%-10s", what ? what : "");
if (obj)
fprintf(stderr, "(%*p) ", (unsigned int)(2 * sizeof(void *)), obj);
else
fprintf(stderr, " %*s ", (unsigned int)(2 * sizeof(void *)), "");
if (indented) {
#define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
#define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
#define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
#define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
#define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */
static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
fprintf(stderr,
"%2u %s" VRBAR "%s",
level,
bars + sizeof(bars) - 1 -
hb_min((unsigned int)sizeof(bars) - 1, (unsigned int)(sizeof(VBAR) - 1) * level),
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
} else
fprintf(stderr, " " VRBAR LBAR);
_hb_print_func(func);
if (message) {
fprintf(stderr, ": ");
vfprintf(stderr, message, ap);
}
fprintf(stderr, "\n");
}
template <>
inline void HB_PRINTF_FUNC(7, 0) _hb_debug_msg_va<0>(const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
bool indented HB_UNUSED,
unsigned int level HB_UNUSED,
int level_dir HB_UNUSED,
const char *message HB_UNUSED,
va_list ap HB_UNUSED)
{
}
template <int max_level>
static inline void _hb_debug_msg(const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
...) HB_PRINTF_FUNC(7, 8);
template <int max_level>
static inline void HB_PRINTF_FUNC(7, 8) _hb_debug_msg(const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
...)
{
va_list ap;
va_start(ap, message);
_hb_debug_msg_va<max_level>(what, obj, func, indented, level, level_dir, message, ap);
va_end(ap);
}
template <>
inline void _hb_debug_msg<0>(const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
bool indented HB_UNUSED,
unsigned int level HB_UNUSED,
int level_dir HB_UNUSED,
const char *message HB_UNUSED,
...) HB_PRINTF_FUNC(7, 8);
template <>
inline void HB_PRINTF_FUNC(7, 8) _hb_debug_msg<0>(const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
bool indented HB_UNUSED,
unsigned int level HB_UNUSED,
int level_dir HB_UNUSED,
const char *message HB_UNUSED,
...)
{
}
#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) \
_hb_debug_msg<HB_DEBUG_##WHAT>(#WHAT, (OBJ), nullptr, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT>(#WHAT, (OBJ), nullptr, false, 0, 0, __VA_ARGS__)
#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT>(#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
/*
* Printer
*/
template <typename T> struct hb_printer_t
{
const char *print(const T &)
{
return "something";
}
};
template <> struct hb_printer_t<bool>
{
const char *print(bool v)
{
return v ? "true" : "false";
}
};
template <> struct hb_printer_t<hb_empty_t>
{
const char *print(hb_empty_t)
{
return "";
}
};
/*
* Trace
*/
template <typename T> static inline void _hb_warn_no_return(bool returned)
{
if (unlikely(!returned)) {
fprintf(stderr, "OUCH, returned with no call to return_trace(). This is a bug, please report.\n");
}
}
template <>
/*static*/ inline void _hb_warn_no_return<hb_empty_t>(bool returned HB_UNUSED)
{
}
template <int max_level, typename ret_t> struct hb_auto_trace_t
{
explicit inline hb_auto_trace_t(
unsigned int *plevel_, const char *what_, const void *obj_, const char *func, const char *message, ...)
HB_PRINTF_FUNC(6, 7)
: plevel(plevel_)
, what(what_)
, obj(obj_)
, returned(false)
{
if (plevel)
++*plevel;
va_list ap;
va_start(ap, message);
_hb_debug_msg_va<max_level>(what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
va_end(ap);
}
~hb_auto_trace_t()
{
_hb_warn_no_return<ret_t>(returned);
if (!returned) {
_hb_debug_msg<max_level>(what, obj, nullptr, true, plevel ? *plevel : 1, -1, " ");
}
if (plevel)
--*plevel;
}
template <typename T> T ret(T &&v, const char *func = "", unsigned int line = 0)
{
if (unlikely(returned)) {
fprintf(stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
return hb_forward<T>(v);
}
_hb_debug_msg<max_level>(what,
obj,
func,
true,
plevel ? *plevel : 1,
-1,
"return %s (line %d)",
hb_printer_t<decltype(v)>().print(v),
line);
if (plevel)
--*plevel;
plevel = nullptr;
returned = true;
return hb_forward<T>(v);
}
private:
unsigned int *plevel;
const char *what;
const void *obj;
bool returned;
};
template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */
struct hb_auto_trace_t<0, ret_t>
{
explicit inline hb_auto_trace_t(
unsigned int *plevel_, const char *what_, const void *obj_, const char *func, const char *message, ...)
HB_PRINTF_FUNC(6, 7)
{
}
template <typename T> T ret(T &&v, const char *func HB_UNUSED = nullptr, unsigned int line HB_UNUSED = 0)
{
return hb_forward<T>(v);
}
};
/* For disabled tracing; optimize out everything.
* https://github.com/harfbuzz/harfbuzz/pull/605 */
template <typename ret_t> struct hb_no_trace_t
{
template <typename T> T ret(T &&v, const char *func HB_UNUSED = nullptr, unsigned int line HB_UNUSED = 0)
{
return hb_forward<T>(v);
}
};
#define return_trace(RET) return trace.ret(RET, HB_FUNC, __LINE__)
/*
* Instances.
*/
#ifndef HB_DEBUG_ARABIC
#define HB_DEBUG_ARABIC (HB_DEBUG + 0)
#endif
#ifndef HB_DEBUG_BLOB
#define HB_DEBUG_BLOB (HB_DEBUG + 0)
#endif
#ifndef HB_DEBUG_CORETEXT
#define HB_DEBUG_CORETEXT (HB_DEBUG + 0)
#endif
#ifndef HB_DEBUG_DIRECTWRITE
#define HB_DEBUG_DIRECTWRITE (HB_DEBUG + 0)
#endif
#ifndef HB_DEBUG_FT
#define HB_DEBUG_FT (HB_DEBUG + 0)
#endif
#ifndef HB_DEBUG_OBJECT
#define HB_DEBUG_OBJECT (HB_DEBUG + 0)
#endif
#ifndef HB_DEBUG_SHAPE_PLAN
#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG + 0)
#endif
#ifndef HB_DEBUG_UNISCRIBE
#define HB_DEBUG_UNISCRIBE (HB_DEBUG + 0)
#endif
/*
* With tracing.
*/
#ifndef HB_DEBUG_APPLY
#define HB_DEBUG_APPLY (HB_DEBUG + 0)
#endif
#if HB_DEBUG_APPLY
#define TRACE_APPLY(this) \
hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace(&c->debug_depth, \
c->get_name(), \
this, \
HB_FUNC, \
"idx %d gid %u lookup %d", \
c->buffer->idx, \
c->buffer->cur().codepoint, \
(int)c->lookup_index)
#else
#define TRACE_APPLY(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_SANITIZE
#define HB_DEBUG_SANITIZE (HB_DEBUG + 0)
#endif
#if HB_DEBUG_SANITIZE
#define TRACE_SANITIZE(this) \
hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace(&c->debug_depth, c->get_name(), this, HB_FUNC, " ")
#else
#define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_SERIALIZE
#define HB_DEBUG_SERIALIZE (HB_DEBUG + 0)
#endif
#if HB_DEBUG_SERIALIZE
#define TRACE_SERIALIZE(this) \
hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace(&c->debug_depth, "SERIALIZE", c, HB_FUNC, " ")
#else
#define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_SUBSET
#define HB_DEBUG_SUBSET (HB_DEBUG + 0)
#endif
#if HB_DEBUG_SUBSET
#define TRACE_SUBSET(this) \
hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace(&c->debug_depth, c->get_name(), this, HB_FUNC, " ")
#else
#define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_DISPATCH
#define HB_DEBUG_DISPATCH (HB_DEBUG_APPLY + HB_DEBUG_SANITIZE + HB_DEBUG_SERIALIZE + HB_DEBUG_SUBSET + 0)
#endif
#if HB_DEBUG_DISPATCH
#define TRACE_DISPATCH(this, format) \
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace( \
&c->debug_depth, c->get_name(), this, HB_FUNC, "format %d", (int)format)
#else
#define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
#endif
#endif /* HB_DEBUG_HH */

View File

@ -0,0 +1,82 @@
/*
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
* Copyright © 2012,2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_DISPATCH_HH
#define HB_DISPATCH_HH
#include "hb.hh"
/*
* Dispatch
*/
template <typename Context, typename Return = hb_empty_t, unsigned int MaxDebugDepth = 0> struct hb_dispatch_context_t
{
hb_dispatch_context_t()
: debug_depth(0)
{
}
private:
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
const Context *thiz() const
{
return static_cast<const Context *>(this);
}
Context *thiz()
{
return static_cast<Context *>(this);
}
public:
const char *get_name()
{
return "UNKNOWN";
}
static constexpr unsigned max_debug_depth = MaxDebugDepth;
typedef Return return_t;
template <typename T, typename F> bool may_dispatch(const T *obj HB_UNUSED, const F *format HB_UNUSED)
{
return true;
}
template <typename T, typename... Ts> return_t dispatch(const T &obj, Ts &&... ds)
{
return obj.dispatch(thiz(), hb_forward<Ts>(ds)...);
}
static return_t no_dispatch_return_value()
{
return Context::default_return_value();
}
static bool stop_sublookup_iteration(const return_t r HB_UNUSED)
{
return false;
}
unsigned debug_depth;
};
#endif /* HB_DISPATCH_HH */

372
harfbuzz/src/hb-face.cc Normal file
View File

@ -0,0 +1,372 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#include "hb-face.hh"
#include "hb-blob.hh"
#include "hb-open-file.hh"
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
/**
* SECTION:hb-face
* @title: hb-face
* @short_description: Font face objects
* @include: hb.h
*
* Font face is objects represent a single face in a font family.
* More exactly, a font face represents a single face in a binary font file.
* Font faces are typically built from a binary blob and a face index.
* Font faces are used to create fonts.
**/
/**
* hb_face_count:
* @blob: a blob.
*
* Get number of faces in a blob.
*
* Return value: Number of faces in @blob
*
* Since: 1.7.7
**/
unsigned int hb_face_count(hb_blob_t *blob)
{
if (unlikely(!blob))
return 0;
/* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
/* Make API signature const after. */
hb_blob_t *sanitized = hb_sanitize_context_t().sanitize_blob<OT::OpenTypeFontFile>(hb_blob_reference(blob));
const OT::OpenTypeFontFile &ot = *sanitized->as<OT::OpenTypeFontFile>();
unsigned int ret = ot.get_face_count();
hb_blob_destroy(sanitized);
return ret;
}
/*
* hb_face_t
*/
DEFINE_NULL_INSTANCE(hb_face_t) = {
HB_OBJECT_HEADER_STATIC,
nullptr, /* reference_table_func */
nullptr, /* user_data */
nullptr, /* destroy */
0, /* index */
HB_ATOMIC_INT_INIT(1000), /* upem */
HB_ATOMIC_INT_INIT(0), /* num_glyphs */
/* Zero for the rest is fine. */
};
/**
* hb_face_create_for_tables:
* @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Return value: (transfer full)
*
* Since: 0.9.2
**/
hb_face_t *
hb_face_create_for_tables(hb_reference_table_func_t reference_table_func, void *user_data, hb_destroy_func_t destroy)
{
hb_face_t *face;
if (!reference_table_func || !(face = hb_object_create<hb_face_t>())) {
if (destroy)
destroy(user_data);
return hb_face_get_empty();
}
face->reference_table_func = reference_table_func;
face->user_data = user_data;
face->destroy = destroy;
face->num_glyphs.set_relaxed(-1);
face->data.init0(face);
face->table.init0(face);
return face;
}
typedef struct hb_face_for_data_closure_t
{
hb_blob_t *blob;
unsigned int index;
} hb_face_for_data_closure_t;
static hb_face_for_data_closure_t *_hb_face_for_data_closure_create(hb_blob_t *blob, unsigned int index)
{
hb_face_for_data_closure_t *closure;
closure = (hb_face_for_data_closure_t *)calloc(1, sizeof(hb_face_for_data_closure_t));
if (unlikely(!closure))
return nullptr;
closure->blob = blob;
closure->index = index;
return closure;
}
static void _hb_face_for_data_closure_destroy(void *data)
{
hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *)data;
hb_blob_destroy(closure->blob);
free(closure);
}
static hb_blob_t *_hb_face_for_data_reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *)user_data;
if (tag == HB_TAG_NONE)
return hb_blob_reference(data->blob);
const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile>();
unsigned int base_offset;
const OT::OpenTypeFontFace &ot_face = ot_file.get_face(data->index, &base_offset);
const OT::OpenTypeTable &table = ot_face.get_table_by_tag(tag);
hb_blob_t *blob = hb_blob_create_sub_blob(data->blob, base_offset + table.offset, table.length);
return blob;
}
/**
* hb_face_create: (Xconstructor)
* @blob:
* @index:
*
*
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
hb_face_t *hb_face_create(hb_blob_t *blob, unsigned int index)
{
hb_face_t *face;
if (unlikely(!blob))
blob = hb_blob_get_empty();
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create(
hb_sanitize_context_t().sanitize_blob<OT::OpenTypeFontFile>(hb_blob_reference(blob)), index);
if (unlikely(!closure))
return hb_face_get_empty();
face = hb_face_create_for_tables(_hb_face_for_data_reference_table, closure, _hb_face_for_data_closure_destroy);
face->index = index;
return face;
}
/**
* hb_face_get_empty:
*
*
*
* Return value: (transfer full)
*
* Since: 0.9.2
**/
hb_face_t *hb_face_get_empty()
{
return const_cast<hb_face_t *>(&Null(hb_face_t));
}
/**
* hb_face_reference: (skip)
* @face: a face.
*
*
*
* Return value:
*
* Since: 0.9.2
**/
hb_face_t *hb_face_reference(hb_face_t *face)
{
return hb_object_reference(face);
}
/**
* hb_face_destroy: (skip)
* @face: a face.
*
*
*
* Since: 0.9.2
**/
void hb_face_destroy(hb_face_t *face)
{
if (!hb_object_destroy(face))
return;
for (hb_face_t::plan_node_t *node = face->shape_plans; node;) {
hb_face_t::plan_node_t *next = node->next;
hb_shape_plan_destroy(node->shape_plan);
free(node);
node = next;
}
face->data.fini();
face->table.fini();
if (face->destroy)
face->destroy(face->user_data);
free(face);
}
/**
* hb_face_make_immutable:
* @face: a face.
*
*
*
* Since: 0.9.2
**/
void hb_face_make_immutable(hb_face_t *face)
{
if (hb_object_is_immutable(face))
return;
hb_object_make_immutable(face);
}
/**
* hb_face_is_immutable:
* @face: a face.
*
*
*
* Return value:
*
* Since: 0.9.2
**/
hb_bool_t hb_face_is_immutable(const hb_face_t *face)
{
return hb_object_is_immutable(face);
}
/**
* hb_face_reference_table:
* @face: a face.
* @tag:
*
*
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
hb_blob_t *hb_face_reference_table(const hb_face_t *face, hb_tag_t tag)
{
if (unlikely(tag == HB_TAG_NONE))
return hb_blob_get_empty();
return face->reference_table(tag);
}
/**
* hb_face_reference_blob:
* @face: a face.
*
*
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
hb_blob_t *hb_face_reference_blob(hb_face_t *face)
{
return face->reference_table(HB_TAG_NONE);
}
/**
* hb_face_set_upem:
* @face: a face.
* @upem:
*
*
*
* Since: 0.9.2
**/
void hb_face_set_upem(hb_face_t *face, unsigned int upem)
{
if (hb_object_is_immutable(face))
return;
face->upem.set_relaxed(upem);
}
/**
* hb_face_get_upem:
* @face: a face.
*
*
*
* Return value:
*
* Since: 0.9.2
**/
unsigned int hb_face_get_upem(const hb_face_t *face)
{
return face->get_upem();
}
/**
* hb_face_get_glyph_count:
* @face: a face.
*
*
*
* Return value:
*
* Since: 0.9.7
**/
unsigned int hb_face_get_glyph_count(const hb_face_t *face)
{
return face->get_num_glyphs();
}

78
harfbuzz/src/hb-face.h Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright © 2009 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_FACE_H
#define HB_FACE_H
#include "hb-common.h"
#include "hb-blob.h"
#include "hb-set.h"
HB_BEGIN_DECLS
HB_EXTERN unsigned int hb_face_count(hb_blob_t *blob);
/*
* hb_face_t
*/
typedef struct hb_face_t hb_face_t;
HB_EXTERN hb_face_t *hb_face_create(hb_blob_t *blob, unsigned int index);
typedef hb_blob_t *(*hb_reference_table_func_t)(hb_face_t *face, hb_tag_t tag, void *user_data);
/* calls destroy() when not needing user_data anymore */
HB_EXTERN hb_face_t *
hb_face_create_for_tables(hb_reference_table_func_t reference_table_func, void *user_data, hb_destroy_func_t destroy);
HB_EXTERN hb_face_t *hb_face_get_empty(void);
HB_EXTERN hb_face_t *hb_face_reference(hb_face_t *face);
HB_EXTERN void hb_face_destroy(hb_face_t *face);
HB_EXTERN void hb_face_make_immutable(hb_face_t *face);
HB_EXTERN hb_bool_t hb_face_is_immutable(const hb_face_t *face);
HB_EXTERN hb_blob_t *hb_face_reference_table(const hb_face_t *face, hb_tag_t tag);
HB_EXTERN hb_blob_t *hb_face_reference_blob(hb_face_t *face);
HB_EXTERN void hb_face_set_upem(hb_face_t *face, unsigned int upem);
HB_EXTERN unsigned int hb_face_get_upem(const hb_face_t *face);
HB_EXTERN unsigned int hb_face_get_glyph_count(const hb_face_t *face);
HB_END_DECLS
#endif /* HB_FACE_H */

106
harfbuzz/src/hb-face.hh Normal file
View File

@ -0,0 +1,106 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2011 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_FACE_HH
#define HB_FACE_HH
#include "hb.hh"
#include "hb-shaper.hh"
#include "hb-shape-plan.hh"
#include "hb-ot-face.hh"
/*
* hb_face_t
*/
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, face);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
struct hb_face_t
{
hb_object_header_t header;
hb_reference_table_func_t reference_table_func;
void *user_data;
hb_destroy_func_t destroy;
unsigned int index; /* Face index in a collection, zero-based. */
mutable hb_atomic_int_t upem; /* Units-per-EM. */
mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */
hb_shaper_object_dataset_t<hb_face_t> data; /* Various shaper data. */
hb_ot_face_t table; /* All the face's tables. */
/* Cache */
struct plan_node_t
{
hb_shape_plan_t *shape_plan;
plan_node_t *next;
};
hb_atomic_ptr_t<plan_node_t> shape_plans;
hb_blob_t *reference_table(hb_tag_t tag) const
{
hb_blob_t *blob;
if (unlikely(!reference_table_func))
return hb_blob_get_empty();
blob = reference_table_func(/*XXX*/ const_cast<hb_face_t *>(this), tag, user_data);
if (unlikely(!blob))
return hb_blob_get_empty();
return blob;
}
HB_PURE_FUNC unsigned int get_upem() const
{
unsigned int ret = upem.get_relaxed();
if (unlikely(!ret)) {
return load_upem();
}
return ret;
}
unsigned int get_num_glyphs() const
{
unsigned int ret = num_glyphs.get_relaxed();
if (unlikely(ret == UINT_MAX))
return load_num_glyphs();
return ret;
}
private:
HB_INTERNAL unsigned int load_upem() const;
HB_INTERNAL unsigned int load_num_glyphs() const;
};
DECLARE_NULL_INSTANCE(hb_face_t);
#endif /* HB_FACE_HH */

View File

@ -0,0 +1,111 @@
/*
* Copyright © 2011 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-shaper-impl.hh"
#ifndef HB_NO_FALLBACK_SHAPE
/*
* shaper face data
*/
struct hb_fallback_face_data_t
{
};
hb_fallback_face_data_t *_hb_fallback_shaper_face_data_create(hb_face_t *face HB_UNUSED)
{
return (hb_fallback_face_data_t *)HB_SHAPER_DATA_SUCCEEDED;
}
void _hb_fallback_shaper_face_data_destroy(hb_fallback_face_data_t *data HB_UNUSED) {}
/*
* shaper font data
*/
struct hb_fallback_font_data_t
{
};
hb_fallback_font_data_t *_hb_fallback_shaper_font_data_create(hb_font_t *font HB_UNUSED)
{
return (hb_fallback_font_data_t *)HB_SHAPER_DATA_SUCCEEDED;
}
void _hb_fallback_shaper_font_data_destroy(hb_fallback_font_data_t *data HB_UNUSED) {}
/*
* shaper
*/
hb_bool_t _hb_fallback_shape(hb_shape_plan_t *shape_plan HB_UNUSED,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features HB_UNUSED,
unsigned int num_features HB_UNUSED)
{
/* TODO
*
* - Apply fallback kern.
* - Handle Variation Selectors?
* - Apply normalization?
*
* This will make the fallback shaper into a dumb "TrueType"
* shaper which many people unfortunately still request.
*/
hb_codepoint_t space;
bool has_space = (bool)font->get_nominal_glyph(' ', &space);
buffer->clear_positions();
hb_direction_t direction = buffer->props.direction;
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int i = 0; i < count; i++) {
if (has_space && unicode->is_default_ignorable(info[i].codepoint)) {
info[i].codepoint = space;
pos[i].x_advance = 0;
pos[i].y_advance = 0;
continue;
}
(void)font->get_nominal_glyph(info[i].codepoint, &info[i].codepoint);
font->get_glyph_advance_for_direction(info[i].codepoint, direction, &pos[i].x_advance, &pos[i].y_advance);
font->subtract_glyph_origin_for_direction(info[i].codepoint, direction, &pos[i].x_offset, &pos[i].y_offset);
}
if (HB_DIRECTION_IS_BACKWARD(direction))
hb_buffer_reverse(buffer);
buffer->safe_to_break_all();
return true;
}
#endif

1798
harfbuzz/src/hb-font.cc Normal file

File diff suppressed because it is too large Load Diff

607
harfbuzz/src/hb-font.h Normal file
View File

@ -0,0 +1,607 @@
/*
* Copyright © 2009 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_FONT_H
#define HB_FONT_H
#include "hb-common.h"
#include "hb-face.h"
HB_BEGIN_DECLS
typedef struct hb_font_t hb_font_t;
/*
* hb_font_funcs_t
*/
typedef struct hb_font_funcs_t hb_font_funcs_t;
HB_EXTERN hb_font_funcs_t *hb_font_funcs_create(void);
HB_EXTERN hb_font_funcs_t *hb_font_funcs_get_empty(void);
HB_EXTERN hb_font_funcs_t *hb_font_funcs_reference(hb_font_funcs_t *ffuncs);
HB_EXTERN void hb_font_funcs_destroy(hb_font_funcs_t *ffuncs);
HB_EXTERN hb_bool_t hb_font_funcs_set_user_data(
hb_font_funcs_t *ffuncs, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
HB_EXTERN void *hb_font_funcs_get_user_data(hb_font_funcs_t *ffuncs, hb_user_data_key_t *key);
HB_EXTERN void hb_font_funcs_make_immutable(hb_font_funcs_t *ffuncs);
HB_EXTERN hb_bool_t hb_font_funcs_is_immutable(hb_font_funcs_t *ffuncs);
/* font and glyph extents */
/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
typedef struct hb_font_extents_t
{
hb_position_t ascender; /* typographic ascender. */
hb_position_t descender; /* typographic descender. */
hb_position_t line_gap; /* suggested line spacing gap. */
/*< private >*/
hb_position_t reserved9;
hb_position_t reserved8;
hb_position_t reserved7;
hb_position_t reserved6;
hb_position_t reserved5;
hb_position_t reserved4;
hb_position_t reserved3;
hb_position_t reserved2;
hb_position_t reserved1;
} hb_font_extents_t;
/* Note that height is negative in coordinate systems that grow up. */
typedef struct hb_glyph_extents_t
{
hb_position_t x_bearing; /* left side of glyph from origin. */
hb_position_t y_bearing; /* top side of glyph from origin. */
hb_position_t width; /* distance from left to right side. */
hb_position_t height; /* distance from top to bottom side. */
} hb_glyph_extents_t;
/* func types */
typedef hb_bool_t (*hb_font_get_font_extents_func_t)(hb_font_t *font,
void *font_data,
hb_font_extents_t *extents,
void *user_data);
typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t)(
hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t *glyph, void *user_data);
typedef hb_bool_t (*hb_font_get_variation_glyph_func_t)(hb_font_t *font,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data);
typedef unsigned int (*hb_font_get_nominal_glyphs_func_t)(hb_font_t *font,
void *font_data,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data);
typedef hb_position_t (*hb_font_get_glyph_advance_func_t)(hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
void *user_data);
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
typedef void (*hb_font_get_glyph_advances_func_t)(hb_font_t *font,
void *font_data,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data);
typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_h_advances_func_t;
typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
typedef hb_bool_t (*hb_font_get_glyph_origin_func_t)(
hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y, void *user_data);
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t)(
hb_font_t *font, void *font_data, hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t)(
hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_glyph_extents_t *extents, void *user_data);
typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t)(hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
unsigned int point_index,
hb_position_t *x,
hb_position_t *y,
void *user_data);
typedef hb_bool_t (*hb_font_get_glyph_name_func_t)(
hb_font_t *font, void *font_data, hb_codepoint_t glyph, char *name, unsigned int size, void *user_data);
typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t)(hb_font_t *font,
void *font_data,
const char *name,
int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data);
/* func setters */
/**
* hb_font_funcs_set_font_h_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.1.2
**/
HB_EXTERN void hb_font_funcs_set_font_h_extents_func(hb_font_funcs_t *ffuncs,
hb_font_get_font_h_extents_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_font_v_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.1.2
**/
HB_EXTERN void hb_font_funcs_set_font_v_extents_func(hb_font_funcs_t *ffuncs,
hb_font_get_font_v_extents_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_nominal_glyph_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.2.3
**/
HB_EXTERN void hb_font_funcs_set_nominal_glyph_func(hb_font_funcs_t *ffuncs,
hb_font_get_nominal_glyph_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_nominal_glyphs_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 2.0.0
**/
HB_EXTERN void hb_font_funcs_set_nominal_glyphs_func(hb_font_funcs_t *ffuncs,
hb_font_get_nominal_glyphs_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_variation_glyph_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.2.3
**/
HB_EXTERN void hb_font_funcs_set_variation_glyph_func(hb_font_funcs_t *ffuncs,
hb_font_get_variation_glyph_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_advance_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_h_advance_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_advance_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_advance_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_v_advance_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_advance_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_advances_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.8.6
**/
HB_EXTERN void hb_font_funcs_set_glyph_h_advances_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_advances_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_advances_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.8.6
**/
HB_EXTERN void hb_font_funcs_set_glyph_v_advances_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_advances_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_origin_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_h_origin_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_origin_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_origin_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_v_origin_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_origin_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_h_kerning_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_extents_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_extents_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_contour_point_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_contour_point_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_contour_point_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_name_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_name_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_name_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_from_name_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void hb_font_funcs_set_glyph_from_name_func(hb_font_funcs_t *ffuncs,
hb_font_get_glyph_from_name_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/* func dispatch */
HB_EXTERN hb_bool_t hb_font_get_h_extents(hb_font_t *font, hb_font_extents_t *extents);
HB_EXTERN hb_bool_t hb_font_get_v_extents(hb_font_t *font, hb_font_extents_t *extents);
HB_EXTERN hb_bool_t hb_font_get_nominal_glyph(hb_font_t *font, hb_codepoint_t unicode, hb_codepoint_t *glyph);
HB_EXTERN hb_bool_t hb_font_get_variation_glyph(hb_font_t *font,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph);
HB_EXTERN unsigned int hb_font_get_nominal_glyphs(hb_font_t *font,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride);
HB_EXTERN hb_position_t hb_font_get_glyph_h_advance(hb_font_t *font, hb_codepoint_t glyph);
HB_EXTERN hb_position_t hb_font_get_glyph_v_advance(hb_font_t *font, hb_codepoint_t glyph);
HB_EXTERN void hb_font_get_glyph_h_advances(hb_font_t *font,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
HB_EXTERN void hb_font_get_glyph_v_advances(hb_font_t *font,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
HB_EXTERN hb_bool_t hb_font_get_glyph_h_origin(hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y);
HB_EXTERN hb_bool_t hb_font_get_glyph_v_origin(hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y);
HB_EXTERN hb_position_t hb_font_get_glyph_h_kerning(hb_font_t *font,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph);
HB_EXTERN hb_bool_t hb_font_get_glyph_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents);
HB_EXTERN hb_bool_t hb_font_get_glyph_contour_point(
hb_font_t *font, hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_bool_t hb_font_get_glyph_name(hb_font_t *font, hb_codepoint_t glyph, char *name, unsigned int size);
HB_EXTERN hb_bool_t hb_font_get_glyph_from_name(hb_font_t *font,
const char *name,
int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph);
/* high-level funcs, with fallback */
/* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
* otherwise calls hb_font_get_variation_glyph(). */
HB_EXTERN hb_bool_t hb_font_get_glyph(hb_font_t *font,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph);
HB_EXTERN void hb_font_get_extents_for_direction(hb_font_t *font, hb_direction_t direction, hb_font_extents_t *extents);
HB_EXTERN void hb_font_get_glyph_advance_for_direction(
hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y);
HB_EXTERN void hb_font_get_glyph_advances_for_direction(hb_font_t *font,
hb_direction_t direction,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
HB_EXTERN void hb_font_get_glyph_origin_for_direction(
hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y);
HB_EXTERN void hb_font_add_glyph_origin_for_direction(
hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y);
HB_EXTERN void hb_font_subtract_glyph_origin_for_direction(
hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y);
HB_EXTERN void hb_font_get_glyph_kerning_for_direction(hb_font_t *font,
hb_codepoint_t first_glyph,
hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x,
hb_position_t *y);
HB_EXTERN hb_bool_t hb_font_get_glyph_extents_for_origin(hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_glyph_extents_t *extents);
HB_EXTERN hb_bool_t hb_font_get_glyph_contour_point_for_origin(hb_font_t *font,
hb_codepoint_t glyph,
unsigned int point_index,
hb_direction_t direction,
hb_position_t *x,
hb_position_t *y);
/* Generates gidDDD if glyph has no name. */
HB_EXTERN void hb_font_glyph_to_string(hb_font_t *font, hb_codepoint_t glyph, char *s, unsigned int size);
/* Parses gidDDD and uniUUUU strings automatically. */
HB_EXTERN hb_bool_t hb_font_glyph_from_string(hb_font_t *font,
const char *s,
int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph);
/*
* hb_font_t
*/
/* Fonts are very light-weight objects */
HB_EXTERN hb_font_t *hb_font_create(hb_face_t *face);
HB_EXTERN hb_font_t *hb_font_create_sub_font(hb_font_t *parent);
HB_EXTERN hb_font_t *hb_font_get_empty(void);
HB_EXTERN hb_font_t *hb_font_reference(hb_font_t *font);
HB_EXTERN void hb_font_destroy(hb_font_t *font);
HB_EXTERN hb_bool_t hb_font_set_user_data(
hb_font_t *font, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
HB_EXTERN void *hb_font_get_user_data(hb_font_t *font, hb_user_data_key_t *key);
HB_EXTERN void hb_font_make_immutable(hb_font_t *font);
HB_EXTERN hb_bool_t hb_font_is_immutable(hb_font_t *font);
HB_EXTERN void hb_font_set_parent(hb_font_t *font, hb_font_t *parent);
HB_EXTERN hb_font_t *hb_font_get_parent(hb_font_t *font);
HB_EXTERN void hb_font_set_face(hb_font_t *font, hb_face_t *face);
HB_EXTERN hb_face_t *hb_font_get_face(hb_font_t *font);
HB_EXTERN void hb_font_set_funcs(hb_font_t *font, hb_font_funcs_t *klass, void *font_data, hb_destroy_func_t destroy);
/* Be *very* careful with this function! */
HB_EXTERN void hb_font_set_funcs_data(hb_font_t *font, void *font_data, hb_destroy_func_t destroy);
HB_EXTERN void hb_font_set_scale(hb_font_t *font, int x_scale, int y_scale);
HB_EXTERN void hb_font_get_scale(hb_font_t *font, int *x_scale, int *y_scale);
/*
* A zero value means "no hinting in that direction"
*/
HB_EXTERN void hb_font_set_ppem(hb_font_t *font, unsigned int x_ppem, unsigned int y_ppem);
HB_EXTERN void hb_font_get_ppem(hb_font_t *font, unsigned int *x_ppem, unsigned int *y_ppem);
/*
* Point size per EM. Used for optical-sizing in CoreText.
* A value of zero means "not set".
*/
HB_EXTERN void hb_font_set_ptem(hb_font_t *font, float ptem);
HB_EXTERN float hb_font_get_ptem(hb_font_t *font);
HB_EXTERN void
hb_font_set_variations(hb_font_t *font, const hb_variation_t *variations, unsigned int variations_length);
HB_EXTERN void hb_font_set_var_coords_design(hb_font_t *font, const float *coords, unsigned int coords_length);
HB_EXTERN void hb_font_set_var_coords_normalized(hb_font_t *font,
const int *coords, /* 2.14 normalized */
unsigned int coords_length);
HB_EXTERN const int *hb_font_get_var_coords_normalized(hb_font_t *font, unsigned int *length);
HB_EXTERN void hb_font_set_var_named_instance(hb_font_t *font, unsigned instance_index);
HB_END_DECLS
#endif /* HB_FONT_H */

605
harfbuzz/src/hb-font.hh Normal file
View File

@ -0,0 +1,605 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2011 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_FONT_HH
#define HB_FONT_HH
#include "hb.hh"
#include "hb-face.hh"
#include "hb-shaper.hh"
/*
* hb_font_funcs_t
*/
#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
HB_FONT_FUNC_IMPLEMENT(font_h_extents) \
HB_FONT_FUNC_IMPLEMENT(font_v_extents) \
HB_FONT_FUNC_IMPLEMENT(nominal_glyph) \
HB_FONT_FUNC_IMPLEMENT(nominal_glyphs) \
HB_FONT_FUNC_IMPLEMENT(variation_glyph) \
HB_FONT_FUNC_IMPLEMENT(glyph_h_advance) \
HB_FONT_FUNC_IMPLEMENT(glyph_v_advance) \
HB_FONT_FUNC_IMPLEMENT(glyph_h_advances) \
HB_FONT_FUNC_IMPLEMENT(glyph_v_advances) \
HB_FONT_FUNC_IMPLEMENT(glyph_h_origin) \
HB_FONT_FUNC_IMPLEMENT(glyph_v_origin) \
HB_FONT_FUNC_IMPLEMENT(glyph_h_kerning) \
HB_FONT_FUNC_IMPLEMENT(glyph_extents) \
HB_FONT_FUNC_IMPLEMENT(glyph_contour_point) \
HB_FONT_FUNC_IMPLEMENT(glyph_name) \
HB_FONT_FUNC_IMPLEMENT(glyph_from_name) \
/* ^--- Add new callbacks here */
struct hb_font_funcs_t
{
hb_object_header_t header;
struct
{
#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} user_data;
struct
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} destroy;
/* Don't access these directly. Call font->get_*() instead. */
union get_t {
struct get_funcs_t
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} f;
void (*array[0
#define HB_FONT_FUNC_IMPLEMENT(name) +1
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
])();
} get;
};
DECLARE_NULL_INSTANCE(hb_font_funcs_t);
/*
* hb_font_t
*/
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, font);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
struct hb_font_t
{
hb_object_header_t header;
hb_font_t *parent;
hb_face_t *face;
int32_t x_scale;
int32_t y_scale;
int64_t x_mult;
int64_t y_mult;
unsigned int x_ppem;
unsigned int y_ppem;
float ptem;
/* Font variation coordinates. */
unsigned int num_coords;
int *coords;
float *design_coords;
hb_font_funcs_t *klass;
void *user_data;
hb_destroy_func_t destroy;
hb_shaper_object_dataset_t<hb_font_t> data; /* Various shaper data. */
/* Convert from font-space to user-space */
int64_t dir_mult(hb_direction_t direction)
{
return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult;
}
hb_position_t em_scale_x(int16_t v)
{
return em_mult(v, x_mult);
}
hb_position_t em_scale_y(int16_t v)
{
return em_mult(v, y_mult);
}
hb_position_t em_scalef_x(float v)
{
return em_scalef(v, x_scale);
}
hb_position_t em_scalef_y(float v)
{
return em_scalef(v, y_scale);
}
float em_fscale_x(int16_t v)
{
return em_fscale(v, x_scale);
}
float em_fscale_y(int16_t v)
{
return em_fscale(v, y_scale);
}
hb_position_t em_scale_dir(int16_t v, hb_direction_t direction)
{
return em_mult(v, dir_mult(direction));
}
/* Convert from parent-font user-space to our user-space */
hb_position_t parent_scale_x_distance(hb_position_t v)
{
if (unlikely(parent && parent->x_scale != x_scale))
return (hb_position_t)(v * (int64_t)this->x_scale / this->parent->x_scale);
return v;
}
hb_position_t parent_scale_y_distance(hb_position_t v)
{
if (unlikely(parent && parent->y_scale != y_scale))
return (hb_position_t)(v * (int64_t)this->y_scale / this->parent->y_scale);
return v;
}
hb_position_t parent_scale_x_position(hb_position_t v)
{
return parent_scale_x_distance(v);
}
hb_position_t parent_scale_y_position(hb_position_t v)
{
return parent_scale_y_distance(v);
}
void parent_scale_distance(hb_position_t *x, hb_position_t *y)
{
*x = parent_scale_x_distance(*x);
*y = parent_scale_y_distance(*y);
}
void parent_scale_position(hb_position_t *x, hb_position_t *y)
{
*x = parent_scale_x_position(*x);
*y = parent_scale_y_position(*y);
}
/* Public getters */
HB_INTERNAL bool has_func(unsigned int i);
HB_INTERNAL bool has_func_set(unsigned int i);
/* has_* ... */
#define HB_FONT_FUNC_IMPLEMENT(name) \
bool has_##name##_func() \
{ \
hb_font_funcs_t *funcs = this->klass; \
unsigned int i = offsetof(hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof(funcs->get.array[0]); \
return has_func(i); \
} \
bool has_##name##_func_set() \
{ \
hb_font_funcs_t *funcs = this->klass; \
unsigned int i = offsetof(hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof(funcs->get.array[0]); \
return has_func_set(i); \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
hb_bool_t get_font_h_extents(hb_font_extents_t *extents)
{
memset(extents, 0, sizeof(*extents));
return klass->get.f.font_h_extents(this, user_data, extents, klass->user_data.font_h_extents);
}
hb_bool_t get_font_v_extents(hb_font_extents_t *extents)
{
memset(extents, 0, sizeof(*extents));
return klass->get.f.font_v_extents(this, user_data, extents, klass->user_data.font_v_extents);
}
bool has_glyph(hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
return get_nominal_glyph(unicode, &glyph);
}
hb_bool_t get_nominal_glyph(hb_codepoint_t unicode, hb_codepoint_t *glyph)
{
*glyph = 0;
return klass->get.f.nominal_glyph(this, user_data, unicode, glyph, klass->user_data.nominal_glyph);
}
unsigned int get_nominal_glyphs(unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride)
{
return klass->get.f.nominal_glyphs(this,
user_data,
count,
first_unicode,
unicode_stride,
first_glyph,
glyph_stride,
klass->user_data.nominal_glyphs);
}
hb_bool_t get_variation_glyph(hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph)
{
*glyph = 0;
return klass->get.f.variation_glyph(
this, user_data, unicode, variation_selector, glyph, klass->user_data.variation_glyph);
}
hb_position_t get_glyph_h_advance(hb_codepoint_t glyph)
{
return klass->get.f.glyph_h_advance(this, user_data, glyph, klass->user_data.glyph_h_advance);
}
hb_position_t get_glyph_v_advance(hb_codepoint_t glyph)
{
return klass->get.f.glyph_v_advance(this, user_data, glyph, klass->user_data.glyph_v_advance);
}
void get_glyph_h_advances(unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
{
return klass->get.f.glyph_h_advances(this,
user_data,
count,
first_glyph,
glyph_stride,
first_advance,
advance_stride,
klass->user_data.glyph_h_advances);
}
void get_glyph_v_advances(unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
{
return klass->get.f.glyph_v_advances(this,
user_data,
count,
first_glyph,
glyph_stride,
first_advance,
advance_stride,
klass->user_data.glyph_v_advances);
}
hb_bool_t get_glyph_h_origin(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
return klass->get.f.glyph_h_origin(this, user_data, glyph, x, y, klass->user_data.glyph_h_origin);
}
hb_bool_t get_glyph_v_origin(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
return klass->get.f.glyph_v_origin(this, user_data, glyph, x, y, klass->user_data.glyph_v_origin);
}
hb_position_t get_glyph_h_kerning(hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
{
return 0;
}
hb_position_t get_glyph_v_kerning(hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
{
return 0;
}
hb_bool_t get_glyph_extents(hb_codepoint_t glyph, hb_glyph_extents_t *extents)
{
memset(extents, 0, sizeof(*extents));
return klass->get.f.glyph_extents(this, user_data, glyph, extents, klass->user_data.glyph_extents);
}
hb_bool_t
get_glyph_contour_point(hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
return klass->get.f.glyph_contour_point(
this, user_data, glyph, point_index, x, y, klass->user_data.glyph_contour_point);
}
hb_bool_t get_glyph_name(hb_codepoint_t glyph, char *name, unsigned int size)
{
if (size)
*name = '\0';
return klass->get.f.glyph_name(this, user_data, glyph, name, size, klass->user_data.glyph_name);
}
hb_bool_t get_glyph_from_name(const char *name,
int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph)
{
*glyph = 0;
if (len == -1)
len = strlen(name);
return klass->get.f.glyph_from_name(this, user_data, name, len, glyph, klass->user_data.glyph_from_name);
}
/* A bit higher-level, and with fallback */
void get_h_extents_with_fallback(hb_font_extents_t *extents)
{
if (!get_font_h_extents(extents)) {
extents->ascender = y_scale * .8;
extents->descender = extents->ascender - y_scale;
extents->line_gap = 0;
}
}
void get_v_extents_with_fallback(hb_font_extents_t *extents)
{
if (!get_font_v_extents(extents)) {
extents->ascender = x_scale / 2;
extents->descender = extents->ascender - x_scale;
extents->line_gap = 0;
}
}
void get_extents_for_direction(hb_direction_t direction, hb_font_extents_t *extents)
{
if (likely(HB_DIRECTION_IS_HORIZONTAL(direction)))
get_h_extents_with_fallback(extents);
else
get_v_extents_with_fallback(extents);
}
void
get_glyph_advance_for_direction(hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
if (likely(HB_DIRECTION_IS_HORIZONTAL(direction)))
*x = get_glyph_h_advance(glyph);
else
*y = get_glyph_v_advance(glyph);
}
void get_glyph_advances_for_direction(hb_direction_t direction,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
{
if (likely(HB_DIRECTION_IS_HORIZONTAL(direction)))
get_glyph_h_advances(count, first_glyph, glyph_stride, first_advance, advance_stride);
else
get_glyph_v_advances(count, first_glyph, glyph_stride, first_advance, advance_stride);
}
void guess_v_origin_minus_h_origin(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
*x = get_glyph_h_advance(glyph) / 2;
/* TODO cache this somehow?! */
hb_font_extents_t extents;
get_h_extents_with_fallback(&extents);
*y = extents.ascender;
}
void get_glyph_h_origin_with_fallback(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
if (!get_glyph_h_origin(glyph, x, y) && get_glyph_v_origin(glyph, x, y)) {
hb_position_t dx, dy;
guess_v_origin_minus_h_origin(glyph, &dx, &dy);
*x -= dx;
*y -= dy;
}
}
void get_glyph_v_origin_with_fallback(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
if (!get_glyph_v_origin(glyph, x, y) && get_glyph_h_origin(glyph, x, y)) {
hb_position_t dx, dy;
guess_v_origin_minus_h_origin(glyph, &dx, &dy);
*x += dx;
*y += dy;
}
}
void
get_glyph_origin_for_direction(hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y)
{
if (likely(HB_DIRECTION_IS_HORIZONTAL(direction)))
get_glyph_h_origin_with_fallback(glyph, x, y);
else
get_glyph_v_origin_with_fallback(glyph, x, y);
}
void add_glyph_h_origin(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin_with_fallback(glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
}
void add_glyph_v_origin(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin_with_fallback(glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
}
void
add_glyph_origin_for_direction(hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_origin_for_direction(glyph, direction, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
}
void subtract_glyph_h_origin(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin_with_fallback(glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
}
void subtract_glyph_v_origin(hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin_with_fallback(glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
}
void subtract_glyph_origin_for_direction(hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x,
hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_origin_for_direction(glyph, direction, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
}
void get_glyph_kerning_for_direction(hb_codepoint_t first_glyph,
hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x,
hb_position_t *y)
{
if (likely(HB_DIRECTION_IS_HORIZONTAL(direction))) {
*y = 0;
*x = get_glyph_h_kerning(first_glyph, second_glyph);
} else {
*x = 0;
*y = get_glyph_v_kerning(first_glyph, second_glyph);
}
}
hb_bool_t get_glyph_extents_for_origin(hb_codepoint_t glyph, hb_direction_t direction, hb_glyph_extents_t *extents)
{
hb_bool_t ret = get_glyph_extents(glyph, extents);
if (ret)
subtract_glyph_origin_for_direction(glyph, direction, &extents->x_bearing, &extents->y_bearing);
return ret;
}
hb_bool_t get_glyph_contour_point_for_origin(
hb_codepoint_t glyph, unsigned int point_index, hb_direction_t direction, hb_position_t *x, hb_position_t *y)
{
hb_bool_t ret = get_glyph_contour_point(glyph, point_index, x, y);
if (ret)
subtract_glyph_origin_for_direction(glyph, direction, x, y);
return ret;
}
/* Generates gidDDD if glyph has no name. */
void glyph_to_string(hb_codepoint_t glyph, char *s, unsigned int size)
{
if (get_glyph_name(glyph, s, size))
return;
if (size && snprintf(s, size, "gid%u", glyph) < 0)
*s = '\0';
}
/* Parses gidDDD and uniUUUU strings automatically. */
hb_bool_t glyph_from_string(const char *s,
int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph)
{
if (get_glyph_from_name(s, len, glyph))
return true;
if (len == -1)
len = strlen(s);
/* Straight glyph index. */
if (hb_codepoint_parse(s, len, 10, glyph))
return true;
if (len > 3) {
/* gidDDD syntax for glyph indices. */
if (0 == strncmp(s, "gid", 3) && hb_codepoint_parse(s + 3, len - 3, 10, glyph))
return true;
/* uniUUUU and other Unicode character indices. */
hb_codepoint_t unichar;
if (0 == strncmp(s, "uni", 3) && hb_codepoint_parse(s + 3, len - 3, 16, &unichar) &&
get_nominal_glyph(unichar, glyph))
return true;
}
return false;
}
void mults_changed()
{
signed upem = face->get_upem();
x_mult = ((int64_t)x_scale << 16) / upem;
y_mult = ((int64_t)y_scale << 16) / upem;
}
hb_position_t em_mult(int16_t v, int64_t mult)
{
return (hb_position_t)((v * mult) >> 16);
}
hb_position_t em_scalef(float v, int scale)
{
return (hb_position_t)roundf(v * scale / face->get_upem());
}
float em_fscale(int16_t v, int scale)
{
return (float)v * scale / face->get_upem();
}
};
DECLARE_NULL_INSTANCE(hb_font_t);
#endif /* HB_FONT_HH */

1209
harfbuzz/src/hb-iter.hh Normal file

File diff suppressed because it is too large Load Diff

117
harfbuzz/src/hb-kern.hh Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_KERN_HH
#define HB_KERN_HH
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout-gpos-table.hh"
namespace OT {
template <typename Driver> struct hb_kern_machine_t
{
hb_kern_machine_t(const Driver &driver_, bool crossStream_ = false)
: driver(driver_)
, crossStream(crossStream_)
{
}
HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW
void kern(hb_font_t *font, hb_buffer_t *buffer, hb_mask_t kern_mask, bool scale = true) const
{
OT::hb_ot_apply_context_t c(1, font, buffer);
c.set_lookup_mask(kern_mask);
c.set_lookup_props(OT::LookupFlag::IgnoreMarks);
auto &skippy_iter = c.iter_input;
bool horizontal = HB_DIRECTION_IS_HORIZONTAL(buffer->props.direction);
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int idx = 0; idx < count;) {
if (!(info[idx].mask & kern_mask)) {
idx++;
continue;
}
skippy_iter.reset(idx, 1);
if (!skippy_iter.next()) {
idx++;
continue;
}
unsigned int i = idx;
unsigned int j = skippy_iter.idx;
hb_position_t kern = driver.get_kerning(info[i].codepoint, info[j].codepoint);
if (likely(!kern))
goto skip;
if (horizontal) {
if (scale)
kern = font->em_scale_x(kern);
if (crossStream) {
pos[j].y_offset = kern;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
} else {
hb_position_t kern1 = kern >> 1;
hb_position_t kern2 = kern - kern1;
pos[i].x_advance += kern1;
pos[j].x_advance += kern2;
pos[j].x_offset += kern2;
}
} else {
if (scale)
kern = font->em_scale_y(kern);
if (crossStream) {
pos[j].x_offset = kern;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
} else {
hb_position_t kern1 = kern >> 1;
hb_position_t kern2 = kern - kern1;
pos[i].y_advance += kern1;
pos[j].y_advance += kern2;
pos[j].y_offset += kern2;
}
}
buffer->unsafe_to_break(i, j + 1);
skip:
idx = skippy_iter.idx;
}
}
const Driver &driver;
bool crossStream;
};
} /* namespace OT */
#endif /* HB_KERN_HH */

View File

@ -0,0 +1,373 @@
/*
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
* Copyright © 2012,2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MACHINERY_HH
#define HB_MACHINERY_HH
#include "hb.hh"
#include "hb-blob.hh"
#include "hb-dispatch.hh"
#include "hb-sanitize.hh"
/*
* Casts
*/
/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
* location pointed to by P plus Ofs bytes. */
template <typename Type> static inline const Type &StructAtOffset(const void *P, unsigned int offset)
{
return *reinterpret_cast<const Type *>((const char *)P + offset);
}
template <typename Type> static inline Type &StructAtOffset(void *P, unsigned int offset)
{
return *reinterpret_cast<Type *>((char *)P + offset);
}
template <typename Type> static inline const Type &StructAtOffsetUnaligned(const void *P, unsigned int offset)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
return *reinterpret_cast<const Type *>((const char *)P + offset);
#pragma GCC diagnostic pop
}
template <typename Type> static inline Type &StructAtOffsetUnaligned(void *P, unsigned int offset)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
return *reinterpret_cast<Type *>((char *)P + offset);
#pragma GCC diagnostic pop
}
/* StructAfter<T>(X) returns the struct T& that is placed after X.
* Works with X of variable size also. X must implement get_size() */
template <typename Type, typename TObject> static inline const Type &StructAfter(const TObject &X)
{
return StructAtOffset<Type>(&X, X.get_size());
}
template <typename Type, typename TObject> static inline Type &StructAfter(TObject &X)
{
return StructAtOffset<Type>(&X, X.get_size());
}
/*
* Size checking
*/
/* Check _assertion in a method environment */
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
void _instance_assertion_on_line_##_line() const \
{ \
static_assert((_assertion), ""); \
}
#define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1(_line, _assertion)
#define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0(__LINE__, _assertion)
/* Check that _code compiles in a method environment */
#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
void _compiles_assertion_on_line_##_line() const \
{ \
_code; \
}
#define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1(_line, _code)
#define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0(__LINE__, _code)
#define DEFINE_SIZE_STATIC(size) \
DEFINE_INSTANCE_ASSERTION(sizeof(*this) == (size)) \
unsigned int get_size() const \
{ \
return (size); \
} \
static constexpr unsigned null_size = (size); \
static constexpr unsigned min_size = (size); \
static constexpr unsigned static_size = (size)
#define DEFINE_SIZE_UNION(size, _member) \
DEFINE_COMPILES_ASSERTION((void)this->u._member.static_size) \
DEFINE_INSTANCE_ASSERTION(sizeof(this->u._member) == (size)) \
static constexpr unsigned null_size = (size); \
static constexpr unsigned min_size = (size)
#define DEFINE_SIZE_MIN(size) \
DEFINE_INSTANCE_ASSERTION(sizeof(*this) >= (size)) \
static constexpr unsigned null_size = (size); \
static constexpr unsigned min_size = (size)
#define DEFINE_SIZE_UNBOUNDED(size) \
DEFINE_INSTANCE_ASSERTION(sizeof(*this) >= (size)) \
static constexpr unsigned min_size = (size)
#define DEFINE_SIZE_ARRAY(size, array) \
DEFINE_COMPILES_ASSERTION((void)(array)[0].static_size) \
DEFINE_INSTANCE_ASSERTION(sizeof(*this) == (size) + (HB_VAR_ARRAY + 0) * sizeof((array)[0])) \
static constexpr unsigned null_size = (size); \
static constexpr unsigned min_size = (size)
#define DEFINE_SIZE_ARRAY_SIZED(size, array) \
unsigned int get_size() const \
{ \
return (size - (array).min_size + (array).get_size()); \
} \
DEFINE_SIZE_ARRAY(size, array)
/*
* Lazy loaders.
*/
template <typename Data, unsigned int WheresData> struct hb_data_wrapper_t
{
static_assert(WheresData > 0, "");
Data *get_data() const
{
return *(((Data **)(void *)this) - WheresData);
}
bool is_inert() const
{
return !get_data();
}
template <typename Stored, typename Subclass> Stored *call_create() const
{
return Subclass::create(get_data());
}
};
template <> struct hb_data_wrapper_t<void, 0>
{
bool is_inert() const
{
return false;
}
template <typename Stored, typename Funcs> Stored *call_create() const
{
return Funcs::create();
}
};
template <typename T1, typename T2> struct hb_non_void_t
{
typedef T1 value;
};
template <typename T2> struct hb_non_void_t<void, T2>
{
typedef T2 value;
};
template <typename Returned,
typename Subclass = void,
typename Data = void,
unsigned int WheresData = 0,
typename Stored = Returned>
struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
{
typedef
typename hb_non_void_t<Subclass, hb_lazy_loader_t<Returned, Subclass, Data, WheresData, Stored>>::value Funcs;
void init0() {} /* Init, when memory is already set to 0. No-op for us. */
void init()
{
instance.set_relaxed(nullptr);
}
void fini()
{
do_destroy(instance.get());
}
void free_instance()
{
retry:
Stored *p = instance.get();
if (unlikely(p && !cmpexch(p, nullptr)))
goto retry;
do_destroy(p);
}
static void do_destroy(Stored *p)
{
if (p && p != const_cast<Stored *>(Funcs::get_null()))
Funcs::destroy(p);
}
const Returned *operator->() const
{
return get();
}
const Returned &operator*() const
{
return *get();
}
explicit operator bool() const
{
return get_stored() != Funcs::get_null();
}
template <typename C> operator const C *() const
{
return get();
}
Stored *get_stored() const
{
retry:
Stored *p = this->instance.get();
if (unlikely(!p)) {
if (unlikely(this->is_inert()))
return const_cast<Stored *>(Funcs::get_null());
p = this->template call_create<Stored, Funcs>();
if (unlikely(!p))
p = const_cast<Stored *>(Funcs::get_null());
if (unlikely(!cmpexch(nullptr, p))) {
do_destroy(p);
goto retry;
}
}
return p;
}
Stored *get_stored_relaxed() const
{
return this->instance.get_relaxed();
}
bool cmpexch(Stored *current, Stored *value) const
{
/* This *must* be called when there are no other threads accessing. */
return this->instance.cmpexch(current, value);
}
const Returned *get() const
{
return Funcs::convert(get_stored());
}
const Returned *get_relaxed() const
{
return Funcs::convert(get_stored_relaxed());
}
Returned *get_unconst() const
{
return const_cast<Returned *>(Funcs::convert(get_stored()));
}
/* To be possibly overloaded by subclasses. */
static Returned *convert(Stored *p)
{
return p;
}
/* By default null/init/fini the object. */
static const Stored *get_null()
{
return &Null(Stored);
}
static Stored *create(Data *data)
{
Stored *p = (Stored *)calloc(1, sizeof(Stored));
if (likely(p))
p->init(data);
return p;
}
static Stored *create()
{
Stored *p = (Stored *)calloc(1, sizeof(Stored));
if (likely(p))
p->init();
return p;
}
static void destroy(Stored *p)
{
p->fini();
free(p);
}
// private:
/* Must only have one pointer. */
hb_atomic_ptr_t<Stored *> instance;
};
/* Specializations. */
template <typename T, unsigned int WheresFace>
struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, hb_face_lazy_loader_t<T, WheresFace>, hb_face_t, WheresFace>
{
};
template <typename T, unsigned int WheresFace>
struct hb_table_lazy_loader_t
: hb_lazy_loader_t<T, hb_table_lazy_loader_t<T, WheresFace>, hb_face_t, WheresFace, hb_blob_t>
{
static hb_blob_t *create(hb_face_t *face)
{
return hb_sanitize_context_t().reference_table<T>(face);
}
static void destroy(hb_blob_t *p)
{
hb_blob_destroy(p);
}
static const hb_blob_t *get_null()
{
return hb_blob_get_empty();
}
static const T *convert(const hb_blob_t *blob)
{
return blob->as<T>();
}
hb_blob_t *get_blob() const
{
return this->get_stored();
}
};
template <typename Subclass> struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<hb_font_funcs_t, Subclass>
{
static void destroy(hb_font_funcs_t *p)
{
hb_font_funcs_destroy(p);
}
static const hb_font_funcs_t *get_null()
{
return hb_font_funcs_get_empty();
}
};
template <typename Subclass> struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Subclass>
{
static void destroy(hb_unicode_funcs_t *p)
{
hb_unicode_funcs_destroy(p);
}
static const hb_unicode_funcs_t *get_null()
{
return hb_unicode_funcs_get_empty();
}
};
#endif /* HB_MACHINERY_HH */

241
harfbuzz/src/hb-map.cc Normal file
View File

@ -0,0 +1,241 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-map.hh"
/**
* SECTION:hb-map
* @title: hb-map
* @short_description: Object representing integer to integer mapping
* @include: hb.h
*
* Map objects are integer-to-integer hash-maps. Currently they are
* not used in the HarfBuzz public API, but are provided for client's
* use if desired.
**/
/**
* hb_map_create: (Xconstructor)
*
* Return value: (transfer full):
*
* Since: 1.7.7
**/
hb_map_t *hb_map_create()
{
hb_map_t *map;
if (!(map = hb_object_create<hb_map_t>()))
return hb_map_get_empty();
map->init_shallow();
return map;
}
/**
* hb_map_get_empty:
*
* Return value: (transfer full):
*
* Since: 1.7.7
**/
hb_map_t *hb_map_get_empty()
{
return const_cast<hb_map_t *>(&Null(hb_map_t));
}
/**
* hb_map_reference: (skip)
* @map: a map.
*
* Return value: (transfer full):
*
* Since: 1.7.7
**/
hb_map_t *hb_map_reference(hb_map_t *map)
{
return hb_object_reference(map);
}
/**
* hb_map_destroy: (skip)
* @map: a map.
*
* Since: 1.7.7
**/
void hb_map_destroy(hb_map_t *map)
{
if (!hb_object_destroy(map))
return;
map->fini_shallow();
free(map);
}
/**
* hb_map_set_user_data: (skip)
* @map: a map.
* @key:
* @data:
* @destroy:
* @replace:
*
* Return value:
*
* Since: 1.7.7
**/
hb_bool_t
hb_map_set_user_data(hb_map_t *map, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace)
{
return hb_object_set_user_data(map, key, data, destroy, replace);
}
/**
* hb_map_get_user_data: (skip)
* @map: a map.
* @key:
*
* Return value: (transfer none):
*
* Since: 1.7.7
**/
void *hb_map_get_user_data(hb_map_t *map, hb_user_data_key_t *key)
{
return hb_object_get_user_data(map, key);
}
/**
* hb_map_allocation_successful:
* @map: a map.
*
*
*
* Return value:
*
* Since: 1.7.7
**/
hb_bool_t hb_map_allocation_successful(const hb_map_t *map)
{
return map->successful;
}
/**
* hb_map_set:
* @map: a map.
* @key:
* @value:
*
*
*
* Since: 1.7.7
**/
void hb_map_set(hb_map_t *map, hb_codepoint_t key, hb_codepoint_t value)
{
map->set(key, value);
}
/**
* hb_map_get:
* @map: a map.
* @key:
*
*
*
* Since: 1.7.7
**/
hb_codepoint_t hb_map_get(const hb_map_t *map, hb_codepoint_t key)
{
return map->get(key);
}
/**
* hb_map_del:
* @map: a map.
* @key:
*
*
*
* Since: 1.7.7
**/
void hb_map_del(hb_map_t *map, hb_codepoint_t key)
{
map->del(key);
}
/**
* hb_map_has:
* @map: a map.
* @key:
*
*
*
* Since: 1.7.7
**/
hb_bool_t hb_map_has(const hb_map_t *map, hb_codepoint_t key)
{
return map->has(key);
}
/**
* hb_map_clear:
* @map: a map.
*
*
*
* Since: 1.7.7
**/
void hb_map_clear(hb_map_t *map)
{
return map->clear();
}
/**
* hb_map_is_empty:
* @map: a map.
*
*
*
* Since: 1.7.7
**/
hb_bool_t hb_map_is_empty(const hb_map_t *map)
{
return map->is_empty();
}
/**
* hb_map_get_population:
* @map: a map.
*
*
*
* Since: 1.7.7
**/
unsigned int hb_map_get_population(const hb_map_t *map)
{
return map->get_population();
}

77
harfbuzz/src/hb-map.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_MAP_H
#define HB_MAP_H
#include "hb-common.h"
HB_BEGIN_DECLS
/*
* Since: 1.7.7
*/
#define HB_MAP_VALUE_INVALID ((hb_codepoint_t)-1)
typedef struct hb_map_t hb_map_t;
HB_EXTERN hb_map_t *hb_map_create(void);
HB_EXTERN hb_map_t *hb_map_get_empty(void);
HB_EXTERN hb_map_t *hb_map_reference(hb_map_t *map);
HB_EXTERN void hb_map_destroy(hb_map_t *map);
HB_EXTERN hb_bool_t
hb_map_set_user_data(hb_map_t *map, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
HB_EXTERN void *hb_map_get_user_data(hb_map_t *map, hb_user_data_key_t *key);
/* Returns false if allocation has failed before */
HB_EXTERN hb_bool_t hb_map_allocation_successful(const hb_map_t *map);
HB_EXTERN void hb_map_clear(hb_map_t *map);
HB_EXTERN hb_bool_t hb_map_is_empty(const hb_map_t *map);
HB_EXTERN unsigned int hb_map_get_population(const hb_map_t *map);
HB_EXTERN void hb_map_set(hb_map_t *map, hb_codepoint_t key, hb_codepoint_t value);
HB_EXTERN hb_codepoint_t hb_map_get(const hb_map_t *map, hb_codepoint_t key);
HB_EXTERN void hb_map_del(hb_map_t *map, hb_codepoint_t key);
HB_EXTERN hb_bool_t hb_map_has(const hb_map_t *map, hb_codepoint_t key);
HB_END_DECLS
#endif /* HB_MAP_H */

333
harfbuzz/src/hb-map.hh Normal file
View File

@ -0,0 +1,333 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MAP_HH
#define HB_MAP_HH
#include "hb.hh"
/*
* hb_hashmap_t
*/
template <typename K,
typename V,
K kINVALID = hb_is_pointer(K) ? 0 : hb_is_signed(K) ? hb_int_min(K) : (K)-1,
V vINVALID = hb_is_pointer(V) ? 0 : hb_is_signed(V) ? hb_int_min(V) : (V)-1>
struct hb_hashmap_t
{
HB_DELETE_COPY_ASSIGN(hb_hashmap_t);
hb_hashmap_t()
{
init();
}
~hb_hashmap_t()
{
fini();
}
static_assert(hb_is_integral(K) || hb_is_pointer(K), "");
static_assert(hb_is_integral(V) || hb_is_pointer(V), "");
struct item_t
{
K key;
V value;
uint32_t hash;
void clear()
{
key = kINVALID;
value = vINVALID;
hash = 0;
}
bool operator==(K o)
{
return hb_deref(key) == hb_deref(o);
}
bool operator==(const item_t &o)
{
return *this == o.key;
}
bool is_unused() const
{
return key == kINVALID;
}
bool is_tombstone() const
{
return key != kINVALID && value == vINVALID;
}
bool is_real() const
{
return key != kINVALID && value != vINVALID;
}
hb_pair_t<K, V> get_pair() const
{
return hb_pair_t<K, V>(key, value);
}
};
hb_object_header_t header;
bool successful; /* Allocations successful */
unsigned int population; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */
unsigned int mask;
unsigned int prime;
item_t *items;
void init_shallow()
{
successful = true;
population = occupancy = 0;
mask = 0;
prime = 0;
items = nullptr;
}
void init()
{
hb_object_init(this);
init_shallow();
}
void fini_shallow()
{
free(items);
items = nullptr;
population = occupancy = 0;
}
void fini()
{
hb_object_fini(this);
fini_shallow();
}
void reset()
{
if (unlikely(hb_object_is_immutable(this)))
return;
successful = true;
clear();
}
bool in_error() const
{
return !successful;
}
bool resize()
{
if (unlikely(!successful))
return false;
unsigned int power = hb_bit_storage(population * 2 + 8);
unsigned int new_size = 1u << power;
item_t *new_items = (item_t *)malloc((size_t)new_size * sizeof(item_t));
if (unlikely(!new_items)) {
successful = false;
return false;
}
for (auto &_ : hb_iter(new_items, new_size))
_.clear();
unsigned int old_size = mask + 1;
item_t *old_items = items;
/* Switch to new, empty, array. */
population = occupancy = 0;
mask = new_size - 1;
prime = prime_for(power);
items = new_items;
/* Insert back old items. */
if (old_items)
for (unsigned int i = 0; i < old_size; i++)
if (old_items[i].is_real())
set_with_hash(old_items[i].key, old_items[i].hash, old_items[i].value);
free(old_items);
return true;
}
void set(K key, V value)
{
set_with_hash(key, hb_hash(key), value);
}
V get(K key) const
{
if (unlikely(!items))
return vINVALID;
unsigned int i = bucket_for(key);
return items[i].is_real() && items[i] == key ? items[i].value : vINVALID;
}
void del(K key)
{
set(key, vINVALID);
}
/* Has interface. */
static constexpr V SENTINEL = vINVALID;
typedef V value_t;
value_t operator[](K k) const
{
return get(k);
}
bool has(K k, V *vp = nullptr) const
{
V v = (*this)[k];
if (vp)
*vp = v;
return v != SENTINEL;
}
/* Projection. */
V operator()(K k) const
{
return get(k);
}
void clear()
{
if (unlikely(hb_object_is_immutable(this)))
return;
if (items)
for (auto &_ : hb_iter(items, mask + 1))
_.clear();
population = occupancy = 0;
}
bool is_empty() const
{
return population == 0;
}
unsigned int get_population() const
{
return population;
}
/*
* Iterator
*/
auto iter() const HB_AUTO_RETURN(+hb_array(items, mask ? mask + 1 : 0) | hb_filter(&item_t::is_real) |
hb_map(&item_t::get_pair)) auto keys() const
HB_AUTO_RETURN(+hb_array(items, mask ? mask + 1 : 0) | hb_filter(&item_t::is_real) | hb_map(&item_t::key) |
hb_map(hb_ridentity)) auto values() const
HB_AUTO_RETURN(+hb_array(items, mask ? mask + 1 : 0) | hb_filter(&item_t::is_real) | hb_map(&item_t::value) |
hb_map(hb_ridentity))
/* Sink interface. */
hb_hashmap_t &
operator<<(const hb_pair_t<K, V> &v)
{
set(v.first, v.second);
return *this;
}
protected:
void set_with_hash(K key, uint32_t hash, V value)
{
if (unlikely(!successful))
return;
if (unlikely(key == kINVALID))
return;
if ((occupancy + occupancy / 2) >= mask && !resize())
return;
unsigned int i = bucket_for_hash(key, hash);
if (value == vINVALID && items[i].key != key)
return; /* Trying to delete non-existent key. */
if (!items[i].is_unused()) {
occupancy--;
if (items[i].is_tombstone())
population--;
}
items[i].key = key;
items[i].value = value;
items[i].hash = hash;
occupancy++;
if (!items[i].is_tombstone())
population++;
}
unsigned int bucket_for(K key) const
{
return bucket_for_hash(key, hb_hash(key));
}
unsigned int bucket_for_hash(K key, uint32_t hash) const
{
unsigned int i = hash % prime;
unsigned int step = 0;
unsigned int tombstone = (unsigned)-1;
while (!items[i].is_unused()) {
if (items[i].hash == hash && items[i] == key)
return i;
if (tombstone == (unsigned)-1 && items[i].is_tombstone())
tombstone = i;
i = (i + ++step) & mask;
}
return tombstone == (unsigned)-1 ? i : tombstone;
}
static unsigned int prime_for(unsigned int shift)
{
/* Following comment and table copied from glib. */
/* Each table size has an associated prime modulo (the first prime
* lower than the table size) used to find the initial bucket. Probing
* then works modulo 2^n. The prime modulo is necessary to get a
* good distribution with poor hash functions.
*/
/* Not declaring static to make all kinds of compilers happy... */
/*static*/ const unsigned int prime_mod[32] = {
1, /* For 1 << 0 */
2, 3, 7, 13, 31, 61, 127, 251,
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, /* For 1 << 16 */
131071, 262139, 524287, 1048573, 2097143, 4194301, 8388593, 16777213,
33554393, 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647 /* For 1 << 31 */
};
if (unlikely(shift >= ARRAY_LENGTH(prime_mod)))
return prime_mod[ARRAY_LENGTH(prime_mod) - 1];
return prime_mod[shift];
}
};
/*
* hb_map_t
*/
struct hb_map_t : hb_hashmap_t<hb_codepoint_t, hb_codepoint_t, HB_MAP_VALUE_INVALID, HB_MAP_VALUE_INVALID>
{
};
#endif /* HB_MAP_HH */

496
harfbuzz/src/hb-meta.hh Normal file
View File

@ -0,0 +1,496 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_META_HH
#define HB_META_HH
#include "hb.hh"
/*
* C++ template meta-programming & fundamentals used with them.
*/
/* Void! For when we need a expression-type of void. */
struct hb_empty_t
{
};
/* https://en.cppreference.com/w/cpp/types/void_t */
template <typename... Ts> struct _hb_void_t
{
typedef void type;
};
template <typename... Ts> using hb_void_t = typename _hb_void_t<Ts...>::type;
template <typename Head, typename... Ts> struct _hb_head_t
{
typedef Head type;
};
template <typename... Ts> using hb_head_t = typename _hb_head_t<Ts...>::type;
template <typename T, T v> struct hb_integral_constant
{
static constexpr T value = v;
};
template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
using hb_true_type = hb_bool_constant<true>;
using hb_false_type = hb_bool_constant<false>;
/* Basic type SFINAE. */
template <bool B, typename T = void> struct hb_enable_if
{
};
template <typename T> struct hb_enable_if<true, T>
{
typedef T type;
};
#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type * = nullptr
/* Concepts/Requires alias: */
#define hb_requires(Cond) hb_enable_if((Cond))
template <typename T, typename T2> struct hb_is_same : hb_false_type
{
};
template <typename T> struct hb_is_same<T, T> : hb_true_type
{
};
#define hb_is_same(T, T2) hb_is_same<T, T2>::value
/* Function overloading SFINAE and priority. */
#define HB_RETURN(Ret, E) \
->hb_head_t<Ret, decltype((E))> \
{ \
return (E); \
}
#define HB_AUTO_RETURN(E) \
->decltype((E)) \
{ \
return (E); \
}
#define HB_VOID_RETURN(E) \
->hb_void_t<decltype((E))> \
{ \
(E); \
}
template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1>
{
};
template <> struct hb_priority<0>
{
};
#define hb_prioritize hb_priority<16>()
#define HB_FUNCOBJ(x) static_const x HB_UNUSED
template <typename T> struct hb_type_identity_t
{
typedef T type;
};
template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;
struct
{
template <typename T> constexpr T *operator()(T &arg) const
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
/* https://en.cppreference.com/w/cpp/memory/addressof */
return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(arg)));
#pragma GCC diagnostic pop
}
} HB_FUNCOBJ(hb_addressof);
template <typename T> static inline T hb_declval();
#define hb_declval(T) (hb_declval<T>())
template <typename T> struct hb_match_const : hb_type_identity_t<T>, hb_bool_constant<false>
{
};
template <typename T> struct hb_match_const<const T> : hb_type_identity_t<T>, hb_bool_constant<true>
{
};
template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
template <typename T> using hb_add_const = const T;
#define hb_is_const(T) hb_match_const<T>::value
template <typename T> struct hb_match_reference : hb_type_identity_t<T>, hb_bool_constant<false>
{
};
template <typename T> struct hb_match_reference<T &> : hb_type_identity_t<T>, hb_bool_constant<true>
{
};
template <typename T> struct hb_match_reference<T &&> : hb_type_identity_t<T>, hb_bool_constant<true>
{
};
template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
template <typename T> auto _hb_try_add_lvalue_reference(hb_priority<1>) -> hb_type_identity<T &>;
template <typename T> auto _hb_try_add_lvalue_reference(hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_lvalue_reference = decltype(_hb_try_add_lvalue_reference<T>(hb_prioritize));
template <typename T> auto _hb_try_add_rvalue_reference(hb_priority<1>) -> hb_type_identity<T &&>;
template <typename T> auto _hb_try_add_rvalue_reference(hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_rvalue_reference = decltype(_hb_try_add_rvalue_reference<T>(hb_prioritize));
#define hb_is_reference(T) hb_match_reference<T>::value
template <typename T> struct hb_match_pointer : hb_type_identity_t<T>, hb_bool_constant<false>
{
};
template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_bool_constant<true>
{
};
template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
template <typename T> auto _hb_try_add_pointer(hb_priority<1>) -> hb_type_identity<hb_remove_reference<T> *>;
template <typename T> auto _hb_try_add_pointer(hb_priority<1>) -> hb_type_identity<T>;
template <typename T> using hb_add_pointer = decltype(_hb_try_add_pointer<T>(hb_prioritize));
#define hb_is_pointer(T) hb_match_pointer<T>::value
/* TODO Add feature-parity to std::decay. */
template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
template <bool B, class T, class F> struct _hb_conditional
{
typedef T type;
};
template <class T, class F> struct _hb_conditional<false, T, F>
{
typedef F type;
};
template <bool B, class T, class F> using hb_conditional = typename _hb_conditional<B, T, F>::type;
template <typename From, typename To> struct hb_is_convertible
{
private:
static constexpr bool from_void = hb_is_same(void, hb_decay<From>);
static constexpr bool to_void = hb_is_same(void, hb_decay<To>);
static constexpr bool either_void = from_void || to_void;
static constexpr bool both_void = from_void && to_void;
static hb_true_type impl2(hb_conditional<to_void, int, To>);
template <typename T> static auto impl(hb_priority<1>) -> decltype(impl2(hb_declval(T)));
template <typename T> static hb_false_type impl(hb_priority<0>);
public:
static constexpr bool value =
both_void || (!either_void && decltype(impl<hb_conditional<from_void, int, From>>(hb_prioritize))::value);
};
#define hb_is_convertible(From, To) hb_is_convertible<From, To>::value
template <typename Base, typename Derived>
using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
#define hb_is_base_of(Base, Derived) hb_is_base_of<Base, Derived>::value
template <typename From, typename To>
using hb_is_cr_convertible =
hb_bool_constant<hb_is_same(hb_decay<From>, hb_decay<To>) && (!hb_is_const(From) || hb_is_const(To)) &&
(!hb_is_reference(To) || hb_is_const(To) || hb_is_reference(To))>;
#define hb_is_cr_convertible(From, To) hb_is_cr_convertible<From, To>::value
/* std::move and std::forward */
template <typename T> static constexpr hb_remove_reference<T> &&hb_move(T &&t)
{
return (hb_remove_reference<T> &&)(t);
}
template <typename T> static constexpr T &&hb_forward(hb_remove_reference<T> &t)
{
return (T &&) t;
}
template <typename T> static constexpr T &&hb_forward(hb_remove_reference<T> &&t)
{
return (T &&) t;
}
struct
{
template <typename T>
constexpr auto operator()(T &&v) const HB_AUTO_RETURN(hb_forward<T>(v))
template <typename T>
constexpr auto operator()(T *v) const HB_AUTO_RETURN(*v)
} HB_FUNCOBJ(hb_deref);
struct
{
template <typename T>
constexpr auto operator()(T &&v) const HB_AUTO_RETURN(hb_forward<T>(v))
template <typename T>
constexpr auto operator()(T &v) const HB_AUTO_RETURN(hb_addressof(v))
} HB_FUNCOBJ(hb_ref);
template <typename T> struct hb_reference_wrapper
{
hb_reference_wrapper(T v)
: v(v)
{
}
bool operator==(const hb_reference_wrapper &o) const
{
return v == o.v;
}
bool operator!=(const hb_reference_wrapper &o) const
{
return v != o.v;
}
operator T() const
{
return v;
}
T get() const
{
return v;
}
T v;
};
template <typename T> struct hb_reference_wrapper<T &>
{
hb_reference_wrapper(T &v)
: v(hb_addressof(v))
{
}
bool operator==(const hb_reference_wrapper &o) const
{
return v == o.v;
}
bool operator!=(const hb_reference_wrapper &o) const
{
return v != o.v;
}
operator T &() const
{
return *v;
}
T &get() const
{
return *v;
}
T *v;
};
template <typename T>
using hb_is_integral =
hb_bool_constant<hb_is_same(hb_decay<T>, char) || hb_is_same(hb_decay<T>, signed char) ||
hb_is_same(hb_decay<T>, unsigned char) || hb_is_same(hb_decay<T>, signed int) ||
hb_is_same(hb_decay<T>, unsigned int) || hb_is_same(hb_decay<T>, signed short) ||
hb_is_same(hb_decay<T>, unsigned short) || hb_is_same(hb_decay<T>, signed long) ||
hb_is_same(hb_decay<T>, unsigned long) || hb_is_same(hb_decay<T>, signed long long) ||
hb_is_same(hb_decay<T>, unsigned long long) || false>;
#define hb_is_integral(T) hb_is_integral<T>::value
template <typename T>
using hb_is_floating_point = hb_bool_constant<hb_is_same(hb_decay<T>, float) || hb_is_same(hb_decay<T>, double) ||
hb_is_same(hb_decay<T>, long double) || false>;
#define hb_is_floating_point(T) hb_is_floating_point<T>::value
template <typename T> using hb_is_arithmetic = hb_bool_constant<hb_is_integral(T) || hb_is_floating_point(T) || false>;
#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
template <typename T>
using hb_is_signed = hb_conditional<hb_is_arithmetic(T), hb_bool_constant<(T)-1 < (T)0>, hb_false_type>;
#define hb_is_signed(T) hb_is_signed<T>::value
template <typename T>
using hb_is_unsigned = hb_conditional<hb_is_arithmetic(T), hb_bool_constant<(T)0 < (T)-1>, hb_false_type>;
#define hb_is_unsigned(T) hb_is_unsigned<T>::value
template <typename T> struct hb_int_min;
template <> struct hb_int_min<char> : hb_integral_constant<char, CHAR_MIN>
{
};
template <> struct hb_int_min<signed char> : hb_integral_constant<signed char, SCHAR_MIN>
{
};
template <> struct hb_int_min<unsigned char> : hb_integral_constant<unsigned char, 0>
{
};
template <> struct hb_int_min<signed short> : hb_integral_constant<signed short, SHRT_MIN>
{
};
template <> struct hb_int_min<unsigned short> : hb_integral_constant<unsigned short, 0>
{
};
template <> struct hb_int_min<signed int> : hb_integral_constant<signed int, INT_MIN>
{
};
template <> struct hb_int_min<unsigned int> : hb_integral_constant<unsigned int, 0>
{
};
template <> struct hb_int_min<signed long> : hb_integral_constant<signed long, LONG_MIN>
{
};
template <> struct hb_int_min<unsigned long> : hb_integral_constant<unsigned long, 0>
{
};
template <> struct hb_int_min<signed long long> : hb_integral_constant<signed long long, LLONG_MIN>
{
};
template <> struct hb_int_min<unsigned long long> : hb_integral_constant<unsigned long long, 0>
{
};
#define hb_int_min(T) hb_int_min<T>::value
template <typename T> struct hb_int_max;
template <> struct hb_int_max<char> : hb_integral_constant<char, CHAR_MAX>
{
};
template <> struct hb_int_max<signed char> : hb_integral_constant<signed char, SCHAR_MAX>
{
};
template <> struct hb_int_max<unsigned char> : hb_integral_constant<unsigned char, UCHAR_MAX>
{
};
template <> struct hb_int_max<signed short> : hb_integral_constant<signed short, SHRT_MAX>
{
};
template <> struct hb_int_max<unsigned short> : hb_integral_constant<unsigned short, USHRT_MAX>
{
};
template <> struct hb_int_max<signed int> : hb_integral_constant<signed int, INT_MAX>
{
};
template <> struct hb_int_max<unsigned int> : hb_integral_constant<unsigned int, UINT_MAX>
{
};
template <> struct hb_int_max<signed long> : hb_integral_constant<signed long, LONG_MAX>
{
};
template <> struct hb_int_max<unsigned long> : hb_integral_constant<unsigned long, ULONG_MAX>
{
};
template <> struct hb_int_max<signed long long> : hb_integral_constant<signed long long, LLONG_MAX>
{
};
template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigned long long, ULLONG_MAX>
{
};
#define hb_int_max(T) hb_int_max<T>::value
template <typename T, typename> struct _hb_is_destructible : hb_false_type
{
};
template <typename T> struct _hb_is_destructible<T, hb_void_t<decltype(hb_declval(T).~T())>> : hb_true_type
{
};
template <typename T> using hb_is_destructible = _hb_is_destructible<T, void>;
#define hb_is_destructible(T) hb_is_destructible<T>::value
template <typename T, typename, typename... Ts> struct _hb_is_constructible : hb_false_type
{
};
template <typename T, typename... Ts>
struct _hb_is_constructible<T, hb_void_t<decltype(T(hb_declval(Ts)...))>, Ts...> : hb_true_type
{
};
template <typename T, typename... Ts> using hb_is_constructible = _hb_is_constructible<T, void, Ts...>;
#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value
template <typename T> using hb_is_default_constructible = hb_is_constructible<T>;
#define hb_is_default_constructible(T) hb_is_default_constructible<T>::value
template <typename T> using hb_is_copy_constructible = hb_is_constructible<T, hb_add_lvalue_reference<hb_add_const<T>>>;
#define hb_is_copy_constructible(T) hb_is_copy_constructible<T>::value
template <typename T> using hb_is_move_constructible = hb_is_constructible<T, hb_add_rvalue_reference<hb_add_const<T>>>;
#define hb_is_move_constructible(T) hb_is_move_constructible<T>::value
template <typename T, typename U, typename> struct _hb_is_assignable : hb_false_type
{
};
template <typename T, typename U>
struct _hb_is_assignable<T, U, hb_void_t<decltype(hb_declval(T) = hb_declval(U))>> : hb_true_type
{
};
template <typename T, typename U> using hb_is_assignable = _hb_is_assignable<T, U, void>;
#define hb_is_assignable(T, U) hb_is_assignable<T, U>::value
template <typename T>
using hb_is_copy_assignable = hb_is_assignable<hb_add_lvalue_reference<T>, hb_add_lvalue_reference<hb_add_const<T>>>;
#define hb_is_copy_assignable(T) hb_is_copy_assignable<T>::value
template <typename T>
using hb_is_move_assignable = hb_is_assignable<hb_add_lvalue_reference<T>, hb_add_rvalue_reference<T>>;
#define hb_is_move_assignable(T) hb_is_move_assignable<T>::value
/* Trivial versions. */
template <typename T> union hb_trivial {
T value;
};
/* Don't know how to do the following. */
template <typename T> using hb_is_trivially_destructible = hb_is_destructible<hb_trivial<T>>;
#define hb_is_trivially_destructible(T) hb_is_trivially_destructible<T>::value
/* Don't know how to do the following. */
// template <typename T, typename ...Ts>
// using hb_is_trivially_constructible= hb_is_constructible<hb_trivial<T>, hb_trivial<Ts>...>;
//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value
template <typename T> using hb_is_trivially_default_constructible = hb_is_default_constructible<hb_trivial<T>>;
#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible<T>::value
template <typename T> using hb_is_trivially_copy_constructible = hb_is_copy_constructible<hb_trivial<T>>;
#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible<T>::value
template <typename T> using hb_is_trivially_move_constructible = hb_is_move_constructible<hb_trivial<T>>;
#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible<T>::value
/* Don't know how to do the following. */
// template <typename T, typename U>
// using hb_is_trivially_assignable= hb_is_assignable<hb_trivial<T>, hb_trivial<U>>;
//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable<T, U>::value
template <typename T> using hb_is_trivially_copy_assignable = hb_is_copy_assignable<hb_trivial<T>>;
#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable<T>::value
template <typename T> using hb_is_trivially_move_assignable = hb_is_move_assignable<hb_trivial<T>>;
#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable<T>::value
template <typename T>
using hb_is_trivially_copyable =
hb_bool_constant<hb_is_trivially_destructible(T) &&
(!hb_is_move_assignable(T) || hb_is_trivially_move_assignable(T)) &&
(!hb_is_move_constructible(T) || hb_is_trivially_move_constructible(T)) &&
(!hb_is_copy_assignable(T) || hb_is_trivially_copy_assignable(T)) &&
(!hb_is_copy_constructible(T) || hb_is_trivially_copy_constructible(T)) && true>;
#define hb_is_trivially_copyable(T) hb_is_trivially_copyable<T>::value
template <typename T>
using hb_is_trivial = hb_bool_constant<hb_is_trivially_copyable(T) && hb_is_trivially_default_constructible(T)>;
#define hb_is_trivial(T) hb_is_trivial<T>::value
/* hb_unwrap_type (T)
* If T has no T::type, returns T. Otherwise calls itself on T::type recursively.
*/
template <typename T, typename> struct _hb_unwrap_type : hb_type_identity_t<T>
{
};
template <typename T> struct _hb_unwrap_type<T, hb_void_t<typename T::type>> : _hb_unwrap_type<typename T::type, void>
{
};
template <typename T> using hb_unwrap_type = _hb_unwrap_type<T, void>;
#define hb_unwrap_type(T) typename hb_unwrap_type<T>::type
#endif /* HB_META_HH */

167
harfbuzz/src/hb-mutex.hh Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright © 2007 Chris Wilson
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MUTEX_HH
#define HB_MUTEX_HH
#include "hb.hh"
/* mutex */
/* We need external help for these */
#if defined(HB_MUTEX_IMPL_INIT) && defined(hb_mutex_impl_init) && defined(hb_mutex_impl_lock) && \
defined(hb_mutex_impl_unlock) && defined(hb_mutex_impl_finish)
/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
#include <pthread.h>
typedef pthread_mutex_t hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER
#define hb_mutex_impl_init(M) pthread_mutex_init(M, nullptr)
#define hb_mutex_impl_lock(M) pthread_mutex_lock(M)
#define hb_mutex_impl_unlock(M) pthread_mutex_unlock(M)
#define hb_mutex_impl_finish(M) pthread_mutex_destroy(M)
#elif !defined(HB_NO_MT) && defined(_WIN32)
#include <windows.h>
typedef CRITICAL_SECTION hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT \
{ \
0 \
}
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#define hb_mutex_impl_init(M) InitializeCriticalSectionEx(M, 0, 0)
#else
#define hb_mutex_impl_init(M) InitializeCriticalSection(M)
#endif
#define hb_mutex_impl_lock(M) EnterCriticalSection(M)
#define hb_mutex_impl_unlock(M) LeaveCriticalSection(M)
#define hb_mutex_impl_finish(M) DeleteCriticalSection(M)
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
#include <sched.h>
#define HB_SCHED_YIELD() sched_yield()
#else
#define HB_SCHED_YIELD() \
HB_STMT_START {} \
HB_STMT_END
#endif
/* This actually is not a totally awful implementation. */
typedef volatile int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) *(M) = 0
#define hb_mutex_impl_lock(M) \
HB_STMT_START \
{ \
while (__sync_lock_test_and_set((M), 1)) \
HB_SCHED_YIELD(); \
} \
HB_STMT_END
#define hb_mutex_impl_unlock(M) __sync_lock_release(M)
#define hb_mutex_impl_finish(M) \
HB_STMT_START {} \
HB_STMT_END
#elif defined(HB_NO_MT)
typedef int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) \
HB_STMT_START {} \
HB_STMT_END
#define hb_mutex_impl_lock(M) \
HB_STMT_START {} \
HB_STMT_END
#define hb_mutex_impl_unlock(M) \
HB_STMT_START {} \
HB_STMT_END
#define hb_mutex_impl_finish(M) \
HB_STMT_START {} \
HB_STMT_END
#else
#error "Could not find any system to define mutex macros."
#error "Check hb-mutex.hh for possible resolutions."
#endif
#define HB_MUTEX_INIT \
{ \
HB_MUTEX_IMPL_INIT \
}
struct hb_mutex_t
{
hb_mutex_impl_t m;
void init()
{
hb_mutex_impl_init(&m);
}
void lock()
{
hb_mutex_impl_lock(&m);
}
void unlock()
{
hb_mutex_impl_unlock(&m);
}
void fini()
{
hb_mutex_impl_finish(&m);
}
};
struct hb_lock_t
{
hb_lock_t(hb_mutex_t &mutex_)
: mutex(mutex_)
{
mutex.lock();
}
~hb_lock_t()
{
mutex.unlock();
}
private:
hb_mutex_t &mutex;
};
#endif /* HB_MUTEX_HH */

220
harfbuzz/src/hb-null.hh Normal file
View File

@ -0,0 +1,220 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_NULL_HH
#define HB_NULL_HH
#include "hb.hh"
#include "hb-meta.hh"
/*
* Static pools
*/
/* Global nul-content Null pool. Enlarge as necessary. */
#define HB_NULL_POOL_SIZE 384
/* Use SFINAE to sniff whether T has min_size; in which case return T::null_size,
* otherwise return sizeof(T). */
/* The hard way...
* https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
*/
template <typename T, typename> struct _hb_null_size : hb_integral_constant<unsigned, sizeof(T)>
{
};
template <typename T>
struct _hb_null_size<T, hb_void_t<decltype(T::min_size)>> : hb_integral_constant<unsigned, T::null_size>
{
};
template <typename T> using hb_null_size = _hb_null_size<T, void>;
#define hb_null_size(T) hb_null_size<T>::value
/* These doesn't belong here, but since is copy/paste from above, put it here. */
/* hb_static_size (T)
* Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */
template <typename T, typename> struct _hb_static_size : hb_integral_constant<unsigned, sizeof(T)>
{
};
template <typename T>
struct _hb_static_size<T, hb_void_t<decltype(T::min_size)>> : hb_integral_constant<unsigned, T::static_size>
{
};
template <typename T> using hb_static_size = _hb_static_size<T, void>;
#define hb_static_size(T) hb_static_size<T>::value
/*
* Null()
*/
extern HB_INTERNAL uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof(uint64_t) - 1) / sizeof(uint64_t)];
/* Generic nul-content Null objects. */
template <typename Type> struct Null
{
static Type const &get_null()
{
static_assert(hb_null_size(Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
return *reinterpret_cast<Type const *>(_hb_NullPool);
}
};
template <typename QType> struct NullHelper
{
typedef hb_remove_const<hb_remove_reference<QType>> Type;
static const Type &get_null()
{
return Null<Type>::get_null();
}
};
#define Null(Type) NullHelper<Type>::get_null()
/* Specializations for arbitrary-content Null objects expressed in bytes. */
#define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \
} /* Close namespace. */ \
extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \
template <> struct Null<Namespace::Type> \
{ \
static Namespace::Type const &get_null() \
{ \
return *reinterpret_cast<const Namespace::Type *>(_hb_Null_##Namespace##_##Type); \
} \
}; \
namespace Namespace { \
static_assert(true, "") /* Require semicolon after. */
#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]
/* Specializations for arbitrary-content Null objects expressed as struct initializer. */
#define DECLARE_NULL_INSTANCE(Type) \
extern HB_INTERNAL const Type _hb_Null_##Type; \
template <> struct Null<Type> \
{ \
static Type const &get_null() \
{ \
return _hb_Null_##Type; \
} \
}; \
static_assert(true, "") /* Require semicolon after. */
#define DEFINE_NULL_INSTANCE(Type) const Type _hb_Null_##Type
/* Global writable pool. Enlarge as necessary. */
/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool
* for correct operation. It only exist to catch and divert program logic bugs instead of
* causing bad memory access. So, races there are not actually introducing incorrectness
* in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
extern HB_INTERNAL
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof(uint64_t) - 1) / sizeof(uint64_t)];
/* CRAP pool: Common Region for Access Protection. */
template <typename Type> static inline Type &Crap()
{
static_assert(hb_null_size(Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
Type *obj = reinterpret_cast<Type *>(_hb_CrapPool);
memcpy(obj, &Null(Type), sizeof(*obj));
return *obj;
}
template <typename QType> struct CrapHelper
{
typedef hb_remove_const<hb_remove_reference<QType>> Type;
static Type &get_crap()
{
return Crap<Type>();
}
};
#define Crap(Type) CrapHelper<Type>::get_crap()
template <typename Type> struct CrapOrNullHelper
{
static Type &get()
{
return Crap(Type);
}
};
template <typename Type> struct CrapOrNullHelper<const Type>
{
static const Type &get()
{
return Null(Type);
}
};
#define CrapOrNull(Type) CrapOrNullHelper<Type>::get()
/*
* hb_nonnull_ptr_t
*/
template <typename P> struct hb_nonnull_ptr_t
{
typedef hb_remove_pointer<P> T;
hb_nonnull_ptr_t(T *v_ = nullptr)
: v(v_)
{
}
T *operator=(T *v_)
{
return v = v_;
}
T *operator->() const
{
return get();
}
T &operator*() const
{
return *get();
}
T **operator&() const
{
return &v;
}
/* Only auto-cast to const types. */
template <typename C> operator const C *() const
{
return get();
}
operator const char *() const
{
return (const char *)get();
}
T *get() const
{
return v ? v : const_cast<T *>(&Null(T));
}
T *get_raw() const
{
return v;
}
T *v;
};
#endif /* HB_NULL_HH */

View File

@ -0,0 +1,190 @@
#line 1 "hb-number-parser.rl"
/*
* Copyright © 2019 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
*/
#ifndef HB_NUMBER_PARSER_HH
#define HB_NUMBER_PARSER_HH
#include "hb.hh"
#line 35 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 46u, 101u, 0};
static const char _double_parser_key_spans[] = {0, 15, 12, 10, 15, 10, 54, 10, 56};
static const unsigned char _double_parser_index_offsets[] = {0, 0, 16, 29, 40, 56, 67, 122, 133};
static const char _double_parser_indicies[] = {
0, 1, 2, 3, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 3, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1, 6, 1, 7, 1, 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 9, 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 3, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 0};
static const char _double_parser_trans_targs[] = {2, 0, 2, 3, 8, 6, 5, 5, 7, 4};
static const char _double_parser_trans_actions[] = {0, 0, 1, 0, 2, 3, 0, 4, 5, 0};
static const int double_parser_start = 1;
static const int double_parser_first_final = 6;
static const int double_parser_error = 0;
static const int double_parser_en_main = 1;
#line 68 "hb-number-parser.rl"
/* Works only for n < 512 */
static inline double _pow10(unsigned exponent)
{
static const double _powers_of_10[] = {1.0e+256, 1.0e+128, 1.0e+64, 1.0e+32, 1.0e+16, 1.0e+8, 10000., 100., 10.};
unsigned mask = 1 << (ARRAY_LENGTH(_powers_of_10) - 1);
double result = 1;
for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
if (exponent & mask)
result *= *power;
return result;
}
/* a variant of strtod that also gets end of buffer in its second argument */
static inline double strtod_rl(const char *p, const char **end_ptr /* IN/OUT */)
{
double value = 0;
double frac = 0;
double frac_count = 0;
unsigned exp = 0;
bool neg = false, exp_neg = false, exp_overflow = false;
const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */
const char *pe = *end_ptr;
while (p < pe && ISSPACE(*p))
p++;
int cs;
#line 139 "hb-number-parser.hh"
{
cs = double_parser_start;
}
#line 144 "hb-number-parser.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if (p == pe)
goto _test_eof;
if (cs == 0)
goto _out;
_resume:
_keys = _double_parser_trans_keys + (cs << 1);
_inds = _double_parser_indicies + _double_parser_index_offsets[cs];
_slen = _double_parser_key_spans[cs];
_trans = _inds[_slen > 0 && _keys[0] <= (*p) && (*p) <= _keys[1] ? (*p) - _keys[0] : _slen];
cs = _double_parser_trans_targs[_trans];
if (_double_parser_trans_actions[_trans] == 0)
goto _again;
switch (_double_parser_trans_actions[_trans]) {
case 1:
#line 37 "hb-number-parser.rl"
{
neg = true;
} break;
case 4:
#line 38 "hb-number-parser.rl"
{
exp_neg = true;
} break;
case 2:
#line 40 "hb-number-parser.rl"
{
value = value * 10. + ((*p) - '0');
} break;
case 3:
#line 43 "hb-number-parser.rl"
{
if (likely(frac <= MAX_FRACT / 10)) {
frac = frac * 10. + ((*p) - '0');
++frac_count;
}
} break;
case 5:
#line 50 "hb-number-parser.rl"
{
if (likely(exp * 10 + ((*p) - '0') <= MAX_EXP))
exp = exp * 10 + ((*p) - '0');
else
exp_overflow = true;
} break;
#line 202 "hb-number-parser.hh"
}
_again:
if (cs == 0)
goto _out;
if (++p != pe)
goto _resume;
_test_eof : {
}
_out : {
}
}
#line 113 "hb-number-parser.rl"
*end_ptr = p;
if (frac_count)
value += frac / _pow10(frac_count);
if (neg)
value *= -1.;
if (unlikely(exp_overflow)) {
if (value == 0)
return value;
if (exp_neg)
return neg ? -DBL_MIN : DBL_MIN;
else
return neg ? -DBL_MAX : DBL_MAX;
}
if (exp) {
if (exp_neg)
value /= _pow10(exp);
else
value *= _pow10(exp);
}
return value;
}
#endif /* HB_NUMBER_PARSER_HH */

72
harfbuzz/src/hb-number.cc Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright © 2019 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
*/
#include "hb.hh"
#include "hb-machinery.hh"
#include "hb-number.hh"
#include "hb-number-parser.hh"
template <typename T, typename Func>
static bool _parse_number(const char **pp, const char *end, T *pv, bool whole_buffer, Func f)
{
char buf[32];
unsigned len = hb_min(ARRAY_LENGTH(buf) - 1, (unsigned)(end - *pp));
strncpy(buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
errno = 0;
*pv = f(p, &pend);
if (unlikely(errno || p == pend ||
/* Check if consumed whole buffer if is requested */
(whole_buffer && pend - p != end - *pp)))
return false;
*pp += pend - p;
return true;
}
bool hb_parse_int(const char **pp, const char *end, int *pv, bool whole_buffer)
{
return _parse_number<int>(pp, end, pv, whole_buffer, [](const char *p, char **end) { return strtol(p, end, 10); });
}
bool hb_parse_uint(const char **pp, const char *end, unsigned *pv, bool whole_buffer, int base)
{
return _parse_number<unsigned>(
pp, end, pv, whole_buffer, [base](const char *p, char **end) { return strtoul(p, end, base); });
}
bool hb_parse_double(const char **pp, const char *end, double *pv, bool whole_buffer)
{
const char *pend = end;
*pv = strtod_rl(*pp, &pend);
if (unlikely(*pp == pend))
return false;
*pp = pend;
return !whole_buffer || end == pend;
}

36
harfbuzz/src/hb-number.hh Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright © 2019 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
*/
#ifndef HB_NUMBER_HH
#define HB_NUMBER_HH
HB_INTERNAL bool hb_parse_int(const char **pp, const char *end, int *pv, bool whole_buffer = false);
HB_INTERNAL bool
hb_parse_uint(const char **pp, const char *end, unsigned int *pv, bool whole_buffer = false, int base = 10);
HB_INTERNAL bool hb_parse_double(const char **pp, const char *end, double *pv, bool whole_buffer = false);
#endif /* HB_NUMBER_HH */

346
harfbuzz/src/hb-object.hh Normal file
View File

@ -0,0 +1,346 @@
/*
* Copyright © 2007 Chris Wilson
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OBJECT_HH
#define HB_OBJECT_HH
#include "hb.hh"
#include "hb-atomic.hh"
#include "hb-mutex.hh"
#include "hb-vector.hh"
/*
* Lockable set
*/
template <typename item_t, typename lock_t> struct hb_lockable_set_t
{
hb_vector_t<item_t> items;
void init()
{
items.init();
}
template <typename T> item_t *replace_or_insert(T v, lock_t &l, bool replace)
{
l.lock();
item_t *item = items.find(v);
if (item) {
if (replace) {
item_t old = *item;
*item = v;
l.unlock();
old.fini();
} else {
item = nullptr;
l.unlock();
}
} else {
item = items.push(v);
l.unlock();
}
return item;
}
template <typename T> void remove(T v, lock_t &l)
{
l.lock();
item_t *item = items.find(v);
if (item) {
item_t old = *item;
*item = items[items.length - 1];
items.pop();
l.unlock();
old.fini();
} else {
l.unlock();
}
}
template <typename T> bool find(T v, item_t *i, lock_t &l)
{
l.lock();
item_t *item = items.find(v);
if (item)
*i = *item;
l.unlock();
return !!item;
}
template <typename T> item_t *find_or_insert(T v, lock_t &l)
{
l.lock();
item_t *item = items.find(v);
if (!item) {
item = items.push(v);
}
l.unlock();
return item;
}
void fini(lock_t &l)
{
if (!items.length) {
/* No need to lock. */
items.fini();
return;
}
l.lock();
while (items.length) {
item_t old = items[items.length - 1];
items.pop();
l.unlock();
old.fini();
l.lock();
}
items.fini();
l.unlock();
}
};
/*
* Reference-count.
*/
#define HB_REFERENCE_COUNT_INERT_VALUE 0
#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
#define HB_REFERENCE_COUNT_INIT \
{ \
HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE) \
}
struct hb_reference_count_t
{
mutable hb_atomic_int_t ref_count;
void init(int v = 1)
{
ref_count.set_relaxed(v);
}
int get_relaxed() const
{
return ref_count.get_relaxed();
}
int inc() const
{
return ref_count.inc();
}
int dec() const
{
return ref_count.dec();
}
void fini()
{
ref_count.set_relaxed(HB_REFERENCE_COUNT_POISON_VALUE);
}
bool is_inert() const
{
return ref_count.get_relaxed() == HB_REFERENCE_COUNT_INERT_VALUE;
}
bool is_valid() const
{
return ref_count.get_relaxed() > 0;
}
};
/* user_data */
struct hb_user_data_array_t
{
struct hb_user_data_item_t
{
hb_user_data_key_t *key;
void *data;
hb_destroy_func_t destroy;
bool operator==(hb_user_data_key_t *other_key) const
{
return key == other_key;
}
bool operator==(hb_user_data_item_t &other) const
{
return key == other.key;
}
void fini()
{
if (destroy)
destroy(data);
}
};
hb_mutex_t lock;
hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items;
void init()
{
lock.init();
items.init();
}
HB_INTERNAL bool set(hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
HB_INTERNAL void *get(hb_user_data_key_t *key);
void fini()
{
items.fini(lock);
lock.fini();
}
};
/*
* Object header
*/
struct hb_object_header_t
{
hb_reference_count_t ref_count;
mutable hb_atomic_int_t writable;
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
};
#define HB_OBJECT_HEADER_STATIC \
{ \
HB_REFERENCE_COUNT_INIT, HB_ATOMIC_INT_INIT(false), HB_ATOMIC_PTR_INIT(nullptr) \
}
/*
* Object
*/
template <typename Type> static inline void hb_object_trace(const Type *obj, const char *function)
{
DEBUG_MSG(OBJECT, (void *)obj, "%s refcount=%d", function, obj ? obj->header.ref_count.get_relaxed() : 0);
}
template <typename Type> static inline Type *hb_object_create()
{
Type *obj = (Type *)calloc(1, sizeof(Type));
if (unlikely(!obj))
return obj;
hb_object_init(obj);
hb_object_trace(obj, HB_FUNC);
return obj;
}
template <typename Type> static inline void hb_object_init(Type *obj)
{
obj->header.ref_count.init();
obj->header.writable.set_relaxed(true);
obj->header.user_data.init();
}
template <typename Type> static inline bool hb_object_is_inert(const Type *obj)
{
return unlikely(obj->header.ref_count.is_inert());
}
template <typename Type> static inline bool hb_object_is_valid(const Type *obj)
{
return likely(obj->header.ref_count.is_valid());
}
template <typename Type> static inline bool hb_object_is_immutable(const Type *obj)
{
return !obj->header.writable.get_relaxed();
}
template <typename Type> static inline void hb_object_make_immutable(const Type *obj)
{
obj->header.writable.set_relaxed(false);
}
template <typename Type> static inline Type *hb_object_reference(Type *obj)
{
hb_object_trace(obj, HB_FUNC);
if (unlikely(!obj || hb_object_is_inert(obj)))
return obj;
assert(hb_object_is_valid(obj));
obj->header.ref_count.inc();
return obj;
}
template <typename Type> static inline bool hb_object_destroy(Type *obj)
{
hb_object_trace(obj, HB_FUNC);
if (unlikely(!obj || hb_object_is_inert(obj)))
return false;
assert(hb_object_is_valid(obj));
if (obj->header.ref_count.dec() != 1)
return false;
hb_object_fini(obj);
return true;
}
template <typename Type> static inline void hb_object_fini(Type *obj)
{
obj->header.ref_count.fini(); /* Do this before user_data */
hb_user_data_array_t *user_data = obj->header.user_data.get();
if (user_data) {
user_data->fini();
free(user_data);
user_data = nullptr;
}
}
template <typename Type>
static inline bool
hb_object_set_user_data(Type *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace)
{
if (unlikely(!obj || hb_object_is_inert(obj)))
return false;
assert(hb_object_is_valid(obj));
retry:
hb_user_data_array_t *user_data = obj->header.user_data.get();
if (unlikely(!user_data)) {
user_data = (hb_user_data_array_t *)calloc(sizeof(hb_user_data_array_t), 1);
if (unlikely(!user_data))
return false;
user_data->init();
if (unlikely(!obj->header.user_data.cmpexch(nullptr, user_data))) {
user_data->fini();
free(user_data);
goto retry;
}
}
return user_data->set(key, data, destroy, replace);
}
template <typename Type> static inline void *hb_object_get_user_data(Type *obj, hb_user_data_key_t *key)
{
if (unlikely(!obj || hb_object_is_inert(obj)))
return nullptr;
assert(hb_object_is_valid(obj));
hb_user_data_array_t *user_data = obj->header.user_data.get();
if (!user_data)
return nullptr;
return user_data->get(key);
}
#endif /* HB_OBJECT_HH */

View File

@ -0,0 +1,460 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OPEN_FILE_HH
#define HB_OPEN_FILE_HH
#include "hb-open-type.hh"
#include "hb-ot-head-table.hh"
namespace OT {
/*
*
* The OpenType Font File
*
*/
/*
* Organization of an OpenType Font
*/
struct OpenTypeFontFile;
struct OffsetTable;
struct TTCHeader;
typedef struct TableRecord
{
int cmp(Tag t) const
{
return -t.cmp(tag);
}
HB_INTERNAL static int cmp(const void *pa, const void *pb)
{
const TableRecord *a = (const TableRecord *)pa;
const TableRecord *b = (const TableRecord *)pb;
return b->cmp(a->tag);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
Tag tag; /* 4-byte identifier. */
CheckSum checkSum; /* CheckSum for this table. */
Offset32 offset; /* Offset from beginning of TrueType font
* file. */
HBUINT32 length; /* Length of this table. */
public:
DEFINE_SIZE_STATIC(16);
} OpenTypeTable;
typedef struct OffsetTable
{
friend struct OpenTypeFontFile;
unsigned int get_table_count() const
{
return tables.len;
}
const TableRecord &get_table(unsigned int i) const
{
return tables[i];
}
unsigned int get_table_tags(unsigned int start_offset,
unsigned int *table_count, /* IN/OUT */
hb_tag_t *table_tags /* OUT */) const
{
if (table_count) {
+tables.sub_array(start_offset, table_count) | hb_map(&TableRecord::tag) |
hb_sink(hb_array(table_tags, *table_count));
}
return tables.len;
}
bool find_table_index(hb_tag_t tag, unsigned int *table_index) const
{
Tag t;
t = tag;
return tables.bfind(t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
}
const TableRecord &get_table_by_tag(hb_tag_t tag) const
{
unsigned int table_index;
find_table_index(tag, &table_index);
return get_table(table_index);
}
public:
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && tables.sanitize(c));
}
protected:
Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
BinSearchArrayOf<TableRecord> tables;
public:
DEFINE_SIZE_ARRAY(12, tables);
} OpenTypeFontFace;
/*
* TrueType Collections
*/
struct TTCHeaderVersion1
{
friend struct TTCHeader;
unsigned int get_face_count() const
{
return table.len;
}
const OpenTypeFontFace &get_face(unsigned int i) const
{
return this + table[i];
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(table.sanitize(c, this));
}
protected:
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<> version; /* Version of the TTC Header (1.0),
* 0x00010000u */
LArrayOf<LOffsetTo<OffsetTable>> table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
DEFINE_SIZE_ARRAY(12, table);
};
struct TTCHeader
{
friend struct OpenTypeFontFile;
private:
unsigned int get_face_count() const
{
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
case 1:
return u.version1.get_face_count();
default:
return 0;
}
}
const OpenTypeFontFace &get_face(unsigned int i) const
{
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
case 1:
return u.version1.get_face(i);
default:
return Null(OpenTypeFontFace);
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (unlikely(!u.header.version.sanitize(c)))
return_trace(false);
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
case 1:
return_trace(u.version1.sanitize(c));
default:
return_trace(true);
}
}
protected:
union {
struct
{
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<> version; /* Version of the TTC Header (1.0 or 2.0),
* 0x00010000u or 0x00020000u */
} header;
TTCHeaderVersion1 version1;
} u;
};
/*
* Mac Resource Fork
*
* http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html
*/
struct ResourceRecord
{
const OpenTypeFontFace &get_face(const void *data_base) const
{
return *reinterpret_cast<const OpenTypeFontFace *>((data_base + offset).arrayZ);
}
bool sanitize(hb_sanitize_context_t *c, const void *data_base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && offset.sanitize(c, data_base) && get_face(data_base).sanitize(c));
}
protected:
HBUINT16 id; /* Resource ID. */
HBINT16 nameOffset; /* Offset from beginning of resource name list
* to resource name, -1 means there is none. */
HBUINT8 attrs; /* Resource attributes */
NNOffsetTo<LArrayOf<HBUINT8>, HBUINT24> offset; /* Offset from beginning of data block to
* data for this resource */
HBUINT32 reserved; /* Reserved for handle to resource */
public:
DEFINE_SIZE_STATIC(12);
};
#define HB_TAG_sfnt HB_TAG('s', 'f', 'n', 't')
struct ResourceTypeRecord
{
unsigned int get_resource_count() const
{
return tag == HB_TAG_sfnt ? resCountM1 + 1 : 0;
}
bool is_sfnt() const
{
return tag == HB_TAG_sfnt;
}
const ResourceRecord &get_resource_record(unsigned int i, const void *type_base) const
{
return (type_base + resourcesZ).as_array(get_resource_count())[i];
}
bool sanitize(hb_sanitize_context_t *c, const void *type_base, const void *data_base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && resourcesZ.sanitize(c, type_base, get_resource_count(), data_base));
}
protected:
Tag tag; /* Resource type. */
HBUINT16 resCountM1; /* Number of resources minus 1. */
NNOffsetTo<UnsizedArrayOf<ResourceRecord>> resourcesZ; /* Offset from beginning of resource type list
* to reference item list for this type. */
public:
DEFINE_SIZE_STATIC(8);
};
struct ResourceMap
{
unsigned int get_face_count() const
{
unsigned int count = get_type_count();
for (unsigned int i = 0; i < count; i++) {
const ResourceTypeRecord &type = get_type_record(i);
if (type.is_sfnt())
return type.get_resource_count();
}
return 0;
}
const OpenTypeFontFace &get_face(unsigned int idx, const void *data_base) const
{
unsigned int count = get_type_count();
for (unsigned int i = 0; i < count; i++) {
const ResourceTypeRecord &type = get_type_record(i);
/* The check for idx < count is here because ResourceRecord is NOT null-safe.
* Because an offset of 0 there does NOT mean null. */
if (type.is_sfnt() && idx < type.get_resource_count())
return type.get_resource_record(idx, &(this + typeList)).get_face(data_base);
}
return Null(OpenTypeFontFace);
}
bool sanitize(hb_sanitize_context_t *c, const void *data_base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && typeList.sanitize(c, this, &(this + typeList), data_base));
}
private:
unsigned int get_type_count() const
{
return (this + typeList).lenM1 + 1;
}
const ResourceTypeRecord &get_type_record(unsigned int i) const
{
return (this + typeList)[i];
}
protected:
HBUINT8 reserved0[16]; /* Reserved for copy of resource header */
HBUINT32 reserved1; /* Reserved for handle to next resource map */
HBUINT16 resreved2; /* Reserved for file reference number */
HBUINT16 attrs; /* Resource fork attribute */
NNOffsetTo<ArrayOfM1<ResourceTypeRecord>> typeList; /* Offset from beginning of map to
* resource type list */
Offset16 nameList; /* Offset from beginning of map to
* resource name list */
public:
DEFINE_SIZE_STATIC(28);
};
struct ResourceForkHeader
{
unsigned int get_face_count() const
{
return (this + map).get_face_count();
}
const OpenTypeFontFace &get_face(unsigned int idx, unsigned int *base_offset = nullptr) const
{
const OpenTypeFontFace &face = (this + map).get_face(idx, &(this + data));
if (base_offset)
*base_offset = (const char *)&face - (const char *)this;
return face;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && data.sanitize(c, this, dataLen) && map.sanitize(c, this, &(this + data)));
}
protected:
LNNOffsetTo<UnsizedArrayOf<HBUINT8>> data; /* Offset from beginning of resource fork
* to resource data */
LNNOffsetTo<ResourceMap> map; /* Offset from beginning of resource fork
* to resource map */
HBUINT32 dataLen; /* Length of resource data */
HBUINT32 mapLen; /* Length of resource map */
public:
DEFINE_SIZE_STATIC(16);
};
/*
* OpenType Font File
*/
struct OpenTypeFontFile
{
enum {
CFFTag = HB_TAG('O', 'T', 'T', 'O'), /* OpenType with Postscript outlines */
TrueTypeTag = HB_TAG(0, 1, 0, 0), /* OpenType with TrueType outlines */
TTCTag = HB_TAG('t', 't', 'c', 'f'), /* TrueType Collection */
DFontTag = HB_TAG(0, 0, 1, 0), /* DFont Mac Resource Fork */
TrueTag = HB_TAG('t', 'r', 'u', 'e'), /* Obsolete Apple TrueType */
Typ1Tag = HB_TAG('t', 'y', 'p', '1') /* Obsolete Apple Type1 font in SFNT container */
};
hb_tag_t get_tag() const
{
return u.tag;
}
unsigned int get_face_count() const
{
switch (u.tag) {
case CFFTag: /* All the non-collection tags */
case TrueTag:
case Typ1Tag:
case TrueTypeTag:
return 1;
case TTCTag:
return u.ttcHeader.get_face_count();
case DFontTag:
return u.rfHeader.get_face_count();
default:
return 0;
}
}
const OpenTypeFontFace &get_face(unsigned int i, unsigned int *base_offset = nullptr) const
{
if (base_offset)
*base_offset = 0;
switch (u.tag) {
/* Note: for non-collection SFNT data we ignore index. This is because
* Apple dfont container is a container of SFNT's. So each SFNT is a
* non-TTC, but the index is more than zero. */
case CFFTag: /* All the non-collection tags */
case TrueTag:
case Typ1Tag:
case TrueTypeTag:
return u.fontFace;
case TTCTag:
return u.ttcHeader.get_face(i);
case DFontTag:
return u.rfHeader.get_face(i, base_offset);
default:
return Null(OpenTypeFontFace);
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (unlikely(!u.tag.sanitize(c)))
return_trace(false);
switch (u.tag) {
case CFFTag: /* All the non-collection tags */
case TrueTag:
case Typ1Tag:
case TrueTypeTag:
return_trace(u.fontFace.sanitize(c));
case TTCTag:
return_trace(u.ttcHeader.sanitize(c));
case DFontTag:
return_trace(u.rfHeader.sanitize(c));
default:
return_trace(true);
}
}
protected:
union {
Tag tag; /* 4-byte identifier. */
OpenTypeFontFace fontFace;
TTCHeader ttcHeader;
ResourceForkHeader rfHeader;
} u;
public:
DEFINE_SIZE_UNION(4, tag);
};
} /* namespace OT */
#endif /* HB_OPEN_FILE_HH */

1137
harfbuzz/src/hb-open-type.hh Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,393 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_OT_CFF_COMMON_HH
#define HB_OT_CFF_COMMON_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
#include "hb-cff-interp-dict-common.hh"
namespace CFF {
using namespace OT;
#define CFF_UNDEF_CODE 0xFFFFFFFF
/* utility macro */
template <typename Type> static inline const Type &StructAtOffsetOrNull(const void *P, unsigned int offset)
{
return offset ? StructAtOffset<Type>(P, offset) : Null(Type);
}
inline unsigned int calcOffSize(unsigned int dataSize)
{
unsigned int size = 1;
unsigned int offset = dataSize + 1;
while (offset & ~0xFF) {
size++;
offset >>= 8;
}
/* format does not support size > 4; caller should handle it as an error */
return size;
}
struct code_pair_t
{
hb_codepoint_t code;
hb_codepoint_t glyph;
};
typedef hb_vector_t<unsigned char> str_buff_t;
struct str_buff_vec_t : hb_vector_t<str_buff_t>
{
void fini()
{
SUPER::fini_deep();
}
unsigned int total_size() const
{
unsigned int size = 0;
for (unsigned int i = 0; i < length; i++)
size += (*this)[i].length;
return size;
}
private:
typedef hb_vector_t<str_buff_t> SUPER;
};
/* CFF INDEX */
template <typename COUNT> struct CFFIndex
{
static unsigned int calculate_offset_array_size(unsigned int offSize, unsigned int count)
{
return offSize * (count + 1);
}
unsigned int offset_array_size() const
{
return calculate_offset_array_size(offSize, count);
}
void set_offset_at(unsigned int index, unsigned int offset)
{
HBUINT8 *p = offsets + offSize * index + offSize;
unsigned int size = offSize;
for (; size; size--) {
--p;
*p = offset & 0xFF;
offset >>= 8;
}
}
unsigned int offset_at(unsigned int index) const
{
assert(index <= count);
const HBUINT8 *p = offsets + offSize * index;
unsigned int size = offSize;
unsigned int offset = 0;
for (; size; size--)
offset = (offset << 8) + *p++;
return offset;
}
unsigned int length_at(unsigned int index) const
{
if (unlikely((offset_at(index + 1) < offset_at(index)) || (offset_at(index + 1) > offset_at(count))))
return 0;
return offset_at(index + 1) - offset_at(index);
}
const unsigned char *data_base() const
{
return (const unsigned char *)this + min_size + offset_array_size();
}
unsigned int data_size() const
{
return HBINT8::static_size;
}
byte_str_t operator[](unsigned int index) const
{
if (unlikely(index >= count))
return Null(byte_str_t);
return byte_str_t(data_base() + offset_at(index) - 1, length_at(index));
}
unsigned int get_size() const
{
if (this == &Null(CFFIndex))
return 0;
if (count > 0)
return min_size + offset_array_size() + (offset_at(count) - 1);
return count.static_size; /* empty CFFIndex contains count only */
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely((c->check_struct(this) && count == 0) || /* empty INDEX */
(c->check_struct(this) && offSize >= 1 && offSize <= 4 &&
c->check_array(offsets, offSize, count + 1) &&
c->check_array((const HBUINT8 *)data_base(), 1, max_offset() - 1))));
}
protected:
unsigned int max_offset() const
{
unsigned int max = 0;
for (unsigned int i = 0; i < count + 1u; i++) {
unsigned int off = offset_at(i);
if (off > max)
max = off;
}
return max;
}
public:
COUNT count; /* Number of object data. Note there are (count+1) offsets */
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
HBUINT8 offsets[HB_VAR_ARRAY];
/* The array of (count + 1) offsets into objects array (1-base). */
/* HBUINT8 data[HB_VAR_ARRAY]; Object data */
public:
DEFINE_SIZE_ARRAY(COUNT::static_size + HBUINT8::static_size, offsets);
};
template <typename COUNT, typename TYPE> struct CFFIndexOf : CFFIndex<COUNT>
{
const byte_str_t operator[](unsigned int index) const
{
if (likely(index < CFFIndex<COUNT>::count))
return byte_str_t(CFFIndex<COUNT>::data_base() + CFFIndex<COUNT>::offset_at(index) - 1,
CFFIndex<COUNT>::length_at(index));
return Null(byte_str_t);
}
};
/* Top Dict, Font Dict, Private Dict */
struct Dict : UnsizedByteStr
{
};
struct TopDict : Dict
{
};
struct FontDict : Dict
{
};
struct PrivateDict : Dict
{
};
struct table_info_t
{
void init()
{
offset = size = 0;
// link = 0;
}
unsigned int offset;
unsigned int size;
// objidx_t link;
};
template <typename COUNT> struct FDArray : CFFIndexOf<COUNT, FontDict>
{
};
/* FDSelect */
struct FDSelect0
{
bool sanitize(hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE(this);
if (unlikely(!(c->check_struct(this))))
return_trace(false);
for (unsigned int i = 0; i < c->get_num_glyphs(); i++)
if (unlikely(!fds[i].sanitize(c)))
return_trace(false);
return_trace(true);
}
hb_codepoint_t get_fd(hb_codepoint_t glyph) const
{
return (hb_codepoint_t)fds[glyph];
}
unsigned int get_size(unsigned int num_glyphs) const
{
return HBUINT8::static_size * num_glyphs;
}
HBUINT8 fds[HB_VAR_ARRAY];
DEFINE_SIZE_MIN(0);
};
template <typename GID_TYPE, typename FD_TYPE> struct FDSelect3_4_Range
{
bool sanitize(hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
{
TRACE_SANITIZE(this);
return_trace(first < c->get_num_glyphs() && (fd < fdcount));
}
GID_TYPE first;
FD_TYPE fd;
public:
DEFINE_SIZE_STATIC(GID_TYPE::static_size + FD_TYPE::static_size);
};
template <typename GID_TYPE, typename FD_TYPE> struct FDSelect3_4
{
unsigned int get_size() const
{
return GID_TYPE::static_size * 2 + ranges.get_size();
}
bool sanitize(hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE(this);
if (unlikely(!c->check_struct(this) || !ranges.sanitize(c, nullptr, fdcount) || (nRanges() == 0) ||
ranges[0].first != 0))
return_trace(false);
for (unsigned int i = 1; i < nRanges(); i++)
if (unlikely(ranges[i - 1].first >= ranges[i].first))
return_trace(false);
if (unlikely(!sentinel().sanitize(c) || (sentinel() != c->get_num_glyphs())))
return_trace(false);
return_trace(true);
}
hb_codepoint_t get_fd(hb_codepoint_t glyph) const
{
unsigned int i;
for (i = 1; i < nRanges(); i++)
if (glyph < ranges[i].first)
break;
return (hb_codepoint_t)ranges[i - 1].fd;
}
GID_TYPE &nRanges()
{
return ranges.len;
}
GID_TYPE nRanges() const
{
return ranges.len;
}
GID_TYPE &sentinel()
{
return StructAfter<GID_TYPE>(ranges[nRanges() - 1]);
}
const GID_TYPE &sentinel() const
{
return StructAfter<GID_TYPE>(ranges[nRanges() - 1]);
}
ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges;
/* GID_TYPE sentinel */
DEFINE_SIZE_ARRAY(GID_TYPE::static_size, ranges);
};
typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
struct FDSelect
{
unsigned int get_size(unsigned int num_glyphs) const
{
switch (format) {
case 0:
return format.static_size + u.format0.get_size(num_glyphs);
case 3:
return format.static_size + u.format3.get_size();
default:
return 0;
}
}
hb_codepoint_t get_fd(hb_codepoint_t glyph) const
{
if (this == &Null(FDSelect))
return 0;
switch (format) {
case 0:
return u.format0.get_fd(glyph);
case 3:
return u.format3.get_fd(glyph);
default:
return 0;
}
}
bool sanitize(hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE(this);
if (unlikely(!c->check_struct(this)))
return_trace(false);
switch (format) {
case 0:
return_trace(u.format0.sanitize(c, fdcount));
case 3:
return_trace(u.format3.sanitize(c, fdcount));
default:
return_trace(false);
}
}
HBUINT8 format;
union {
FDSelect0 format0;
FDSelect3 format3;
} u;
public:
DEFINE_SIZE_MIN(1);
};
template <typename COUNT> struct Subrs : CFFIndex<COUNT>
{
typedef COUNT count_type;
typedef CFFIndex<COUNT> SUPER;
};
} /* namespace CFF */
#endif /* HB_OT_CFF_COMMON_HH */

View File

@ -0,0 +1,425 @@
/*
* Copyright © 2019 Adobe, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_OT_CFF1_STD_STR_HH
#if 0 /* Make checks happy. */
#define HB_OT_CFF1_STD_STR_HH
#include "hb.hh"
#endif
_S(".notdef")
_S("space")
_S("exclam")
_S("quotedbl")
_S("numbersign")
_S("dollar")
_S("percent")
_S("ampersand")
_S("quoteright")
_S("parenleft")
_S("parenright")
_S("asterisk")
_S("plus")
_S("comma")
_S("hyphen")
_S("period")
_S("slash")
_S("zero")
_S("one")
_S("two")
_S("three")
_S("four")
_S("five")
_S("six")
_S("seven")
_S("eight")
_S("nine")
_S("colon")
_S("semicolon")
_S("less")
_S("equal")
_S("greater")
_S("question")
_S("at")
_S("A")
_S("B")
_S("C")
_S("D")
_S("E")
_S("F")
_S("G")
_S("H")
_S("I")
_S("J")
_S("K")
_S("L")
_S("M")
_S("N")
_S("O")
_S("P")
_S("Q")
_S("R")
_S("S")
_S("T")
_S("U")
_S("V")
_S("W")
_S("X")
_S("Y")
_S("Z")
_S("bracketleft")
_S("backslash")
_S("bracketright")
_S("asciicircum")
_S("underscore")
_S("quoteleft")
_S("a")
_S("b")
_S("c")
_S("d")
_S("e")
_S("f")
_S("g")
_S("h")
_S("i")
_S("j")
_S("k")
_S("l")
_S("m")
_S("n")
_S("o")
_S("p")
_S("q")
_S("r")
_S("s")
_S("t")
_S("u")
_S("v")
_S("w")
_S("x")
_S("y")
_S("z")
_S("braceleft")
_S("bar")
_S("braceright")
_S("asciitilde")
_S("exclamdown")
_S("cent")
_S("sterling")
_S("fraction")
_S("yen")
_S("florin")
_S("section")
_S("currency")
_S("quotesingle")
_S("quotedblleft")
_S("guillemotleft")
_S("guilsinglleft")
_S("guilsinglright")
_S("fi")
_S("fl")
_S("endash")
_S("dagger")
_S("daggerdbl")
_S("periodcentered")
_S("paragraph")
_S("bullet")
_S("quotesinglbase")
_S("quotedblbase")
_S("quotedblright")
_S("guillemotright")
_S("ellipsis")
_S("perthousand")
_S("questiondown")
_S("grave")
_S("acute")
_S("circumflex")
_S("tilde")
_S("macron")
_S("breve")
_S("dotaccent")
_S("dieresis")
_S("ring")
_S("cedilla")
_S("hungarumlaut")
_S("ogonek")
_S("caron")
_S("emdash")
_S("AE")
_S("ordfeminine")
_S("Lslash")
_S("Oslash")
_S("OE")
_S("ordmasculine")
_S("ae")
_S("dotlessi")
_S("lslash")
_S("oslash")
_S("oe")
_S("germandbls")
_S("onesuperior")
_S("logicalnot")
_S("mu")
_S("trademark")
_S("Eth")
_S("onehalf")
_S("plusminus")
_S("Thorn")
_S("onequarter")
_S("divide")
_S("brokenbar")
_S("degree")
_S("thorn")
_S("threequarters")
_S("twosuperior")
_S("registered")
_S("minus")
_S("eth")
_S("multiply")
_S("threesuperior")
_S("copyright")
_S("Aacute")
_S("Acircumflex")
_S("Adieresis")
_S("Agrave")
_S("Aring")
_S("Atilde")
_S("Ccedilla")
_S("Eacute")
_S("Ecircumflex")
_S("Edieresis")
_S("Egrave")
_S("Iacute")
_S("Icircumflex")
_S("Idieresis")
_S("Igrave")
_S("Ntilde")
_S("Oacute")
_S("Ocircumflex")
_S("Odieresis")
_S("Ograve")
_S("Otilde")
_S("Scaron")
_S("Uacute")
_S("Ucircumflex")
_S("Udieresis")
_S("Ugrave")
_S("Yacute")
_S("Ydieresis")
_S("Zcaron")
_S("aacute")
_S("acircumflex")
_S("adieresis")
_S("agrave")
_S("aring")
_S("atilde")
_S("ccedilla")
_S("eacute")
_S("ecircumflex")
_S("edieresis")
_S("egrave")
_S("iacute")
_S("icircumflex")
_S("idieresis")
_S("igrave")
_S("ntilde")
_S("oacute")
_S("ocircumflex")
_S("odieresis")
_S("ograve")
_S("otilde")
_S("scaron")
_S("uacute")
_S("ucircumflex")
_S("udieresis")
_S("ugrave")
_S("yacute")
_S("ydieresis")
_S("zcaron")
_S("exclamsmall")
_S("Hungarumlautsmall")
_S("dollaroldstyle")
_S("dollarsuperior")
_S("ampersandsmall")
_S("Acutesmall")
_S("parenleftsuperior")
_S("parenrightsuperior")
_S("twodotenleader")
_S("onedotenleader")
_S("zerooldstyle")
_S("oneoldstyle")
_S("twooldstyle")
_S("threeoldstyle")
_S("fouroldstyle")
_S("fiveoldstyle")
_S("sixoldstyle")
_S("sevenoldstyle")
_S("eightoldstyle")
_S("nineoldstyle")
_S("commasuperior")
_S("threequartersemdash")
_S("periodsuperior")
_S("questionsmall")
_S("asuperior")
_S("bsuperior")
_S("centsuperior")
_S("dsuperior")
_S("esuperior")
_S("isuperior")
_S("lsuperior")
_S("msuperior")
_S("nsuperior")
_S("osuperior")
_S("rsuperior")
_S("ssuperior")
_S("tsuperior")
_S("ff")
_S("ffi")
_S("ffl")
_S("parenleftinferior")
_S("parenrightinferior")
_S("Circumflexsmall")
_S("hyphensuperior")
_S("Gravesmall")
_S("Asmall")
_S("Bsmall")
_S("Csmall")
_S("Dsmall")
_S("Esmall")
_S("Fsmall")
_S("Gsmall")
_S("Hsmall")
_S("Ismall")
_S("Jsmall")
_S("Ksmall")
_S("Lsmall")
_S("Msmall")
_S("Nsmall")
_S("Osmall")
_S("Psmall")
_S("Qsmall")
_S("Rsmall")
_S("Ssmall")
_S("Tsmall")
_S("Usmall")
_S("Vsmall")
_S("Wsmall")
_S("Xsmall")
_S("Ysmall")
_S("Zsmall")
_S("colonmonetary")
_S("onefitted")
_S("rupiah")
_S("Tildesmall")
_S("exclamdownsmall")
_S("centoldstyle")
_S("Lslashsmall")
_S("Scaronsmall")
_S("Zcaronsmall")
_S("Dieresissmall")
_S("Brevesmall")
_S("Caronsmall")
_S("Dotaccentsmall")
_S("Macronsmall")
_S("figuredash")
_S("hypheninferior")
_S("Ogoneksmall")
_S("Ringsmall")
_S("Cedillasmall")
_S("questiondownsmall")
_S("oneeighth")
_S("threeeighths")
_S("fiveeighths")
_S("seveneighths")
_S("onethird")
_S("twothirds")
_S("zerosuperior")
_S("foursuperior")
_S("fivesuperior")
_S("sixsuperior")
_S("sevensuperior")
_S("eightsuperior")
_S("ninesuperior")
_S("zeroinferior")
_S("oneinferior")
_S("twoinferior")
_S("threeinferior")
_S("fourinferior")
_S("fiveinferior")
_S("sixinferior")
_S("seveninferior")
_S("eightinferior")
_S("nineinferior")
_S("centinferior")
_S("dollarinferior")
_S("periodinferior")
_S("commainferior")
_S("Agravesmall")
_S("Aacutesmall")
_S("Acircumflexsmall")
_S("Atildesmall")
_S("Adieresissmall")
_S("Aringsmall")
_S("AEsmall")
_S("Ccedillasmall")
_S("Egravesmall")
_S("Eacutesmall")
_S("Ecircumflexsmall")
_S("Edieresissmall")
_S("Igravesmall")
_S("Iacutesmall")
_S("Icircumflexsmall")
_S("Idieresissmall")
_S("Ethsmall")
_S("Ntildesmall")
_S("Ogravesmall")
_S("Oacutesmall")
_S("Ocircumflexsmall")
_S("Otildesmall")
_S("Odieresissmall")
_S("OEsmall")
_S("Oslashsmall")
_S("Ugravesmall")
_S("Uacutesmall")
_S("Ucircumflexsmall")
_S("Udieresissmall")
_S("Yacutesmall")
_S("Thornsmall")
_S("Ydieresissmall")
_S("001.000")
_S("001.001")
_S("001.002")
_S("001.003")
_S("Black")
_S("Bold")
_S("Book")
_S("Light")
_S("Medium")
_S("Regular")
_S("Roman")
_S("Semibold")
#endif /* HB_OT_CFF1_STD_STR_HH */

View File

@ -0,0 +1,447 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#include "hb.hh"
#ifndef HB_NO_CFF
#include "hb-algs.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-cff1-interp-cs.hh"
using namespace CFF;
struct sid_to_gid_t
{
uint16_t sid;
uint8_t gid;
int cmp(uint16_t a) const
{
if (a == sid)
return 0;
return (a < sid) ? -1 : 1;
}
};
/* SID to code */
static const uint8_t standard_encoding_to_code[] = {
0, 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, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
175, 177, 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 191, 193, 194, 195, 196, 197, 198, 199, 200,
202, 203, 205, 206, 207, 208, 225, 227, 232, 233, 234, 235, 241, 245, 248, 249, 250, 251};
/* SID to code */
static const uint8_t expert_encoding_to_code[] = {
0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 58, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 189, 0, 0, 188, 0, 0,
0, 0, 190, 202, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33,
34, 36, 37, 38, 39, 40, 41, 42, 43, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 60, 61, 62, 63,
65, 66, 67, 68, 69, 73, 76, 77, 78, 79, 82, 83, 84, 86, 89, 90, 91, 93, 94, 95, 96, 97, 98,
99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
122, 123, 124, 125, 126, 161, 162, 163, 166, 167, 168, 169, 170, 172, 175, 178, 179, 182, 183, 184, 191, 192, 193,
194, 195, 196, 197, 200, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
/* glyph ID to SID */
static const uint16_t expert_charset_to_sid[] = {
0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243,
244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281,
282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302,
303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163, 319, 320,
321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338,
339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378};
/* glyph ID to SID */
static const uint16_t expert_subset_charset_to_sid[] = {
0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
27, 28, 249, 250, 251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267,
268, 269, 270, 272, 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326, 150, 164,
169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346};
/* SID to glyph ID */
static const sid_to_gid_t expert_charset_sid_to_gid[] = {
{1, 1}, {13, 12}, {14, 13}, {15, 14}, {27, 26}, {28, 27}, {99, 15}, {109, 46}, {110, 47},
{150, 111}, {155, 101}, {158, 100}, {163, 102}, {164, 112}, {169, 113}, {229, 2}, {230, 3}, {231, 4},
{232, 5}, {233, 6}, {234, 7}, {235, 8}, {236, 9}, {237, 10}, {238, 11}, {239, 16}, {240, 17},
{241, 18}, {242, 19}, {243, 20}, {244, 21}, {245, 22}, {246, 23}, {247, 24}, {248, 25}, {249, 28},
{250, 29}, {251, 30}, {252, 31}, {253, 32}, {254, 33}, {255, 34}, {256, 35}, {257, 36}, {258, 37},
{259, 38}, {260, 39}, {261, 40}, {262, 41}, {263, 42}, {264, 43}, {265, 44}, {266, 45}, {267, 48},
{268, 49}, {269, 50}, {270, 51}, {271, 52}, {272, 53}, {273, 54}, {274, 55}, {275, 56}, {276, 57},
{277, 58}, {278, 59}, {279, 60}, {280, 61}, {281, 62}, {282, 63}, {283, 64}, {284, 65}, {285, 66},
{286, 67}, {287, 68}, {288, 69}, {289, 70}, {290, 71}, {291, 72}, {292, 73}, {293, 74}, {294, 75},
{295, 76}, {296, 77}, {297, 78}, {298, 79}, {299, 80}, {300, 81}, {301, 82}, {302, 83}, {303, 84},
{304, 85}, {305, 86}, {306, 87}, {307, 88}, {308, 89}, {309, 90}, {310, 91}, {311, 92}, {312, 93},
{313, 94}, {314, 95}, {315, 96}, {316, 97}, {317, 98}, {318, 99}, {319, 103}, {320, 104}, {321, 105},
{322, 106}, {323, 107}, {324, 108}, {325, 109}, {326, 110}, {327, 114}, {328, 115}, {329, 116}, {330, 117},
{331, 118}, {332, 119}, {333, 120}, {334, 121}, {335, 122}, {336, 123}, {337, 124}, {338, 125}, {339, 126},
{340, 127}, {341, 128}, {342, 129}, {343, 130}, {344, 131}, {345, 132}, {346, 133}, {347, 134}, {348, 135},
{349, 136}, {350, 137}, {351, 138}, {352, 139}, {353, 140}, {354, 141}, {355, 142}, {356, 143}, {357, 144},
{358, 145}, {359, 146}, {360, 147}, {361, 148}, {362, 149}, {363, 150}, {364, 151}, {365, 152}, {366, 153},
{367, 154}, {368, 155}, {369, 156}, {370, 157}, {371, 158}, {372, 159}, {373, 160}, {374, 161}, {375, 162},
{376, 163}, {377, 164}, {378, 165}};
/* SID to glyph ID */
static const sid_to_gid_t expert_subset_charset_sid_to_gid[] = {
{1, 1}, {13, 8}, {14, 9}, {15, 10}, {27, 22}, {28, 23}, {99, 11}, {109, 41}, {110, 42}, {150, 64},
{155, 55}, {158, 54}, {163, 56}, {164, 65}, {169, 66}, {231, 2}, {232, 3}, {235, 4}, {236, 5}, {237, 6},
{238, 7}, {239, 12}, {240, 13}, {241, 14}, {242, 15}, {243, 16}, {244, 17}, {245, 18}, {246, 19}, {247, 20},
{248, 21}, {249, 24}, {250, 25}, {251, 26}, {253, 27}, {254, 28}, {255, 29}, {256, 30}, {257, 31}, {258, 32},
{259, 33}, {260, 34}, {261, 35}, {262, 36}, {263, 37}, {264, 38}, {265, 39}, {266, 40}, {267, 43}, {268, 44},
{269, 45}, {270, 46}, {272, 47}, {300, 48}, {301, 49}, {302, 50}, {305, 51}, {314, 52}, {315, 53}, {320, 57},
{321, 58}, {322, 59}, {323, 60}, {324, 61}, {325, 62}, {326, 63}, {327, 67}, {328, 68}, {329, 69}, {330, 70},
{331, 71}, {332, 72}, {333, 73}, {334, 74}, {335, 75}, {336, 76}, {337, 77}, {338, 78}, {339, 79}, {340, 80},
{341, 81}, {342, 82}, {343, 83}, {344, 84}, {345, 85}, {346, 86}};
/* code to SID */
static const uint8_t standard_encoding_to_sid[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123, 0, 124, 125, 126, 127, 128,
129, 130, 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, 0, 144,
0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0};
hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code(hb_codepoint_t sid)
{
if (sid < ARRAY_LENGTH(standard_encoding_to_code))
return (hb_codepoint_t)standard_encoding_to_code[sid];
else
return 0;
}
hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code(hb_codepoint_t sid)
{
if (sid < ARRAY_LENGTH(expert_encoding_to_code))
return (hb_codepoint_t)expert_encoding_to_code[sid];
else
return 0;
}
hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid(hb_codepoint_t glyph)
{
if (glyph < ARRAY_LENGTH(expert_charset_to_sid))
return (hb_codepoint_t)expert_charset_to_sid[glyph];
else
return 0;
}
hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid(hb_codepoint_t glyph)
{
if (glyph < ARRAY_LENGTH(expert_subset_charset_to_sid))
return (hb_codepoint_t)expert_subset_charset_to_sid[glyph];
else
return 0;
}
hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph(hb_codepoint_t sid)
{
const auto *pair = hb_sorted_array(expert_charset_sid_to_gid).bsearch(sid);
return pair ? pair->gid : 0;
}
hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph(hb_codepoint_t sid)
{
const auto *pair = hb_sorted_array(expert_subset_charset_sid_to_gid).bsearch(sid);
return pair ? pair->gid : 0;
}
hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid(hb_codepoint_t code)
{
if (code < ARRAY_LENGTH(standard_encoding_to_sid))
return (hb_codepoint_t)standard_encoding_to_sid[code];
else
return CFF_UNDEF_SID;
}
struct bounds_t
{
void init()
{
min.set_int(INT_MAX, INT_MAX);
max.set_int(INT_MIN, INT_MIN);
}
void update(const point_t &pt)
{
if (pt.x < min.x)
min.x = pt.x;
if (pt.x > max.x)
max.x = pt.x;
if (pt.y < min.y)
min.y = pt.y;
if (pt.y > max.y)
max.y = pt.y;
}
void merge(const bounds_t &b)
{
if (empty())
*this = b;
else if (!b.empty()) {
if (b.min.x < min.x)
min.x = b.min.x;
if (b.max.x > max.x)
max.x = b.max.x;
if (b.min.y < min.y)
min.y = b.min.y;
if (b.max.y > max.y)
max.y = b.max.y;
}
}
void offset(const point_t &delta)
{
if (!empty()) {
min.move(delta);
max.move(delta);
}
}
bool empty() const
{
return (min.x >= max.x) || (min.y >= max.y);
}
point_t min;
point_t max;
};
struct cff1_extents_param_t
{
void init(const OT::cff1::accelerator_t *_cff)
{
path_open = false;
cff = _cff;
bounds.init();
}
void start_path()
{
path_open = true;
}
void end_path()
{
path_open = false;
}
bool is_path_open() const
{
return path_open;
}
bool path_open;
bounds_t bounds;
const OT::cff1::accelerator_t *cff;
};
struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
{
static void moveto(cff1_cs_interp_env_t &env, cff1_extents_param_t &param, const point_t &pt)
{
param.end_path();
env.moveto(pt);
}
static void line(cff1_cs_interp_env_t &env, cff1_extents_param_t &param, const point_t &pt1)
{
if (!param.is_path_open()) {
param.start_path();
param.bounds.update(env.get_pt());
}
env.moveto(pt1);
param.bounds.update(env.get_pt());
}
static void curve(cff1_cs_interp_env_t &env,
cff1_extents_param_t &param,
const point_t &pt1,
const point_t &pt2,
const point_t &pt3)
{
if (!param.is_path_open()) {
param.start_path();
param.bounds.update(env.get_pt());
}
/* include control points */
param.bounds.update(pt1);
param.bounds.update(pt2);
env.moveto(pt3);
param.bounds.update(env.get_pt());
}
};
static bool
_get_bounds(const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac = false);
struct cff1_cs_opset_extents_t
: cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
{
static void process_seac(cff1_cs_interp_env_t &env, cff1_extents_param_t &param)
{
unsigned int n = env.argStack.get_count();
point_t delta;
delta.x = env.argStack[n - 4];
delta.y = env.argStack[n - 3];
hb_codepoint_t base = param.cff->std_code_to_glyph(env.argStack[n - 2].to_int());
hb_codepoint_t accent = param.cff->std_code_to_glyph(env.argStack[n - 1].to_int());
bounds_t base_bounds, accent_bounds;
if (likely(!env.in_seac && base && accent && _get_bounds(param.cff, base, base_bounds, true) &&
_get_bounds(param.cff, accent, accent_bounds, true))) {
param.bounds.merge(base_bounds);
accent_bounds.offset(delta);
param.bounds.merge(accent_bounds);
} else
env.set_error();
}
};
bool _get_bounds(const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac)
{
bounds.init();
if (unlikely(!cff->is_valid() || (glyph >= cff->num_glyphs)))
return false;
unsigned int fd = cff->fdSelect->get_fd(glyph);
cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp;
const byte_str_t str = (*cff->charStrings)[glyph];
interp.env.init(str, *cff, fd);
interp.env.set_in_seac(in_seac);
cff1_extents_param_t param;
param.init(cff);
if (unlikely(!interp.interpret(param)))
return false;
bounds = param.bounds;
return true;
}
bool OT::cff1::accelerator_t::get_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
return true;
#endif
bounds_t bounds;
if (!_get_bounds(this, glyph, bounds))
return false;
if (bounds.min.x >= bounds.max.x) {
extents->width = 0;
extents->x_bearing = 0;
} else {
extents->x_bearing = font->em_scalef_x(bounds.min.x.to_real());
extents->width = font->em_scalef_x(bounds.max.x.to_real() - bounds.min.x.to_real());
}
if (bounds.min.y >= bounds.max.y) {
extents->height = 0;
extents->y_bearing = 0;
} else {
extents->y_bearing = font->em_scalef_y(bounds.max.y.to_real());
extents->height = font->em_scalef_y(bounds.min.y.to_real() - bounds.max.y.to_real());
}
return true;
}
struct get_seac_param_t
{
void init(const OT::cff1::accelerator_t *_cff)
{
cff = _cff;
base = 0;
accent = 0;
}
bool has_seac() const
{
return base && accent;
}
const OT::cff1::accelerator_t *cff;
hb_codepoint_t base;
hb_codepoint_t accent;
};
struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
{
static void process_seac(cff1_cs_interp_env_t &env, get_seac_param_t &param)
{
unsigned int n = env.argStack.get_count();
hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n - 2].to_int();
hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n - 1].to_int();
param.base = param.cff->std_code_to_glyph(base_char);
param.accent = param.cff->std_code_to_glyph(accent_char);
}
};
bool OT::cff1::accelerator_t::get_seac_components(hb_codepoint_t glyph,
hb_codepoint_t *base,
hb_codepoint_t *accent) const
{
if (unlikely(!is_valid() || (glyph >= num_glyphs)))
return false;
unsigned int fd = fdSelect->get_fd(glyph);
cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp;
const byte_str_t str = (*charStrings)[glyph];
interp.env.init(str, *this, fd);
get_seac_param_t param;
param.init(this);
if (unlikely(!interp.interpret(param)))
return false;
if (param.has_seac()) {
*base = param.base;
*accent = param.accent;
return true;
}
return false;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#include "hb.hh"
#ifndef HB_NO_OT_FONT_CFF
#include "hb-ot-cff2-table.hh"
#include "hb-cff2-interp-cs.hh"
using namespace CFF;
struct cff2_extents_param_t
{
void init()
{
path_open = false;
min_x.set_int(INT_MAX);
min_y.set_int(INT_MAX);
max_x.set_int(INT_MIN);
max_y.set_int(INT_MIN);
}
void start_path()
{
path_open = true;
}
void end_path()
{
path_open = false;
}
bool is_path_open() const
{
return path_open;
}
void update_bounds(const point_t &pt)
{
if (pt.x < min_x)
min_x = pt.x;
if (pt.x > max_x)
max_x = pt.x;
if (pt.y < min_y)
min_y = pt.y;
if (pt.y > max_y)
max_y = pt.y;
}
bool path_open;
number_t min_x;
number_t min_y;
number_t max_x;
number_t max_y;
};
struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
{
static void moveto(cff2_cs_interp_env_t &env, cff2_extents_param_t &param, const point_t &pt)
{
param.end_path();
env.moveto(pt);
}
static void line(cff2_cs_interp_env_t &env, cff2_extents_param_t &param, const point_t &pt1)
{
if (!param.is_path_open()) {
param.start_path();
param.update_bounds(env.get_pt());
}
env.moveto(pt1);
param.update_bounds(env.get_pt());
}
static void curve(cff2_cs_interp_env_t &env,
cff2_extents_param_t &param,
const point_t &pt1,
const point_t &pt2,
const point_t &pt3)
{
if (!param.is_path_open()) {
param.start_path();
param.update_bounds(env.get_pt());
}
/* include control points */
param.update_bounds(pt1);
param.update_bounds(pt2);
env.moveto(pt3);
param.update_bounds(env.get_pt());
}
};
struct cff2_cs_opset_extents_t
: cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t>
{
};
bool OT::cff2::accelerator_t::get_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
return true;
#endif
if (unlikely(!is_valid() || (glyph >= num_glyphs)))
return false;
unsigned int fd = fdSelect->get_fd(glyph);
cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
const byte_str_t str = (*charStrings)[glyph];
interp.env.init(str, *this, fd, font->coords, font->num_coords);
cff2_extents_param_t param;
param.init();
if (unlikely(!interp.interpret(param)))
return false;
if (param.min_x >= param.max_x) {
extents->width = 0;
extents->x_bearing = 0;
} else {
extents->x_bearing = font->em_scalef_x(param.min_x.to_real());
extents->width = font->em_scalef_x(param.max_x.to_real() - param.min_x.to_real());
}
if (param.min_y >= param.max_y) {
extents->height = 0;
extents->y_bearing = 0;
} else {
extents->y_bearing = font->em_scalef_y(param.max_y.to_real());
extents->height = font->em_scalef_y(param.min_y.to_real() - param.max_y.to_real());
}
return true;
}
#endif

View File

@ -0,0 +1,564 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_OT_CFF2_TABLE_HH
#define HB_OT_CFF2_TABLE_HH
#include "hb-ot-cff-common.hh"
namespace CFF {
/*
* CFF2 -- Compact Font Format (CFF) Version 2
* https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
*/
#define HB_OT_TAG_cff2 HB_TAG('C', 'F', 'F', '2')
typedef CFFIndex<HBUINT32> CFF2Index;
template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type>
{
};
typedef CFF2Index CFF2CharStrings;
typedef Subrs<HBUINT32> CFF2Subrs;
typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
struct CFF2FDSelect
{
unsigned int get_size(unsigned int num_glyphs) const
{
switch (format) {
case 0:
return format.static_size + u.format0.get_size(num_glyphs);
case 3:
return format.static_size + u.format3.get_size();
case 4:
return format.static_size + u.format4.get_size();
default:
return 0;
}
}
hb_codepoint_t get_fd(hb_codepoint_t glyph) const
{
if (this == &Null(CFF2FDSelect))
return 0;
switch (format) {
case 0:
return u.format0.get_fd(glyph);
case 3:
return u.format3.get_fd(glyph);
case 4:
return u.format4.get_fd(glyph);
default:
return 0;
}
}
bool sanitize(hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE(this);
if (unlikely(!c->check_struct(this)))
return_trace(false);
switch (format) {
case 0:
return_trace(u.format0.sanitize(c, fdcount));
case 3:
return_trace(u.format3.sanitize(c, fdcount));
case 4:
return_trace(u.format4.sanitize(c, fdcount));
default:
return_trace(false);
}
}
HBUINT8 format;
union {
FDSelect0 format0;
FDSelect3 format3;
FDSelect4 format4;
} u;
public:
DEFINE_SIZE_MIN(2);
};
struct CFF2VariationStore
{
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this)) && c->check_range(&varStore, size) && varStore.sanitize(c));
}
unsigned int get_size() const
{
return HBUINT16::static_size + size;
}
HBUINT16 size;
VariationStore varStore;
DEFINE_SIZE_MIN(2 + VariationStore::min_size);
};
struct cff2_top_dict_values_t : top_dict_values_t<>
{
void init()
{
top_dict_values_t<>::init();
vstoreOffset = 0;
FDSelectOffset = 0;
}
void fini()
{
top_dict_values_t<>::fini();
}
unsigned int vstoreOffset;
unsigned int FDSelectOffset;
};
struct cff2_top_dict_opset_t : top_dict_opset_t<>
{
static void process_op(op_code_t op, num_interp_env_t &env, cff2_top_dict_values_t &dictval)
{
switch (op) {
case OpCode_FontMatrix: {
dict_val_t val;
val.init();
dictval.add_op(op, env.str_ref);
env.clear_args();
} break;
case OpCode_vstore:
dictval.vstoreOffset = env.argStack.pop_uint();
env.clear_args();
break;
case OpCode_FDSelect:
dictval.FDSelectOffset = env.argStack.pop_uint();
env.clear_args();
break;
default:
SUPER::process_op(op, env, dictval);
/* Record this operand below if stack is empty, otherwise done */
if (!env.argStack.is_empty())
return;
}
if (unlikely(env.in_error()))
return;
dictval.add_op(op, env.str_ref);
}
typedef top_dict_opset_t<> SUPER;
};
struct cff2_font_dict_values_t : dict_values_t<op_str_t>
{
void init()
{
dict_values_t<op_str_t>::init();
privateDictInfo.init();
}
void fini()
{
dict_values_t<op_str_t>::fini();
}
table_info_t privateDictInfo;
};
struct cff2_font_dict_opset_t : dict_opset_t
{
static void process_op(op_code_t op, num_interp_env_t &env, cff2_font_dict_values_t &dictval)
{
switch (op) {
case OpCode_Private:
dictval.privateDictInfo.offset = env.argStack.pop_uint();
dictval.privateDictInfo.size = env.argStack.pop_uint();
env.clear_args();
break;
default:
SUPER::process_op(op, env);
if (!env.argStack.is_empty())
return;
}
if (unlikely(env.in_error()))
return;
dictval.add_op(op, env.str_ref);
}
private:
typedef dict_opset_t SUPER;
};
template <typename VAL> struct cff2_private_dict_values_base_t : dict_values_t<VAL>
{
void init()
{
dict_values_t<VAL>::init();
subrsOffset = 0;
localSubrs = &Null(CFF2Subrs);
ivs = 0;
}
void fini()
{
dict_values_t<VAL>::fini();
}
unsigned int subrsOffset;
const CFF2Subrs *localSubrs;
unsigned int ivs;
};
typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t;
typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t;
struct cff2_priv_dict_interp_env_t : num_interp_env_t
{
void init(const byte_str_t &str)
{
num_interp_env_t::init(str);
ivs = 0;
seen_vsindex = false;
}
void process_vsindex()
{
if (likely(!seen_vsindex)) {
set_ivs(argStack.pop_uint());
}
seen_vsindex = true;
}
unsigned int get_ivs() const
{
return ivs;
}
void set_ivs(unsigned int ivs_)
{
ivs = ivs_;
}
protected:
unsigned int ivs;
bool seen_vsindex;
};
struct cff2_private_dict_opset_t : dict_opset_t
{
static void process_op(op_code_t op, cff2_priv_dict_interp_env_t &env, cff2_private_dict_values_t &dictval)
{
num_dict_val_t val;
val.init();
switch (op) {
case OpCode_StdHW:
case OpCode_StdVW:
case OpCode_BlueScale:
case OpCode_BlueShift:
case OpCode_BlueFuzz:
case OpCode_ExpansionFactor:
case OpCode_LanguageGroup:
val.single_val = env.argStack.pop_num();
env.clear_args();
break;
case OpCode_BlueValues:
case OpCode_OtherBlues:
case OpCode_FamilyBlues:
case OpCode_FamilyOtherBlues:
case OpCode_StemSnapH:
case OpCode_StemSnapV:
env.clear_args();
break;
case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint();
env.clear_args();
break;
case OpCode_vsindexdict:
env.process_vsindex();
dictval.ivs = env.get_ivs();
env.clear_args();
break;
case OpCode_blenddict:
break;
default:
dict_opset_t::process_op(op, env);
if (!env.argStack.is_empty())
return;
break;
}
if (unlikely(env.in_error()))
return;
dictval.add_op(op, env.str_ref, val);
}
};
struct cff2_private_dict_opset_subset_t : dict_opset_t
{
static void process_op(op_code_t op, cff2_priv_dict_interp_env_t &env, cff2_private_dict_values_subset_t &dictval)
{
switch (op) {
case OpCode_BlueValues:
case OpCode_OtherBlues:
case OpCode_FamilyBlues:
case OpCode_FamilyOtherBlues:
case OpCode_StdHW:
case OpCode_StdVW:
case OpCode_BlueScale:
case OpCode_BlueShift:
case OpCode_BlueFuzz:
case OpCode_StemSnapH:
case OpCode_StemSnapV:
case OpCode_LanguageGroup:
case OpCode_ExpansionFactor:
env.clear_args();
break;
case OpCode_blenddict:
env.clear_args();
return;
case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint();
env.clear_args();
break;
default:
SUPER::process_op(op, env);
if (!env.argStack.is_empty())
return;
break;
}
if (unlikely(env.in_error()))
return;
dictval.add_op(op, env.str_ref);
}
private:
typedef dict_opset_t SUPER;
};
typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
struct CFF2FDArray : FDArray<HBUINT32>
{
};
} /* namespace CFF */
namespace OT {
using namespace CFF;
struct cff2
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && likely(version.major == 2));
}
template <typename PRIVOPSET, typename PRIVDICTVAL> struct accelerator_templ_t
{
void init(hb_face_t *face)
{
topDict.init();
fontDicts.init();
privateDicts.init();
this->blob = sc.reference_table<cff2>(face);
/* setup for run-time santization */
sc.init(this->blob);
sc.start_processing();
const OT::cff2 *cff2 = this->blob->template as<OT::cff2>();
if (cff2 == &Null(OT::cff2)) {
fini();
return;
}
{ /* parse top dict */
byte_str_t topDictStr(cff2 + cff2->topDict, cff2->topDictSize);
if (unlikely(!topDictStr.sanitize(&sc))) {
fini();
return;
}
cff2_top_dict_interpreter_t top_interp;
top_interp.env.init(topDictStr);
topDict.init();
if (unlikely(!top_interp.interpret(topDict))) {
fini();
return;
}
}
globalSubrs = &StructAtOffset<CFF2Subrs>(cff2, cff2->topDict + cff2->topDictSize);
varStore = &StructAtOffsetOrNull<CFF2VariationStore>(cff2, topDict.vstoreOffset);
charStrings = &StructAtOffsetOrNull<CFF2CharStrings>(cff2, topDict.charStringsOffset);
fdArray = &StructAtOffsetOrNull<CFF2FDArray>(cff2, topDict.FDArrayOffset);
fdSelect = &StructAtOffsetOrNull<CFF2FDSelect>(cff2, topDict.FDSelectOffset);
if (((varStore != &Null(CFF2VariationStore)) && unlikely(!varStore->sanitize(&sc))) ||
(charStrings == &Null(CFF2CharStrings)) || unlikely(!charStrings->sanitize(&sc)) ||
(globalSubrs == &Null(CFF2Subrs)) || unlikely(!globalSubrs->sanitize(&sc)) ||
(fdArray == &Null(CFF2FDArray)) || unlikely(!fdArray->sanitize(&sc)) ||
(((fdSelect != &Null(CFF2FDSelect)) && unlikely(!fdSelect->sanitize(&sc, fdArray->count))))) {
fini();
return;
}
num_glyphs = charStrings->count;
if (num_glyphs != sc.get_num_glyphs()) {
fini();
return;
}
fdCount = fdArray->count;
privateDicts.resize(fdCount);
/* parse font dicts and gather private dicts */
for (unsigned int i = 0; i < fdCount; i++) {
const byte_str_t fontDictStr = (*fdArray)[i];
if (unlikely(!fontDictStr.sanitize(&sc))) {
fini();
return;
}
cff2_font_dict_values_t *font;
cff2_font_dict_interpreter_t font_interp;
font_interp.env.init(fontDictStr);
font = fontDicts.push();
if (unlikely(font == &Crap(cff2_font_dict_values_t))) {
fini();
return;
}
font->init();
if (unlikely(!font_interp.interpret(*font))) {
fini();
return;
}
const byte_str_t privDictStr(StructAtOffsetOrNull<UnsizedByteStr>(cff2, font->privateDictInfo.offset),
font->privateDictInfo.size);
if (unlikely(!privDictStr.sanitize(&sc))) {
fini();
return;
}
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp;
priv_interp.env.init(privDictStr);
privateDicts[i].init();
if (unlikely(!priv_interp.interpret(privateDicts[i]))) {
fini();
return;
}
privateDicts[i].localSubrs =
&StructAtOffsetOrNull<CFF2Subrs>(&privDictStr[0], privateDicts[i].subrsOffset);
if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
unlikely(!privateDicts[i].localSubrs->sanitize(&sc))) {
fini();
return;
}
}
}
void fini()
{
sc.end_processing();
topDict.fini();
fontDicts.fini_deep();
privateDicts.fini_deep();
hb_blob_destroy(blob);
blob = nullptr;
}
bool is_valid() const
{
return blob;
}
protected:
hb_blob_t *blob;
hb_sanitize_context_t sc;
public:
cff2_top_dict_values_t topDict;
const CFF2Subrs *globalSubrs;
const CFF2VariationStore *varStore;
const CFF2CharStrings *charStrings;
const CFF2FDArray *fdArray;
const CFF2FDSelect *fdSelect;
unsigned int fdCount;
hb_vector_t<cff2_font_dict_values_t> fontDicts;
hb_vector_t<PRIVDICTVAL> privateDicts;
unsigned int num_glyphs;
};
struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t>
{
HB_INTERNAL bool get_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
};
typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>
accelerator_subset_t;
public:
FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */
NNOffsetTo<TopDict, HBUINT8> topDict; /* headerSize = Offset to Top DICT. */
HBUINT16 topDictSize; /* Top DICT size */
public:
DEFINE_SIZE_STATIC(5);
};
struct cff2_accelerator_t : cff2::accelerator_t
{
};
} /* namespace OT */
#endif /* HB_OT_CFF2_TABLE_HH */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,593 @@
/*
* Copyright © 2016 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Seigo Nonaka, Calder Kitagawa
*/
#ifndef HB_OT_COLOR_CBDT_TABLE_HH
#define HB_OT_COLOR_CBDT_TABLE_HH
#include "hb-open-type.hh"
#include "hb-font.hh"
/*
* CBLC -- Color Bitmap Location
* https://docs.microsoft.com/en-us/typography/opentype/spec/cblc
* https://docs.microsoft.com/en-us/typography/opentype/spec/eblc
* CBDT -- Color Bitmap Data
* https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt
* https://docs.microsoft.com/en-us/typography/opentype/spec/ebdt
*/
#define HB_OT_TAG_CBLC HB_TAG('C', 'B', 'L', 'C')
#define HB_OT_TAG_CBDT HB_TAG('C', 'B', 'D', 'T')
namespace OT {
struct cblc_bitmap_size_subset_context_t
{
const char *cbdt;
unsigned int cbdt_length;
hb_vector_t<char> *cbdt_prime;
unsigned int size; /* INOUT
* Input: old size of IndexSubtable
* Output: new size of IndexSubtable
*/
unsigned int num_tables; /* INOUT
* Input: old number of subtables.
* Output: new number of subtables.
*/
hb_codepoint_t start_glyph; /* OUT */
hb_codepoint_t end_glyph; /* OUT */
};
static inline bool _copy_data_to_cbdt(hb_vector_t<char> *cbdt_prime, const void *data, unsigned length)
{
unsigned int new_len = cbdt_prime->length + length;
if (unlikely(!cbdt_prime->alloc(new_len)))
return false;
memcpy(cbdt_prime->arrayZ + cbdt_prime->length, data, length);
cbdt_prime->length = new_len;
return true;
}
struct SmallGlyphMetrics
{
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
void get_extents(hb_font_t *font, hb_glyph_extents_t *extents) const
{
extents->x_bearing = font->em_scale_x(bearingX);
extents->y_bearing = font->em_scale_y(bearingY);
extents->width = font->em_scale_x(width);
extents->height = font->em_scale_y(-static_cast<int>(height));
}
HBUINT8 height;
HBUINT8 width;
HBINT8 bearingX;
HBINT8 bearingY;
HBUINT8 advance;
public:
DEFINE_SIZE_STATIC(5);
};
struct BigGlyphMetrics : SmallGlyphMetrics
{
HBINT8 vertBearingX;
HBINT8 vertBearingY;
HBUINT8 vertAdvance;
public:
DEFINE_SIZE_STATIC(8);
};
struct SBitLineMetrics
{
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
HBINT8 ascender;
HBINT8 decender;
HBUINT8 widthMax;
HBINT8 caretSlopeNumerator;
HBINT8 caretSlopeDenominator;
HBINT8 caretOffset;
HBINT8 minOriginSB;
HBINT8 minAdvanceSB;
HBINT8 maxBeforeBL;
HBINT8 minAfterBL;
HBINT8 padding1;
HBINT8 padding2;
public:
DEFINE_SIZE_STATIC(12);
};
/*
* Index Subtables.
*/
struct IndexSubtableHeader
{
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
HBUINT16 indexFormat;
HBUINT16 imageFormat;
HBUINT32 imageDataOffset;
public:
DEFINE_SIZE_STATIC(8);
};
template <typename OffsetType> struct IndexSubtableFormat1Or3
{
bool sanitize(hb_sanitize_context_t *c, unsigned int glyph_count) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && offsetArrayZ.sanitize(c, glyph_count + 1));
}
bool get_image_data(unsigned int idx, unsigned int *offset, unsigned int *length) const
{
if (unlikely(offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
return false;
*offset = header.imageDataOffset + offsetArrayZ[idx];
*length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
return true;
}
IndexSubtableHeader header;
UnsizedArrayOf<Offset<OffsetType>> offsetArrayZ;
public:
DEFINE_SIZE_ARRAY(8, offsetArrayZ);
};
struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32>
{
};
struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<HBUINT16>
{
};
struct IndexSubtable
{
bool sanitize(hb_sanitize_context_t *c, unsigned int glyph_count) const
{
TRACE_SANITIZE(this);
if (!u.header.sanitize(c))
return_trace(false);
switch (u.header.indexFormat) {
case 1:
return_trace(u.format1.sanitize(c, glyph_count));
case 3:
return_trace(u.format3.sanitize(c, glyph_count));
default:
return_trace(true);
}
}
bool get_extents(hb_glyph_extents_t *extents HB_UNUSED) const
{
switch (u.header.indexFormat) {
case 2:
case 5: /* TODO */
case 1:
case 3:
case 4: /* Variable-metrics formats do not have metrics here. */
default:
return (false);
}
}
bool get_image_data(unsigned int idx, unsigned int *offset, unsigned int *length, unsigned int *format) const
{
*format = u.header.imageFormat;
switch (u.header.indexFormat) {
case 1:
return u.format1.get_image_data(idx, offset, length);
case 3:
return u.format3.get_image_data(idx, offset, length);
default:
return false;
}
}
const IndexSubtableHeader *get_header() const
{
return &u.header;
}
void
populate_header(unsigned index_format, unsigned image_format, unsigned int image_data_offset, unsigned int *size)
{
u.header.indexFormat = index_format;
u.header.imageFormat = image_format;
u.header.imageDataOffset = image_data_offset;
switch (u.header.indexFormat) {
case 1:
*size += IndexSubtableFormat1::min_size;
break;
case 3:
*size += IndexSubtableFormat3::min_size;
break;
}
}
protected:
union {
IndexSubtableHeader header;
IndexSubtableFormat1 format1;
IndexSubtableFormat3 format3;
/* TODO: Format 2, 4, 5. */
} u;
public:
DEFINE_SIZE_UNION(8, header);
};
struct IndexSubtableRecord
{
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && firstGlyphIndex <= lastGlyphIndex &&
offsetToSubtable.sanitize(c, base, lastGlyphIndex - firstGlyphIndex + 1));
}
const IndexSubtable *get_subtable(const void *base) const
{
return &(base + offsetToSubtable);
}
unsigned int add_glyph_for_subset(hb_codepoint_t gid)
{
if (firstGlyphIndex > lastGlyphIndex) {
firstGlyphIndex = gid;
lastGlyphIndex = gid;
return 0;
}
// TODO maybe assert? this shouldn't occur.
if (lastGlyphIndex > gid)
return 0;
unsigned int num_missing = (unsigned int)(gid - lastGlyphIndex - 1);
lastGlyphIndex = gid;
return num_missing;
}
bool get_extents(hb_glyph_extents_t *extents, const void *base) const
{
return (base + offsetToSubtable).get_extents(extents);
}
bool get_image_data(
unsigned int gid, const void *base, unsigned int *offset, unsigned int *length, unsigned int *format) const
{
if (gid < firstGlyphIndex || gid > lastGlyphIndex)
return false;
return (base + offsetToSubtable).get_image_data(gid - firstGlyphIndex, offset, length, format);
}
HBGlyphID firstGlyphIndex;
HBGlyphID lastGlyphIndex;
LOffsetTo<IndexSubtable> offsetToSubtable;
public:
DEFINE_SIZE_STATIC(8);
};
struct IndexSubtableArray
{
friend struct CBDT;
bool sanitize(hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE(this);
return_trace(indexSubtablesZ.sanitize(c, count, this));
}
public:
const IndexSubtableRecord *find_table(hb_codepoint_t glyph, unsigned int numTables) const
{
for (unsigned int i = 0; i < numTables; ++i) {
unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex)
return &indexSubtablesZ[i];
}
return nullptr;
}
protected:
UnsizedArrayOf<IndexSubtableRecord> indexSubtablesZ;
};
struct BitmapSizeTable
{
friend struct CBLC;
friend struct CBDT;
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && indexSubtableArrayOffset.sanitize(c, base, numberOfIndexSubtables) &&
horizontal.sanitize(c) && vertical.sanitize(c));
}
const IndexSubtableRecord *find_table(hb_codepoint_t glyph, const void *base, const void **out_base) const
{
*out_base = &(base + indexSubtableArrayOffset);
return (base + indexSubtableArrayOffset).find_table(glyph, numberOfIndexSubtables);
}
protected:
LNNOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
HBUINT32 indexTablesSize;
HBUINT32 numberOfIndexSubtables;
HBUINT32 colorRef;
SBitLineMetrics horizontal;
SBitLineMetrics vertical;
HBGlyphID startGlyphIndex;
HBGlyphID endGlyphIndex;
HBUINT8 ppemX;
HBUINT8 ppemY;
HBUINT8 bitDepth;
HBINT8 flags;
public:
DEFINE_SIZE_STATIC(48);
};
/*
* Glyph Bitmap Data Formats.
*/
struct GlyphBitmapDataFormat17
{
SmallGlyphMetrics glyphMetrics;
LArrayOf<HBUINT8> data;
public:
DEFINE_SIZE_ARRAY(9, data);
};
struct GlyphBitmapDataFormat18
{
BigGlyphMetrics glyphMetrics;
LArrayOf<HBUINT8> data;
public:
DEFINE_SIZE_ARRAY(12, data);
};
struct GlyphBitmapDataFormat19
{
LArrayOf<HBUINT8> data;
public:
DEFINE_SIZE_ARRAY(4, data);
};
struct CBLC
{
friend struct CBDT;
static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC;
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && likely(version.major == 2 || version.major == 3) &&
sizeTables.sanitize(c, this));
}
protected:
const BitmapSizeTable &choose_strike(hb_font_t *font) const
{
unsigned count = sizeTables.len;
if (unlikely(!count))
return Null(BitmapSizeTable);
unsigned int requested_ppem = hb_max(font->x_ppem, font->y_ppem);
if (!requested_ppem)
requested_ppem = 1 << 30; /* Choose largest strike. */
unsigned int best_i = 0;
unsigned int best_ppem = hb_max(sizeTables[0].ppemX, sizeTables[0].ppemY);
for (unsigned int i = 1; i < count; i++) {
unsigned int ppem = hb_max(sizeTables[i].ppemX, sizeTables[i].ppemY);
if ((requested_ppem <= ppem && ppem < best_ppem) || (requested_ppem > best_ppem && ppem > best_ppem)) {
best_i = i;
best_ppem = ppem;
}
}
return sizeTables[best_i];
}
protected:
FixedVersion<> version;
LArrayOf<BitmapSizeTable> sizeTables;
public:
DEFINE_SIZE_ARRAY(8, sizeTables);
};
struct CBDT
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT;
struct accelerator_t
{
void init(hb_face_t *face)
{
cblc = hb_sanitize_context_t().reference_table<CBLC>(face);
cbdt = hb_sanitize_context_t().reference_table<CBDT>(face);
upem = hb_face_get_upem(face);
}
void fini()
{
this->cblc.destroy();
this->cbdt.destroy();
}
bool get_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
const void *base;
const BitmapSizeTable &strike = this->cblc->choose_strike(font);
const IndexSubtableRecord *subtable_record = strike.find_table(glyph, cblc, &base);
if (!subtable_record || !strike.ppemX || !strike.ppemY)
return false;
if (subtable_record->get_extents(extents, base))
return true;
unsigned int image_offset = 0, image_length = 0, image_format = 0;
if (!subtable_record->get_image_data(glyph, base, &image_offset, &image_length, &image_format))
return false;
unsigned int cbdt_len = cbdt.get_length();
if (unlikely(image_offset > cbdt_len || cbdt_len - image_offset < image_length))
return false;
switch (image_format) {
case 17: {
if (unlikely(image_length < GlyphBitmapDataFormat17::min_size))
return false;
auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17>(this->cbdt, image_offset);
glyphFormat17.glyphMetrics.get_extents(font, extents);
break;
}
case 18: {
if (unlikely(image_length < GlyphBitmapDataFormat18::min_size))
return false;
auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18>(this->cbdt, image_offset);
glyphFormat18.glyphMetrics.get_extents(font, extents);
break;
}
default:
return false; /* TODO: Support other image formats. */
}
/* Convert to font units. */
float x_scale = upem / (float)strike.ppemX;
float y_scale = upem / (float)strike.ppemY;
extents->x_bearing = roundf(extents->x_bearing * x_scale);
extents->y_bearing = roundf(extents->y_bearing * y_scale);
extents->width = roundf(extents->width * x_scale);
extents->height = roundf(extents->height * y_scale);
return true;
}
hb_blob_t *reference_png(hb_font_t *font, hb_codepoint_t glyph) const
{
const void *base;
const BitmapSizeTable &strike = this->cblc->choose_strike(font);
const IndexSubtableRecord *subtable_record = strike.find_table(glyph, cblc, &base);
if (!subtable_record || !strike.ppemX || !strike.ppemY)
return hb_blob_get_empty();
unsigned int image_offset = 0, image_length = 0, image_format = 0;
if (!subtable_record->get_image_data(glyph, base, &image_offset, &image_length, &image_format))
return hb_blob_get_empty();
unsigned int cbdt_len = cbdt.get_length();
if (unlikely(image_offset > cbdt_len || cbdt_len - image_offset < image_length))
return hb_blob_get_empty();
switch (image_format) {
case 17: {
if (unlikely(image_length < GlyphBitmapDataFormat17::min_size))
return hb_blob_get_empty();
auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17>(this->cbdt, image_offset);
return hb_blob_create_sub_blob(
cbdt.get_blob(), image_offset + GlyphBitmapDataFormat17::min_size, glyphFormat17.data.len);
}
case 18: {
if (unlikely(image_length < GlyphBitmapDataFormat18::min_size))
return hb_blob_get_empty();
auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18>(this->cbdt, image_offset);
return hb_blob_create_sub_blob(
cbdt.get_blob(), image_offset + GlyphBitmapDataFormat18::min_size, glyphFormat18.data.len);
}
case 19: {
if (unlikely(image_length < GlyphBitmapDataFormat19::min_size))
return hb_blob_get_empty();
auto &glyphFormat19 = StructAtOffset<GlyphBitmapDataFormat19>(this->cbdt, image_offset);
return hb_blob_create_sub_blob(
cbdt.get_blob(), image_offset + GlyphBitmapDataFormat19::min_size, glyphFormat19.data.len);
}
default:
return hb_blob_get_empty(); /* TODO: Support other image formats. */
}
}
bool has_data() const
{
return cbdt.get_length();
}
private:
hb_blob_ptr_t<CBLC> cblc;
hb_blob_ptr_t<CBDT> cbdt;
unsigned int upem;
};
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && likely(version.major == 2 || version.major == 3));
}
protected:
FixedVersion<> version;
UnsizedArrayOf<HBUINT8> dataZ;
public:
DEFINE_SIZE_ARRAY(4, dataZ);
};
struct CBDT_accelerator_t : CBDT::accelerator_t
{
};
} /* namespace OT */
#endif /* HB_OT_COLOR_CBDT_TABLE_HH */

View File

@ -0,0 +1,293 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2020 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Calder Kitagawa
*/
#ifndef HB_OT_COLOR_SBIX_TABLE_HH
#define HB_OT_COLOR_SBIX_TABLE_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
/*
* sbix -- Standard Bitmap Graphics
* https://docs.microsoft.com/en-us/typography/opentype/spec/sbix
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html
*/
#define HB_OT_TAG_sbix HB_TAG('s', 'b', 'i', 'x')
namespace OT {
struct SBIXGlyph
{
HBINT16 xOffset; /* The horizontal (x-axis) offset from the left
* edge of the graphic to the glyphs origin.
* That is, the x-coordinate of the point on the
* baseline at the left edge of the glyph. */
HBINT16 yOffset; /* The vertical (y-axis) offset from the bottom
* edge of the graphic to the glyphs origin.
* That is, the y-coordinate of the point on the
* baseline at the left edge of the glyph. */
Tag graphicType; /* Indicates the format of the embedded graphic
* data: one of 'jpg ', 'png ' or 'tiff', or the
* special format 'dupe'. */
UnsizedArrayOf<HBUINT8> data; /* The actual embedded graphic data. The total
* length is inferred from sequential entries in
* the glyphDataOffsets array and the fixed size
* (8 bytes) of the preceding fields. */
public:
DEFINE_SIZE_ARRAY(8, data);
};
struct SBIXStrike
{
static unsigned int get_size(unsigned num_glyphs)
{
return min_size + num_glyphs * HBUINT32::static_size;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && imageOffsetsZ.sanitize_shallow(c, c->get_num_glyphs() + 1));
}
hb_blob_t *get_glyph_blob(unsigned int glyph_id,
hb_blob_t *sbix_blob,
hb_tag_t file_type,
int *x_offset,
int *y_offset,
unsigned int num_glyphs,
unsigned int *strike_ppem) const
{
if (unlikely(!ppem))
return hb_blob_get_empty(); /* To get Null() object out of the way. */
unsigned int retry_count = 8;
unsigned int sbix_len = sbix_blob->length;
unsigned int strike_offset = (const char *)this - (const char *)sbix_blob->data;
assert(strike_offset < sbix_len);
retry:
if (unlikely(glyph_id >= num_glyphs || imageOffsetsZ[glyph_id + 1] <= imageOffsetsZ[glyph_id] ||
imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] <= SBIXGlyph::min_size ||
(unsigned int)imageOffsetsZ[glyph_id + 1] > sbix_len - strike_offset))
return hb_blob_get_empty();
unsigned int glyph_offset = strike_offset + (unsigned int)imageOffsetsZ[glyph_id] + SBIXGlyph::min_size;
unsigned int glyph_length = imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size;
const SBIXGlyph *glyph = &(this + imageOffsetsZ[glyph_id]);
if (glyph->graphicType == HB_TAG('d', 'u', 'p', 'e')) {
if (glyph_length >= 2) {
glyph_id = *((HBUINT16 *)&glyph->data);
if (retry_count--)
goto retry;
}
return hb_blob_get_empty();
}
if (unlikely(file_type != glyph->graphicType))
return hb_blob_get_empty();
if (strike_ppem)
*strike_ppem = ppem;
if (x_offset)
*x_offset = glyph->xOffset;
if (y_offset)
*y_offset = glyph->yOffset;
return hb_blob_create_sub_blob(sbix_blob, glyph_offset, glyph_length);
}
public:
HBUINT16 ppem; /* The PPEM size for which this strike was designed. */
HBUINT16 resolution; /* The device pixel density (in PPI) for which this
* strike was designed. (E.g., 96 PPI, 192 PPI.) */
protected:
UnsizedArrayOf<LOffsetTo<SBIXGlyph>> imageOffsetsZ; /* Offset from the beginning of the strike data header
* to bitmap data for an individual glyph ID. */
public:
DEFINE_SIZE_ARRAY(4, imageOffsetsZ);
};
struct sbix
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix;
bool has_data() const
{
return version;
}
const SBIXStrike &get_strike(unsigned int i) const
{
return this + strikes[i];
}
struct accelerator_t
{
void init(hb_face_t *face)
{
table = hb_sanitize_context_t().reference_table<sbix>(face);
num_glyphs = face->get_num_glyphs();
}
void fini()
{
table.destroy();
}
bool has_data() const
{
return table->has_data();
}
bool get_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
/* We only support PNG right now, and following function checks type. */
return get_png_extents(font, glyph, extents);
}
hb_blob_t *reference_png(
hb_font_t *font, hb_codepoint_t glyph_id, int *x_offset, int *y_offset, unsigned int *available_ppem) const
{
return choose_strike(font).get_glyph_blob(
glyph_id, table.get_blob(), HB_TAG('p', 'n', 'g', ' '), x_offset, y_offset, num_glyphs, available_ppem);
}
private:
const SBIXStrike &choose_strike(hb_font_t *font) const
{
unsigned count = table->strikes.len;
if (unlikely(!count))
return Null(SBIXStrike);
unsigned int requested_ppem = hb_max(font->x_ppem, font->y_ppem);
if (!requested_ppem)
requested_ppem = 1 << 30; /* Choose largest strike. */
/* TODO Add DPI sensitivity as well? */
unsigned int best_i = 0;
unsigned int best_ppem = table->get_strike(0).ppem;
for (unsigned int i = 1; i < count; i++) {
unsigned int ppem = (table->get_strike(i)).ppem;
if ((requested_ppem <= ppem && ppem < best_ppem) || (requested_ppem > best_ppem && ppem > best_ppem)) {
best_i = i;
best_ppem = ppem;
}
}
return table->get_strike(best_i);
}
struct PNGHeader
{
HBUINT8 signature[8];
struct
{
struct
{
HBUINT32 length;
Tag type;
} header;
HBUINT32 width;
HBUINT32 height;
HBUINT8 bitDepth;
HBUINT8 colorType;
HBUINT8 compressionMethod;
HBUINT8 filterMethod;
HBUINT8 interlaceMethod;
} IHDR;
public:
DEFINE_SIZE_STATIC(29);
};
bool get_png_extents(hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
/* Following code is safe to call even without data.
* But faster to short-circuit. */
if (!has_data())
return false;
int x_offset = 0, y_offset = 0;
unsigned int strike_ppem = 0;
hb_blob_t *blob = reference_png(font, glyph, &x_offset, &y_offset, &strike_ppem);
const PNGHeader &png = *blob->as<PNGHeader>();
extents->x_bearing = x_offset;
extents->y_bearing = png.IHDR.height + y_offset;
extents->width = png.IHDR.width;
extents->height = -1 * png.IHDR.height;
/* Convert to font units. */
if (strike_ppem) {
float scale = font->face->get_upem() / (float)strike_ppem;
extents->x_bearing = font->em_scalef_x(extents->x_bearing * scale);
extents->y_bearing = font->em_scalef_y(extents->y_bearing * scale);
extents->width = font->em_scalef_x(extents->width * scale);
extents->height = font->em_scalef_y(extents->height * scale);
} else {
extents->x_bearing = font->em_scale_x(extents->x_bearing);
extents->y_bearing = font->em_scale_y(extents->y_bearing);
extents->width = font->em_scale_x(extents->width);
extents->height = font->em_scale_y(extents->height);
}
hb_blob_destroy(blob);
return strike_ppem;
}
private:
hb_blob_ptr_t<sbix> table;
unsigned int num_glyphs;
};
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && version >= 1 && strikes.sanitize(c, this)));
}
protected:
HBUINT16 version; /* Table version number — set to 1 */
HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines.
* Bits 2 to 15: reserved (set to 0). */
LOffsetLArrayOf<SBIXStrike> strikes; /* Offsets from the beginning of the 'sbix'
* table to data for each individual bitmap strike. */
public:
DEFINE_SIZE_ARRAY(8, strikes);
};
struct sbix_accelerator_t : sbix::accelerator_t
{
};
} /* namespace OT */
#endif /* HB_OT_COLOR_SBIX_TABLE_HH */

View File

@ -0,0 +1,131 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_OT_COLOR_SVG_TABLE_HH
#define HB_OT_COLOR_SVG_TABLE_HH
#include "hb-open-type.hh"
/*
* SVG -- SVG (Scalable Vector Graphics)
* https://docs.microsoft.com/en-us/typography/opentype/spec/svg
*/
#define HB_OT_TAG_SVG HB_TAG('S', 'V', 'G', ' ')
namespace OT {
struct SVGDocumentIndexEntry
{
int cmp(hb_codepoint_t g) const
{
return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0;
}
hb_blob_t *reference_blob(hb_blob_t *svg_blob, unsigned int index_offset) const
{
return hb_blob_create_sub_blob(svg_blob, index_offset + (unsigned int)svgDoc, svgDocLength);
}
bool sanitize(hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && svgDoc.sanitize(c, base, svgDocLength));
}
protected:
HBUINT16 startGlyphID; /* The first glyph ID in the range described by
* this index entry. */
HBUINT16 endGlyphID; /* The last glyph ID in the range described by
* this index entry. Must be >= startGlyphID. */
LNNOffsetTo<UnsizedArrayOf<HBUINT8>> svgDoc; /* Offset from the beginning of the SVG Document Index
* to an SVG document. Must be non-zero. */
HBUINT32 svgDocLength; /* Length of the SVG document.
* Must be non-zero. */
public:
DEFINE_SIZE_STATIC(12);
};
struct SVG
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG;
bool has_data() const
{
return svgDocEntries;
}
struct accelerator_t
{
void init(hb_face_t *face)
{
table = hb_sanitize_context_t().reference_table<SVG>(face);
}
void fini()
{
table.destroy();
}
hb_blob_t *reference_blob_for_glyph(hb_codepoint_t glyph_id) const
{
return table->get_glyph_entry(glyph_id).reference_blob(table.get_blob(), table->svgDocEntries);
}
bool has_data() const
{
return table->has_data();
}
private:
hb_blob_ptr_t<SVG> table;
};
const SVGDocumentIndexEntry &get_glyph_entry(hb_codepoint_t glyph_id) const
{
return (this + svgDocEntries).bsearch(glyph_id);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && (this + svgDocEntries).sanitize_shallow(c)));
}
protected:
HBUINT16 version; /* Table version (starting at 0). */
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>> svgDocEntries; /* Offset (relative to the start of the SVG table) to
* the SVG Documents Index. Must be non-zero. */
/* Array of SVG Document Index Entries. */
HBUINT32 reserved; /* Set to 0. */
public:
DEFINE_SIZE_STATIC(10);
};
struct SVG_accelerator_t : SVG::accelerator_t
{
};
} /* namespace OT */
#endif /* HB_OT_COLOR_SVG_TABLE_HH */

View File

@ -0,0 +1,114 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012,2013 Google, Inc.
* Copyright © 2019, Facebook Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
* Facebook Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_FACE_TABLE_LIST_HH
#define HB_OT_FACE_TABLE_LIST_HH
#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
#ifndef HB_OT_ACCELERATOR
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE(Namespace, Type)
#define _HB_OT_ACCELERATOR_UNDEF
#endif
/* This lists font tables that the hb_face_t will contain and lazily
* load. Don't add a table unless it's used though. This is not
* exactly free. */
/* v--- Add new tables in the right place here. */
/* OpenType fundamentals. */
HB_OT_TABLE(OT, head)
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
HB_OT_ACCELERATOR(OT, cmap)
#endif
HB_OT_TABLE(OT, hhea)
HB_OT_ACCELERATOR(OT, hmtx)
HB_OT_TABLE(OT, OS2)
#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE)
HB_OT_ACCELERATOR(OT, post)
#endif
#ifndef HB_NO_STYLE
HB_OT_TABLE(AAT, fdsc)
#endif
/* Vertical layout. */
HB_OT_TABLE(OT, vhea)
HB_OT_ACCELERATOR(OT, vmtx)
/* TrueType outlines. */
HB_OT_ACCELERATOR(OT, glyf)
/* CFF outlines. */
#ifndef HB_NO_CFF
HB_OT_ACCELERATOR(OT, cff1)
HB_OT_ACCELERATOR(OT, cff2)
HB_OT_TABLE(OT, VORG)
#endif
/* OpenType variations. */
#ifndef HB_NO_VAR
HB_OT_TABLE(OT, fvar)
HB_OT_TABLE(OT, avar)
HB_OT_ACCELERATOR(OT, gvar)
HB_OT_TABLE(OT, MVAR)
#endif
/* Legacy kern. */
#ifndef HB_NO_OT_KERN
HB_OT_TABLE(OT, kern)
#endif
/* OpenType shaping. */
#ifndef HB_NO_OT_LAYOUT
HB_OT_ACCELERATOR(OT, GDEF)
HB_OT_ACCELERATOR(OT, GSUB)
HB_OT_ACCELERATOR(OT, GPOS)
#endif
/* AAT shaping. */
#ifndef HB_NO_AAT
HB_OT_TABLE(AAT, morx)
HB_OT_TABLE(AAT, mort)
HB_OT_TABLE(AAT, kerx)
HB_OT_TABLE(AAT, ankr)
HB_OT_TABLE(AAT, trak)
HB_OT_TABLE(AAT, feat)
#endif
/* OpenType color fonts. */
#ifndef HB_NO_COLOR
HB_OT_ACCELERATOR(OT, CBDT)
HB_OT_ACCELERATOR(OT, sbix)
HB_OT_ACCELERATOR(OT, SVG)
#endif
#ifdef _HB_OT_ACCELERATOR_UNDEF
#undef HB_OT_ACCELERATOR
#endif

View File

@ -0,0 +1,55 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-kern-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
void hb_ot_face_t::init0(hb_face_t *face)
{
this->face = face;
#define HB_OT_TABLE(Namespace, Type) Type.init0();
#include "hb-ot-face-table-list.hh"
#undef HB_OT_TABLE
}
void hb_ot_face_t::fini()
{
#define HB_OT_TABLE(Namespace, Type) Type.fini();
#include "hb-ot-face-table-list.hh"
#undef HB_OT_TABLE
}

View File

@ -0,0 +1,72 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_FACE_HH
#define HB_OT_FACE_HH
#include "hb.hh"
#include "hb-machinery.hh"
/*
* hb_ot_face_t
*/
/* Declare tables. */
#define HB_OT_TABLE(Namespace, Type) \
namespace Namespace { \
struct Type; \
}
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE(Namespace, Type##_accelerator_t)
#include "hb-ot-face-table-list.hh"
#undef HB_OT_ACCELERATOR
#undef HB_OT_TABLE
struct hb_ot_face_t
{
HB_INTERNAL void init0(hb_face_t *face);
HB_INTERNAL void fini();
#define HB_OT_TABLE_ORDER(Namespace, Type) HB_PASTE(ORDER_, HB_PASTE(Namespace, HB_PASTE(_, Type)))
enum order_t {
ORDER_ZERO,
#define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER(Namespace, Type),
#include "hb-ot-face-table-list.hh"
#undef HB_OT_TABLE
};
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
#define HB_OT_TABLE(Namespace, Type) hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER(Namespace, Type)> Type;
#define HB_OT_ACCELERATOR(Namespace, Type) \
hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER(Namespace, Type)> Type;
#include "hb-ot-face-table-list.hh"
#undef HB_OT_ACCELERATOR
#undef HB_OT_TABLE
};
#endif /* HB_OT_FACE_HH */

316
harfbuzz/src/hb-ot-font.cc Normal file
View File

@ -0,0 +1,316 @@
/*
* Copyright © 2011,2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#include "hb.hh"
#ifndef HB_NO_OT_FONT
#include "hb-ot.h"
#include "hb-font.hh"
#include "hb-machinery.hh"
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-vorg-table.hh"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-sbix-table.hh"
/**
* SECTION:hb-ot-font
* @title: hb-ot-font
* @short_description: OpenType font implementation
* @include: hb-ot.h
*
* Functions for using OpenType fonts with hb_shape(). Note that fonts returned
* by hb_font_create() default to using these functions, so most clients would
* never need to call these functions directly.
**/
static hb_bool_t hb_ot_get_nominal_glyph(hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
return ot_face->cmap->get_nominal_glyph(unicode, glyph);
}
static unsigned int hb_ot_get_nominal_glyphs(hb_font_t *font HB_UNUSED,
void *font_data,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
return ot_face->cmap->get_nominal_glyphs(count, first_unicode, unicode_stride, first_glyph, glyph_stride);
}
static hb_bool_t hb_ot_get_variation_glyph(hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
return ot_face->cmap->get_variation_glyph(unicode, variation_selector, glyph);
}
static void hb_ot_get_glyph_h_advances(hb_font_t *font,
void *font_data,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
for (unsigned int i = 0; i < count; i++) {
*first_advance = font->em_scale_x(hmtx.get_advance(*first_glyph, font));
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t>(first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t>(first_advance, advance_stride);
}
}
static void hb_ot_get_glyph_v_advances(hb_font_t *font,
void *font_data,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
for (unsigned int i = 0; i < count; i++) {
*first_advance = font->em_scale_y(-(int)vmtx.get_advance(*first_glyph, font));
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t>(first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t>(first_advance, advance_stride);
}
}
static hb_bool_t hb_ot_get_glyph_v_origin(hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
*x = font->get_glyph_h_advance(glyph) / 2;
#ifndef HB_NO_OT_FONT_CFF
const OT::VORG &VORG = *ot_face->VORG;
if (VORG.has_data()) {
*y = font->em_scale_y(VORG.get_y_origin(glyph));
return true;
}
#endif
hb_glyph_extents_t extents = {0};
if (ot_face->glyf->get_extents(font, glyph, &extents)) {
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
hb_position_t tsb = vmtx.get_side_bearing(font, glyph);
*y = extents.y_bearing + font->em_scale_y(tsb);
return true;
}
hb_font_extents_t font_extents;
font->get_h_extents_with_fallback(&font_extents);
*y = font_extents.ascender;
return true;
}
static hb_bool_t hb_ot_get_glyph_extents(
hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_glyph_extents_t *extents, void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
if (ot_face->sbix->get_extents(font, glyph, extents))
return true;
#endif
if (ot_face->glyf->get_extents(font, glyph, extents))
return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_extents(font, glyph, extents))
return true;
if (ot_face->cff2->get_extents(font, glyph, extents))
return true;
#endif
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
if (ot_face->CBDT->get_extents(font, glyph, extents))
return true;
#endif
// TODO Hook up side-bearings variations.
return false;
}
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
static hb_bool_t hb_ot_get_glyph_name(hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
char *name,
unsigned int size,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
if (ot_face->post->get_glyph_name(glyph, name, size))
return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_glyph_name(glyph, name, size))
return true;
#endif
return false;
}
static hb_bool_t hb_ot_get_glyph_from_name(hb_font_t *font HB_UNUSED,
void *font_data,
const char *name,
int len,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_face_t *ot_face = (const hb_ot_face_t *)font_data;
if (ot_face->post->get_glyph_from_name(name, len, glyph))
return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_glyph_from_name(name, len, glyph))
return true;
#endif
return false;
}
#endif
static hb_bool_t hb_ot_get_font_h_extents(hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
return _hb_ot_metrics_get_position_common(font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
_hb_ot_metrics_get_position_common(font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
_hb_ot_metrics_get_position_common(font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
}
static hb_bool_t hb_ot_get_font_v_extents(hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
return _hb_ot_metrics_get_position_common(font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) &&
_hb_ot_metrics_get_position_common(font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
_hb_ot_metrics_get_position_common(font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
}
#if HB_USE_ATEXIT
static void free_static_ot_funcs();
#endif
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
{
static hb_font_funcs_t *create()
{
hb_font_funcs_t *funcs = hb_font_funcs_create();
hb_font_funcs_set_font_h_extents_func(funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_font_v_extents_func(funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func(funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
hb_font_funcs_set_nominal_glyphs_func(funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func(funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func(funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advances_func(funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr);
// hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func(funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func(funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
// hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
hb_font_funcs_set_glyph_name_func(funcs, hb_ot_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func(funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
#endif
hb_font_funcs_make_immutable(funcs);
#if HB_USE_ATEXIT
atexit(free_static_ot_funcs);
#endif
return funcs;
}
} static_ot_funcs;
#if HB_USE_ATEXIT
static void free_static_ot_funcs()
{
static_ot_funcs.free_instance();
}
#endif
static hb_font_funcs_t *_hb_ot_get_font_funcs()
{
return static_ot_funcs.get_unconst();
}
/**
* hb_ot_font_set_funcs:
*
* Since: 0.9.28
**/
void hb_ot_font_set_funcs(hb_font_t *font)
{
hb_font_set_funcs(font, _hb_ot_get_font_funcs(), &font->face->table, nullptr);
}
#ifndef HB_NO_VAR
int _glyf_get_side_bearing_var(hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
{
return font->face->table.glyf->get_side_bearing_var(font, glyph, is_vertical);
}
unsigned _glyf_get_advance_var(hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
{
return font->face->table.glyf->get_advance_var(font, glyph, is_vertical);
}
#endif
#endif

42
harfbuzz/src/hb-ot-font.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright © 2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_FONT_H
#define HB_OT_FONT_H
#include "hb.h"
HB_BEGIN_DECLS
HB_EXTERN void hb_ot_font_set_funcs(hb_font_t *font);
HB_END_DECLS
#endif /* HB_OT_FONT_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#ifndef HB_OT_HDMX_TABLE_HH
#define HB_OT_HDMX_TABLE_HH
#include "hb-open-type.hh"
/*
* hdmx -- Horizontal Device Metrics
* https://docs.microsoft.com/en-us/typography/opentype/spec/hdmx
*/
#define HB_OT_TAG_hdmx HB_TAG('h', 'd', 'm', 'x')
namespace OT {
struct DeviceRecord
{
static unsigned int get_size(unsigned count)
{
return hb_ceil_to_4(min_size + count * HBUINT8::static_size);
}
template <typename Iterator, hb_requires(hb_is_iterator(Iterator))>
bool serialize(hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
{
TRACE_SERIALIZE(this);
unsigned length = it.len();
if (unlikely(!c->extend(*this, length)))
return_trace(false);
this->pixelSize = pixelSize;
this->maxWidth = +it | hb_reduce(hb_max, 0u);
+it | hb_sink(widthsZ.as_array(length));
return_trace(true);
}
bool sanitize(hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
{
TRACE_SANITIZE(this);
return_trace(likely(c->check_struct(this) && c->check_range(this, sizeDeviceRecord)));
}
HBUINT8 pixelSize; /* Pixel size for following widths (as ppem). */
HBUINT8 maxWidth; /* Maximum width. */
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
public:
DEFINE_SIZE_ARRAY(2, widthsZ);
};
struct hdmx
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
unsigned int get_size() const
{
return min_size + numRecords * sizeDeviceRecord;
}
const DeviceRecord &operator[](unsigned int i) const
{
/* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed.
* https://github.com/harfbuzz/harfbuzz/issues/1300 */
if (unlikely(i >= numRecords))
return Null(DeviceRecord);
return StructAtOffset<DeviceRecord>(&this->firstDeviceRecord, i * sizeDeviceRecord);
}
template <typename Iterator, hb_requires(hb_is_iterator(Iterator))>
bool serialize(hb_serialize_context_t *c, unsigned version, Iterator it)
{
TRACE_SERIALIZE(this);
if (unlikely(!c->extend_min((*this))))
return_trace(false);
this->version = version;
this->numRecords = it.len();
this->sizeDeviceRecord = DeviceRecord::get_size(it ? (*it).second.len() : 0);
for (const hb_item_type<Iterator> &_ : +it)
c->start_embed<DeviceRecord>()->serialize(c, _.first, _.second);
return_trace(c->successful);
}
unsigned get_num_glyphs() const
{
return sizeDeviceRecord - DeviceRecord::min_size;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && !hb_unsigned_mul_overflows(numRecords, sizeDeviceRecord) &&
sizeDeviceRecord >= DeviceRecord::min_size && c->check_range(this, get_size()));
}
protected:
HBUINT16 version; /* Table version number (0) */
HBUINT16 numRecords; /* Number of device records. */
HBUINT32 sizeDeviceRecord;
/* Size of a device record, 32-bit aligned. */
DeviceRecord firstDeviceRecord;
/* Array of device records. */
public:
DEFINE_SIZE_MIN(8);
};
} /* namespace OT */
#endif /* HB_OT_HDMX_TABLE_HH */

View File

@ -0,0 +1,170 @@
/*
* Copyright © 2010 Red Hat, Inc.
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_HEAD_TABLE_HH
#define HB_OT_HEAD_TABLE_HH
#include "hb-open-type.hh"
/*
* head -- Font Header
* https://docs.microsoft.com/en-us/typography/opentype/spec/head
*/
#define HB_OT_TAG_head HB_TAG('h', 'e', 'a', 'd')
namespace OT {
struct head
{
friend struct OffsetTable;
static constexpr hb_tag_t tableTag = HB_OT_TAG_head;
unsigned int get_upem() const
{
unsigned int upem = unitsPerEm;
/* If no valid head table found, assume 1000, which matches typical Type1 usage. */
return 16 <= upem && upem <= 16384 ? upem : 1000;
}
enum mac_style_flag_t {
BOLD = 1u << 0,
ITALIC = 1u << 1,
UNDERLINE = 1u << 2,
OUTLINE = 1u << 3,
SHADOW = 1u << 4,
CONDENSED = 1u << 5
};
bool is_bold() const
{
return macStyle & BOLD;
}
bool is_italic() const
{
return macStyle & ITALIC;
}
bool is_condensed() const
{
return macStyle & CONDENSED;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && version.major == 1 && magicNumber == 0x5F0F3CF5u);
}
protected:
FixedVersion<> version; /* Version of the head table--currently
* 0x00010000u for version 1.0. */
FixedVersion<> fontRevision; /* Set by font manufacturer. */
HBUINT32 checkSumAdjustment; /* To compute: set it to 0, sum the
* entire font as HBUINT32, then store
* 0xB1B0AFBAu - sum. */
HBUINT32 magicNumber; /* Set to 0x5F0F3CF5u. */
HBUINT16 flags; /* Bit 0: Baseline for font at y=0;
* Bit 1: Left sidebearing point at x=0;
* Bit 2: Instructions may depend on point size;
* Bit 3: Force ppem to integer values for all
* internal scaler math; may use fractional
* ppem sizes if this bit is clear;
* Bit 4: Instructions may alter advance width
* (the advance widths might not scale linearly);
* Bits 5-10: These should be set according to
* Apple's specification. However, they are not
* implemented in OpenType.
* Bit 5: This bit should be set in fonts that are
* intended to e laid out vertically, and in
* which the glyphs have been drawn such that an
* x-coordinate of 0 corresponds to the desired
* vertical baseline.
* Bit 6: This bit must be set to zero.
* Bit 7: This bit should be set if the font
* requires layout for correct linguistic
* rendering (e.g. Arabic fonts).
* Bit 8: This bit should be set for a GX font
* which has one or more metamorphosis effects
* designated as happening by default.
* Bit 9: This bit should be set if the font
* contains any strong right-to-left glyphs.
* Bit 10: This bit should be set if the font
* contains Indic-style rearrangement effects.
* Bit 11: Font data is 'lossless,' as a result
* of having been compressed and decompressed
* with the Agfa MicroType Express engine.
* Bit 12: Font converted (produce compatible metrics)
* Bit 13: Font optimized for ClearType.
* Note, fonts that rely on embedded bitmaps (EBDT)
* for rendering should not be considered optimized
* for ClearType, and therefore should keep this bit
* cleared.
* Bit 14: Last Resort font. If set, indicates that
* the glyphs encoded in the cmap subtables are simply
* generic symbolic representations of code point
* ranges and dont truly represent support for those
* code points. If unset, indicates that the glyphs
* encoded in the cmap subtables represent proper
* support for those code points.
* Bit 15: Reserved, set to 0. */
HBUINT16 unitsPerEm; /* Valid range is from 16 to 16384. This value
* should be a power of 2 for fonts that have
* TrueType outlines. */
LONGDATETIME created; /* Number of seconds since 12:00 midnight,
January 1, 1904. 64-bit integer */
LONGDATETIME modified; /* Number of seconds since 12:00 midnight,
January 1, 1904. 64-bit integer */
HBINT16 xMin; /* For all glyph bounding boxes. */
HBINT16 yMin; /* For all glyph bounding boxes. */
HBINT16 xMax; /* For all glyph bounding boxes. */
HBINT16 yMax; /* For all glyph bounding boxes. */
HBUINT16 macStyle; /* Bit 0: Bold (if set to 1);
* Bit 1: Italic (if set to 1)
* Bit 2: Underline (if set to 1)
* Bit 3: Outline (if set to 1)
* Bit 4: Shadow (if set to 1)
* Bit 5: Condensed (if set to 1)
* Bit 6: Extended (if set to 1)
* Bits 7-15: Reserved (set to 0). */
HBUINT16 lowestRecPPEM; /* Smallest readable size in pixels. */
HBINT16 fontDirectionHint; /* Deprecated (Set to 2).
* 0: Fully mixed directional glyphs;
* 1: Only strongly left to right;
* 2: Like 1 but also contains neutrals;
* -1: Only strongly right to left;
* -2: Like -1 but also contains neutrals. */
public:
HBUINT16 indexToLocFormat; /* 0 for short offsets, 1 for long. */
HBUINT16 glyphDataFormat; /* 0 for current format. */
DEFINE_SIZE_STATIC(54);
};
} /* namespace OT */
#endif /* HB_OT_HEAD_TABLE_HH */

View File

@ -0,0 +1,104 @@
/*
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_HHEA_TABLE_HH
#define HB_OT_HHEA_TABLE_HH
#include "hb-open-type.hh"
/*
* hhea -- Horizontal Header
* https://docs.microsoft.com/en-us/typography/opentype/spec/hhea
* vhea -- Vertical Header
* https://docs.microsoft.com/en-us/typography/opentype/spec/vhea
*/
#define HB_OT_TAG_hhea HB_TAG('h', 'h', 'e', 'a')
#define HB_OT_TAG_vhea HB_TAG('v', 'h', 'e', 'a')
namespace OT {
template <typename T> struct _hea
{
bool has_data() const
{
return version.major;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && likely(version.major == 1));
}
public:
FixedVersion<> version; /* 0x00010000u for version 1.0. */
FWORD ascender; /* Typographic ascent. */
FWORD descender; /* Typographic descent. */
FWORD lineGap; /* Typographic line gap. */
UFWORD advanceMax; /* Maximum advance width/height value in
* metrics table. */
FWORD minLeadingBearing;
/* Minimum left/top sidebearing value in
* metrics table. */
FWORD minTrailingBearing;
/* Minimum right/bottom sidebearing value;
* calculated as Min(aw - lsb -
* (xMax - xMin)) for horizontal. */
FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)),
* vertical: minLeadingBearing+(yMax-yMin). */
HBINT16 caretSlopeRise; /* Used to calculate the slope of the
* cursor (rise/run); 1 for vertical caret,
* 0 for horizontal.*/
HBINT16 caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */
HBINT16 caretOffset; /* The amount by which a slanted
* highlight on a glyph needs
* to be shifted to produce the
* best appearance. Set to 0 for
* non-slanted fonts. */
HBINT16 reserved1; /* Set to 0. */
HBINT16 reserved2; /* Set to 0. */
HBINT16 reserved3; /* Set to 0. */
HBINT16 reserved4; /* Set to 0. */
HBINT16 metricDataFormat; /* 0 for current format. */
HBUINT16 numberOfLongMetrics;
/* Number of LongMetric entries in metric
* table. */
public:
DEFINE_SIZE_STATIC(36);
};
struct hhea : _hea<hhea>
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_hhea;
};
struct vhea : _hea<vhea>
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_vhea;
};
} /* namespace OT */
#endif /* HB_OT_HHEA_TABLE_HH */

View File

@ -0,0 +1,225 @@
/*
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod, Roderick Sheeter
*/
#ifndef HB_OT_HMTX_TABLE_HH
#define HB_OT_HMTX_TABLE_HH
#include "hb-open-type.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-ot-metrics.hh"
/*
* hmtx -- Horizontal Metrics
* https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx
* vmtx -- Vertical Metrics
* https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx
*/
#define HB_OT_TAG_hmtx HB_TAG('h', 'm', 't', 'x')
#define HB_OT_TAG_vmtx HB_TAG('v', 'm', 't', 'x')
HB_INTERNAL int _glyf_get_side_bearing_var(hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
HB_INTERNAL unsigned _glyf_get_advance_var(hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
namespace OT {
struct LongMetric
{
UFWORD advance; /* Advance width/height. */
FWORD sb; /* Leading (left/top) side bearing. */
public:
DEFINE_SIZE_STATIC(4);
};
template <typename T, typename H> struct hmtxvmtx
{
bool sanitize(hb_sanitize_context_t *c HB_UNUSED) const
{
TRACE_SANITIZE(this);
/* We don't check for anything specific here. The users of the
* struct do all the hard work... */
return_trace(true);
}
struct accelerator_t
{
friend struct hmtxvmtx;
void init(hb_face_t *face, unsigned int default_advance_ = 0)
{
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem(face);
num_advances =
T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
table = hb_sanitize_context_t().reference_table<hmtxvmtx>(face, T::tableTag);
/* Cap num_metrics() and num_advances() based on table length. */
unsigned int len = table.get_length();
if (unlikely(num_advances * 4 > len))
num_advances = len / 4;
num_metrics = num_advances + (len - 4 * num_advances) / 2;
/* We MUST set num_metrics to zero if num_advances is zero.
* Our get_advance() depends on that. */
if (unlikely(!num_advances)) {
num_metrics = num_advances = 0;
table.destroy();
table = hb_blob_get_empty();
}
var_table = hb_sanitize_context_t().reference_table<HVARVVAR>(face, T::variationsTag);
}
void fini()
{
table.destroy();
var_table.destroy();
}
int get_side_bearing(hb_codepoint_t glyph) const
{
if (glyph < num_advances)
return table->longMetricZ[glyph].sb;
if (unlikely(glyph >= num_metrics))
return 0;
const FWORD *bearings = (const FWORD *)&table->longMetricZ[num_advances];
return bearings[glyph - num_advances];
}
int get_side_bearing(hb_font_t *font, hb_codepoint_t glyph) const
{
int side_bearing = get_side_bearing(glyph);
#ifndef HB_NO_VAR
if (unlikely(glyph >= num_metrics) || !font->num_coords)
return side_bearing;
if (var_table.get_length())
return side_bearing +
var_table->get_side_bearing_var(glyph, font->coords, font->num_coords); // TODO Optimize?!
return _glyf_get_side_bearing_var(font, glyph, T::tableTag == HB_OT_TAG_vmtx);
#else
return side_bearing;
#endif
}
unsigned int get_advance(hb_codepoint_t glyph) const
{
if (unlikely(glyph >= num_metrics)) {
/* If num_metrics is zero, it means we don't have the metrics table
* for this direction: return default advance. Otherwise, it means that the
* glyph index is out of bound: return zero. */
if (num_metrics)
return 0;
else
return default_advance;
}
return table->longMetricZ[hb_min(glyph, (uint32_t)num_advances - 1)].advance;
}
unsigned int get_advance(hb_codepoint_t glyph, hb_font_t *font) const
{
unsigned int advance = get_advance(glyph);
#ifndef HB_NO_VAR
if (unlikely(glyph >= num_metrics) || !font->num_coords)
return advance;
if (var_table.get_length())
return advance + roundf(var_table->get_advance_var(glyph, font)); // TODO Optimize?!
return _glyf_get_advance_var(font, glyph, T::tableTag == HB_OT_TAG_vmtx);
#else
return advance;
#endif
}
protected:
unsigned int num_metrics;
unsigned int num_advances;
unsigned int default_advance;
private:
hb_blob_ptr_t<hmtxvmtx> table;
hb_blob_ptr_t<HVARVVAR> var_table;
};
protected:
UnsizedArrayOf<LongMetric> longMetricZ; /* Paired advance width and leading
* bearing values for each glyph. The
* value numOfHMetrics comes from
* the 'hhea' table. If the font is
* monospaced, only one entry need
* be in the array, but that entry is
* required. The last entry applies to
* all subsequent glyphs. */
/*UnsizedArrayOf<FWORD> leadingBearingX;*/
/* Here the advance is assumed
* to be the same as the advance
* for the last entry above. The
* number of entries in this array is
* derived from numGlyphs (from 'maxp'
* table) minus numberOfLongMetrics.
* This generally is used with a run
* of monospaced glyphs (e.g., Kanji
* fonts or Courier fonts). Only one
* run is allowed and it must be at
* the end. This allows a monospaced
* font to vary the side bearing
* values for each glyph. */
public:
DEFINE_SIZE_ARRAY(0, longMetricZ);
};
struct hmtx : hmtxvmtx<hmtx, hhea>
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
static constexpr bool is_horizontal = true;
};
struct vmtx : hmtxvmtx<vmtx, vhea>
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
static constexpr bool is_horizontal = false;
};
struct hmtx_accelerator_t : hmtx::accelerator_t
{
};
struct vmtx_accelerator_t : vmtx::accelerator_t
{
};
} /* namespace OT */
#endif /* HB_OT_HMTX_TABLE_HH */

View File

@ -0,0 +1,394 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_KERN_TABLE_HH
#define HB_OT_KERN_TABLE_HH
#include "hb-aat-layout-kerx-table.hh"
/*
* kern -- Kerning
* https://docs.microsoft.com/en-us/typography/opentype/spec/kern
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
*/
#define HB_OT_TAG_kern HB_TAG('k', 'e', 'r', 'n')
namespace OT {
template <typename KernSubTableHeader> struct KernSubTableFormat3
{
int get_kerning(hb_codepoint_t left, hb_codepoint_t right) const
{
hb_array_t<const FWORD> kernValue = kernValueZ.as_array(kernValueCount);
hb_array_t<const HBUINT8> leftClass =
StructAfter<const UnsizedArrayOf<HBUINT8>>(kernValue).as_array(glyphCount);
hb_array_t<const HBUINT8> rightClass =
StructAfter<const UnsizedArrayOf<HBUINT8>>(leftClass).as_array(glyphCount);
hb_array_t<const HBUINT8> kernIndex =
StructAfter<const UnsizedArrayOf<HBUINT8>>(rightClass).as_array(leftClassCount * rightClassCount);
unsigned int leftC = leftClass[left];
unsigned int rightC = rightClass[right];
if (unlikely(leftC >= leftClassCount || rightC >= rightClassCount))
return 0;
unsigned int i = leftC * rightClassCount + rightC;
return kernValue[kernIndex[i]];
}
bool apply(AAT::hb_aat_apply_context_t *c) const
{
TRACE_APPLY(this);
if (!c->plan->requested_kerning)
return false;
if (header.coverage & header.Backwards)
return false;
hb_kern_machine_t<KernSubTableFormat3> machine(*this, header.coverage & header.CrossStream);
machine.kern(c->font, c->buffer, c->plan->kern_mask);
return_trace(true);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && c->check_range(kernValueZ,
kernValueCount * sizeof(FWORD) + glyphCount * 2 +
leftClassCount * rightClassCount));
}
protected:
KernSubTableHeader header;
HBUINT16 glyphCount; /* The number of glyphs in this font. */
HBUINT8 kernValueCount; /* The number of kerning values. */
HBUINT8 leftClassCount; /* The number of left-hand classes. */
HBUINT8 rightClassCount; /* The number of right-hand classes. */
HBUINT8 flags; /* Set to zero (reserved for future use). */
UnsizedArrayOf<FWORD> kernValueZ; /* The kerning values.
* Length kernValueCount. */
#if 0
UnsizedArrayOf<HBUINT8>
leftClass; /* The left-hand classes.
* Length glyphCount. */
UnsizedArrayOf<HBUINT8>
rightClass; /* The right-hand classes.
* Length glyphCount. */
UnsizedArrayOf<HBUINT8>kernIndex;
/* The indices into the kernValue array.
* Length leftClassCount * rightClassCount */
#endif
public:
DEFINE_SIZE_ARRAY(KernSubTableHeader::static_size + 6, kernValueZ);
};
template <typename KernSubTableHeader> struct KernSubTable
{
unsigned int get_size() const
{
return u.header.length;
}
unsigned int get_type() const
{
return u.header.format;
}
int get_kerning(hb_codepoint_t left, hb_codepoint_t right) const
{
switch (get_type()) {
/* This method hooks up to hb_font_t's get_h_kerning. Only support Format0. */
case 0:
return u.format0.get_kerning(left, right);
default:
return 0;
}
}
template <typename context_t, typename... Ts> typename context_t::return_t dispatch(context_t *c, Ts &&... ds) const
{
unsigned int subtable_type = get_type();
TRACE_DISPATCH(this, subtable_type);
switch (subtable_type) {
case 0:
return_trace(c->dispatch(u.format0));
#ifndef HB_NO_AAT_SHAPE
case 1:
return_trace(u.header.apple ? c->dispatch(u.format1, hb_forward<Ts>(ds)...) : c->default_return_value());
#endif
case 2:
return_trace(c->dispatch(u.format2));
#ifndef HB_NO_AAT_SHAPE
case 3:
return_trace(u.header.apple ? c->dispatch(u.format3, hb_forward<Ts>(ds)...) : c->default_return_value());
#endif
default:
return_trace(c->default_return_value());
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (unlikely(!u.header.sanitize(c) || u.header.length < u.header.min_size ||
!c->check_range(this, u.header.length)))
return_trace(false);
return_trace(dispatch(c));
}
public:
union {
KernSubTableHeader header;
AAT::KerxSubTableFormat0<KernSubTableHeader> format0;
AAT::KerxSubTableFormat1<KernSubTableHeader> format1;
AAT::KerxSubTableFormat2<KernSubTableHeader> format2;
KernSubTableFormat3<KernSubTableHeader> format3;
} u;
public:
DEFINE_SIZE_MIN(KernSubTableHeader::static_size);
};
struct KernOTSubTableHeader
{
static constexpr bool apple = false;
typedef AAT::ObsoleteTypes Types;
unsigned tuple_count() const
{
return 0;
}
bool is_horizontal() const
{
return (coverage & Horizontal);
}
enum Coverage {
Horizontal = 0x01u,
Minimum = 0x02u,
CrossStream = 0x04u,
Override = 0x08u,
/* Not supported: */
Backwards = 0x00u,
Variation = 0x00u,
};
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
public:
HBUINT16 versionZ; /* Unused. */
HBUINT16 length; /* Length of the subtable (including this header). */
HBUINT8 format; /* Subtable format. */
HBUINT8 coverage; /* Coverage bits. */
public:
DEFINE_SIZE_STATIC(6);
};
struct KernOT : AAT::KerxTable<KernOT>
{
friend struct AAT::KerxTable<KernOT>;
static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
static constexpr unsigned minVersion = 0u;
typedef KernOTSubTableHeader SubTableHeader;
typedef SubTableHeader::Types Types;
typedef KernSubTable<SubTableHeader> SubTable;
protected:
HBUINT16 version; /* Version--0x0000u */
HBUINT16 tableCount; /* Number of subtables in the kerning table. */
SubTable firstSubTable; /* Subtables. */
public:
DEFINE_SIZE_MIN(4);
};
struct KernAATSubTableHeader
{
static constexpr bool apple = true;
typedef AAT::ObsoleteTypes Types;
unsigned tuple_count() const
{
return 0;
}
bool is_horizontal() const
{
return !(coverage & Vertical);
}
enum Coverage {
Vertical = 0x80u,
CrossStream = 0x40u,
Variation = 0x20u,
/* Not supported: */
Backwards = 0x00u,
};
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
public:
HBUINT32 length; /* Length of the subtable (including this header). */
HBUINT8 coverage; /* Coverage bits. */
HBUINT8 format; /* Subtable format. */
HBUINT16 tupleIndex; /* The tuple index (used for variations fonts).
* This value specifies which tuple this subtable covers.
* Note: We don't implement. */
public:
DEFINE_SIZE_STATIC(8);
};
struct KernAAT : AAT::KerxTable<KernAAT>
{
friend struct AAT::KerxTable<KernAAT>;
static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
static constexpr unsigned minVersion = 0x00010000u;
typedef KernAATSubTableHeader SubTableHeader;
typedef SubTableHeader::Types Types;
typedef KernSubTable<SubTableHeader> SubTable;
protected:
HBUINT32 version; /* Version--0x00010000u */
HBUINT32 tableCount; /* Number of subtables in the kerning table. */
SubTable firstSubTable; /* Subtables. */
public:
DEFINE_SIZE_MIN(8);
};
struct kern
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
bool has_data() const
{
return u.version32;
}
unsigned get_type() const
{
return u.major;
}
bool has_state_machine() const
{
switch (get_type()) {
case 0:
return u.ot.has_state_machine();
#ifndef HB_NO_AAT_SHAPE
case 1:
return u.aat.has_state_machine();
#endif
default:
return false;
}
}
bool has_cross_stream() const
{
switch (get_type()) {
case 0:
return u.ot.has_cross_stream();
#ifndef HB_NO_AAT_SHAPE
case 1:
return u.aat.has_cross_stream();
#endif
default:
return false;
}
}
int get_h_kerning(hb_codepoint_t left, hb_codepoint_t right) const
{
switch (get_type()) {
case 0:
return u.ot.get_h_kerning(left, right);
#ifndef HB_NO_AAT_SHAPE
case 1:
return u.aat.get_h_kerning(left, right);
#endif
default:
return 0;
}
}
bool apply(AAT::hb_aat_apply_context_t *c) const
{
return dispatch(c);
}
template <typename context_t, typename... Ts> typename context_t::return_t dispatch(context_t *c, Ts &&... ds) const
{
unsigned int subtable_type = get_type();
TRACE_DISPATCH(this, subtable_type);
switch (subtable_type) {
case 0:
return_trace(c->dispatch(u.ot, hb_forward<Ts>(ds)...));
#ifndef HB_NO_AAT_SHAPE
case 1:
return_trace(c->dispatch(u.aat, hb_forward<Ts>(ds)...));
#endif
default:
return_trace(c->default_return_value());
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (!u.version32.sanitize(c))
return_trace(false);
return_trace(dispatch(c));
}
protected:
union {
HBUINT32 version32;
HBUINT16 major;
KernOT ot;
#ifndef HB_NO_AAT_SHAPE
KernAAT aat;
#endif
} u;
public:
DEFINE_SIZE_UNION(4, version32);
};
} /* namespace OT */
#endif /* HB_OT_KERN_TABLE_HH */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,594 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_LAYOUT_GDEF_TABLE_HH
#define HB_OT_LAYOUT_GDEF_TABLE_HH
#include "hb-ot-layout-common.hh"
#include "hb-font.hh"
namespace OT {
/*
* Attachment List Table
*/
/* Array of contour point indices--in increasing numerical order */
struct AttachPoint : ArrayOf<HBUINT16>
{
};
struct AttachList
{
unsigned int get_attach_points(hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{
unsigned int index = (this + coverage).get_coverage(glyph_id);
if (index == NOT_COVERED) {
if (point_count)
*point_count = 0;
return 0;
}
const AttachPoint &points = this + attachPoint[index];
if (point_count) {
+points.sub_array(start_offset, point_count) | hb_sink(hb_array(point_array, *point_count));
}
return points.len;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(coverage.sanitize(c, this) && attachPoint.sanitize(c, this));
}
protected:
OffsetTo<Coverage> coverage; /* Offset to Coverage table -- from
* beginning of AttachList table */
OffsetArrayOf<AttachPoint> attachPoint; /* Array of AttachPoint tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY(4, attachPoint);
};
/*
* Ligature Caret Table
*/
struct CaretValueFormat1
{
friend struct CaretValue;
private:
hb_position_t get_caret_value(hb_font_t *font, hb_direction_t direction) const
{
return HB_DIRECTION_IS_HORIZONTAL(direction) ? font->em_scale_x(coordinate) : font->em_scale_y(coordinate);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 1 */
FWORD coordinate; /* X or Y value, in design units */
public:
DEFINE_SIZE_STATIC(4);
};
struct CaretValueFormat2
{
friend struct CaretValue;
private:
hb_position_t get_caret_value(hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
{
hb_position_t x, y;
font->get_glyph_contour_point_for_origin(glyph_id, caretValuePoint, direction, &x, &y);
return HB_DIRECTION_IS_HORIZONTAL(direction) ? x : y;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 2 */
HBUINT16 caretValuePoint; /* Contour point index on glyph */
public:
DEFINE_SIZE_STATIC(4);
};
struct CaretValueFormat3
{
friend struct CaretValue;
hb_position_t get_caret_value(hb_font_t *font, hb_direction_t direction, const VariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL(direction)
? font->em_scale_x(coordinate) + (this + deviceTable).get_x_delta(font, var_store)
: font->em_scale_y(coordinate) + (this + deviceTable).get_y_delta(font, var_store);
}
void collect_variation_indices(hb_set_t *layout_variation_indices) const
{
(this + deviceTable).collect_variation_indices(layout_variation_indices);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this) && deviceTable.sanitize(c, this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 3 */
FWORD coordinate; /* X or Y value, in design units */
OffsetTo<Device> deviceTable; /* Offset to Device table for X or Y
* value--from beginning of CaretValue
* table */
public:
DEFINE_SIZE_STATIC(6);
};
struct CaretValue
{
hb_position_t get_caret_value(hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store) const
{
switch (u.format) {
case 1:
return u.format1.get_caret_value(font, direction);
case 2:
return u.format2.get_caret_value(font, direction, glyph_id);
case 3:
return u.format3.get_caret_value(font, direction, var_store);
default:
return 0;
}
}
template <typename context_t, typename... Ts> typename context_t::return_t dispatch(context_t *c, Ts &&... ds) const
{
TRACE_DISPATCH(this, u.format);
if (unlikely(!c->may_dispatch(this, &u.format)))
return_trace(c->no_dispatch_return_value());
switch (u.format) {
case 1:
return_trace(c->dispatch(u.format1, hb_forward<Ts>(ds)...));
case 2:
return_trace(c->dispatch(u.format2, hb_forward<Ts>(ds)...));
case 3:
return_trace(c->dispatch(u.format3, hb_forward<Ts>(ds)...));
default:
return_trace(c->default_return_value());
}
}
void collect_variation_indices(hb_set_t *layout_variation_indices) const
{
switch (u.format) {
case 1:
case 2:
return;
case 3:
u.format3.collect_variation_indices(layout_variation_indices);
return;
default:
return;
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (!u.format.sanitize(c))
return_trace(false);
switch (u.format) {
case 1:
return_trace(u.format1.sanitize(c));
case 2:
return_trace(u.format2.sanitize(c));
case 3:
return_trace(u.format3.sanitize(c));
default:
return_trace(true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
CaretValueFormat1 format1;
CaretValueFormat2 format2;
CaretValueFormat3 format3;
} u;
public:
DEFINE_SIZE_UNION(2, format);
};
struct LigGlyph
{
unsigned get_lig_carets(hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
if (caret_count) {
+carets.sub_array(start_offset, caret_count) | hb_map(hb_add(this)) | hb_map([&](const CaretValue &value) {
return value.get_caret_value(font, direction, glyph_id, var_store);
}) | hb_sink(hb_array(caret_array, *caret_count));
}
return carets.len;
}
void collect_variation_indices(hb_collect_variation_indices_context_t *c) const
{
for (const OffsetTo<CaretValue> &offset : carets.iter())
(this + offset).collect_variation_indices(c->layout_variation_indices);
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(carets.sanitize(c, this));
}
protected:
OffsetArrayOf<CaretValue> carets; /* Offset array of CaretValue tables
* --from beginning of LigGlyph table
* --in increasing coordinate order */
public:
DEFINE_SIZE_ARRAY(2, carets);
};
struct LigCaretList
{
unsigned int get_lig_carets(hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
unsigned int index = (this + coverage).get_coverage(glyph_id);
if (index == NOT_COVERED) {
if (caret_count)
*caret_count = 0;
return 0;
}
const LigGlyph &lig_glyph = this + ligGlyph[index];
return lig_glyph.get_lig_carets(font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
}
void collect_variation_indices(hb_collect_variation_indices_context_t *c) const
{
+hb_zip(this + coverage, ligGlyph) | hb_filter(c->glyph_set, hb_first) | hb_map(hb_second) |
hb_map(hb_add(this)) | hb_apply([c](const LigGlyph &_) { _.collect_variation_indices(c); });
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(coverage.sanitize(c, this) && ligGlyph.sanitize(c, this));
}
protected:
OffsetTo<Coverage> coverage; /* Offset to Coverage table--from
* beginning of LigCaretList table */
OffsetArrayOf<LigGlyph> ligGlyph; /* Array of LigGlyph tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY(4, ligGlyph);
};
struct MarkGlyphSetsFormat1
{
bool covers(unsigned int set_index, hb_codepoint_t glyph_id) const
{
return (this + coverage[set_index]).get_coverage(glyph_id) != NOT_COVERED;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(coverage.sanitize(c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 1 */
ArrayOf<LOffsetTo<Coverage>> coverage; /* Array of long offsets to mark set
* coverage tables */
public:
DEFINE_SIZE_ARRAY(4, coverage);
};
struct MarkGlyphSets
{
bool covers(unsigned int set_index, hb_codepoint_t glyph_id) const
{
switch (u.format) {
case 1:
return u.format1.covers(set_index, glyph_id);
default:
return false;
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (!u.format.sanitize(c))
return_trace(false);
switch (u.format) {
case 1:
return_trace(u.format1.sanitize(c));
default:
return_trace(true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
MarkGlyphSetsFormat1 format1;
} u;
public:
DEFINE_SIZE_UNION(2, format);
};
/*
* GDEF -- Glyph Definition
* https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
*/
struct GDEF
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
enum GlyphClasses { UnclassifiedGlyph = 0, BaseGlyph = 1, LigatureGlyph = 2, MarkGlyph = 3, ComponentGlyph = 4 };
bool has_data() const
{
return version.to_int();
}
bool has_glyph_classes() const
{
return glyphClassDef != 0;
}
unsigned int get_glyph_class(hb_codepoint_t glyph) const
{
return (this + glyphClassDef).get_class(glyph);
}
void get_glyphs_in_class(unsigned int klass, hb_set_t *glyphs) const
{
(this + glyphClassDef).collect_class(glyphs, klass);
}
bool has_mark_attachment_types() const
{
return markAttachClassDef != 0;
}
unsigned int get_mark_attachment_type(hb_codepoint_t glyph) const
{
return (this + markAttachClassDef).get_class(glyph);
}
bool has_attach_points() const
{
return attachList != 0;
}
unsigned int get_attach_points(hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{
return (this + attachList).get_attach_points(glyph_id, start_offset, point_count, point_array);
}
bool has_lig_carets() const
{
return ligCaretList != 0;
}
unsigned int get_lig_carets(hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
return (this + ligCaretList)
.get_lig_carets(font, direction, glyph_id, get_var_store(), start_offset, caret_count, caret_array);
}
bool has_mark_sets() const
{
return version.to_int() >= 0x00010002u && markGlyphSetsDef != 0;
}
bool mark_set_covers(unsigned int set_index, hb_codepoint_t glyph_id) const
{
return version.to_int() >= 0x00010002u && (this + markGlyphSetsDef).covers(set_index, glyph_id);
}
bool has_var_store() const
{
return version.to_int() >= 0x00010003u && varStore != 0;
}
const VariationStore &get_var_store() const
{
return version.to_int() >= 0x00010003u ? this + varStore : Null(VariationStore);
}
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit the mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
unsigned int get_glyph_props(hb_codepoint_t glyph) const
{
unsigned int klass = get_glyph_class(glyph);
static_assert(((unsigned int)HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int)LookupFlag::IgnoreBaseGlyphs),
"");
static_assert(((unsigned int)HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int)LookupFlag::IgnoreLigatures),
"");
static_assert(((unsigned int)HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int)LookupFlag::IgnoreMarks), "");
switch (klass) {
default:
return 0;
case BaseGlyph:
return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
case LigatureGlyph:
return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
case MarkGlyph:
klass = get_mark_attachment_type(glyph);
return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
}
}
HB_INTERNAL bool is_blocklisted(hb_blob_t *blob, hb_face_t *face) const;
struct accelerator_t
{
void init(hb_face_t *face)
{
this->table = hb_sanitize_context_t().reference_table<GDEF>(face);
if (unlikely(this->table->is_blocklisted(this->table.get_blob(), face))) {
hb_blob_destroy(this->table.get_blob());
this->table = hb_blob_get_empty();
}
}
void fini()
{
this->table.destroy();
}
hb_blob_ptr_t<GDEF> table;
};
unsigned int get_size() const
{
return min_size + (version.to_int() >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
(version.to_int() >= 0x00010003u ? varStore.static_size : 0);
}
void collect_variation_indices(hb_collect_variation_indices_context_t *c) const
{
(this + ligCaretList).collect_variation_indices(c);
}
void remap_layout_variation_indices(const hb_set_t *layout_variation_indices,
hb_map_t *layout_variation_idx_map /* OUT */) const
{
if (version.to_int() < 0x00010003u || !varStore)
return;
if (layout_variation_indices->is_empty())
return;
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min()) >> 16;
for (unsigned idx : layout_variation_indices->iter()) {
uint16_t major = idx >> 16;
if (major >= (this + varStore).get_sub_table_count())
break;
if (major != last_major) {
new_minor = 0;
++new_major;
}
unsigned new_idx = (new_major << 16) + new_minor;
layout_variation_idx_map->set(idx, new_idx);
++new_minor;
last_major = major;
}
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(version.sanitize(c) && likely(version.major == 1) && glyphClassDef.sanitize(c, this) &&
attachList.sanitize(c, this) && ligCaretList.sanitize(c, this) &&
markAttachClassDef.sanitize(c, this) &&
(version.to_int() < 0x00010002u || markGlyphSetsDef.sanitize(c, this)) &&
(version.to_int() < 0x00010003u || varStore.sanitize(c, this)));
}
protected:
FixedVersion<> version; /* Version of the GDEF table--currently
* 0x00010003u */
OffsetTo<ClassDef> glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
* GDEF header (may be Null) */
OffsetTo<AttachList> attachList; /* Offset to list of glyphs with
* attachment points--from beginning
* of GDEF header (may be Null) */
OffsetTo<LigCaretList> ligCaretList; /* Offset to list of positioning points
* for ligature carets--from beginning
* of GDEF header (may be Null) */
OffsetTo<ClassDef> markAttachClassDef; /* Offset to class definition table for
* mark attachment type--from beginning
* of GDEF header (may be Null) */
OffsetTo<MarkGlyphSets> markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
LOffsetTo<VariationStore> varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010003. */
public:
DEFINE_SIZE_MIN(12);
};
struct GDEF_accelerator_t : GDEF::accelerator_t
{
};
} /* namespace OT */
#endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1734
harfbuzz/src/hb-ot-layout.cc Normal file

File diff suppressed because it is too large Load Diff

346
harfbuzz/src/hb-ot-layout.h Normal file
View File

@ -0,0 +1,346 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_LAYOUT_H
#define HB_OT_LAYOUT_H
#include "hb.h"
#include "hb-ot-name.h"
HB_BEGIN_DECLS
#define HB_OT_TAG_BASE HB_TAG('B', 'A', 'S', 'E')
#define HB_OT_TAG_GDEF HB_TAG('G', 'D', 'E', 'F')
#define HB_OT_TAG_GSUB HB_TAG('G', 'S', 'U', 'B')
#define HB_OT_TAG_GPOS HB_TAG('G', 'P', 'O', 'S')
#define HB_OT_TAG_JSTF HB_TAG('J', 'S', 'T', 'F')
/*
* Script & Language tags.
*/
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG('D', 'F', 'L', 'T')
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG('d', 'f', 'l', 't')
/**
* HB_OT_MAX_TAGS_PER_SCRIPT:
*
* Since: 2.0.0
**/
#define HB_OT_MAX_TAGS_PER_SCRIPT 3u
/**
* HB_OT_MAX_TAGS_PER_LANGUAGE:
*
* Since: 2.0.0
**/
#define HB_OT_MAX_TAGS_PER_LANGUAGE 3u
HB_EXTERN void hb_ot_tags_from_script_and_language(hb_script_t script,
hb_language_t language,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */,
unsigned int *language_count /* IN/OUT */,
hb_tag_t *language_tags /* OUT */);
HB_EXTERN hb_script_t hb_ot_tag_to_script(hb_tag_t tag);
HB_EXTERN hb_language_t hb_ot_tag_to_language(hb_tag_t tag);
HB_EXTERN void hb_ot_tags_to_script_and_language(hb_tag_t script_tag,
hb_tag_t language_tag,
hb_script_t *script /* OUT */,
hb_language_t *language /* OUT */);
/*
* GDEF
*/
HB_EXTERN hb_bool_t hb_ot_layout_has_glyph_classes(hb_face_t *face);
/**
* hb_ot_layout_glyph_class_t:
* @HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: Glyphs not matching the other classifications
* @HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: Spacing, single characters, capable of accepting marks
* @HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: Glyphs that represent ligation of multiple characters
* @HB_OT_LAYOUT_GLYPH_CLASS_MARK: Non-spacing, combining glyphs that represent marks
* @HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: Spacing glyphs that represent part of a single character
*
* The GDEF classes defined for glyphs.
*
**/
typedef enum {
HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0,
HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 1,
HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 2,
HB_OT_LAYOUT_GLYPH_CLASS_MARK = 3,
HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 4
} hb_ot_layout_glyph_class_t;
HB_EXTERN hb_ot_layout_glyph_class_t hb_ot_layout_get_glyph_class(hb_face_t *face, hb_codepoint_t glyph);
HB_EXTERN void
hb_ot_layout_get_glyphs_in_class(hb_face_t *face, hb_ot_layout_glyph_class_t klass, hb_set_t *glyphs /* OUT */);
/* Not that useful. Provides list of attach points for a glyph that a
* client may want to cache */
HB_EXTERN unsigned int hb_ot_layout_get_attach_points(hb_face_t *face,
hb_codepoint_t glyph,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */);
/*
* GSUB/GPOS feature query and enumeration interface
*/
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_VARIATIONS_INDEX 0xFFFFFFFFu
HB_EXTERN unsigned int hb_ot_layout_table_get_script_tags(hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */);
HB_EXTERN hb_bool_t hb_ot_layout_table_find_script(hb_face_t *face,
hb_tag_t table_tag,
hb_tag_t script_tag,
unsigned int *script_index /* OUT */);
HB_EXTERN hb_bool_t hb_ot_layout_table_select_script(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_count,
const hb_tag_t *script_tags,
unsigned int *script_index /* OUT */,
hb_tag_t *chosen_script /* OUT */);
HB_EXTERN unsigned int hb_ot_layout_table_get_feature_tags(hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */);
HB_EXTERN unsigned int hb_ot_layout_script_get_language_tags(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int start_offset,
unsigned int *language_count /* IN/OUT */,
hb_tag_t *language_tags /* OUT */);
HB_EXTERN hb_bool_t hb_ot_layout_script_select_language(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_count,
const hb_tag_t *language_tags,
unsigned int *language_index /* OUT */);
HB_EXTERN hb_bool_t hb_ot_layout_language_get_required_feature_index(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index /* OUT */);
HB_EXTERN hb_bool_t hb_ot_layout_language_get_required_feature(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index /* OUT */,
hb_tag_t *feature_tag /* OUT */);
HB_EXTERN unsigned int hb_ot_layout_language_get_feature_indexes(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
unsigned int *feature_indexes /* OUT */);
HB_EXTERN unsigned int hb_ot_layout_language_get_feature_tags(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */);
HB_EXTERN hb_bool_t hb_ot_layout_language_find_feature(hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
hb_tag_t feature_tag,
unsigned int *feature_index /* OUT */);
HB_EXTERN unsigned int hb_ot_layout_feature_get_lookups(hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int start_offset,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */);
HB_EXTERN unsigned int hb_ot_layout_table_get_lookup_count(hb_face_t *face, hb_tag_t table_tag);
HB_EXTERN void hb_ot_layout_collect_features(hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *scripts,
const hb_tag_t *languages,
const hb_tag_t *features,
hb_set_t *feature_indexes /* OUT */);
HB_EXTERN void hb_ot_layout_collect_lookups(hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *scripts,
const hb_tag_t *languages,
const hb_tag_t *features,
hb_set_t *lookup_indexes /* OUT */);
HB_EXTERN void hb_ot_layout_lookup_collect_glyphs(hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
hb_set_t *glyphs_before, /* OUT. May be NULL */
hb_set_t *glyphs_input, /* OUT. May be NULL */
hb_set_t *glyphs_after, /* OUT. May be NULL */
hb_set_t *glyphs_output /* OUT. May be NULL */);
#ifdef HB_NOT_IMPLEMENTED
typedef struct
{
const hb_codepoint_t *before, unsigned int before_length, const hb_codepoint_t *input, unsigned int input_length,
const hb_codepoint_t *after, unsigned int after_length,
} hb_ot_layout_glyph_sequence_t;
typedef hb_bool_t (*hb_ot_layout_glyph_sequence_func_t)(hb_font_t *font,
hb_tag_t table_tag,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
void *user_data);
HB_EXTERN void Xhb_ot_layout_lookup_enumerate_sequences(hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
hb_ot_layout_glyph_sequence_func_t callback,
void *user_data);
#endif
/* Variations support */
HB_EXTERN hb_bool_t hb_ot_layout_table_find_feature_variations(hb_face_t *face,
hb_tag_t table_tag,
const int *coords,
unsigned int num_coords,
unsigned int *variations_index /* out */);
HB_EXTERN unsigned int hb_ot_layout_feature_with_variations_get_lookups(hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int variations_index,
unsigned int start_offset,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */);
/*
* GSUB
*/
HB_EXTERN hb_bool_t hb_ot_layout_has_substitution(hb_face_t *face);
HB_EXTERN unsigned hb_ot_layout_lookup_get_glyph_alternates(hb_face_t *face,
unsigned lookup_index,
hb_codepoint_t glyph,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT */,
hb_codepoint_t *alternate_glyphs /* OUT */);
HB_EXTERN hb_bool_t hb_ot_layout_lookup_would_substitute(hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
hb_bool_t zero_context);
HB_EXTERN void hb_ot_layout_lookup_substitute_closure(hb_face_t *face, unsigned int lookup_index, hb_set_t *glyphs
/*TODO , hb_bool_t inclusive */);
HB_EXTERN void hb_ot_layout_lookups_substitute_closure(hb_face_t *face, const hb_set_t *lookups, hb_set_t *glyphs);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
HB_EXTERN hb_bool_t Xhb_ot_layout_lookup_substitute(hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
unsigned int out_size,
hb_codepoint_t *glyphs_out, /* OUT */
unsigned int *clusters_out, /* OUT */
unsigned int *out_length /* OUT */);
#endif
/*
* GPOS
*/
HB_EXTERN hb_bool_t hb_ot_layout_has_positioning(hb_face_t *face);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
HB_EXTERN hb_bool_t Xhb_ot_layout_lookup_position(hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
hb_glyph_position_t *positions /* IN / OUT */);
#endif
/* Optical 'size' feature info. Returns true if found.
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
HB_EXTERN hb_bool_t hb_ot_layout_get_size_params(hb_face_t *face,
unsigned int *design_size, /* OUT. May be NULL */
unsigned int *subfamily_id, /* OUT. May be NULL */
hb_ot_name_id_t *subfamily_name_id, /* OUT. May be NULL */
unsigned int *range_start, /* OUT. May be NULL */
unsigned int *range_end /* OUT. May be NULL */);
HB_EXTERN hb_bool_t hb_ot_layout_feature_get_name_ids(hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
hb_ot_name_id_t *label_id /* OUT. May be NULL */,
hb_ot_name_id_t *tooltip_id /* OUT. May be NULL */,
hb_ot_name_id_t *sample_id /* OUT. May be NULL */,
unsigned int *num_named_parameters /* OUT. May be NULL */,
hb_ot_name_id_t *first_param_id /* OUT. May be NULL */);
HB_EXTERN unsigned int hb_ot_layout_feature_get_characters(hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int start_offset,
unsigned int *char_count /* IN/OUT. May be NULL */,
hb_codepoint_t *characters /* OUT. May be NULL */);
HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */

View File

@ -0,0 +1,529 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_LAYOUT_HH
#define HB_OT_LAYOUT_HH
#include "hb.hh"
#include "hb-font.hh"
#include "hb-buffer.hh"
#include "hb-open-type.hh"
#include "hb-ot-shape.hh"
#include "hb-set-digest.hh"
struct hb_ot_shape_plan_t;
/*
* kern
*/
HB_INTERNAL bool hb_ot_layout_has_kerning(hb_face_t *face);
HB_INTERNAL bool hb_ot_layout_has_machine_kerning(hb_face_t *face);
HB_INTERNAL bool hb_ot_layout_has_cross_kerning(hb_face_t *face);
HB_INTERNAL void hb_ot_layout_kern(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
/* Private API corresponding to hb-ot-layout.h: */
HB_INTERNAL bool
hb_ot_layout_table_find_feature(hb_face_t *face, hb_tag_t table_tag, hb_tag_t feature_tag, unsigned int *feature_index);
/*
* GDEF
*/
enum hb_ot_layout_glyph_props_flags_t {
/* The following three match LookupFlags::Ignore* numbers. */
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x02u,
HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE = 0x04u,
HB_OT_LAYOUT_GLYPH_PROPS_MARK = 0x08u,
HB_OT_LAYOUT_GLYPH_PROPS_CLASS_MASK =
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH | HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE | HB_OT_LAYOUT_GLYPH_PROPS_MARK,
/* The following are used internally; not derived from GDEF. */
HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u,
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u,
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x40u,
};
HB_MARK_AS_FLAG_T(hb_ot_layout_glyph_props_flags_t);
/*
* GSUB/GPOS
*/
/* Should be called before all the substitute_lookup's are done. */
HB_INTERNAL void hb_ot_layout_substitute_start(hb_font_t *font, hb_buffer_t *buffer);
HB_INTERNAL void hb_ot_layout_delete_glyphs_inplace(hb_buffer_t *buffer, bool (*filter)(const hb_glyph_info_t *info));
namespace OT {
struct hb_ot_apply_context_t;
struct SubstLookup;
struct hb_ot_layout_lookup_accelerator_t;
} // namespace OT
HB_INTERNAL void hb_ot_layout_substitute_lookup(OT::hb_ot_apply_context_t *c,
const OT::SubstLookup &lookup,
const OT::hb_ot_layout_lookup_accelerator_t &accel);
/* Should be called before all the position_lookup's are done. */
HB_INTERNAL void hb_ot_layout_position_start(hb_font_t *font, hb_buffer_t *buffer);
/* Should be called after all the position_lookup's are done, to fini advances. */
HB_INTERNAL void hb_ot_layout_position_finish_advances(hb_font_t *font, hb_buffer_t *buffer);
/* Should be called after hb_ot_layout_position_finish_advances, to fini offsets. */
HB_INTERNAL void hb_ot_layout_position_finish_offsets(hb_font_t *font, hb_buffer_t *buffer);
/*
* Buffer var routines.
*/
/* buffer var allocations, used during the entire shaping process */
#define unicode_props() var2.u16[0]
/* buffer var allocations, used during the GSUB/GPOS processing */
#define glyph_props() var1.u16[0] /* GDEF glyph properties */
#define lig_props() var1.u8[2] /* GSUB/GPOS ligature tracking */
#define syllable() var1.u8[3] /* GSUB/GPOS shaping boundaries */
/* Loop over syllables. Based on foreach_cluster(). */
#define foreach_syllable(buffer, start, end) \
for (unsigned int _count = buffer->len, start = 0, end = _count ? _hb_next_syllable(buffer, 0) : 0; \
start < _count; \
start = end, end = _hb_next_syllable(buffer, start))
static inline unsigned int _hb_next_syllable(hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
unsigned int syllable = info[start].syllable();
while (++start < count && syllable == info[start].syllable())
;
return start;
}
static inline void
_hb_clear_syllables(const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
info[i].syllable() = 0;
}
/* unicode_props */
/* Design:
* unicode_props() is a two-byte number. The low byte includes:
* - General_Category: 5 bits.
* - A bit each for:
* * Is it Default_Ignorable(); we have a modified Default_Ignorable().
* * Whether it's one of the three Mongolian Free Variation Selectors,
* CGJ, or other characters that are hidden but should not be ignored
* like most other Default_Ignorable()s do during matching.
* * Whether it's a grapheme continuation.
*
* The high-byte has different meanings, switched by the Gen-Cat:
* - For Mn,Mc,Me: the modified Combining_Class.
* - For Cf: whether it's ZWJ, ZWNJ, or something else.
* - For Ws: index of which space character this is, if space fallback
* is needed, ie. we don't set this by default, only if asked to.
*/
enum hb_unicode_props_flags_t {
UPROPS_MASK_GEN_CAT = 0x001Fu,
UPROPS_MASK_IGNORABLE = 0x0020u,
UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, or TAG characters */
UPROPS_MASK_CONTINUATION = 0x0080u,
/* If GEN_CAT=FORMAT, top byte masks: */
UPROPS_MASK_Cf_ZWJ = 0x0100u,
UPROPS_MASK_Cf_ZWNJ = 0x0200u
};
HB_MARK_AS_FLAG_T(hb_unicode_props_flags_t);
static inline void _hb_glyph_info_set_unicode_props(hb_glyph_info_t *info, hb_buffer_t *buffer)
{
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int u = info->codepoint;
unsigned int gen_cat = (unsigned int)unicode->general_category(u);
unsigned int props = gen_cat;
if (u >= 0x80u) {
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
if (unlikely(unicode->is_default_ignorable(u))) {
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
props |= UPROPS_MASK_IGNORABLE;
if (u == 0x200Cu)
props |= UPROPS_MASK_Cf_ZWNJ;
else if (u == 0x200Du)
props |= UPROPS_MASK_Cf_ZWJ;
/* Mongolian Free Variation Selectors need to be remembered
* because although we need to hide them like default-ignorables,
* they need to non-ignorable during shaping. This is similar to
* what we do for joiners in Indic-like shapers, but since the
* FVSes are GC=Mn, we have use a separate bit to remember them.
* Fixes:
* https://github.com/harfbuzz/harfbuzz/issues/234 */
else if (unlikely(hb_in_range<hb_codepoint_t>(u, 0x180Bu, 0x180Du)))
props |= UPROPS_MASK_HIDDEN;
/* TAG characters need similar treatment. Fixes:
* https://github.com/harfbuzz/harfbuzz/issues/463 */
else if (unlikely(hb_in_range<hb_codepoint_t>(u, 0xE0020u, 0xE007Fu)))
props |= UPROPS_MASK_HIDDEN;
/* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
* https://github.com/harfbuzz/harfbuzz/issues/554 */
else if (unlikely(u == 0x034Fu)) {
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CGJ;
props |= UPROPS_MASK_HIDDEN;
}
}
if (unlikely(HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat))) {
props |= UPROPS_MASK_CONTINUATION;
props |= unicode->modified_combining_class(u) << 8;
}
}
info->unicode_props() = props;
}
static inline void _hb_glyph_info_set_general_category(hb_glyph_info_t *info, hb_unicode_general_category_t gen_cat)
{
/* Clears top-byte. */
info->unicode_props() = (unsigned int)gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
}
static inline hb_unicode_general_category_t _hb_glyph_info_get_general_category(const hb_glyph_info_t *info)
{
return (hb_unicode_general_category_t)(info->unicode_props() & UPROPS_MASK_GEN_CAT);
}
static inline bool _hb_glyph_info_is_unicode_mark(const hb_glyph_info_t *info)
{
return HB_UNICODE_GENERAL_CATEGORY_IS_MARK(info->unicode_props() & UPROPS_MASK_GEN_CAT);
}
static inline void _hb_glyph_info_set_modified_combining_class(hb_glyph_info_t *info, unsigned int modified_class)
{
if (unlikely(!_hb_glyph_info_is_unicode_mark(info)))
return;
info->unicode_props() = (modified_class << 8) | (info->unicode_props() & 0xFF);
}
static inline unsigned int _hb_glyph_info_get_modified_combining_class(const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_mark(info) ? info->unicode_props() >> 8 : 0;
}
#define info_cc(info) (_hb_glyph_info_get_modified_combining_class(&(info)))
static inline bool _hb_glyph_info_is_unicode_space(const hb_glyph_info_t *info)
{
return _hb_glyph_info_get_general_category(info) == HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
}
static inline void _hb_glyph_info_set_unicode_space_fallback_type(hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
{
if (unlikely(!_hb_glyph_info_is_unicode_space(info)))
return;
info->unicode_props() = (((unsigned int)s) << 8) | (info->unicode_props() & 0xFF);
}
static inline hb_unicode_funcs_t::space_t _hb_glyph_info_get_unicode_space_fallback_type(const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_space(info) ? (hb_unicode_funcs_t::space_t)(info->unicode_props() >> 8)
: hb_unicode_funcs_t::NOT_SPACE;
}
static inline bool _hb_glyph_info_ligated(const hb_glyph_info_t *info);
static inline bool _hb_glyph_info_is_default_ignorable(const hb_glyph_info_t *info)
{
return (info->unicode_props() & UPROPS_MASK_IGNORABLE) && !_hb_glyph_info_ligated(info);
}
static inline bool _hb_glyph_info_is_default_ignorable_and_not_hidden(const hb_glyph_info_t *info)
{
return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE | UPROPS_MASK_HIDDEN)) == UPROPS_MASK_IGNORABLE) &&
!_hb_glyph_info_ligated(info);
}
static inline void _hb_glyph_info_unhide(hb_glyph_info_t *info)
{
info->unicode_props() &= ~UPROPS_MASK_HIDDEN;
}
static inline void _hb_glyph_info_set_continuation(hb_glyph_info_t *info)
{
info->unicode_props() |= UPROPS_MASK_CONTINUATION;
}
static inline void _hb_glyph_info_reset_continuation(hb_glyph_info_t *info)
{
info->unicode_props() &= ~UPROPS_MASK_CONTINUATION;
}
static inline bool _hb_glyph_info_is_continuation(const hb_glyph_info_t *info)
{
return info->unicode_props() & UPROPS_MASK_CONTINUATION;
}
/* Loop over grapheme. Based on foreach_cluster(). */
#define foreach_grapheme(buffer, start, end) \
for (unsigned int _count = buffer->len, start = 0, end = _count ? _hb_next_grapheme(buffer, 0) : 0; \
start < _count; \
start = end, end = _hb_next_grapheme(buffer, start))
static inline unsigned int _hb_next_grapheme(hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
while (++start < count && _hb_glyph_info_is_continuation(&info[start]))
;
return start;
}
static inline bool _hb_glyph_info_is_unicode_format(const hb_glyph_info_t *info)
{
return _hb_glyph_info_get_general_category(info) == HB_UNICODE_GENERAL_CATEGORY_FORMAT;
}
static inline bool _hb_glyph_info_is_zwnj(const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format(info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ);
}
static inline bool _hb_glyph_info_is_zwj(const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format(info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
}
static inline bool _hb_glyph_info_is_joiner(const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format(info) &&
(info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ));
}
static inline void _hb_glyph_info_flip_joiners(hb_glyph_info_t *info)
{
if (!_hb_glyph_info_is_unicode_format(info))
return;
info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
}
/* lig_props: aka lig_id / lig_comp
*
* When a ligature is formed:
*
* - The ligature glyph and any marks in between all the same newly allocated
* lig_id,
* - The ligature glyph will get lig_num_comps set to the number of components
* - The marks get lig_comp > 0, reflecting which component of the ligature
* they were applied to.
* - This is used in GPOS to attach marks to the right component of a ligature
* in MarkLigPos,
* - Note that when marks are ligated together, much of the above is skipped
* and the current lig_id reused.
*
* When a multiple-substitution is done:
*
* - All resulting glyphs will have lig_id = 0,
* - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
* - This is used in GPOS to attach marks to the first component of a
* multiple substitution in MarkBasePos.
*
* The numbers are also used in GPOS to do mark-to-mark positioning only
* to marks that belong to the same component of the same ligature.
*/
static inline void _hb_glyph_info_clear_lig_props(hb_glyph_info_t *info)
{
info->lig_props() = 0;
}
#define IS_LIG_BASE 0x10
static inline void
_hb_glyph_info_set_lig_props_for_ligature(hb_glyph_info_t *info, unsigned int lig_id, unsigned int lig_num_comps)
{
info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
}
static inline void
_hb_glyph_info_set_lig_props_for_mark(hb_glyph_info_t *info, unsigned int lig_id, unsigned int lig_comp)
{
info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
}
static inline void _hb_glyph_info_set_lig_props_for_component(hb_glyph_info_t *info, unsigned int comp)
{
_hb_glyph_info_set_lig_props_for_mark(info, 0, comp);
}
static inline unsigned int _hb_glyph_info_get_lig_id(const hb_glyph_info_t *info)
{
return info->lig_props() >> 5;
}
static inline bool _hb_glyph_info_ligated_internal(const hb_glyph_info_t *info)
{
return !!(info->lig_props() & IS_LIG_BASE);
}
static inline unsigned int _hb_glyph_info_get_lig_comp(const hb_glyph_info_t *info)
{
if (_hb_glyph_info_ligated_internal(info))
return 0;
else
return info->lig_props() & 0x0F;
}
static inline unsigned int _hb_glyph_info_get_lig_num_comps(const hb_glyph_info_t *info)
{
if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) && _hb_glyph_info_ligated_internal(info))
return info->lig_props() & 0x0F;
else
return 1;
}
static inline uint8_t _hb_allocate_lig_id(hb_buffer_t *buffer)
{
uint8_t lig_id = buffer->next_serial() & 0x07;
if (unlikely(!lig_id))
lig_id = _hb_allocate_lig_id(buffer); /* in case of overflow */
return lig_id;
}
/* glyph_props: */
static inline void _hb_glyph_info_set_glyph_props(hb_glyph_info_t *info, unsigned int props)
{
info->glyph_props() = props;
}
static inline unsigned int _hb_glyph_info_get_glyph_props(const hb_glyph_info_t *info)
{
return info->glyph_props();
}
static inline bool _hb_glyph_info_is_base_glyph(const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
}
static inline bool _hb_glyph_info_is_ligature(const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
}
static inline bool _hb_glyph_info_is_mark(const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
}
static inline bool _hb_glyph_info_substituted(const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}
static inline bool _hb_glyph_info_ligated(const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
}
static inline bool _hb_glyph_info_multiplied(const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}
static inline bool _hb_glyph_info_ligated_and_didnt_multiply(const hb_glyph_info_t *info)
{
return _hb_glyph_info_ligated(info) && !_hb_glyph_info_multiplied(info);
}
static inline void _hb_glyph_info_clear_ligated_and_multiplied(hb_glyph_info_t *info)
{
info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED | HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}
static inline void _hb_glyph_info_clear_substituted(hb_glyph_info_t *info)
{
info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}
static inline void
_hb_clear_substitution_flags(const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_clear_substituted(&info[i]);
}
/* Allocation / deallocation. */
static inline void _hb_buffer_allocate_unicode_vars(hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR(buffer, unicode_props);
}
static inline void _hb_buffer_deallocate_unicode_vars(hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR(buffer, unicode_props);
}
static inline void _hb_buffer_assert_unicode_vars(hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR(buffer, unicode_props);
}
static inline void _hb_buffer_allocate_gsubgpos_vars(hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR(buffer, glyph_props);
HB_BUFFER_ALLOCATE_VAR(buffer, lig_props);
HB_BUFFER_ALLOCATE_VAR(buffer, syllable);
}
static inline void _hb_buffer_deallocate_gsubgpos_vars(hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR(buffer, syllable);
HB_BUFFER_DEALLOCATE_VAR(buffer, lig_props);
HB_BUFFER_DEALLOCATE_VAR(buffer, glyph_props);
}
static inline void _hb_buffer_assert_gsubgpos_vars(hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR(buffer, glyph_props);
HB_BUFFER_ASSERT_VAR(buffer, lig_props);
HB_BUFFER_ASSERT_VAR(buffer, syllable);
}
/* Make sure no one directly touches our props... */
#undef unicode_props0
#undef unicode_props1
#undef lig_props
#undef glyph_props
#endif /* HB_OT_LAYOUT_HH */

316
harfbuzz/src/hb-ot-map.cc Normal file
View File

@ -0,0 +1,316 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2010,2011,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifndef HB_NO_OT_SHAPE
#include "hb-set.hh"
#include "hb-ot-map.hh"
#include "hb-ot-shape.hh"
#include "hb-ot-layout.hh"
void hb_ot_map_t::collect_lookups(unsigned int table_index, hb_set_t *lookups_out) const
{
for (unsigned int i = 0; i < lookups[table_index].length; i++)
lookups_out->add(lookups[table_index][i].index);
}
hb_ot_map_builder_t::hb_ot_map_builder_t(hb_face_t *face_, const hb_segment_properties_t *props_)
{
memset(this, 0, sizeof(*this));
feature_infos.init();
for (unsigned int table_index = 0; table_index < 2; table_index++)
stages[table_index].init();
face = face_;
props = *props_;
/* Fetch script/language indices for GSUB/GPOS. We need these later to skip
* features not available in either table and not waste precious bits for them. */
unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
unsigned int language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
hb_ot_tags_from_script_and_language(
props.script, props.language, &script_count, script_tags, &language_count, language_tags);
for (unsigned int table_index = 0; table_index < 2; table_index++) {
hb_tag_t table_tag = table_tags[table_index];
found_script[table_index] = (bool)hb_ot_layout_table_select_script(
face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]);
hb_ot_layout_script_select_language(
face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]);
}
}
hb_ot_map_builder_t::~hb_ot_map_builder_t()
{
feature_infos.fini();
for (unsigned int table_index = 0; table_index < 2; table_index++)
stages[table_index].fini();
}
void hb_ot_map_builder_t::add_feature(hb_tag_t tag, hb_ot_map_feature_flags_t flags, unsigned int value)
{
if (unlikely(!tag))
return;
feature_info_t *info = feature_infos.push();
info->tag = tag;
info->seq = feature_infos.length;
info->max_value = value;
info->flags = flags;
info->default_value = (flags & F_GLOBAL) ? value : 0;
info->stage[0] = current_stage[0];
info->stage[1] = current_stage[1];
}
void hb_ot_map_builder_t::add_lookups(hb_ot_map_t &m,
unsigned int table_index,
unsigned int feature_index,
unsigned int variations_index,
hb_mask_t mask,
bool auto_zwnj,
bool auto_zwj,
bool random)
{
unsigned int lookup_indices[32];
unsigned int offset, len;
unsigned int table_lookup_count;
table_lookup_count = hb_ot_layout_table_get_lookup_count(face, table_tags[table_index]);
offset = 0;
do {
len = ARRAY_LENGTH(lookup_indices);
hb_ot_layout_feature_with_variations_get_lookups(
face, table_tags[table_index], feature_index, variations_index, offset, &len, lookup_indices);
for (unsigned int i = 0; i < len; i++) {
if (lookup_indices[i] >= table_lookup_count)
continue;
hb_ot_map_t::lookup_map_t *lookup = m.lookups[table_index].push();
lookup->mask = mask;
lookup->index = lookup_indices[i];
lookup->auto_zwnj = auto_zwnj;
lookup->auto_zwj = auto_zwj;
lookup->random = random;
}
offset += len;
} while (len == ARRAY_LENGTH(lookup_indices));
}
void hb_ot_map_builder_t::add_pause(unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
{
stage_info_t *s = stages[table_index].push();
s->index = current_stage[table_index];
s->pause_func = pause_func;
current_stage[table_index]++;
}
void hb_ot_map_builder_t::compile(hb_ot_map_t &m, const hb_ot_shape_plan_key_t &key)
{
static_assert((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
unsigned int global_bit_shift = hb_popcount(HB_GLYPH_FLAG_DEFINED);
m.global_mask = global_bit_mask;
unsigned int required_feature_index[2];
hb_tag_t required_feature_tag[2];
/* We default to applying required feature in stage 0. If the required
* feature has a tag that is known to the shaper, we apply required feature
* in the stage for that tag.
*/
unsigned int required_feature_stage[2] = {0, 0};
for (unsigned int table_index = 0; table_index < 2; table_index++) {
m.chosen_script[table_index] = chosen_script[table_index];
m.found_script[table_index] = found_script[table_index];
hb_ot_layout_language_get_required_feature(face,
table_tags[table_index],
script_index[table_index],
language_index[table_index],
&required_feature_index[table_index],
&required_feature_tag[table_index]);
}
/* Sort features and merge duplicates */
if (feature_infos.length) {
feature_infos.qsort();
unsigned int j = 0;
for (unsigned int i = 1; i < feature_infos.length; i++)
if (feature_infos[i].tag != feature_infos[j].tag)
feature_infos[++j] = feature_infos[i];
else {
if (feature_infos[i].flags & F_GLOBAL) {
feature_infos[j].flags |= F_GLOBAL;
feature_infos[j].max_value = feature_infos[i].max_value;
feature_infos[j].default_value = feature_infos[i].default_value;
} else {
if (feature_infos[j].flags & F_GLOBAL)
feature_infos[j].flags ^= F_GLOBAL;
feature_infos[j].max_value = hb_max(feature_infos[j].max_value, feature_infos[i].max_value);
/* Inherit default_value from j */
}
feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
feature_infos[j].stage[0] = hb_min(feature_infos[j].stage[0], feature_infos[i].stage[0]);
feature_infos[j].stage[1] = hb_min(feature_infos[j].stage[1], feature_infos[i].stage[1]);
}
feature_infos.shrink(j + 1);
}
/* Allocate bits now */
unsigned int next_bit = global_bit_shift + 1;
for (unsigned int i = 0; i < feature_infos.length; i++) {
const feature_info_t *info = &feature_infos[i];
unsigned int bits_needed;
if ((info->flags & F_GLOBAL) && info->max_value == 1)
/* Uses the global bit */
bits_needed = 0;
else
/* Limit bits per feature. */
bits_needed = hb_min(HB_OT_MAP_MAX_BITS, hb_bit_storage(info->max_value));
if (!info->max_value || next_bit + bits_needed > 8 * sizeof(hb_mask_t))
continue; /* Feature disabled, or not enough bits. */
bool found = false;
unsigned int feature_index[2];
for (unsigned int table_index = 0; table_index < 2; table_index++) {
if (required_feature_tag[table_index] == info->tag)
required_feature_stage[table_index] = info->stage[table_index];
found |= (bool)hb_ot_layout_language_find_feature(face,
table_tags[table_index],
script_index[table_index],
language_index[table_index],
info->tag,
&feature_index[table_index]);
}
if (!found && (info->flags & F_GLOBAL_SEARCH)) {
for (unsigned int table_index = 0; table_index < 2; table_index++) {
found |= (bool)hb_ot_layout_table_find_feature(
face, table_tags[table_index], info->tag, &feature_index[table_index]);
}
}
if (!found && !(info->flags & F_HAS_FALLBACK))
continue;
hb_ot_map_t::feature_map_t *map = m.features.push();
map->tag = info->tag;
map->index[0] = feature_index[0];
map->index[1] = feature_index[1];
map->stage[0] = info->stage[0];
map->stage[1] = info->stage[1];
map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
map->random = !!(info->flags & F_RANDOM);
if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */
map->shift = global_bit_shift;
map->mask = global_bit_mask;
} else {
map->shift = next_bit;
map->mask = (1u << (next_bit + bits_needed)) - (1u << next_bit);
next_bit += bits_needed;
m.global_mask |= (info->default_value << map->shift) & map->mask;
}
map->_1_mask = (1u << map->shift) & map->mask;
map->needs_fallback = !found;
}
feature_infos.shrink(0); /* Done with these */
add_gsub_pause(nullptr);
add_gpos_pause(nullptr);
for (unsigned int table_index = 0; table_index < 2; table_index++) {
/* Collect lookup indices for features */
unsigned int stage_index = 0;
unsigned int last_num_lookups = 0;
for (unsigned stage = 0; stage < current_stage[table_index]; stage++) {
if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
required_feature_stage[table_index] == stage)
add_lookups(m,
table_index,
required_feature_index[table_index],
key.variations_index[table_index],
global_bit_mask);
for (unsigned i = 0; i < m.features.length; i++)
if (m.features[i].stage[table_index] == stage)
add_lookups(m,
table_index,
m.features[i].index[table_index],
key.variations_index[table_index],
m.features[i].mask,
m.features[i].auto_zwnj,
m.features[i].auto_zwj,
m.features[i].random);
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].length) {
m.lookups[table_index].qsort(last_num_lookups, m.lookups[table_index].length);
unsigned int j = last_num_lookups;
for (unsigned int i = j + 1; i < m.lookups[table_index].length; i++)
if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
m.lookups[table_index][++j] = m.lookups[table_index][i];
else {
m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
m.lookups[table_index][j].auto_zwnj &= m.lookups[table_index][i].auto_zwnj;
m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
}
m.lookups[table_index].shrink(j + 1);
}
last_num_lookups = m.lookups[table_index].length;
if (stage_index < stages[table_index].length && stages[table_index][stage_index].index == stage) {
hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push();
stage_map->last_lookup = last_num_lookups;
stage_map->pause_func = stages[table_index][stage_index].pause_func;
stage_index++;
}
}
}
}
#endif

288
harfbuzz/src/hb-ot-map.hh Normal file
View File

@ -0,0 +1,288 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2010,2011,2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_MAP_HH
#define HB_OT_MAP_HH
#include "hb-buffer.hh"
#define HB_OT_MAP_MAX_BITS 8u
#define HB_OT_MAP_MAX_VALUE ((1u << HB_OT_MAP_MAX_BITS) - 1u)
struct hb_ot_shape_plan_t;
static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
struct hb_ot_map_t
{
friend struct hb_ot_map_builder_t;
public:
struct feature_map_t
{
hb_tag_t tag; /* should be first for our bsearch to work */
unsigned int index[2]; /* GSUB/GPOS */
unsigned int stage[2]; /* GSUB/GPOS */
unsigned int shift;
hb_mask_t mask;
hb_mask_t _1_mask; /* mask for value=1, for quick access */
unsigned int needs_fallback : 1;
unsigned int auto_zwnj : 1;
unsigned int auto_zwj : 1;
unsigned int random : 1;
int cmp(const hb_tag_t tag_) const
{
return tag_ < tag ? -1 : tag_ > tag ? 1 : 0;
}
};
struct lookup_map_t
{
unsigned short index;
unsigned short auto_zwnj : 1;
unsigned short auto_zwj : 1;
unsigned short random : 1;
hb_mask_t mask;
HB_INTERNAL static int cmp(const void *pa, const void *pb)
{
const lookup_map_t *a = (const lookup_map_t *)pa;
const lookup_map_t *b = (const lookup_map_t *)pb;
return a->index < b->index ? -1 : a->index > b->index ? 1 : 0;
}
};
typedef void (*pause_func_t)(const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
struct stage_map_t
{
unsigned int last_lookup; /* Cumulative */
pause_func_t pause_func;
};
void init()
{
memset(this, 0, sizeof(*this));
features.init();
for (unsigned int table_index = 0; table_index < 2; table_index++) {
lookups[table_index].init();
stages[table_index].init();
}
}
void fini()
{
features.fini();
for (unsigned int table_index = 0; table_index < 2; table_index++) {
lookups[table_index].fini();
stages[table_index].fini();
}
}
hb_mask_t get_global_mask() const
{
return global_mask;
}
hb_mask_t get_mask(hb_tag_t feature_tag, unsigned int *shift = nullptr) const
{
const feature_map_t *map = features.bsearch(feature_tag);
if (shift)
*shift = map ? map->shift : 0;
return map ? map->mask : 0;
}
bool needs_fallback(hb_tag_t feature_tag) const
{
const feature_map_t *map = features.bsearch(feature_tag);
return map ? map->needs_fallback : false;
}
hb_mask_t get_1_mask(hb_tag_t feature_tag) const
{
const feature_map_t *map = features.bsearch(feature_tag);
return map ? map->_1_mask : 0;
}
unsigned int get_feature_index(unsigned int table_index, hb_tag_t feature_tag) const
{
const feature_map_t *map = features.bsearch(feature_tag);
return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
}
unsigned int get_feature_stage(unsigned int table_index, hb_tag_t feature_tag) const
{
const feature_map_t *map = features.bsearch(feature_tag);
return map ? map->stage[table_index] : UINT_MAX;
}
void get_stage_lookups(unsigned int table_index,
unsigned int stage,
const struct lookup_map_t **plookups,
unsigned int *lookup_count) const
{
if (unlikely(stage == UINT_MAX)) {
*plookups = nullptr;
*lookup_count = 0;
return;
}
assert(stage <= stages[table_index].length);
unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
unsigned int end =
stage < stages[table_index].length ? stages[table_index][stage].last_lookup : lookups[table_index].length;
*plookups = end == start ? nullptr : &lookups[table_index][start];
*lookup_count = end - start;
}
HB_INTERNAL void collect_lookups(unsigned int table_index, hb_set_t *lookups) const;
template <typename Proxy>
HB_INTERNAL void
apply(const Proxy &proxy, const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
HB_INTERNAL void substitute(const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
HB_INTERNAL void position(const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
public:
hb_tag_t chosen_script[2];
bool found_script[2];
private:
hb_mask_t global_mask;
hb_sorted_vector_t<feature_map_t> features;
hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
hb_vector_t<stage_map_t> stages[2]; /* GSUB/GPOS */
};
enum hb_ot_map_feature_flags_t {
F_NONE = 0x0000u,
F_GLOBAL = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
F_HAS_FALLBACK = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
F_MANUAL_ZWNJ = 0x0004u, /* Don't skip over ZWNJ when matching **context**. */
F_MANUAL_ZWJ = 0x0008u, /* Don't skip over ZWJ when matching **input**. */
F_MANUAL_JOINERS = F_MANUAL_ZWNJ | F_MANUAL_ZWJ,
F_GLOBAL_MANUAL_JOINERS = F_GLOBAL | F_MANUAL_JOINERS,
F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK,
F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
};
HB_MARK_AS_FLAG_T(hb_ot_map_feature_flags_t);
struct hb_ot_map_feature_t
{
hb_tag_t tag;
hb_ot_map_feature_flags_t flags;
};
struct hb_ot_shape_plan_key_t;
struct hb_ot_map_builder_t
{
public:
HB_INTERNAL hb_ot_map_builder_t(hb_face_t *face_, const hb_segment_properties_t *props_);
HB_INTERNAL ~hb_ot_map_builder_t();
HB_INTERNAL void add_feature(hb_tag_t tag, hb_ot_map_feature_flags_t flags = F_NONE, unsigned int value = 1);
void add_feature(const hb_ot_map_feature_t &feat)
{
add_feature(feat.tag, feat.flags);
}
void enable_feature(hb_tag_t tag, hb_ot_map_feature_flags_t flags = F_NONE, unsigned int value = 1)
{
add_feature(tag, F_GLOBAL | flags, value);
}
void disable_feature(hb_tag_t tag)
{
add_feature(tag, F_GLOBAL, 0);
}
void add_gsub_pause(hb_ot_map_t::pause_func_t pause_func)
{
add_pause(0, pause_func);
}
void add_gpos_pause(hb_ot_map_t::pause_func_t pause_func)
{
add_pause(1, pause_func);
}
HB_INTERNAL void compile(hb_ot_map_t &m, const hb_ot_shape_plan_key_t &key);
private:
HB_INTERNAL void add_lookups(hb_ot_map_t &m,
unsigned int table_index,
unsigned int feature_index,
unsigned int variations_index,
hb_mask_t mask,
bool auto_zwnj = true,
bool auto_zwj = true,
bool random = false);
struct feature_info_t
{
hb_tag_t tag;
unsigned int seq; /* sequence#, used for stable sorting only */
unsigned int max_value;
hb_ot_map_feature_flags_t flags;
unsigned int default_value; /* for non-global features, what should the unset glyphs take */
unsigned int stage[2]; /* GSUB/GPOS */
HB_INTERNAL static int cmp(const void *pa, const void *pb)
{
const feature_info_t *a = (const feature_info_t *)pa;
const feature_info_t *b = (const feature_info_t *)pb;
return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
}
};
struct stage_info_t
{
unsigned int index;
hb_ot_map_t::pause_func_t pause_func;
};
HB_INTERNAL void add_pause(unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
public:
hb_face_t *face;
hb_segment_properties_t props;
hb_tag_t chosen_script[2];
bool found_script[2];
unsigned int script_index[2], language_index[2];
private:
unsigned int current_stage[2]; /* GSUB/GPOS */
hb_vector_t<feature_info_t> feature_infos;
hb_vector_t<stage_info_t> stages[2]; /* GSUB/GPOS */
};
#endif /* HB_OT_MAP_HH */

View File

@ -0,0 +1,120 @@
/*
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_MAXP_TABLE_HH
#define HB_OT_MAXP_TABLE_HH
#include "hb-open-type.hh"
namespace OT {
/*
* maxp -- Maximum Profile
* https://docs.microsoft.com/en-us/typography/opentype/spec/maxp
*/
#define HB_OT_TAG_maxp HB_TAG('m', 'a', 'x', 'p')
struct maxpV1Tail
{
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
return_trace(c->check_struct(this));
}
HBUINT16 maxPoints; /* Maximum points in a non-composite glyph. */
HBUINT16 maxContours; /* Maximum contours in a non-composite glyph. */
HBUINT16 maxCompositePoints; /* Maximum points in a composite glyph. */
HBUINT16 maxCompositeContours; /* Maximum contours in a composite glyph. */
HBUINT16 maxZones; /* 1 if instructions do not use the twilight zone (Z0),
* or 2 if instructions do use Z0; should be set to 2 in
* most cases. */
HBUINT16 maxTwilightPoints; /* Maximum points used in Z0. */
HBUINT16 maxStorage; /* Number of Storage Area locations. */
HBUINT16 maxFunctionDefs; /* Number of FDEFs, equal to the highest function number + 1. */
HBUINT16 maxInstructionDefs; /* Number of IDEFs. */
HBUINT16 maxStackElements; /* Maximum stack depth. (This includes Font and CVT
* Programs, as well as the instructions for each glyph.) */
HBUINT16 maxSizeOfInstructions; /* Maximum byte count for glyph instructions. */
HBUINT16 maxComponentElements; /* Maximum number of components referenced at
* "top level" for any composite glyph. */
HBUINT16 maxComponentDepth; /* Maximum levels of recursion; 1 for simple components. */
public:
DEFINE_SIZE_STATIC(26);
};
struct maxp
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_maxp;
unsigned int get_num_glyphs() const
{
return numGlyphs;
}
void set_num_glyphs(unsigned int count)
{
numGlyphs = count;
}
bool sanitize(hb_sanitize_context_t *c) const
{
TRACE_SANITIZE(this);
if (unlikely(!c->check_struct(this)))
return_trace(false);
if (version.major == 1) {
const maxpV1Tail &v1 = StructAfter<maxpV1Tail>(*this);
return_trace(v1.sanitize(c));
}
return_trace(likely(version.major == 0 && version.minor == 0x5000u));
}
static void drop_hint_fields(maxpV1Tail *dest_v1)
{
dest_v1->maxZones = 1;
dest_v1->maxTwilightPoints = 0;
dest_v1->maxStorage = 0;
dest_v1->maxFunctionDefs = 0;
dest_v1->maxInstructionDefs = 0;
dest_v1->maxStackElements = 0;
dest_v1->maxSizeOfInstructions = 0;
}
protected:
FixedVersion<> version; /* Version of the maxp table (0.5 or 1.0),
* 0x00005000u or 0x00010000u. */
HBUINT16 numGlyphs;
/* The number of glyphs in the font. */
/*maxpV1Tail v1Tail[HB_VAR_ARRAY]; */
public:
DEFINE_SIZE_STATIC(6);
};
} /* namespace OT */
#endif /* HB_OT_MAXP_TABLE_HH */

Some files were not shown because too many files have changed in this diff Show More