diff --git a/scripts/gen-shaping-tests.py b/scripts/gen-shaping-tests.py index 9545ea65..7118074f 100755 --- a/scripts/gen-shaping-tests.py +++ b/scripts/gen-shaping-tests.py @@ -48,19 +48,15 @@ # which we don't do yet. Is basically the same as morx_20_005, but with `--show-flags` "glyph_flags_002", - # These currently return different results from harfbuzz. - "colr_003", - "colr_006", - "colr_007", - "colr_008", - "colr_009", - "colr_010", + # The glyph extents are shifted 100 units to the right in HarfBuzz due to "undocumented rasterizer behavior" + # (see https://github.com/harfbuzz/harfbuzz/blob/462a54895b97cf5a3fd023f4ea5528a9b0e14e0e/src/OT/glyf/Glyph.hh#L520-L528 + # and https://github.com/harfbuzz/harfbuzz/pull/1999). + # ttf-parser currently does not implement this. "colr_011", - "colr_012", + + # Requires support in ttf-parser (https://github.com/harfbuzz/ttf-parser/pull/185) "colr_014", - "colr_015", - "colr_016", - "colr_018", + "colr_021", ] diff --git a/src/hb/face.rs b/src/hb/face.rs index 1198913a..11890f5f 100644 --- a/src/hb/face.rs +++ b/src/hb/face.rs @@ -267,10 +267,6 @@ impl<'a> hb_font_t<'a> { return true; } } else if let Some(colr) = self.ttfp_face.tables().colr { - if colr.is_simple() { - return false; - } - if let Some(clip_box) = colr.clip_box(glyph, self.variation_coordinates()) { // Floor glyph_extents.x_bearing = (clip_box.x_min).round() as i32; @@ -304,7 +300,9 @@ impl<'a> hb_font_t<'a> { glyph_extents.height = (e.y_min - e.y_max) as i32; } - return ret; + if ret { + return true; + } } let mut bbox = None; diff --git a/src/hb/paint_extents.rs b/src/hb/paint_extents.rs index d41a4142..df2e0610 100644 --- a/src/hb/paint_extents.rs +++ b/src/hb/paint_extents.rs @@ -26,17 +26,17 @@ impl hb_extents_t { } pub fn union_(&mut self, o: &hb_extents_t) { - self.x_min = o.x_min.min(o.x_min); - self.y_min = o.y_min.min(o.y_min); - self.x_max = o.x_max.max(o.x_max); - self.y_max = o.y_max.max(o.y_max); + self.x_min = self.x_min.min(o.x_min); + self.y_min = self.y_min.min(o.y_min); + self.x_max = self.x_max.max(o.x_max); + self.y_max = self.y_max.max(o.y_max); } pub fn intersect(&mut self, o: &hb_extents_t) { - self.x_min = o.x_min.max(o.x_min); - self.y_min = o.y_min.max(o.y_min); - self.x_max = o.x_max.min(o.x_max); - self.y_max = o.y_max.min(o.y_max); + self.x_min = self.x_min.max(o.x_min); + self.y_min = self.y_min.max(o.y_min); + self.x_max = self.x_max.min(o.x_max); + self.y_max = self.y_max.min(o.y_max); } } @@ -174,7 +174,10 @@ impl<'a> hb_paint_extents_context_t<'a> { r.transform_extents(&mut extents); } - let b = hb_bounds_t::from_extents(&extents); + let mut b = hb_bounds_t::from_extents(&extents); + if let Some(clip) = self.clips.last() { + b.intersect(clip); + } self.clips.push(b); } diff --git a/tests/custom/colr.tests b/tests/custom/colr.tests index 9759744b..f08a9849 100644 --- a/tests/custom/colr.tests +++ b/tests/custom/colr.tests @@ -17,4 +17,5 @@ tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf;--show-extents;U+F tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf;--show-extents;U+F1100,U+F1101; tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf;--show-extents;U+F1200; tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf;--show-extents;U+F1300,U+F1301,U+F1302,U+F1303,U+F1304,U+F1305,U+F1306,U+F1307,U+F1308,U+F1309,U+F130A,U+F130B,U+F130C,U+F130D,U+F130E,U+F130F,U+F1310,U+F1311,U+F1312,U+F1313,U+F1314,U+F1315,U+F1316,U+F1317; -tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf;--show-extents;U+F1400,U+F1401,U+F1402,U+F1403,U+F1404,U+F1405,U+F1406,U+F1407,U+F1408,U+F1409,U+F140A,U+F140B,U+F140C,U+F140D,U+F140E,U+F140F; \ No newline at end of file +tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf;--show-extents;U+F1400,U+F1401,U+F1402,U+F1403,U+F1404,U+F1405,U+F1406,U+F1407,U+F1408,U+F1409,U+F140A,U+F140B,U+F140C,U+F140D,U+F140E,U+F140F; +tests/fonts/rb_custom/BungeeTint-Regular.ttf;--show-extents;U+0041,U+0042,U+0043,U+002C; \ No newline at end of file diff --git a/tests/fonts/rb_custom/BungeeTint-Regular-OFL.txt b/tests/fonts/rb_custom/BungeeTint-Regular-OFL.txt new file mode 100644 index 00000000..6f47072f --- /dev/null +++ b/tests/fonts/rb_custom/BungeeTint-Regular-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2023 The Bungee Project Authors (https://github.com/djrrb/Bungee) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/tests/fonts/rb_custom/BungeeTint-Regular.ttf b/tests/fonts/rb_custom/BungeeTint-Regular.ttf new file mode 100644 index 00000000..0fd831f2 Binary files /dev/null and b/tests/fonts/rb_custom/BungeeTint-Regular.ttf differ diff --git a/tests/shaping/custom.rs b/tests/shaping/custom.rs index ed968451..2062dbf0 100644 --- a/tests/shaping/custom.rs +++ b/tests/shaping/custom.rs @@ -145,6 +145,23 @@ fn colr_002() { ); } +#[test] +fn colr_003() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0300}\u{F0301}\u{F0302}\u{F0303}\u{F0304}\u{F0305}", + "--show-extents", + ), + "scale_0.5_1.5_center_500.0_500.0=0+1000<250,875,500,-750>|\ + scale_1.5_1.5_center_500.0_500.0=1+1000<125,875,750,-750>|\ + scale_0.5_1.5_center_0_0=2+1000<125,1125,625,-875>|\ + scale_1.5_1.5_center_0_0=3+1000<250,1125,875,-875>|\ + scale_0.5_1.5_center_1000_1000=4+1000<250,750,625,-875>|\ + scale_1.5_1.5_center_1000_1000=5+1000<-125,750,875,-875>" + ); +} + #[test] fn colr_004() { assert_eq!( @@ -176,6 +193,135 @@ fn colr_005() { ); } +#[test] +fn colr_006() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0600}\u{F0601}\u{F0602}\u{F0603}", + "--show-extents", + ), + "rotate_10_center_0_0=0+1000<115,868,634,-618>|\ + rotate_-10_center_1000_1000=1+1000<131,884,618,-634>|\ + rotate_25_center_500.0_500.0=2+1000<167,832,664,-664>|\ + rotate_-15_center_500.0_500.0=3+1000<193,806,612,-612>" + ); +} + +#[test] +fn colr_007() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0700}\u{F0701}\u{F0702}\u{F0703}\u{F0704}\u{F0705}", + "--show-extents", + ), + "skew_25_0_center_0_0=0+1000<-99,750,849,-500>|\ + skew_25_0_center_500.0_500.0=1+1000<133,750,733,-500>|\ + skew_0_15_center_0_0=2+1000<250,950,500,-700>|\ + skew_0_15_center_500.0_500.0=3+1000<250,816,500,-633>|\ + skew_-10_20_center_500.0_500.0=4+1000<205,840,588,-681>|\ + skew_-10_20_center_1000_1000=5+1000<117,750,632,-772>" + ); +} + +#[test] +fn colr_008() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0800}\u{F0801}\u{F0802}\u{F0803}", + "--show-extents", + ), + "transform_matrix_1_0_0_1_125_125=0+1000<250,875,625,-625>|\ + transform_matrix_1.5_0_0_1.5_0_0=1+1000<250,1125,875,-875>|\ + transform_matrix_0.9659_0.2588_-0.2588_0.9659_0_0=2+1000<47,918,702,-668>|\ + transform_matrix_1.0_0.0_0.6_1.0_-300.0_0.0=3+1000<100,750,800,-500>" + ); +} + +#[test] +fn colr_009() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0900}\u{F0901}\u{F0902}\u{F0903}\u{F0904}\u{F0905}\u{F0906}", + "--show-extents", + ), + "translate_0_0=0+1000<250,750,500,-500>|\ + translate_0_100=1+1000<250,850,500,-600>|\ + translate_0_-100=2+1000<250,750,500,-600>|\ + translate_100_0=3+1000<250,750,600,-500>|\ + translate_-100_0=4+1000<150,750,600,-500>|\ + translate_200_200=5+1000<250,950,700,-700>|\ + translate_-200_-200=6+1000<50,750,700,-700>" + ); +} + +#[test] +fn colr_010() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0A00}\u{F0A01}\u{F0A02}\u{F0A03}\u{F0A04}\u{F0A05}\u{F0A06}\u{F0A07}\u{F0A08}\u{F0A09}\ + \u{F0A0A}\u{F0A0B}\u{F0A0C}\u{F0A0D}\u{F0A0E}\u{F0A0F}\u{F0A10}\u{F0A11}\u{F0A12}\u{F0A13}\ + \u{F0A14}\u{F0A15}\u{F0A16}\u{F0A17}\u{F0A18}\u{F0A19}\u{F0A1A}\u{F0A1B}", + "--show-extents", + ), + "composite_CLEAR=0+1000<250,750,500,-500>|\ + composite_SRC=1+1000<250,750,583,-583>|\ + composite_DEST=2+1000<166,833,583,-583>|\ + composite_SRC_OVER=3+1000<166,833,667,-667>|\ + composite_DEST_OVER=4+1000<166,833,667,-667>|\ + composite_SRC_IN=5+1000<250,750,500,-500>|\ + composite_DEST_IN=6+1000<250,750,500,-500>|\ + composite_SRC_OUT=7+1000<250,750,583,-583>|\ + composite_DEST_OUT=8+1000<166,833,583,-583>|\ + composite_SRC_ATOP=9+1000<166,833,667,-667>|\ + composite_DEST_ATOP=10+1000<166,833,667,-667>|\ + composite_XOR=11+1000<166,833,667,-667>|\ + composite_PLUS=12+1000<166,833,667,-667>|\ + composite_SCREEN=13+1000<166,833,667,-667>|\ + composite_OVERLAY=14+1000<166,833,667,-667>|\ + composite_DARKEN=15+1000<166,833,667,-667>|\ + composite_LIGHTEN=16+1000<166,833,667,-667>|\ + composite_COLOR_DODGE=17+1000<166,833,667,-667>|\ + composite_COLOR_BURN=18+1000<166,833,667,-667>|\ + composite_HARD_LIGHT=19+1000<166,833,667,-667>|\ + composite_SOFT_LIGHT=20+1000<166,833,667,-667>|\ + composite_DIFFERENCE=21+1000<166,833,667,-667>|\ + composite_EXCLUSION=22+1000<166,833,667,-667>|\ + composite_MULTIPLY=23+1000<166,833,667,-667>|\ + composite_HSL_HUE=24+1000<166,833,667,-667>|\ + composite_HSL_SATURATION=25+1000<166,833,667,-667>|\ + composite_HSL_COLOR=26+1000<166,833,667,-667>|\ + composite_HSL_LUMINOSITY=27+1000<166,833,667,-667>" + ); +} + +#[test] +fn colr_012() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0C00}\u{F0C01}\u{F0C02}\u{F0C03}\u{F0C04}\u{F0C05}\u{F0C06}\u{F0C07}\u{F0C08}\u{F0C09}\ + \u{F0C0A}", + "--show-extents", + ), + "clip_box_top_left=0+1000<0,1000,1000,-1000>|\ + clip_box_bottom_left=1+1000<0,1000,1000,-1000>|\ + clip_box_bottom_right=2+1000<0,1000,1000,-1000>|\ + clip_box_top_right=3+1000<0,1000,1000,-1000>|\ + clip_box_center=4+1000<0,1000,1000,-1000>|\ + clip_shade_top_left=5+1000<0,1000,500,-500>|\ + clip_shade_bottom_left=6+1000<0,500,500,-500>|\ + clip_shade_bottom_right=7+1000<500,500,500,-500>|\ + clip_shade_top_right=8+1000<500,1000,500,-500>|\ + clip_shade_center=9+1000<250,750,500,-500>|\ + inset_clipped_radial_reflect=10+1000<0,1000,1000,-1000>" + ); +} + #[test] fn colr_013() { assert_eq!( @@ -188,6 +334,36 @@ fn colr_013() { ); } +#[test] +fn colr_015() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F0F00}\u{F0F01}\u{F0F02}\u{F0F03}\u{F0F04}\u{F0F05}\u{F0F06}", + "--show-extents", + ), + "circle_r50=0+1000<450,650,100,-100>|\ + circle_r100=1+1000<400,700,200,-200>|\ + circle_r150=2+1000<350,750,300,-300>|\ + circle_r200=3+1000<300,800,400,-400>|\ + circle_r250=4+1000<250,850,500,-500>|\ + circle_r300=5+1000<200,900,600,-600>|\ + circle_r350=6+1000<150,950,700,-700>" + ); +} + +#[test] +fn colr_016() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F1000}", + "--show-extents", + ), + "solid_colorline_alpha=0+1000<0,950,1000,-700>" + ); +} + #[test] fn colr_017() { assert_eq!( @@ -201,6 +377,18 @@ fn colr_017() { ); } +#[test] +fn colr_018() { + assert_eq!( + shape( + "tests/fonts/rb_custom/test_glyphs-glyf_colr_1_no_cliplist.ttf", + "\u{F1200}", + "--show-extents", + ), + "no_cycle_multi_colrglyph=0+1000<0,950,1000,-700>" + ); +} + #[test] fn colr_019() { assert_eq!(