From 3740a7e694b51a4af0e9b6d06cd4c9a66997cd6a Mon Sep 17 00:00:00 2001 From: AJ Ballway Date: Wed, 1 Mar 2017 09:48:13 -0800 Subject: [PATCH] Implement CTFontGetVerticalTranslationsForGlyphs (#2104) Fixes #2025 There is a magic number that the reference platform adds to every vertical glyph translation independent of font. With this constant added to all vertical translations we are within 1 design unit of reference platform values. --- Frameworks/CoreText/CTFont.mm | 29 ++++++++++++++++++++----- include/CoreText/CTFont.h | 5 ++--- tests/unittests/CoreText/CTFontTests.mm | 26 ++++++++++++++++++++-- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/Frameworks/CoreText/CTFont.mm b/Frameworks/CoreText/CTFont.mm index 0eba0367ac..40e7a30890 100644 --- a/Frameworks/CoreText/CTFont.mm +++ b/Frameworks/CoreText/CTFont.mm @@ -96,6 +96,9 @@ const CFStringRef kCTFontDefaultItalicFontName = CFSTR("Arial Italic"); const CFStringRef kCTFontDefaultMonospacedFontName = CFSTR("Courier New"); +// Reference platform adds a constant amount of space (scaled by font size) to each glyph's vertical translation +static const int sc_verticalTranslationSpace = 102; + using namespace Microsoft::WRL; struct __CTFont { @@ -710,8 +713,8 @@ CGPathRef CTFontCreatePathForGlyph(CTFontRef font, CGGlyph glyph, const CGAffine } /** - @Status Stub - @Notes + @Status NotInPlan + @Notes Not much usage, can be easily replaced with CTFontGetGlyphsForCharacters in most common uses */ CGGlyph CTFontGetGlyphWithName(CTFontRef font, CFStringRef glyphName) { UNIMPLEMENTED(); @@ -796,11 +799,27 @@ CGRect CTFontGetBoundingRectsForGlyphs( } /** - @Status Stub + @Status Interoperable @Notes */ void CTFontGetVerticalTranslationsForGlyphs(CTFontRef font, const CGGlyph glyphs[], CGSize translations[], CFIndex count) { - UNIMPLEMENTED(); + if (font && glyphs && translations && count > 0L) { + DWRITE_GLYPH_METRICS metrics[count]; + if (FAILED(font->_dwriteFontFace->GetDesignGlyphMetrics(glyphs, count, metrics, false))) { + TraceError(g_logTag, L"Unable to get glyph metrics"); + return; + } + + std::transform(metrics, metrics + count, translations, [font](const DWRITE_GLYPH_METRICS& metrics) { + if (metrics.advanceWidth == metrics.rightSideBearing && metrics.verticalOriginY == metrics.topSideBearing) { + // Special case of empty glyph, should just return CGRectZero; + return CGSizeZero; + } + + return CGSize{ -__CTFontScaleMetric(font, (metrics.advanceWidth / 2)), + -__CTFontScaleMetric(font, metrics.verticalOriginY - metrics.topSideBearing + sc_verticalTranslationSpace) }; + }); + } } /** @@ -951,4 +970,4 @@ DWRITE_FONT_STYLE _CTFontGetDWriteStyle(CTFontRef font) { return fontFace3->GetStyle(); } return DWRITE_FONT_STYLE_NORMAL; -} \ No newline at end of file +} diff --git a/include/CoreText/CTFont.h b/include/CoreText/CTFont.h index 73cb6131eb..88173f7269 100644 --- a/include/CoreText/CTFont.h +++ b/include/CoreText/CTFont.h @@ -229,13 +229,12 @@ CORETEXT_EXPORT CGFloat CTFontGetSlantAngle(CTFontRef font); CORETEXT_EXPORT CGFloat CTFontGetCapHeight(CTFontRef font); CORETEXT_EXPORT CGFloat CTFontGetXHeight(CTFontRef font); CORETEXT_EXPORT CGPathRef CTFontCreatePathForGlyph(CTFontRef font, CGGlyph glyph, const CGAffineTransform* matrix); -CORETEXT_EXPORT CGGlyph CTFontGetGlyphWithName(CTFontRef font, CFStringRef glyphName) STUB_METHOD; +CORETEXT_EXPORT CGGlyph CTFontGetGlyphWithName(CTFontRef font, CFStringRef glyphName) NOTINPLAN_METHOD; CORETEXT_EXPORT CGRect CTFontGetBoundingRectsForGlyphs( CTFontRef font, CTFontOrientation orientation, const CGGlyph glyphs[], CGRect* boundingRects, CFIndex count); CORETEXT_EXPORT double CTFontGetAdvancesForGlyphs( CTFontRef font, CTFontOrientation orientation, const CGGlyph glyphs[], CGSize* advances, CFIndex count); -CORETEXT_EXPORT void CTFontGetVerticalTranslationsForGlyphs(CTFontRef font, const CGGlyph glyphs[], CGSize translations[], CFIndex count) - STUB_METHOD; +CORETEXT_EXPORT void CTFontGetVerticalTranslationsForGlyphs(CTFontRef font, const CGGlyph glyphs[], CGSize translations[], CFIndex count); CORETEXT_EXPORT CFArrayRef CTFontCopyVariationAxes(CTFontRef font) STUB_METHOD; CORETEXT_EXPORT CFDictionaryRef CTFontCopyVariation(CTFontRef font) STUB_METHOD; CORETEXT_EXPORT CFArrayRef CTFontCopyFeatures(CTFontRef font) STUB_METHOD; diff --git a/tests/unittests/CoreText/CTFontTests.mm b/tests/unittests/CoreText/CTFontTests.mm index 10b17e5561..384d2b4ad9 100644 --- a/tests/unittests/CoreText/CTFontTests.mm +++ b/tests/unittests/CoreText/CTFontTests.mm @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // @@ -740,4 +740,26 @@ virtual void TearDown() { }); CGPathApply(pathWithFontSizeAndTransforms, &comparePathContext, comparePathToExpected); ASSERT_EQ(expectedElements.size(), comparePathContext.count); -} \ No newline at end of file +} + +TEST(CTFont, GetVerticalTranslationsForGLyphs) { + auto font = woc::MakeAutoCF(CTFontCreateWithName(CFSTR("Arial"), 20, nullptr)); + UniChar chars[6] = { 'T', 'e', 's', 't', ' ', '_' }; + CGGlyph glyphs[6]; + CTFontGetGlyphsForCharacters(font, chars, glyphs, 6); + + CGSize translations[6]; + CTFontGetVerticalTranslationsForGlyphs(font, glyphs, translations, 6); + EXPECT_NEAR(-6.1035, translations[0].width, c_errorMargin); + EXPECT_NEAR(-5.5566, translations[1].width, c_errorMargin); + EXPECT_NEAR(-5.000, translations[2].width, c_errorMargin); + EXPECT_NEAR(-2.7734, translations[3].width, c_errorMargin); + EXPECT_NEAR(0, translations[4].width, c_errorMargin); + EXPECT_NEAR(-5.5566, translations[5].width, c_errorMargin); + EXPECT_NEAR(-15.3125, translations[0].height, c_errorMargin); + EXPECT_NEAR(-11.6016, translations[1].height, c_errorMargin); + EXPECT_NEAR(-11.6016, translations[2].height, c_errorMargin); + EXPECT_NEAR(-14.9902, translations[3].height, c_errorMargin); + EXPECT_NEAR(0, translations[4].height, c_errorMargin); + EXPECT_NEAR(1.70898, translations[5].height, c_errorMargin); +}