1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkDWrite.h" 9#include "SkHRESULT.h" 10#include "SkOnce.h" 11#include "SkString.h" 12 13#include <dwrite.h> 14 15static IDWriteFactory* gDWriteFactory = NULL; 16 17static void release_dwrite_factory() { 18 if (gDWriteFactory) { 19 gDWriteFactory->Release(); 20 } 21} 22 23static void create_dwrite_factory(IDWriteFactory** factory) { 24 typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; 25 DWriteCreateFactoryProc dWriteCreateFactoryProc = reinterpret_cast<DWriteCreateFactoryProc>( 26 GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory")); 27 28 if (!dWriteCreateFactoryProc) { 29 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 30 if (!IS_ERROR(hr)) { 31 hr = ERROR_PROC_NOT_FOUND; 32 } 33 HRVM(hr, "Could not get DWriteCreateFactory proc."); 34 } 35 36 HRVM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED, 37 __uuidof(IDWriteFactory), 38 reinterpret_cast<IUnknown**>(factory)), 39 "Could not create DirectWrite factory."); 40 atexit(release_dwrite_factory); 41} 42 43 44IDWriteFactory* sk_get_dwrite_factory() { 45 SK_DECLARE_STATIC_ONCE(once); 46 SkOnce(&once, create_dwrite_factory, &gDWriteFactory); 47 48 return gDWriteFactory; 49} 50 51//////////////////////////////////////////////////////////////////////////////// 52// String conversion 53 54/** Converts a utf8 string to a WCHAR string. */ 55HRESULT sk_cstring_to_wchar(const char* skname, SkSMallocWCHAR* name) { 56 int wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, NULL, 0); 57 if (0 == wlen) { 58 HRM(HRESULT_FROM_WIN32(GetLastError()), 59 "Could not get length for wchar to utf-8 conversion."); 60 } 61 name->reset(wlen); 62 wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, name->get(), wlen); 63 if (0 == wlen) { 64 HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert wchar to utf-8."); 65 } 66 return S_OK; 67} 68 69/** Converts a WCHAR string to a utf8 string. */ 70HRESULT sk_wchar_to_skstring(WCHAR* name, SkString* skname) { 71 int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); 72 if (0 == len) { 73 HRM(HRESULT_FROM_WIN32(GetLastError()), 74 "Could not get length for utf-8 to wchar conversion."); 75 } 76 skname->resize(len - 1); 77 78 // TODO: remove after https://code.google.com/p/skia/issues/detail?id=1989 is fixed. 79 // If we resize to 0 then the skname points to gEmptyRec (the unique empty SkString::Rec). 80 // gEmptyRec is static const and on Windows this means the value is in a read only page. 81 // Writing to it in the following call to WideCharToMultiByte will cause an access violation. 82 if (1 == len) { 83 return S_OK; 84 } 85 86 len = WideCharToMultiByte(CP_UTF8, 0, name, -1, skname->writable_str(), len, NULL, NULL); 87 if (0 == len) { 88 HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert utf-8 to wchar."); 89 } 90 return S_OK; 91} 92 93//////////////////////////////////////////////////////////////////////////////// 94// Locale 95 96void sk_get_locale_string(IDWriteLocalizedStrings* names, const WCHAR* preferedLocale, 97 SkString* skname) { 98 UINT32 nameIndex = 0; 99 if (preferedLocale) { 100 // Ignore any errors and continue with index 0 if there is a problem. 101 BOOL nameExists; 102 names->FindLocaleName(preferedLocale, &nameIndex, &nameExists); 103 if (!nameExists) { 104 nameIndex = 0; 105 } 106 } 107 108 UINT32 nameLength; 109 HRVM(names->GetStringLength(nameIndex, &nameLength), "Could not get name length."); 110 nameLength += 1; 111 112 SkSMallocWCHAR name(nameLength); 113 HRVM(names->GetString(nameIndex, name.get(), nameLength), "Could not get string."); 114 115 HRV(sk_wchar_to_skstring(name.get(), skname)); 116} 117 118HRESULT SkGetGetUserDefaultLocaleNameProc(SkGetUserDefaultLocaleNameProc* proc) { 119 *proc = reinterpret_cast<SkGetUserDefaultLocaleNameProc>( 120 GetProcAddress(LoadLibraryW(L"Kernel32.dll"), "GetUserDefaultLocaleName") 121 ); 122 if (!*proc) { 123 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 124 if (!IS_ERROR(hr)) { 125 hr = ERROR_PROC_NOT_FOUND; 126 } 127 return hr; 128 } 129 return S_OK; 130} 131