Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support glyph transforms for writing modes #2288

Merged
merged 2 commits into from Jan 15, 2018
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

support axis-aligned font transforms via font instance flags for writ…

…ing modes
  • Loading branch information
lsalzman committed Jan 11, 2018
commit d1fc5a711e314bd7795dcf8aadec377bff507853
@@ -1283,8 +1283,10 @@ impl FrameBuilder {
let mut render_mode = self.config
.default_font_render_mode
.limit_by(font.render_mode);
let mut flags = font.flags;
if let Some(options) = glyph_options {
render_mode = render_mode.limit_by(options.render_mode);
flags |= options.flags;
}

// There are some conditions under which we can't use
@@ -1309,7 +1311,7 @@ impl FrameBuilder {
font.bg_color,
render_mode,
font.subpx_dir,
font.flags,
flags,
font.platform_options,
font.variations.clone(),
);
@@ -114,6 +114,18 @@ impl FontTransform {
self.scale_y - self.skew_y * skew_factor,
)
}

pub fn swap_xy(&self) -> Self {
FontTransform::new(self.skew_x, self.scale_x, self.scale_y, self.skew_y)
}

pub fn flip_x(&self) -> Self {
FontTransform::new(-self.scale_x, self.skew_x, -self.skew_y, self.scale_y)
}

pub fn flip_y(&self) -> Self {
FontTransform::new(self.scale_x, -self.skew_y, self.skew_y, -self.scale_y)
}
}

impl<'a> From<&'a LayerToWorldTransform> for FontTransform {
@@ -361,8 +361,23 @@ impl FontContext {
let glyph = key.index as CGGlyph;
let bitmap = is_bitmap_font(ct_font);
let (x_offset, y_offset) = if bitmap { (0.0, 0.0) } else { font.get_subpx_offset(key) };
let transform = if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
let shape = FontTransform::identity().synthesize_italics(OBLIQUE_SKEW_FACTOR);
let transform = if font.flags.intersects(FontInstanceFlags::SYNTHETIC_ITALICS |
FontInstanceFlags::TRANSPOSE |
FontInstanceFlags::FLIP_X |
FontInstanceFlags::FLIP_Y) {
let mut shape = FontTransform::identity();
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}
Some(CGAffineTransform {
a: shape.scale_x as f64,
b: -shape.skew_y as f64,
@@ -483,6 +498,15 @@ impl FontContext {
} else {
(font.transform.invert_scale(y_scale, y_scale), font.get_subpx_offset(key))
};
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}
@@ -105,6 +105,38 @@ fn skew_bitmap(bitmap: &[u8], width: usize, height: usize, left: i32, top: i32)
(skew_buffer, skew_width, left + skew_min as i32)
}

fn transpose_bitmap(bitmap: &[u8], width: usize, height: usize) -> Vec<u8> {
let mut transposed = vec![0u8; width * height * 4];
for (y, row) in bitmap.chunks(width * 4).enumerate() {
let mut offset = y * 4;
for src in row.chunks(4) {
transposed[offset .. offset + 4].copy_from_slice(src);
offset += height * 4;
}
}
transposed
}

fn flip_bitmap_x(bitmap: &mut [u8], width: usize, height: usize) {
assert!(bitmap.len() == width * height * 4);
let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
for row in pixels.chunks_mut(width) {
row.reverse();
}
}

fn flip_bitmap_y(bitmap: &mut [u8], width: usize, height: usize) {
assert!(bitmap.len() == width * height * 4);
let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
for y in 0 .. height / 2 {
let low_row = y * width;
let high_row = (height - 1 - y) * width;
for x in 0 .. width {
pixels.swap(low_row + x, high_row + x);
}
}
}

impl FontContext {
pub fn new() -> FontContext {
let mut lib: FT_Library = ptr::null_mut();
@@ -250,6 +282,15 @@ impl FontContext {
self.choose_bitmap_size(face.face, req_size * y_scale)
} else {
let mut shape = font.transform.invert_scale(x_scale, y_scale);
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
};
@@ -391,6 +432,18 @@ impl FontContext {
left += skew_min as i32;
width += (skew_max - skew_min) as u32;
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
mem::swap(&mut width, &mut height);
mem::swap(&mut left, &mut top);
left -= width as i32;
top += height as i32;
}
if font.flags.contains(FontInstanceFlags::FLIP_X) {
left = -(left + width as i32);
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
top = -(top - height as i32);
}
}
Some(GlyphDimensions {
left,
@@ -570,7 +623,7 @@ impl FontContext {

let bitmap = unsafe { &(*slot).bitmap };
let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
let (mut actual_width, actual_height) = match pixel_mode {
let (mut actual_width, mut actual_height) = match pixel_mode {
FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
assert!(bitmap.width % 3 == 0);
((bitmap.width / 3) as usize, bitmap.rows as usize)
@@ -677,6 +730,21 @@ impl FontContext {
actual_width = skew_width;
left = skew_left;
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
final_buffer = transpose_bitmap(&final_buffer, actual_width, actual_height);
mem::swap(&mut actual_width, &mut actual_height);
mem::swap(&mut left, &mut top);
left -= actual_width as i32;
top += actual_height as i32;
}
if font.flags.contains(FontInstanceFlags::FLIP_X) {
flip_bitmap_x(&mut final_buffer, actual_width, actual_height);
left = -(left + actual_width as i32);
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
flip_bitmap_y(&mut final_buffer, actual_width, actual_height);
top = -(top - actual_height as i32);
}
}
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
unsafe {
@@ -236,8 +236,23 @@ impl FontContext {
) -> Option<GlyphDimensions> {
let size = font.size.to_f32_px();
let bitmaps = is_bitmap_font(font);
let transform = if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
let shape = FontTransform::identity().synthesize_italics(OBLIQUE_SKEW_FACTOR);
let transform = if font.flags.intersects(FontInstanceFlags::SYNTHETIC_ITALICS |
FontInstanceFlags::TRANSPOSE |
FontInstanceFlags::FLIP_X |
FontInstanceFlags::FLIP_Y) {
let mut shape = FontTransform::identity();
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}
Some(dwrote::DWRITE_MATRIX {
m11: shape.scale_x,
m12: shape.skew_y,
@@ -359,6 +374,15 @@ impl FontContext {
} else {
(font.transform.invert_scale(y_scale, y_scale), font.get_subpx_offset(key))
};
if font.flags.contains(FontInstanceFlags::FLIP_X) {
shape = shape.flip_x();
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
shape = shape.flip_y();
}
if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
shape = shape.swap_xy();
}
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
}
@@ -199,6 +199,16 @@ impl Hash for FontVariation {
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct GlyphOptions {
pub render_mode: FontRenderMode,
pub flags: FontInstanceFlags,
}

impl Default for GlyphOptions {
fn default() -> GlyphOptions {
GlyphOptions {
render_mode: FontRenderMode::Subpixel,
flags: FontInstanceFlags::empty(),
}
}
}

bitflags! {
@@ -210,6 +220,9 @@ bitflags! {
const SYNTHETIC_BOLD = 1 << 1;
const EMBEDDED_BITMAPS = 1 << 2;
const SUBPIXEL_BGR = 1 << 3;
const TRANSPOSE = 1 << 4;
const FLIP_X = 1 << 5;
const FLIP_Y = 1 << 6;

// Windows flags
const FORCE_GDI = 1 << 16;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.