{"action":"created","comment":{"url":"https://api.github.com/repos/Microsoft/WinObjC/pulls/comments/84748322","pull_request_review_id":5506218,"id":84748322,"diff_hunk":"@@ -0,0 +1,525 @@\n+//******************************************************************************\n+//\n+// Copyright (c) Microsoft. All rights reserved.\n+//\n+// This code is licensed under the MIT License (MIT).\n+//\n+// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n+// THE SOFTWARE.\n+//\n+//******************************************************************************\n+\n+// #1207: Do not move this block, it has to come first for some reason\n+#include <COMIncludes.h>\n+#import <wrl/implements.h>\n+#include <COMIncludes_End.h>\n+\n+#import <CoreGraphics/DWriteWrapper.h>\n+#import <Starboard.h>\n+\n+#import <vector>\n+\n+using namespace std;\n+using namespace Microsoft::WRL;\n+\n+static const wchar_t* TAG = L\"_DWriteWrapper\";\n+static const wchar_t* c_defaultUserLanguage = L\"en-us\";\n+\n+/**\n+ * Private helper method to return the user set default locale string.\n+ *\n+ * @return use set locale string as wstring.\n+ */\n+static wstring __GetUserDefaultLocaleName() {\n+    wchar_t localeName[LOCALE_NAME_MAX_LENGTH];\n+    int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);\n+\n+    // If the default locale is returned, find that locale name, otherwise use \"en-us\".\n+    return wstring(defaultLocaleSuccess ? localeName : c_defaultUserLanguage);\n+}\n+\n+/**\n+ * Helper method to convert IDWriteLocalizedStrings object to CFString object.\n+ *\n+ * @parameter localizedString IDWriteLocalizedStrings object to convert.\n+ *\n+ * @return CFString object.\n+ */\n+CFStringRef _CFStringFromLocalizedString(IDWriteLocalizedStrings* localizedString) {\n+    if (localizedString == NULL) {\n+        TraceError(TAG, L\"The input parameter is invalid!\");\n+        return nil;\n+    }\n+\n+    // Get the default locale for this user.\n+    wstring localeName = __GetUserDefaultLocaleName();\n+\n+    uint32_t index = 0;\n+    BOOL exists = false;\n+\n+    // If the default locale is returned, find that locale name, otherwise use \"en-us\".\n+    RETURN_NULL_IF_FAILED(localizedString->FindLocaleName(localeName.c_str(), &index, &exists));\n+    if (!exists) {\n+        RETURN_NULL_IF_FAILED(localizedString->FindLocaleName(c_defaultUserLanguage, &index, &exists));\n+    }\n+\n+    // If the specified locale doesn't exist, select the first on the list.\n+    if (!exists) {\n+        index = 0;\n+    }\n+\n+    // Get the string length.\n+    uint32_t length = 0;\n+    RETURN_NULL_IF_FAILED(localizedString->GetStringLength(index, &length));\n+\n+    // Get the string.\n+    vector<wchar_t> wcharString = std::vector<wchar_t>(length + 1, 0);\n+    RETURN_NULL_IF_FAILED(localizedString->GetString(index, wcharString.data(), length + 1));\n+\n+    // Strip out unnecessary null terminator\n+    return (CFStringRef)CFAutorelease(\n+        CFStringCreateWithCharacters(kCFAllocatorSystemDefault, reinterpret_cast<UniChar*>(wcharString.data()), length));\n+}\n+\n+/**\n+ * Helper method to retrieve font family names installed in the system.\n+ *\n+ * @return Immutable array of font family name strings that are installed in the system.\n+ */\n+CFArrayRef _DWriteGetFontFamilyNames() {\n+    woc::unique_cf<CFMutableArrayRef> fontFamilyNames(CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks));\n+\n+    // Get the direct write factory instance\n+    ComPtr<IDWriteFactory> dwriteFactory;\n+    RETURN_NULL_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &dwriteFactory));\n+\n+    // Get the system font collection.\n+    ComPtr<IDWriteFontCollection> fontCollection;\n+    RETURN_NULL_IF_FAILED(dwriteFactory->GetSystemFontCollection(&fontCollection));\n+\n+    // Get the number of font families in the collection.\n+    uint32_t count = 0;\n+    count = fontCollection->GetFontFamilyCount();\n+\n+    for (uint32_t i = 0; i < count; ++i) {\n+        // Get the font family.\n+        ComPtr<IDWriteFontFamily> fontFamily;\n+        RETURN_NULL_IF_FAILED(fontCollection->GetFontFamily(i, &fontFamily));\n+\n+        // Get a list of localized strings for the family name.\n+        ComPtr<IDWriteLocalizedStrings> familyNames;\n+        RETURN_NULL_IF_FAILED(fontFamily->GetFamilyNames(&familyNames));\n+\n+        CFStringRef name = _CFStringFromLocalizedString(familyNames.Get());\n+        if (CFStringGetLength(name) == 0) {\n+            TraceError(TAG, L\"Failed to convert the localized string to wide string.\");\n+            continue;\n+        }\n+\n+        CFArrayAppendValue(fontFamilyNames.get(), name);\n+    }\n+\n+    return static_cast<CFArrayRef>(CFAutorelease(fontFamilyNames.release()));\n+}\n+\n+/**\n+ * Helper method to retrieve names of individual fonts under a font family.\n+ */\n+CFArrayRef _DWriteGetFontNamesForFamilyName(CFStringRef familyName) {\n+    woc::unique_cf<CFMutableArrayRef> fontNames(CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks));\n+\n+    ComPtr<IDWriteFactory> dwriteFactory;\n+    RETURN_NULL_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &dwriteFactory));\n+\n+    // Get the system font collection.\n+    ComPtr<IDWriteFontCollection> fontCollection;\n+    RETURN_NULL_IF_FAILED(dwriteFactory->GetSystemFontCollection(&fontCollection));\n+\n+    // Get the font family.\n+    CFIndex familyNameLength = CFStringGetLength(familyName);\n+    std::vector<UniChar> unicharFamilyName(familyNameLength + 1);\n+    CFStringGetCharacters(familyName, CFRangeMake(0, familyNameLength), unicharFamilyName.data());\n+\n+    size_t index = 0;\n+    BOOL exists = false;\n+\n+    RETURN_NULL_IF_FAILED(fontCollection->FindFamilyName(reinterpret_cast<wchar_t*>(unicharFamilyName.data()), &index, &exists));\n+    if (!exists) {\n+        TraceError(TAG, L\"Failed to find the font family name.\");\n+        return static_cast<CFArrayRef>(CFAutorelease(fontNames.release()));\n+    }\n+\n+    ComPtr<IDWriteFontFamily> fontFamily;\n+    RETURN_NULL_IF_FAILED(fontCollection->GetFontFamily(index, &fontFamily));\n+\n+    ComPtr<IDWriteFontList> fontList;\n+    RETURN_NULL_IF_FAILED(\n+        fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_THIN, DWRITE_FONT_STRETCH_UNDEFINED, DWRITE_FONT_STYLE_NORMAL, &fontList));\n+\n+    size_t count = fontList->GetFontCount();\n+\n+    for (size_t i = 0; i < count; i++) {\n+        ComPtr<IDWriteFont> font;\n+        RETURN_NULL_IF_FAILED(fontList->GetFont(i, &font));\n+\n+        ComPtr<IDWriteLocalizedStrings> fullName;\n+        BOOL exist = FALSE;\n+        RETURN_NULL_IF_FAILED(font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fullName, &exist));\n+\n+        if (exist) {\n+            CFStringRef name = _CFStringFromLocalizedString(fullName.Get());\n+            if (CFStringGetLength(name) == 0) {\n+                TraceError(TAG, L\"Failed to convert the localized string to wide string.\");\n+                continue;\n+            }\n+\n+            CFArrayAppendValue(fontNames.get(), name);\n+        }\n+    }\n+\n+    return static_cast<CFArrayRef>(CFAutorelease(fontNames.release()));\n+}\n+\n+/**\n+ * Helper method that maps a font name to the name of its family.\n+ *\n+ * Note: This function currently uses a cache, meaning that fonts installed during runtime will not be reflected\n+ */\n+CFStringRef _DWriteGetFamilyNameForFontName(CFStringRef fontName) {\n+    woc::unique_cf<CFLocaleRef> locale(CFLocaleCopyCurrent());\n+\n+    static CFDictionaryRef fontToFamilyMap = [&locale]() {\n+        // initialize fontToFamilyMap\n+        woc::unique_cf<CFMutableDictionaryRef> initMap(\n+            CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));\n+\n+        CFArrayRef familyNames = _DWriteGetFontFamilyNames();\n+\n+        for (size_t i = 0; i < CFArrayGetCount(familyNames); ++i) {\n+            CFStringRef familyName = static_cast<CFStringRef>(CFArrayGetValueAtIndex(familyNames, i));\n+            CFArrayRef fontNames = _DWriteGetFontNamesForFamilyName(familyName);\n+\n+            for (size_t j = 0; j < CFArrayGetCount(fontNames); j++) {\n+                CFStringRef systemFontName = static_cast<CFStringRef>(CFArrayGetValueAtIndex(fontNames, j));\n+                woc::unique_cf<CFMutableStringRef> upperSystemFontName(\n+                    CFStringCreateMutableCopy(nullptr, CFStringGetLength(systemFontName), systemFontName));\n+                CFStringUppercase(upperSystemFontName.get(), locale.get());\n+                CFDictionaryAddValue(initMap.get(), upperSystemFontName.get(), familyName);\n+            }\n+        }\n+\n+        return CFDictionaryCreateCopy(kCFAllocatorSystemDefault, initMap.get());\n+    }();\n+\n+    woc::unique_cf<CFMutableStringRef> upperFontName(CFStringCreateMutableCopy(nullptr, CFStringGetLength(fontName), fontName));\n+    CFStringUppercase(upperFontName.get(), locale.get());\n+    return static_cast<CFStringRef>(CFDictionaryGetValue(fontToFamilyMap, upperFontName.get()));\n+}\n+\n+// Represents a mapping between multiple representations of the same font weight across font names, DWrite, and CoreText\n+// eg: CFSTR(\"BOLD\") = DWRITE_FONT_WEIGHT_BOLD = kCTFontWeightBold\n+struct WeightMapping {\n+    CFStringRef stringValue;\n+    DWRITE_FONT_WEIGHT dwriteValue;\n+};\n+\n+// Mapping for weight\n+// Some loss of precision here as CT presents fewer values than DWrite\n+// Note also that Thin and Ultra/Extra-Light are in opposite order in DWrite and CoreText/UIKit constants\n+// (However, \"Thin\" fonts on the reference platform have UIFontWeightUltraLight...)\n+static const struct WeightMapping c_weightMap[] = { { CFSTR(\"THIN\"), DWRITE_FONT_WEIGHT_THIN },\n+                                                    { CFSTR(\"EXTRALIGHT\"), DWRITE_FONT_WEIGHT_EXTRA_LIGHT },\n+                                                    { CFSTR(\"ULTRALIGHT\"), DWRITE_FONT_WEIGHT_ULTRA_LIGHT },\n+                                                    { CFSTR(\"LIGHT\"), DWRITE_FONT_WEIGHT_LIGHT },\n+                                                    { CFSTR(\"SEMILIGHT\"), DWRITE_FONT_WEIGHT_SEMI_LIGHT },\n+                                                    { CFSTR(\"NORMAL\"), DWRITE_FONT_WEIGHT_NORMAL },\n+                                                    { CFSTR(\"REGULAR\"), DWRITE_FONT_WEIGHT_REGULAR },\n+                                                    { CFSTR(\"MEDIUM\"), DWRITE_FONT_WEIGHT_REGULAR },\n+                                                    { CFSTR(\"DEMIBOLD\"), DWRITE_FONT_WEIGHT_DEMI_BOLD },\n+                                                    { CFSTR(\"DEMI\"), DWRITE_FONT_WEIGHT_DEMI_BOLD },\n+                                                    { CFSTR(\"SEMIBOLD\"), DWRITE_FONT_WEIGHT_SEMI_BOLD },\n+                                                    { CFSTR(\"BOLD\"), DWRITE_FONT_WEIGHT_BOLD },\n+                                                    { CFSTR(\"EXTRABOLD\"), DWRITE_FONT_WEIGHT_EXTRA_BOLD },\n+                                                    { CFSTR(\"ULTRABOLD\"), DWRITE_FONT_WEIGHT_ULTRA_BOLD },\n+                                                    { CFSTR(\"BLACK\"), DWRITE_FONT_WEIGHT_BLACK },\n+                                                    { CFSTR(\"HEAVY\"), DWRITE_FONT_WEIGHT_HEAVY },\n+                                                    { CFSTR(\"EXTRABLACK\"), DWRITE_FONT_WEIGHT_EXTRA_BLACK },\n+                                                    { CFSTR(\"ULTRABLACK\"), DWRITE_FONT_WEIGHT_ULTRA_BLACK } };\n+\n+/**\n+ * Helper that parses a font name, and returns appropriate weight, stretch, style, and family name values\n+ */\n+_DWriteFontProperties _DWriteGetFontPropertiesFromName(CFStringRef fontName) {\n+    _DWriteFontProperties ret;\n+\n+    // Set some defaults for when weight/stretch/style are not mentioned in the name\n+    ret.weight = DWRITE_FONT_WEIGHT_NORMAL;\n+    ret.stretch = DWRITE_FONT_STRETCH_NORMAL;\n+    ret.style = DWRITE_FONT_STYLE_NORMAL;\n+\n+    ret.familyName = _DWriteGetFamilyNameForFontName(fontName);\n+\n+    // Relationship of family name -> font name not always consistent\n+    // Usually, properties are added to the end (eg: Arial -> Arial Narrow Bold)\n+    // However, this is not always the case (eg: Eras ITC -> Eras Bold ITC)\n+    // In addition, some fonts with properties are occasionally placed into their own family (eg: Segoe WP SemiLight -> Segoe WP SemiLight)\n+    // Try to be more prudent about these edge cases, by looking only at the difference between the font name and family name\n+    woc::unique_cf<CFArrayRef> fontNameTokens(CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, fontName, CFSTR(\" \")));\n+    woc::unique_cf<CFMutableSetRef> propertyTokens(CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks));\n+\n+    for (size_t i = 0; i < CFArrayGetCount(fontNameTokens.get()); ++i) {\n+        CFSetAddValue(propertyTokens.get(), CFArrayGetValueAtIndex(fontNameTokens.get(), i));\n+    }\n+\n+    if (ret.familyName) {\n+        woc::unique_cf<CFArrayRef> familyNameTokens(\n+            CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, ret.familyName, CFSTR(\" \")));\n+        for (size_t i = 0; i < CFArrayGetCount(familyNameTokens.get()); ++i) {\n+            CFSetRemoveValue(propertyTokens.get(), CFArrayGetValueAtIndex(familyNameTokens.get(), i));\n+        }\n+    }\n+\n+    CFSetApplierFunction initPropertyFromToken = [](const void* value, void* context) {\n+        CFMutableStringRef propertyToken = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, static_cast<CFStringRef>(value));\n+        _DWriteFontProperties* properties = reinterpret_cast<_DWriteFontProperties*>(context);\n+\n+        // Font names are not always consistent about capitalization (SemiLight vs Semilight)\n+        // Standardize on uppercase\n+        CFStringUppercase(propertyToken, CFLocaleGetSystem());\n+\n+        // Possible optimization here that can be done by using a dictionary,\n+        // but seems excessive given that font names generally don't have more than three modifiers\n+        for (const auto& weightMapping : c_weightMap) {\n+            if (CFEqual(propertyToken, weightMapping.stringValue)) {\n+                properties->weight = weightMapping.dwriteValue;\n+                break;\n+            }\n+        }\n+\n+        if (CFEqual(propertyToken, CFSTR(\"UNDEFINED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_UNDEFINED;\n+        } else if (CFEqual(propertyToken, CFSTR(\"ULTRACONDENSED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_ULTRA_CONDENSED;\n+        } else if (CFEqual(propertyToken, CFSTR(\"EXTRACONDENSED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_EXTRA_CONDENSED;\n+        } else if (CFEqual(propertyToken, CFSTR(\"CONDENSED\")) || CFEqual(propertyToken, CFSTR(\"NARROW\")) ||\n+                   CFEqual(propertyToken, CFSTR(\"COND\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_CONDENSED;\n+        } else if (CFEqual(propertyToken, CFSTR(\"SEMICONDENSED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_SEMI_CONDENSED;\n+            // skip since this is the default\n+            // } else if (CFEqual(propertyToken, CFSTR(\"NORMAL\"))) {\n+            //     properties->stretch = DWRITE_FONT_STRETCH_NORMAL;\n+\n+        } else if (CFEqual(propertyToken, CFSTR(\"SEMIEXPANDED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_SEMI_EXPANDED;\n+        } else if (CFEqual(propertyToken, CFSTR(\"EXPANDED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_EXPANDED;\n+        } else if (CFEqual(propertyToken, CFSTR(\"EXTRAEXPANDED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_EXTRA_EXPANDED;\n+        } else if (CFEqual(propertyToken, CFSTR(\"ULTRAEXPANDED\"))) {\n+            properties->stretch = DWRITE_FONT_STRETCH_ULTRA_EXPANDED;\n+\n+            // skip since this is the default\n+            // } else if (CFEqual(propertyToken, CFSTR(\"NORMAL\"))) {\n+            //     properties->style = DWRITE_FONT_STYLE_NORMAL;\n+        } else if (CFEqual(propertyToken, CFSTR(\"OBLIQUE\"))) {\n+            properties->style = DWRITE_FONT_STYLE_OBLIQUE;\n+        } else if (CFEqual(propertyToken, CFSTR(\"ITALIC\"))) {\n+            properties->style = DWRITE_FONT_STYLE_ITALIC;\n+        }\n+    };\n+\n+    CFSetApplyFunction(propertyTokens.get(), initPropertyFromToken, &ret);\n+    return ret;\n+}\n+\n+/**\n+ * Creates a DWrite text format object using the system font collection\n+ */\n+HRESULT _DWriteCreateTextFormat(const wchar_t* fontFamilyName,\n+                                DWRITE_FONT_WEIGHT weight,\n+                                DWRITE_FONT_STYLE style,\n+                                DWRITE_FONT_STRETCH stretch,\n+                                float fontSize,\n+                                IDWriteTextFormat** outTextFormat) {\n+    // Get the direct write factory instance\n+    ComPtr<IDWriteFactory> dwriteFactory;\n+    RETURN_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &dwriteFactory));\n+\n+    return dwriteFactory->CreateTextFormat(fontFamilyName,\n+                                           nullptr,\n+                                           weight,\n+                                           style,\n+                                           stretch,\n+                                           fontSize,\n+                                           __GetUserDefaultLocaleName().data(),\n+                                           outTextFormat); //\n+}\n+\n+/**\n+ * Helper that creates a IDWriteFontFamily object for a given family name\n+ */\n+HRESULT _DWriteCreateFontFamilyWithName(CFStringRef familyName, IDWriteFontFamily** outFontFamily) {\n+    ComPtr<IDWriteFactory> dwriteFactory;\n+    RETURN_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &dwriteFactory));\n+\n+    ComPtr<IDWriteFontCollection> systemFontCollection;\n+    RETURN_IF_FAILED(dwriteFactory->GetSystemFontCollection(&systemFontCollection));\n+\n+    CFIndex familyNameLength = CFStringGetLength(familyName);\n+    std::vector<UniChar> unicharFamilyName(familyNameLength + 1);\n+    CFStringGetCharacters(familyName, CFRangeMake(0, familyNameLength), unicharFamilyName.data());\n+\n+    size_t fontFamilyIndex;\n+    BOOL fontFamilyExists;\n+\n+    RETURN_IF_FAILED(systemFontCollection->FindFamilyName(reinterpret_cast<const wchar_t*>(unicharFamilyName.data()),\n+                                                          &fontFamilyIndex,\n+                                                          &fontFamilyExists));\n+\n+    if (!fontFamilyExists) {\n+        TraceError(TAG, L\"Unable to find font family \\\"%ws\\\"\", unicharFamilyName.data());\n+        return E_INVALIDARG;\n+    }\n+\n+    return systemFontCollection->GetFontFamily(fontFamilyIndex, outFontFamily);\n+}\n+\n+/**\n+ * Helper function that creates an IDWriteFontFace object for a given font name.\n+ */\n+HRESULT _DWriteCreateFontFaceWithName(CFStringRef name, IDWriteFontFace** outFontFace) {\n+    // Parse the font name for font weight, stretch, and style\n+    // Eg: Bold, Condensed, Light, Italic\n+    _DWriteFontProperties properties = _DWriteGetFontPropertiesFromName(name);\n+\n+    RETURN_HR_IF_NULL(E_INVALIDARG, properties.familyName);\n+\n+    ComPtr<IDWriteFontFamily> fontFamily;\n+    RETURN_IF_FAILED(_DWriteCreateFontFamilyWithName(properties.familyName, &fontFamily));\n+    RETURN_HR_IF_NULL(E_INVALIDARG, fontFamily);\n+\n+    ComPtr<IDWriteFont> font;\n+    RETURN_IF_FAILED(fontFamily->GetFirstMatchingFont(properties.weight, properties.stretch, properties.style, &font));\n+\n+    return font->CreateFontFace(outFontFace);\n+}\n+\n+/**\n+ * Gets an informational string as a CFString from a DWrite font face.\n+ */\n+CFStringRef _DWriteFontCopyInformationalString(const ComPtr<IDWriteFontFace>& fontFace,\n+                                               DWRITE_INFORMATIONAL_STRING_ID informationalStringId) {\n+    RETURN_NULL_IF(!fontFace);\n+\n+    ComPtr<IDWriteFontFace3> dwriteFontFace3;\n+    RETURN_NULL_IF_FAILED(fontFace.As(&dwriteFontFace3));\n+\n+    ComPtr<IDWriteLocalizedStrings> name;\n+    BOOL exists;\n+\n+    RETURN_NULL_IF_FAILED(dwriteFontFace3->GetInformationalStrings(informationalStringId, &name, &exists));\n+    return exists ? static_cast<CFStringRef>(CFRetain(_CFStringFromLocalizedString(name.Get()))) : nullptr;\n+}\n+\n+/**\n+ * Gets a font table as a CFDataRef from a DWrite font face\n+ */\n+CFDataRef _DWriteFontCopyTable(const ComPtr<IDWriteFontFace>& fontFace, uint32_t tag) {\n+    const void* tableData;\n+    uint32_t tableSize;\n+    void* tableContext;\n+    BOOL exists;\n+\n+    if (FAILED(fontFace->TryGetFontTable(tag, &tableData, &tableSize, &tableContext, &exists)) || !exists) {\n+        TraceError(TAG, L\"Unable to get font table for tag %u\", tag);\n+        return nullptr;\n+    }","path":"Frameworks/CoreGraphics/DWriteWrapper.mm","position":443,"original_position":443,"commit_id":"43b6e0acff20544c2264bfebcf2e94c982bb3ecd","original_commit_id":"43b6e0acff20544c2264bfebcf2e94c982bb3ecd","user":{"login":"bbowman","id":15642573,"avatar_url":"https://avatars.githubusercontent.com/u/15642573?v=3","gravatar_id":"","url":"https://api.github.com/users/bbowman","html_url":"https://github.com/bbowman","followers_url":"https://api.github.com/users/bbowman/followers","following_url":"https://api.github.com/users/bbowman/following{/other_user}","gists_url":"https://api.github.com/users/bbowman/gists{/gist_id}","starred_url":"https://api.github.com/users/bbowman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bbowman/subscriptions","organizations_url":"https://api.github.com/users/bbowman/orgs","repos_url":"https://api.github.com/users/bbowman/repos","events_url":"https://api.github.com/users/bbowman/events{/privacy}","received_events_url":"https://api.github.com/users/bbowman/received_events","type":"User","site_admin":false},"body":"return macro?","created_at":"2016-10-24T18:11:46Z","updated_at":"2016-10-24T18:11:46Z","html_url":"https://github.com/Microsoft/WinObjC/pull/1145#discussion_r84748322","pull_request_url":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145","_links":{"self":{"href":"https://api.github.com/repos/Microsoft/WinObjC/pulls/comments/84748322"},"html":{"href":"https://github.com/Microsoft/WinObjC/pull/1145#discussion_r84748322"},"pull_request":{"href":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145"}}},"pull_request":{"url":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145","id":89276794,"html_url":"https://github.com/Microsoft/WinObjC/pull/1145","diff_url":"https://github.com/Microsoft/WinObjC/pull/1145.diff","patch_url":"https://github.com/Microsoft/WinObjC/pull/1145.patch","issue_url":"https://api.github.com/repos/Microsoft/WinObjC/issues/1145","number":1145,"state":"open","locked":false,"title":"Implement CGFont with DWrite","user":{"login":"ms-jihua","id":16024095,"avatar_url":"https://avatars.githubusercontent.com/u/16024095?v=3","gravatar_id":"","url":"https://api.github.com/users/ms-jihua","html_url":"https://github.com/ms-jihua","followers_url":"https://api.github.com/users/ms-jihua/followers","following_url":"https://api.github.com/users/ms-jihua/following{/other_user}","gists_url":"https://api.github.com/users/ms-jihua/gists{/gist_id}","starred_url":"https://api.github.com/users/ms-jihua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ms-jihua/subscriptions","organizations_url":"https://api.github.com/users/ms-jihua/orgs","repos_url":"https://api.github.com/users/ms-jihua/repos","events_url":"https://api.github.com/users/ms-jihua/events{/privacy}","received_events_url":"https://api.github.com/users/ms-jihua/received_events","type":"User","site_admin":false},"body":" - Move majority of DWriteWrapper into CoreGraphics, leave CT-specific functions in CoreText as DWriteWrapper_CoreText\r\n     - Minor edits to handling of keywords \"Medium\", \"Demi\", and \"Cond\" when creating a font with name\r\n - Strip out use of FreeType in CGContextCairo/Impl\r\n - Implement CTFont bounding box functions, as they had counterparts in CGFont\r\n - Add unit tests\r\n\r\nFixes #1018\r\nFixes #1065","created_at":"2016-10-13T20:31:52Z","updated_at":"2016-10-24T18:11:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0429efe06bcfe352f8e360e45a6d5cf475f36189","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145/commits","review_comments_url":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145/comments","review_comment_url":"https://api.github.com/repos/Microsoft/WinObjC/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Microsoft/WinObjC/issues/1145/comments","statuses_url":"https://api.github.com/repos/Microsoft/WinObjC/statuses/43b6e0acff20544c2264bfebcf2e94c982bb3ecd","head":{"label":"ms-jihua:cgfont_1013","ref":"cgfont_1013","sha":"43b6e0acff20544c2264bfebcf2e94c982bb3ecd","user":{"login":"ms-jihua","id":16024095,"avatar_url":"https://avatars.githubusercontent.com/u/16024095?v=3","gravatar_id":"","url":"https://api.github.com/users/ms-jihua","html_url":"https://github.com/ms-jihua","followers_url":"https://api.github.com/users/ms-jihua/followers","following_url":"https://api.github.com/users/ms-jihua/following{/other_user}","gists_url":"https://api.github.com/users/ms-jihua/gists{/gist_id}","starred_url":"https://api.github.com/users/ms-jihua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ms-jihua/subscriptions","organizations_url":"https://api.github.com/users/ms-jihua/orgs","repos_url":"https://api.github.com/users/ms-jihua/repos","events_url":"https://api.github.com/users/ms-jihua/events{/privacy}","received_events_url":"https://api.github.com/users/ms-jihua/received_events","type":"User","site_admin":false},"repo":{"id":63092436,"name":"WinObjC","full_name":"ms-jihua/WinObjC","owner":{"login":"ms-jihua","id":16024095,"avatar_url":"https://avatars.githubusercontent.com/u/16024095?v=3","gravatar_id":"","url":"https://api.github.com/users/ms-jihua","html_url":"https://github.com/ms-jihua","followers_url":"https://api.github.com/users/ms-jihua/followers","following_url":"https://api.github.com/users/ms-jihua/following{/other_user}","gists_url":"https://api.github.com/users/ms-jihua/gists{/gist_id}","starred_url":"https://api.github.com/users/ms-jihua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ms-jihua/subscriptions","organizations_url":"https://api.github.com/users/ms-jihua/orgs","repos_url":"https://api.github.com/users/ms-jihua/repos","events_url":"https://api.github.com/users/ms-jihua/events{/privacy}","received_events_url":"https://api.github.com/users/ms-jihua/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ms-jihua/WinObjC","description":"Objective-C for Windows","fork":true,"url":"https://api.github.com/repos/ms-jihua/WinObjC","forks_url":"https://api.github.com/repos/ms-jihua/WinObjC/forks","keys_url":"https://api.github.com/repos/ms-jihua/WinObjC/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ms-jihua/WinObjC/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ms-jihua/WinObjC/teams","hooks_url":"https://api.github.com/repos/ms-jihua/WinObjC/hooks","issue_events_url":"https://api.github.com/repos/ms-jihua/WinObjC/issues/events{/number}","events_url":"https://api.github.com/repos/ms-jihua/WinObjC/events","assignees_url":"https://api.github.com/repos/ms-jihua/WinObjC/assignees{/user}","branches_url":"https://api.github.com/repos/ms-jihua/WinObjC/branches{/branch}","tags_url":"https://api.github.com/repos/ms-jihua/WinObjC/tags","blobs_url":"https://api.github.com/repos/ms-jihua/WinObjC/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ms-jihua/WinObjC/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ms-jihua/WinObjC/git/refs{/sha}","trees_url":"https://api.github.com/repos/ms-jihua/WinObjC/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ms-jihua/WinObjC/statuses/{sha}","languages_url":"https://api.github.com/repos/ms-jihua/WinObjC/languages","stargazers_url":"https://api.github.com/repos/ms-jihua/WinObjC/stargazers","contributors_url":"https://api.github.com/repos/ms-jihua/WinObjC/contributors","subscribers_url":"https://api.github.com/repos/ms-jihua/WinObjC/subscribers","subscription_url":"https://api.github.com/repos/ms-jihua/WinObjC/subscription","commits_url":"https://api.github.com/repos/ms-jihua/WinObjC/commits{/sha}","git_commits_url":"https://api.github.com/repos/ms-jihua/WinObjC/git/commits{/sha}","comments_url":"https://api.github.com/repos/ms-jihua/WinObjC/comments{/number}","issue_comment_url":"https://api.github.com/repos/ms-jihua/WinObjC/issues/comments{/number}","contents_url":"https://api.github.com/repos/ms-jihua/WinObjC/contents/{+path}","compare_url":"https://api.github.com/repos/ms-jihua/WinObjC/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ms-jihua/WinObjC/merges","archive_url":"https://api.github.com/repos/ms-jihua/WinObjC/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ms-jihua/WinObjC/downloads","issues_url":"https://api.github.com/repos/ms-jihua/WinObjC/issues{/number}","pulls_url":"https://api.github.com/repos/ms-jihua/WinObjC/pulls{/number}","milestones_url":"https://api.github.com/repos/ms-jihua/WinObjC/milestones{/number}","notifications_url":"https://api.github.com/repos/ms-jihua/WinObjC/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ms-jihua/WinObjC/labels{/name}","releases_url":"https://api.github.com/repos/ms-jihua/WinObjC/releases{/id}","deployments_url":"https://api.github.com/repos/ms-jihua/WinObjC/deployments","created_at":"2016-07-11T18:32:57Z","updated_at":"2016-07-11T18:33:10Z","pushed_at":"2016-10-22T00:35:43Z","git_url":"git://github.com/ms-jihua/WinObjC.git","ssh_url":"git@github.com:ms-jihua/WinObjC.git","clone_url":"https://github.com/ms-jihua/WinObjC.git","svn_url":"https://github.com/ms-jihua/WinObjC","homepage":"","size":331967,"stargazers_count":0,"watchers_count":0,"language":"Objective-C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"develop"}},"base":{"label":"Microsoft:CT-DW","ref":"CT-DW","sha":"1b720bf9c496dcac4c5df38a8ad2368e808523ee","user":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars.githubusercontent.com/u/6154722?v=3","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"repo":{"id":37950166,"name":"WinObjC","full_name":"Microsoft/WinObjC","owner":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars.githubusercontent.com/u/6154722?v=3","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Microsoft/WinObjC","description":"Objective-C for Windows","fork":false,"url":"https://api.github.com/repos/Microsoft/WinObjC","forks_url":"https://api.github.com/repos/Microsoft/WinObjC/forks","keys_url":"https://api.github.com/repos/Microsoft/WinObjC/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Microsoft/WinObjC/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Microsoft/WinObjC/teams","hooks_url":"https://api.github.com/repos/Microsoft/WinObjC/hooks","issue_events_url":"https://api.github.com/repos/Microsoft/WinObjC/issues/events{/number}","events_url":"https://api.github.com/repos/Microsoft/WinObjC/events","assignees_url":"https://api.github.com/repos/Microsoft/WinObjC/assignees{/user}","branches_url":"https://api.github.com/repos/Microsoft/WinObjC/branches{/branch}","tags_url":"https://api.github.com/repos/Microsoft/WinObjC/tags","blobs_url":"https://api.github.com/repos/Microsoft/WinObjC/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Microsoft/WinObjC/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Microsoft/WinObjC/git/refs{/sha}","trees_url":"https://api.github.com/repos/Microsoft/WinObjC/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Microsoft/WinObjC/statuses/{sha}","languages_url":"https://api.github.com/repos/Microsoft/WinObjC/languages","stargazers_url":"https://api.github.com/repos/Microsoft/WinObjC/stargazers","contributors_url":"https://api.github.com/repos/Microsoft/WinObjC/contributors","subscribers_url":"https://api.github.com/repos/Microsoft/WinObjC/subscribers","subscription_url":"https://api.github.com/repos/Microsoft/WinObjC/subscription","commits_url":"https://api.github.com/repos/Microsoft/WinObjC/commits{/sha}","git_commits_url":"https://api.github.com/repos/Microsoft/WinObjC/git/commits{/sha}","comments_url":"https://api.github.com/repos/Microsoft/WinObjC/comments{/number}","issue_comment_url":"https://api.github.com/repos/Microsoft/WinObjC/issues/comments{/number}","contents_url":"https://api.github.com/repos/Microsoft/WinObjC/contents/{+path}","compare_url":"https://api.github.com/repos/Microsoft/WinObjC/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Microsoft/WinObjC/merges","archive_url":"https://api.github.com/repos/Microsoft/WinObjC/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Microsoft/WinObjC/downloads","issues_url":"https://api.github.com/repos/Microsoft/WinObjC/issues{/number}","pulls_url":"https://api.github.com/repos/Microsoft/WinObjC/pulls{/number}","milestones_url":"https://api.github.com/repos/Microsoft/WinObjC/milestones{/number}","notifications_url":"https://api.github.com/repos/Microsoft/WinObjC/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Microsoft/WinObjC/labels{/name}","releases_url":"https://api.github.com/repos/Microsoft/WinObjC/releases{/id}","deployments_url":"https://api.github.com/repos/Microsoft/WinObjC/deployments","created_at":"2015-06-23T23:14:58Z","updated_at":"2016-10-24T06:20:10Z","pushed_at":"2016-10-24T17:00:52Z","git_url":"git://github.com/Microsoft/WinObjC.git","ssh_url":"git@github.com:Microsoft/WinObjC.git","clone_url":"https://github.com/Microsoft/WinObjC.git","svn_url":"https://github.com/Microsoft/WinObjC","homepage":"","size":364210,"stargazers_count":5481,"watchers_count":5481,"language":"Objective-C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":713,"mirror_url":null,"open_issues_count":250,"forks":713,"open_issues":250,"watchers":5481,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145"},"html":{"href":"https://github.com/Microsoft/WinObjC/pull/1145"},"issue":{"href":"https://api.github.com/repos/Microsoft/WinObjC/issues/1145"},"comments":{"href":"https://api.github.com/repos/Microsoft/WinObjC/issues/1145/comments"},"review_comments":{"href":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145/comments"},"review_comment":{"href":"https://api.github.com/repos/Microsoft/WinObjC/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Microsoft/WinObjC/pulls/1145/commits"},"statuses":{"href":"https://api.github.com/repos/Microsoft/WinObjC/statuses/43b6e0acff20544c2264bfebcf2e94c982bb3ecd"}}}}
{"actor":{"display_login":"bbowman"}}