Add test of char to glyph round tripping.
This also tries to work around some surprising behavior on macOS, which
may cause attributing space glyphs to character 9 instead of 32.
This also updates the gdi character to glyph mapping for non BMP
characters on Windows 10. This forces all uniscribe script analysis to
simple to get just the default cmap mapping without shaping.
Change-Id: Id93a2de6de27ab61fbf034f5087e93e4c7e839ba
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/215431
Reviewed-by: Hal Canary <halcanary@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp
index ae53f6a..cd0f29a 100644
--- a/src/ports/SkFontHost_mac.cpp
+++ b/src/ports/SkFontHost_mac.cpp
@@ -1597,7 +1597,10 @@
if (CTFontGetGlyphsForCharacters(ctFont, utf16, glyphs, count)) {
SkASSERT(glyphs[1] == 0);
SkASSERT(glyphs[0] < glyphCount);
- if (glyphToUnicode[glyphs[0]] == 0) {
+ // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support'
+ // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20?
+ // Prefer mappings to codepoints at or above 0x20.
+ if (glyphToUnicode[glyphs[0]] < 0x20) {
glyphToUnicode[glyphs[0]] = codepoint;
}
}
@@ -1605,8 +1608,6 @@
}
}
// Construct Glyph to Unicode table.
-// Unicode code points that require conjugate pairs in utf16 are not
-// supported.
static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
SkUnichar* glyphToUnicode) {
sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index 0d35136..111bebb 100644
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -1889,7 +1889,27 @@
WORD outGlyphs[maxGlyphs];
WORD logClust[numWCHAR];
int numGlyphs;
- HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
+ SCRIPT_ANALYSIS& script = si[0].a;
+ script.eScript = SCRIPT_UNDEFINED;
+ script.fRTL = FALSE;
+ script.fLayoutRTL = FALSE;
+ script.fLinkBefore = FALSE;
+ script.fLinkAfter = FALSE;
+ script.fLogicalOrder = FALSE;
+ script.fNoGlyphIndex = FALSE;
+ script.s.uBidiLevel = 0;
+ script.s.fOverrideDirection = 0;
+ script.s.fInhibitSymSwap = TRUE;
+ script.s.fCharShape = FALSE;
+ script.s.fDigitSubstitute = FALSE;
+ script.s.fInhibitLigate = FALSE;
+ script.s.fDisplayZWG = TRUE;
+ script.s.fArabicNumContext = FALSE;
+ script.s.fGcpClusters = FALSE;
+ script.s.fReserved = 0;
+ script.s.fEngineReserved = 0;
+ // For the future, 0x80040200 from here is USP_E_SCRIPT_NOT_IN_FONT
+ HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &script,
outGlyphs, logClust, vsa, &numGlyphs),
"Could not shape character.");
if (1 == numGlyphs) {
diff --git a/tests/TypefaceTest.cpp b/tests/TypefaceTest.cpp
index b1c330b..e1dfff6 100644
--- a/tests/TypefaceTest.cpp
+++ b/tests/TypefaceTest.cpp
@@ -10,15 +10,20 @@
#include "include/core/SkRefCnt.h"
#include "include/core/SkStream.h"
#include "include/core/SkTypeface.h"
+#include "include/ports/SkTypeface_win.h"
#include "include/private/SkFixed.h"
#include "src/core/SkAdvancedTypefaceMetrics.h"
#include "src/core/SkFontDescriptor.h"
+#include "src/core/SkFontMgrPriv.h"
+#include "src/core/SkFontPriv.h"
#include "src/core/SkMakeUnique.h"
#include "src/core/SkTypefaceCache.h"
#include "src/sfnt/SkOTTable_OS_2.h"
#include "src/sfnt/SkSFNTHeader.h"
+#include "src/utils/SkUTF.h"
#include "tests/Test.h"
#include "tools/Resources.h"
+#include "tools/ToolUtils.h"
#include "tools/fonts/TestEmptyTypeface.h"
#include <memory>
@@ -323,3 +328,38 @@
}
+DEF_TEST(Typeface_glyph_to_char, reporter) {
+ SkFont font(ToolUtils::emoji_typeface(), 12);
+ SkASSERT(font.getTypeface());
+ char const * text = ToolUtils::emoji_sample_text();
+ size_t const textLen = strlen(text);
+ size_t const codepointCount = SkUTF::CountUTF8(text, textLen);
+ char const * const textEnd = text + textLen;
+ std::unique_ptr<SkUnichar[]> originalCodepoints(new SkUnichar[codepointCount]);
+ for (size_t i = 0; i < codepointCount; ++i) {
+ originalCodepoints[i] = SkUTF::NextUTF8(&text, textEnd);
+ }
+ std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[codepointCount]);
+ font.unicharsToGlyphs(originalCodepoints.get(), codepointCount, glyphs.get());
+
+ std::unique_ptr<SkUnichar[]> newCodepoints(new SkUnichar[codepointCount]);
+ SkFontPriv::GlyphsToUnichars(font, glyphs.get(), codepointCount, newCodepoints.get());
+
+ SkString familyName;
+ font.getTypeface()->getFamilyName(&familyName);
+ for (size_t i = 0; i < codepointCount; ++i) {
+#if defined(SK_BUILD_FOR_WIN)
+ // GDI does not support character to glyph mapping outside BMP.
+ if (gSkFontMgr_DefaultFactory == &SkFontMgr_New_GDI &&
+ 0xFFFF < originalCodepoints[i] && newCodepoints[i] == 0)
+ {
+ continue;
+ }
+#endif
+ // If two codepoints map to the same glyph then this assert is not valid.
+ // However, the emoji test font should never have multiple characters map to the same glyph.
+ REPORTER_ASSERT(reporter, originalCodepoints[i] == newCodepoints[i],
+ "name:%s i:%d original:%d new:%d glyph:%d", familyName.c_str(), i,
+ originalCodepoints[i], newCodepoints[i], glyphs[i]);
+ }
+}