172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com/* 272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com * Copyright 2014 Google Inc. 372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com * 472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com * Use of this source code is governed by a BSD-style license that can be 572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com * found in the LICENSE file. 672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com */ 772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com#include "SkDWrite.h" 972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com#include "SkHRESULT.h" 1072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com#include "SkOnce.h" 1172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com#include "SkString.h" 1272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 1372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com#include <dwrite.h> 1472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 1572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.comstatic IDWriteFactory* gDWriteFactory = NULL; 1672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 171b81877880253c75f835eede9a8ee21b9e7b584amtkleinstatic void release_dwrite_factory() { 181b81877880253c75f835eede9a8ee21b9e7b584amtklein if (gDWriteFactory) { 191b81877880253c75f835eede9a8ee21b9e7b584amtklein gDWriteFactory->Release(); 201b81877880253c75f835eede9a8ee21b9e7b584amtklein } 211b81877880253c75f835eede9a8ee21b9e7b584amtklein} 221b81877880253c75f835eede9a8ee21b9e7b584amtklein 2372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.comstatic void create_dwrite_factory(IDWriteFactory** factory) { 2472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; 2572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com DWriteCreateFactoryProc dWriteCreateFactoryProc = reinterpret_cast<DWriteCreateFactoryProc>( 2672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory")); 2772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 2872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (!dWriteCreateFactoryProc) { 2972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 3072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (!IS_ERROR(hr)) { 3172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com hr = ERROR_PROC_NOT_FOUND; 3272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 3372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRVM(hr, "Could not get DWriteCreateFactory proc."); 3472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 3572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 3672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRVM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED, 3772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com __uuidof(IDWriteFactory), 3872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com reinterpret_cast<IUnknown**>(factory)), 3972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com "Could not create DirectWrite factory."); 401b81877880253c75f835eede9a8ee21b9e7b584amtklein atexit(release_dwrite_factory); 4172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com} 4272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 4372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 4472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.comIDWriteFactory* sk_get_dwrite_factory() { 4572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com SK_DECLARE_STATIC_ONCE(once); 461b81877880253c75f835eede9a8ee21b9e7b584amtklein SkOnce(&once, create_dwrite_factory, &gDWriteFactory); 4772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 4872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com return gDWriteFactory; 4972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com} 5072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 5172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com//////////////////////////////////////////////////////////////////////////////// 5272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com// String conversion 5372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 5472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com/** Converts a utf8 string to a WCHAR string. */ 5572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.comHRESULT sk_cstring_to_wchar(const char* skname, SkSMallocWCHAR* name) { 5672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com int wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, NULL, 0); 5772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (0 == wlen) { 5872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRM(HRESULT_FROM_WIN32(GetLastError()), 5972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com "Could not get length for wchar to utf-8 conversion."); 6072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 6172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com name->reset(wlen); 6272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, name->get(), wlen); 6372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (0 == wlen) { 6472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert wchar to utf-8."); 6572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 6672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com return S_OK; 6772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com} 6872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 6972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com/** Converts a WCHAR string to a utf8 string. */ 7072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.comHRESULT sk_wchar_to_skstring(WCHAR* name, SkString* skname) { 7172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); 7272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (0 == len) { 7372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRM(HRESULT_FROM_WIN32(GetLastError()), 7472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com "Could not get length for utf-8 to wchar conversion."); 7572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 7672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com skname->resize(len - 1); 7772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 7872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com // TODO: remove after https://code.google.com/p/skia/issues/detail?id=1989 is fixed. 7972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com // If we resize to 0 then the skname points to gEmptyRec (the unique empty SkString::Rec). 8072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com // gEmptyRec is static const and on Windows this means the value is in a read only page. 8172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com // Writing to it in the following call to WideCharToMultiByte will cause an access violation. 8272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (1 == len) { 8372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com return S_OK; 8472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 8572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 8672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com len = WideCharToMultiByte(CP_UTF8, 0, name, -1, skname->writable_str(), len, NULL, NULL); 8772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (0 == len) { 8872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert utf-8 to wchar."); 8972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 9072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com return S_OK; 9172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com} 9272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 9372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com//////////////////////////////////////////////////////////////////////////////// 9472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com// Locale 9572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 9672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.comvoid sk_get_locale_string(IDWriteLocalizedStrings* names, const WCHAR* preferedLocale, 9772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com SkString* skname) { 9872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com UINT32 nameIndex = 0; 9972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (preferedLocale) { 10072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com // Ignore any errors and continue with index 0 if there is a problem. 10172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com BOOL nameExists; 10272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com names->FindLocaleName(preferedLocale, &nameIndex, &nameExists); 10372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (!nameExists) { 10472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com nameIndex = 0; 10572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 10672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 10772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 10872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com UINT32 nameLength; 10972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRVM(names->GetStringLength(nameIndex, &nameLength), "Could not get name length."); 11072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com nameLength += 1; 11172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 11272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com SkSMallocWCHAR name(nameLength); 11372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRVM(names->GetString(nameIndex, name.get(), nameLength), "Could not get string."); 11472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 11572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRV(sk_wchar_to_skstring(name.get(), skname)); 11672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com} 11772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com 11872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.comHRESULT SkGetGetUserDefaultLocaleNameProc(SkGetUserDefaultLocaleNameProc* proc) { 11972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com *proc = reinterpret_cast<SkGetUserDefaultLocaleNameProc>( 12072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com GetProcAddress(LoadLibraryW(L"Kernel32.dll"), "GetUserDefaultLocaleName") 12172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com ); 12272cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (!*proc) { 12372cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); 12472cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com if (!IS_ERROR(hr)) { 12572cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com hr = ERROR_PROC_NOT_FOUND; 12672cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 12772cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com return hr; 12872cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com } 12972cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com return S_OK; 13072cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com} 131