1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright © 2011,2012,2013 Google, Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * This is part of HarfBuzz, a text shaping library. 5cb93a386Sopenharmony_ci * 6cb93a386Sopenharmony_ci * Permission is hereby granted, without written agreement and without 7cb93a386Sopenharmony_ci * license or royalty fees, to use, copy, modify, and distribute this 8cb93a386Sopenharmony_ci * software and its documentation for any purpose, provided that the 9cb93a386Sopenharmony_ci * above copyright notice and the following two paragraphs appear in 10cb93a386Sopenharmony_ci * all copies of this software. 11cb93a386Sopenharmony_ci * 12cb93a386Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13cb93a386Sopenharmony_ci * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14cb93a386Sopenharmony_ci * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15cb93a386Sopenharmony_ci * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16cb93a386Sopenharmony_ci * DAMAGE. 17cb93a386Sopenharmony_ci * 18cb93a386Sopenharmony_ci * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19cb93a386Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20cb93a386Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21cb93a386Sopenharmony_ci * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22cb93a386Sopenharmony_ci * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23cb93a386Sopenharmony_ci * 24cb93a386Sopenharmony_ci * Google Author(s): Behdad Esfahbod 25cb93a386Sopenharmony_ci */ 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci#include "hb.hh" 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci#ifdef HAVE_UNISCRIBE 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci#ifdef HB_NO_OT_TAG 32cb93a386Sopenharmony_ci#error "Cannot compile 'uniscribe' shaper with HB_NO_OT_TAG." 33cb93a386Sopenharmony_ci#endif 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci#include "hb-shaper-impl.hh" 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci#include <windows.h> 38cb93a386Sopenharmony_ci#include <usp10.h> 39cb93a386Sopenharmony_ci#include <rpc.h> 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci#ifndef E_NOT_SUFFICIENT_BUFFER 42cb93a386Sopenharmony_ci#define E_NOT_SUFFICIENT_BUFFER HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER) 43cb93a386Sopenharmony_ci#endif 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci#include "hb-uniscribe.h" 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci#include "hb-ms-feature-ranges.hh" 48cb93a386Sopenharmony_ci#include "hb-open-file.hh" 49cb93a386Sopenharmony_ci#include "hb-ot-name-table.hh" 50cb93a386Sopenharmony_ci#include "hb-ot-layout.h" 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci/** 54cb93a386Sopenharmony_ci * SECTION:hb-uniscribe 55cb93a386Sopenharmony_ci * @title: hb-uniscribe 56cb93a386Sopenharmony_ci * @short_description: Windows integration 57cb93a386Sopenharmony_ci * @include: hb-uniscribe.h 58cb93a386Sopenharmony_ci * 59cb93a386Sopenharmony_ci * Functions for using HarfBuzz with Windows fonts. 60cb93a386Sopenharmony_ci **/ 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_citypedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/( 63cb93a386Sopenharmony_ci const WCHAR *pwcInChars, 64cb93a386Sopenharmony_ci int cInChars, 65cb93a386Sopenharmony_ci int cMaxItems, 66cb93a386Sopenharmony_ci const SCRIPT_CONTROL *psControl, 67cb93a386Sopenharmony_ci const SCRIPT_STATE *psState, 68cb93a386Sopenharmony_ci SCRIPT_ITEM *pItems, 69cb93a386Sopenharmony_ci OPENTYPE_TAG *pScriptTags, 70cb93a386Sopenharmony_ci int *pcItems 71cb93a386Sopenharmony_ci); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_citypedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/( 74cb93a386Sopenharmony_ci HDC hdc, 75cb93a386Sopenharmony_ci SCRIPT_CACHE *psc, 76cb93a386Sopenharmony_ci SCRIPT_ANALYSIS *psa, 77cb93a386Sopenharmony_ci OPENTYPE_TAG tagScript, 78cb93a386Sopenharmony_ci OPENTYPE_TAG tagLangSys, 79cb93a386Sopenharmony_ci int *rcRangeChars, 80cb93a386Sopenharmony_ci TEXTRANGE_PROPERTIES **rpRangeProperties, 81cb93a386Sopenharmony_ci int cRanges, 82cb93a386Sopenharmony_ci const WCHAR *pwcChars, 83cb93a386Sopenharmony_ci int cChars, 84cb93a386Sopenharmony_ci int cMaxGlyphs, 85cb93a386Sopenharmony_ci WORD *pwLogClust, 86cb93a386Sopenharmony_ci SCRIPT_CHARPROP *pCharProps, 87cb93a386Sopenharmony_ci WORD *pwOutGlyphs, 88cb93a386Sopenharmony_ci SCRIPT_GLYPHPROP *pOutGlyphProps, 89cb93a386Sopenharmony_ci int *pcGlyphs 90cb93a386Sopenharmony_ci); 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_citypedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/( 93cb93a386Sopenharmony_ci HDC hdc, 94cb93a386Sopenharmony_ci SCRIPT_CACHE *psc, 95cb93a386Sopenharmony_ci SCRIPT_ANALYSIS *psa, 96cb93a386Sopenharmony_ci OPENTYPE_TAG tagScript, 97cb93a386Sopenharmony_ci OPENTYPE_TAG tagLangSys, 98cb93a386Sopenharmony_ci int *rcRangeChars, 99cb93a386Sopenharmony_ci TEXTRANGE_PROPERTIES **rpRangeProperties, 100cb93a386Sopenharmony_ci int cRanges, 101cb93a386Sopenharmony_ci const WCHAR *pwcChars, 102cb93a386Sopenharmony_ci WORD *pwLogClust, 103cb93a386Sopenharmony_ci SCRIPT_CHARPROP *pCharProps, 104cb93a386Sopenharmony_ci int cChars, 105cb93a386Sopenharmony_ci const WORD *pwGlyphs, 106cb93a386Sopenharmony_ci const SCRIPT_GLYPHPROP *pGlyphProps, 107cb93a386Sopenharmony_ci int cGlyphs, 108cb93a386Sopenharmony_ci int *piAdvance, 109cb93a386Sopenharmony_ci GOFFSET *pGoffset, 110cb93a386Sopenharmony_ci ABC *pABC 111cb93a386Sopenharmony_ci); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci/* Fallback implementations. */ 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_cistatic HRESULT WINAPI 117cb93a386Sopenharmony_cihb_ScriptItemizeOpenType( 118cb93a386Sopenharmony_ci const WCHAR *pwcInChars, 119cb93a386Sopenharmony_ci int cInChars, 120cb93a386Sopenharmony_ci int cMaxItems, 121cb93a386Sopenharmony_ci const SCRIPT_CONTROL *psControl, 122cb93a386Sopenharmony_ci const SCRIPT_STATE *psState, 123cb93a386Sopenharmony_ci SCRIPT_ITEM *pItems, 124cb93a386Sopenharmony_ci OPENTYPE_TAG *pScriptTags, 125cb93a386Sopenharmony_ci int *pcItems 126cb93a386Sopenharmony_ci) 127cb93a386Sopenharmony_ci{ 128cb93a386Sopenharmony_ci{ 129cb93a386Sopenharmony_ci return ScriptItemize (pwcInChars, 130cb93a386Sopenharmony_ci cInChars, 131cb93a386Sopenharmony_ci cMaxItems, 132cb93a386Sopenharmony_ci psControl, 133cb93a386Sopenharmony_ci psState, 134cb93a386Sopenharmony_ci pItems, 135cb93a386Sopenharmony_ci pcItems); 136cb93a386Sopenharmony_ci} 137cb93a386Sopenharmony_ci} 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_cistatic HRESULT WINAPI 140cb93a386Sopenharmony_cihb_ScriptShapeOpenType( 141cb93a386Sopenharmony_ci HDC hdc, 142cb93a386Sopenharmony_ci SCRIPT_CACHE *psc, 143cb93a386Sopenharmony_ci SCRIPT_ANALYSIS *psa, 144cb93a386Sopenharmony_ci OPENTYPE_TAG tagScript, 145cb93a386Sopenharmony_ci OPENTYPE_TAG tagLangSys, 146cb93a386Sopenharmony_ci int *rcRangeChars, 147cb93a386Sopenharmony_ci TEXTRANGE_PROPERTIES **rpRangeProperties, 148cb93a386Sopenharmony_ci int cRanges, 149cb93a386Sopenharmony_ci const WCHAR *pwcChars, 150cb93a386Sopenharmony_ci int cChars, 151cb93a386Sopenharmony_ci int cMaxGlyphs, 152cb93a386Sopenharmony_ci WORD *pwLogClust, 153cb93a386Sopenharmony_ci SCRIPT_CHARPROP *pCharProps, 154cb93a386Sopenharmony_ci WORD *pwOutGlyphs, 155cb93a386Sopenharmony_ci SCRIPT_GLYPHPROP *pOutGlyphProps, 156cb93a386Sopenharmony_ci int *pcGlyphs 157cb93a386Sopenharmony_ci) 158cb93a386Sopenharmony_ci{ 159cb93a386Sopenharmony_ci SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps; 160cb93a386Sopenharmony_ci return ScriptShape (hdc, 161cb93a386Sopenharmony_ci psc, 162cb93a386Sopenharmony_ci pwcChars, 163cb93a386Sopenharmony_ci cChars, 164cb93a386Sopenharmony_ci cMaxGlyphs, 165cb93a386Sopenharmony_ci psa, 166cb93a386Sopenharmony_ci pwOutGlyphs, 167cb93a386Sopenharmony_ci pwLogClust, 168cb93a386Sopenharmony_ci psva, 169cb93a386Sopenharmony_ci pcGlyphs); 170cb93a386Sopenharmony_ci} 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cistatic HRESULT WINAPI 173cb93a386Sopenharmony_cihb_ScriptPlaceOpenType( 174cb93a386Sopenharmony_ci HDC hdc, 175cb93a386Sopenharmony_ci SCRIPT_CACHE *psc, 176cb93a386Sopenharmony_ci SCRIPT_ANALYSIS *psa, 177cb93a386Sopenharmony_ci OPENTYPE_TAG tagScript, 178cb93a386Sopenharmony_ci OPENTYPE_TAG tagLangSys, 179cb93a386Sopenharmony_ci int *rcRangeChars, 180cb93a386Sopenharmony_ci TEXTRANGE_PROPERTIES **rpRangeProperties, 181cb93a386Sopenharmony_ci int cRanges, 182cb93a386Sopenharmony_ci const WCHAR *pwcChars, 183cb93a386Sopenharmony_ci WORD *pwLogClust, 184cb93a386Sopenharmony_ci SCRIPT_CHARPROP *pCharProps, 185cb93a386Sopenharmony_ci int cChars, 186cb93a386Sopenharmony_ci const WORD *pwGlyphs, 187cb93a386Sopenharmony_ci const SCRIPT_GLYPHPROP *pGlyphProps, 188cb93a386Sopenharmony_ci int cGlyphs, 189cb93a386Sopenharmony_ci int *piAdvance, 190cb93a386Sopenharmony_ci GOFFSET *pGoffset, 191cb93a386Sopenharmony_ci ABC *pABC 192cb93a386Sopenharmony_ci) 193cb93a386Sopenharmony_ci{ 194cb93a386Sopenharmony_ci SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps; 195cb93a386Sopenharmony_ci return ScriptPlace (hdc, 196cb93a386Sopenharmony_ci psc, 197cb93a386Sopenharmony_ci pwGlyphs, 198cb93a386Sopenharmony_ci cGlyphs, 199cb93a386Sopenharmony_ci psva, 200cb93a386Sopenharmony_ci psa, 201cb93a386Sopenharmony_ci piAdvance, 202cb93a386Sopenharmony_ci pGoffset, 203cb93a386Sopenharmony_ci pABC); 204cb93a386Sopenharmony_ci} 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_cistruct hb_uniscribe_shaper_funcs_t 208cb93a386Sopenharmony_ci{ 209cb93a386Sopenharmony_ci SIOT ScriptItemizeOpenType; 210cb93a386Sopenharmony_ci SSOT ScriptShapeOpenType; 211cb93a386Sopenharmony_ci SPOT ScriptPlaceOpenType; 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci void init () 214cb93a386Sopenharmony_ci { 215cb93a386Sopenharmony_ci HMODULE hinstLib; 216cb93a386Sopenharmony_ci this->ScriptItemizeOpenType = nullptr; 217cb93a386Sopenharmony_ci this->ScriptShapeOpenType = nullptr; 218cb93a386Sopenharmony_ci this->ScriptPlaceOpenType = nullptr; 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci hinstLib = GetModuleHandle (TEXT ("usp10.dll")); 221cb93a386Sopenharmony_ci if (hinstLib) 222cb93a386Sopenharmony_ci { 223cb93a386Sopenharmony_ci#pragma GCC diagnostic push 224cb93a386Sopenharmony_ci#pragma GCC diagnostic ignored "-Wcast-function-type" 225cb93a386Sopenharmony_ci this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType"); 226cb93a386Sopenharmony_ci this->ScriptShapeOpenType = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType"); 227cb93a386Sopenharmony_ci this->ScriptPlaceOpenType = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType"); 228cb93a386Sopenharmony_ci#pragma GCC diagnostic pop 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci if (!this->ScriptItemizeOpenType || 231cb93a386Sopenharmony_ci !this->ScriptShapeOpenType || 232cb93a386Sopenharmony_ci !this->ScriptPlaceOpenType) 233cb93a386Sopenharmony_ci { 234cb93a386Sopenharmony_ci DEBUG_MSG (UNISCRIBE, nullptr, "OpenType versions of functions not found; falling back."); 235cb93a386Sopenharmony_ci this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType; 236cb93a386Sopenharmony_ci this->ScriptShapeOpenType = hb_ScriptShapeOpenType; 237cb93a386Sopenharmony_ci this->ScriptPlaceOpenType = hb_ScriptPlaceOpenType; 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci}; 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_cistatic inline void free_static_uniscribe_shaper_funcs (); 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_cistatic struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_uniscribe_shaper_funcs_t, 245cb93a386Sopenharmony_ci hb_uniscribe_shaper_funcs_lazy_loader_t> 246cb93a386Sopenharmony_ci{ 247cb93a386Sopenharmony_ci static hb_uniscribe_shaper_funcs_t *create () 248cb93a386Sopenharmony_ci { 249cb93a386Sopenharmony_ci hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_calloc (1, sizeof (hb_uniscribe_shaper_funcs_t)); 250cb93a386Sopenharmony_ci if (unlikely (!funcs)) 251cb93a386Sopenharmony_ci return nullptr; 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci funcs->init (); 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci hb_atexit (free_static_uniscribe_shaper_funcs); 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci return funcs; 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci static void destroy (hb_uniscribe_shaper_funcs_t *p) 260cb93a386Sopenharmony_ci { 261cb93a386Sopenharmony_ci hb_free ((void *) p); 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci static hb_uniscribe_shaper_funcs_t *get_null () 264cb93a386Sopenharmony_ci { 265cb93a386Sopenharmony_ci return nullptr; 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci} static_uniscribe_shaper_funcs; 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_cistatic inline 270cb93a386Sopenharmony_civoid free_static_uniscribe_shaper_funcs () 271cb93a386Sopenharmony_ci{ 272cb93a386Sopenharmony_ci static_uniscribe_shaper_funcs.free_instance (); 273cb93a386Sopenharmony_ci} 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_cistatic hb_uniscribe_shaper_funcs_t * 276cb93a386Sopenharmony_cihb_uniscribe_shaper_get_funcs () 277cb93a386Sopenharmony_ci{ 278cb93a386Sopenharmony_ci return static_uniscribe_shaper_funcs.get_unconst (); 279cb93a386Sopenharmony_ci} 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci/* 283cb93a386Sopenharmony_ci * shaper face data 284cb93a386Sopenharmony_ci */ 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_cistruct hb_uniscribe_face_data_t { 287cb93a386Sopenharmony_ci HANDLE fh; 288cb93a386Sopenharmony_ci hb_uniscribe_shaper_funcs_t *funcs; 289cb93a386Sopenharmony_ci wchar_t face_name[LF_FACESIZE]; 290cb93a386Sopenharmony_ci}; 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci/* face_name should point to a wchar_t[LF_FACESIZE] object. */ 293cb93a386Sopenharmony_cistatic void 294cb93a386Sopenharmony_ci_hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen) 295cb93a386Sopenharmony_ci{ 296cb93a386Sopenharmony_ci /* We'll create a private name for the font from a UUID using a simple, 297cb93a386Sopenharmony_ci * somewhat base64-like encoding scheme */ 298cb93a386Sopenharmony_ci const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; 299cb93a386Sopenharmony_ci UUID id; 300cb93a386Sopenharmony_ci UuidCreate ((UUID*) &id); 301cb93a386Sopenharmony_ci static_assert ((2 + 3 * (16/2) < LF_FACESIZE), ""); 302cb93a386Sopenharmony_ci unsigned int name_str_len = 0; 303cb93a386Sopenharmony_ci face_name[name_str_len++] = 'F'; 304cb93a386Sopenharmony_ci face_name[name_str_len++] = '_'; 305cb93a386Sopenharmony_ci unsigned char *p = (unsigned char *) &id; 306cb93a386Sopenharmony_ci for (unsigned int i = 0; i < 16; i += 2) 307cb93a386Sopenharmony_ci { 308cb93a386Sopenharmony_ci /* Spread the 16 bits from two bytes of the UUID across three chars of face_name, 309cb93a386Sopenharmony_ci * using the bits in groups of 5,5,6 to select chars from enc. 310cb93a386Sopenharmony_ci * This will generate 24 characters; with the 'F_' prefix we already provided, 311cb93a386Sopenharmony_ci * the name will be 26 chars (plus the NUL terminator), so will always fit within 312cb93a386Sopenharmony_ci * face_name (LF_FACESIZE = 32). */ 313cb93a386Sopenharmony_ci face_name[name_str_len++] = enc[p[i] >> 3]; 314cb93a386Sopenharmony_ci face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f]; 315cb93a386Sopenharmony_ci face_name[name_str_len++] = enc[p[i + 1] & 0x3f]; 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci face_name[name_str_len] = 0; 318cb93a386Sopenharmony_ci if (plen) 319cb93a386Sopenharmony_ci *plen = name_str_len; 320cb93a386Sopenharmony_ci} 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci/* Destroys blob. */ 323cb93a386Sopenharmony_cistatic hb_blob_t * 324cb93a386Sopenharmony_ci_hb_rename_font (hb_blob_t *blob, wchar_t *new_name) 325cb93a386Sopenharmony_ci{ 326cb93a386Sopenharmony_ci /* Create a copy of the font data, with the 'name' table replaced by a 327cb93a386Sopenharmony_ci * table that names the font with our private F_* name created above. 328cb93a386Sopenharmony_ci * For simplicity, we just append a new 'name' table and update the 329cb93a386Sopenharmony_ci * sfnt directory; the original table is left in place, but unused. 330cb93a386Sopenharmony_ci * 331cb93a386Sopenharmony_ci * The new table will contain just 5 name IDs: family, style, unique, 332cb93a386Sopenharmony_ci * full, PS. All of them point to the same name data with our unique name. 333cb93a386Sopenharmony_ci */ 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (blob); 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci unsigned int length, new_length, name_str_len; 338cb93a386Sopenharmony_ci const char *orig_sfnt_data = hb_blob_get_data (blob, &length); 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci _hb_generate_unique_face_name (new_name, &name_str_len); 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 }; 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci unsigned int name_table_length = OT::name::min_size + 345cb93a386Sopenharmony_ci ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size + 346cb93a386Sopenharmony_ci name_str_len * 2; /* for name data in UTF16BE form */ 347cb93a386Sopenharmony_ci unsigned int padded_name_table_length = ((name_table_length + 3) & ~3); 348cb93a386Sopenharmony_ci unsigned int name_table_offset = (length + 3) & ~3; 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci new_length = name_table_offset + padded_name_table_length; 351cb93a386Sopenharmony_ci void *new_sfnt_data = hb_calloc (1, new_length); 352cb93a386Sopenharmony_ci if (!new_sfnt_data) 353cb93a386Sopenharmony_ci { 354cb93a386Sopenharmony_ci hb_blob_destroy (blob); 355cb93a386Sopenharmony_ci return nullptr; 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci memcpy(new_sfnt_data, orig_sfnt_data, length); 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset); 361cb93a386Sopenharmony_ci name.format = 0; 362cb93a386Sopenharmony_ci name.count = ARRAY_LENGTH (name_IDs); 363cb93a386Sopenharmony_ci name.stringOffset = name.get_size (); 364cb93a386Sopenharmony_ci for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++) 365cb93a386Sopenharmony_ci { 366cb93a386Sopenharmony_ci OT::NameRecord &record = name.nameRecordZ[i]; 367cb93a386Sopenharmony_ci record.platformID = 3; 368cb93a386Sopenharmony_ci record.encodingID = 1; 369cb93a386Sopenharmony_ci record.languageID = 0x0409u; /* English */ 370cb93a386Sopenharmony_ci record.nameID = name_IDs[i]; 371cb93a386Sopenharmony_ci record.length = name_str_len * 2; 372cb93a386Sopenharmony_ci record.offset = 0; 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci /* Copy string data from new_name, converting wchar_t to UTF16BE. */ 376cb93a386Sopenharmony_ci unsigned char *p = &StructAfter<unsigned char> (name); 377cb93a386Sopenharmony_ci for (unsigned int i = 0; i < name_str_len; i++) 378cb93a386Sopenharmony_ci { 379cb93a386Sopenharmony_ci *p++ = new_name[i] >> 8; 380cb93a386Sopenharmony_ci *p++ = new_name[i] & 0xff; 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci /* Adjust name table entry to point to new name table */ 384cb93a386Sopenharmony_ci const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data); 385cb93a386Sopenharmony_ci unsigned int face_count = file.get_face_count (); 386cb93a386Sopenharmony_ci for (unsigned int face_index = 0; face_index < face_count; face_index++) 387cb93a386Sopenharmony_ci { 388cb93a386Sopenharmony_ci /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be 389cb93a386Sopenharmony_ci * toe-stepping. But we don't really care. */ 390cb93a386Sopenharmony_ci const OT::OpenTypeFontFace &face = file.get_face (face_index); 391cb93a386Sopenharmony_ci unsigned int index; 392cb93a386Sopenharmony_ci if (face.find_table_index (HB_OT_TAG_name, &index)) 393cb93a386Sopenharmony_ci { 394cb93a386Sopenharmony_ci OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index)); 395cb93a386Sopenharmony_ci record.checkSum.set_for_data (&name, padded_name_table_length); 396cb93a386Sopenharmony_ci record.offset = name_table_offset; 397cb93a386Sopenharmony_ci record.length = name_table_length; 398cb93a386Sopenharmony_ci } 399cb93a386Sopenharmony_ci else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */ 400cb93a386Sopenharmony_ci { 401cb93a386Sopenharmony_ci hb_free (new_sfnt_data); 402cb93a386Sopenharmony_ci hb_blob_destroy (blob); 403cb93a386Sopenharmony_ci return nullptr; 404cb93a386Sopenharmony_ci } 405cb93a386Sopenharmony_ci } 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci /* The checkSumAdjustment field in the 'head' table is now wrong, 408cb93a386Sopenharmony_ci * but that doesn't actually seem to cause any problems so we don't 409cb93a386Sopenharmony_ci * bother. */ 410cb93a386Sopenharmony_ci 411cb93a386Sopenharmony_ci hb_blob_destroy (blob); 412cb93a386Sopenharmony_ci return hb_blob_create ((const char *) new_sfnt_data, new_length, 413cb93a386Sopenharmony_ci HB_MEMORY_MODE_WRITABLE, new_sfnt_data, hb_free); 414cb93a386Sopenharmony_ci} 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_cihb_uniscribe_face_data_t * 417cb93a386Sopenharmony_ci_hb_uniscribe_shaper_face_data_create (hb_face_t *face) 418cb93a386Sopenharmony_ci{ 419cb93a386Sopenharmony_ci hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_calloc (1, sizeof (hb_uniscribe_face_data_t)); 420cb93a386Sopenharmony_ci if (unlikely (!data)) 421cb93a386Sopenharmony_ci return nullptr; 422cb93a386Sopenharmony_ci 423cb93a386Sopenharmony_ci data->funcs = hb_uniscribe_shaper_get_funcs (); 424cb93a386Sopenharmony_ci if (unlikely (!data->funcs)) 425cb93a386Sopenharmony_ci { 426cb93a386Sopenharmony_ci hb_free (data); 427cb93a386Sopenharmony_ci return nullptr; 428cb93a386Sopenharmony_ci } 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ci hb_blob_t *blob = hb_face_reference_blob (face); 431cb93a386Sopenharmony_ci if (unlikely (!hb_blob_get_length (blob))) 432cb93a386Sopenharmony_ci DEBUG_MSG (UNISCRIBE, face, "Face has empty blob"); 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci blob = _hb_rename_font (blob, data->face_name); 435cb93a386Sopenharmony_ci if (unlikely (!blob)) 436cb93a386Sopenharmony_ci { 437cb93a386Sopenharmony_ci hb_free (data); 438cb93a386Sopenharmony_ci return nullptr; 439cb93a386Sopenharmony_ci } 440cb93a386Sopenharmony_ci 441cb93a386Sopenharmony_ci DWORD num_fonts_installed; 442cb93a386Sopenharmony_ci data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, nullptr), 443cb93a386Sopenharmony_ci hb_blob_get_length (blob), 444cb93a386Sopenharmony_ci 0, &num_fonts_installed); 445cb93a386Sopenharmony_ci if (unlikely (!data->fh)) 446cb93a386Sopenharmony_ci { 447cb93a386Sopenharmony_ci DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed"); 448cb93a386Sopenharmony_ci hb_free (data); 449cb93a386Sopenharmony_ci return nullptr; 450cb93a386Sopenharmony_ci } 451cb93a386Sopenharmony_ci 452cb93a386Sopenharmony_ci return data; 453cb93a386Sopenharmony_ci} 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_civoid 456cb93a386Sopenharmony_ci_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_face_data_t *data) 457cb93a386Sopenharmony_ci{ 458cb93a386Sopenharmony_ci RemoveFontMemResourceEx (data->fh); 459cb93a386Sopenharmony_ci hb_free (data); 460cb93a386Sopenharmony_ci} 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci 463cb93a386Sopenharmony_ci/* 464cb93a386Sopenharmony_ci * shaper font data 465cb93a386Sopenharmony_ci */ 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_cistruct hb_uniscribe_font_data_t 468cb93a386Sopenharmony_ci{ 469cb93a386Sopenharmony_ci HDC hdc; 470cb93a386Sopenharmony_ci mutable LOGFONTW log_font; 471cb93a386Sopenharmony_ci HFONT hfont; 472cb93a386Sopenharmony_ci mutable SCRIPT_CACHE script_cache; 473cb93a386Sopenharmony_ci double x_mult, y_mult; /* From LOGFONT space to HB space. */ 474cb93a386Sopenharmony_ci}; 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_cistatic bool 477cb93a386Sopenharmony_cipopulate_log_font (LOGFONTW *lf, 478cb93a386Sopenharmony_ci hb_font_t *font, 479cb93a386Sopenharmony_ci unsigned int font_size) 480cb93a386Sopenharmony_ci{ 481cb93a386Sopenharmony_ci memset (lf, 0, sizeof (*lf)); 482cb93a386Sopenharmony_ci lf->lfHeight = - (int) font_size; 483cb93a386Sopenharmony_ci lf->lfCharSet = DEFAULT_CHARSET; 484cb93a386Sopenharmony_ci 485cb93a386Sopenharmony_ci memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName)); 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_ci return true; 488cb93a386Sopenharmony_ci} 489cb93a386Sopenharmony_ci 490cb93a386Sopenharmony_cihb_uniscribe_font_data_t * 491cb93a386Sopenharmony_ci_hb_uniscribe_shaper_font_data_create (hb_font_t *font) 492cb93a386Sopenharmony_ci{ 493cb93a386Sopenharmony_ci hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_calloc (1, sizeof (hb_uniscribe_font_data_t)); 494cb93a386Sopenharmony_ci if (unlikely (!data)) 495cb93a386Sopenharmony_ci return nullptr; 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci int font_size = font->face->get_upem (); /* Default... */ 498cb93a386Sopenharmony_ci /* No idea if the following is even a good idea. */ 499cb93a386Sopenharmony_ci if (font->y_ppem) 500cb93a386Sopenharmony_ci font_size = font->y_ppem; 501cb93a386Sopenharmony_ci 502cb93a386Sopenharmony_ci if (font_size < 0) 503cb93a386Sopenharmony_ci font_size = -font_size; 504cb93a386Sopenharmony_ci data->x_mult = (double) font->x_scale / font_size; 505cb93a386Sopenharmony_ci data->y_mult = (double) font->y_scale / font_size; 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ci data->hdc = GetDC (nullptr); 508cb93a386Sopenharmony_ci 509cb93a386Sopenharmony_ci if (unlikely (!populate_log_font (&data->log_font, font, font_size))) { 510cb93a386Sopenharmony_ci DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed"); 511cb93a386Sopenharmony_ci _hb_uniscribe_shaper_font_data_destroy (data); 512cb93a386Sopenharmony_ci return nullptr; 513cb93a386Sopenharmony_ci } 514cb93a386Sopenharmony_ci 515cb93a386Sopenharmony_ci data->hfont = CreateFontIndirectW (&data->log_font); 516cb93a386Sopenharmony_ci if (unlikely (!data->hfont)) { 517cb93a386Sopenharmony_ci DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed"); 518cb93a386Sopenharmony_ci _hb_uniscribe_shaper_font_data_destroy (data); 519cb93a386Sopenharmony_ci return nullptr; 520cb93a386Sopenharmony_ci } 521cb93a386Sopenharmony_ci 522cb93a386Sopenharmony_ci if (!SelectObject (data->hdc, data->hfont)) { 523cb93a386Sopenharmony_ci DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed"); 524cb93a386Sopenharmony_ci _hb_uniscribe_shaper_font_data_destroy (data); 525cb93a386Sopenharmony_ci return nullptr; 526cb93a386Sopenharmony_ci } 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci return data; 529cb93a386Sopenharmony_ci} 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_civoid 532cb93a386Sopenharmony_ci_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_font_data_t *data) 533cb93a386Sopenharmony_ci{ 534cb93a386Sopenharmony_ci if (data->hdc) 535cb93a386Sopenharmony_ci ReleaseDC (nullptr, data->hdc); 536cb93a386Sopenharmony_ci if (data->hfont) 537cb93a386Sopenharmony_ci DeleteObject (data->hfont); 538cb93a386Sopenharmony_ci if (data->script_cache) 539cb93a386Sopenharmony_ci ScriptFreeCache (&data->script_cache); 540cb93a386Sopenharmony_ci hb_free (data); 541cb93a386Sopenharmony_ci} 542cb93a386Sopenharmony_ci 543cb93a386Sopenharmony_ci/** 544cb93a386Sopenharmony_ci * hb_uniscribe_font_get_logfontw: 545cb93a386Sopenharmony_ci * @font: The #hb_font_t to work upon 546cb93a386Sopenharmony_ci * 547cb93a386Sopenharmony_ci * Fetches the LOGFONTW structure that corresponds to the 548cb93a386Sopenharmony_ci * specified #hb_font_t font. 549cb93a386Sopenharmony_ci * 550cb93a386Sopenharmony_ci * Return value: a pointer to the LOGFONTW retrieved 551cb93a386Sopenharmony_ci * 552cb93a386Sopenharmony_ci **/ 553cb93a386Sopenharmony_ciLOGFONTW * 554cb93a386Sopenharmony_cihb_uniscribe_font_get_logfontw (hb_font_t *font) 555cb93a386Sopenharmony_ci{ 556cb93a386Sopenharmony_ci const hb_uniscribe_font_data_t *data = font->data.uniscribe; 557cb93a386Sopenharmony_ci return data ? &data->log_font : nullptr; 558cb93a386Sopenharmony_ci} 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci/** 561cb93a386Sopenharmony_ci * hb_uniscribe_font_get_hfont: 562cb93a386Sopenharmony_ci * @font: The #hb_font_t to work upon 563cb93a386Sopenharmony_ci * 564cb93a386Sopenharmony_ci * Fetches the HFONT handle that corresponds to the 565cb93a386Sopenharmony_ci * specified #hb_font_t font. 566cb93a386Sopenharmony_ci * 567cb93a386Sopenharmony_ci * Return value: the HFONT retreieved 568cb93a386Sopenharmony_ci * 569cb93a386Sopenharmony_ci **/ 570cb93a386Sopenharmony_ciHFONT 571cb93a386Sopenharmony_cihb_uniscribe_font_get_hfont (hb_font_t *font) 572cb93a386Sopenharmony_ci{ 573cb93a386Sopenharmony_ci const hb_uniscribe_font_data_t *data = font->data.uniscribe; 574cb93a386Sopenharmony_ci return data ? data->hfont : nullptr; 575cb93a386Sopenharmony_ci} 576cb93a386Sopenharmony_ci 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_ci/* 579cb93a386Sopenharmony_ci * shaper 580cb93a386Sopenharmony_ci */ 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci 583cb93a386Sopenharmony_cihb_bool_t 584cb93a386Sopenharmony_ci_hb_uniscribe_shape (hb_shape_plan_t *shape_plan, 585cb93a386Sopenharmony_ci hb_font_t *font, 586cb93a386Sopenharmony_ci hb_buffer_t *buffer, 587cb93a386Sopenharmony_ci const hb_feature_t *features, 588cb93a386Sopenharmony_ci unsigned int num_features) 589cb93a386Sopenharmony_ci{ 590cb93a386Sopenharmony_ci hb_face_t *face = font->face; 591cb93a386Sopenharmony_ci const hb_uniscribe_face_data_t *face_data = face->data.uniscribe; 592cb93a386Sopenharmony_ci const hb_uniscribe_font_data_t *font_data = font->data.uniscribe; 593cb93a386Sopenharmony_ci hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs; 594cb93a386Sopenharmony_ci 595cb93a386Sopenharmony_ci#define FAIL(...) \ 596cb93a386Sopenharmony_ci HB_STMT_START { \ 597cb93a386Sopenharmony_ci DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \ 598cb93a386Sopenharmony_ci return false; \ 599cb93a386Sopenharmony_ci } HB_STMT_END 600cb93a386Sopenharmony_ci 601cb93a386Sopenharmony_ci HRESULT hr; 602cb93a386Sopenharmony_ci 603cb93a386Sopenharmony_ciretry: 604cb93a386Sopenharmony_ci 605cb93a386Sopenharmony_ci unsigned int scratch_size; 606cb93a386Sopenharmony_ci hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 607cb93a386Sopenharmony_ci 608cb93a386Sopenharmony_ci#define ALLOCATE_ARRAY(Type, name, len) \ 609cb93a386Sopenharmony_ci Type *name = (Type *) scratch; \ 610cb93a386Sopenharmony_ci do { \ 611cb93a386Sopenharmony_ci unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 612cb93a386Sopenharmony_ci assert (_consumed <= scratch_size); \ 613cb93a386Sopenharmony_ci scratch += _consumed; \ 614cb93a386Sopenharmony_ci scratch_size -= _consumed; \ 615cb93a386Sopenharmony_ci } while (0) 616cb93a386Sopenharmony_ci 617cb93a386Sopenharmony_ci#define utf16_index() var1.u32 618cb93a386Sopenharmony_ci 619cb93a386Sopenharmony_ci ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2); 620cb93a386Sopenharmony_ci 621cb93a386Sopenharmony_ci unsigned int chars_len = 0; 622cb93a386Sopenharmony_ci for (unsigned int i = 0; i < buffer->len; i++) 623cb93a386Sopenharmony_ci { 624cb93a386Sopenharmony_ci hb_codepoint_t c = buffer->info[i].codepoint; 625cb93a386Sopenharmony_ci buffer->info[i].utf16_index() = chars_len; 626cb93a386Sopenharmony_ci if (likely (c <= 0xFFFFu)) 627cb93a386Sopenharmony_ci pchars[chars_len++] = c; 628cb93a386Sopenharmony_ci else if (unlikely (c > 0x10FFFFu)) 629cb93a386Sopenharmony_ci pchars[chars_len++] = 0xFFFDu; 630cb93a386Sopenharmony_ci else { 631cb93a386Sopenharmony_ci pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); 632cb93a386Sopenharmony_ci pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1)); 633cb93a386Sopenharmony_ci } 634cb93a386Sopenharmony_ci } 635cb93a386Sopenharmony_ci 636cb93a386Sopenharmony_ci ALLOCATE_ARRAY (WORD, log_clusters, chars_len); 637cb93a386Sopenharmony_ci ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len); 638cb93a386Sopenharmony_ci 639cb93a386Sopenharmony_ci if (num_features) 640cb93a386Sopenharmony_ci { 641cb93a386Sopenharmony_ci /* Need log_clusters to assign features. */ 642cb93a386Sopenharmony_ci chars_len = 0; 643cb93a386Sopenharmony_ci for (unsigned int i = 0; i < buffer->len; i++) 644cb93a386Sopenharmony_ci { 645cb93a386Sopenharmony_ci hb_codepoint_t c = buffer->info[i].codepoint; 646cb93a386Sopenharmony_ci unsigned int cluster = buffer->info[i].cluster; 647cb93a386Sopenharmony_ci log_clusters[chars_len++] = cluster; 648cb93a386Sopenharmony_ci if (hb_in_range (c, 0x10000u, 0x10FFFFu)) 649cb93a386Sopenharmony_ci log_clusters[chars_len++] = cluster; /* Surrogates. */ 650cb93a386Sopenharmony_ci } 651cb93a386Sopenharmony_ci } 652cb93a386Sopenharmony_ci 653cb93a386Sopenharmony_ci /* The -2 in the following is to compensate for possible 654cb93a386Sopenharmony_ci * alignment needed after the WORD array. sizeof(WORD) == 2. */ 655cb93a386Sopenharmony_ci unsigned int glyphs_size = (scratch_size * sizeof (int) - 2) 656cb93a386Sopenharmony_ci / (sizeof (WORD) + 657cb93a386Sopenharmony_ci sizeof (SCRIPT_GLYPHPROP) + 658cb93a386Sopenharmony_ci sizeof (int) + 659cb93a386Sopenharmony_ci sizeof (GOFFSET) + 660cb93a386Sopenharmony_ci sizeof (uint32_t)); 661cb93a386Sopenharmony_ci 662cb93a386Sopenharmony_ci ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); 663cb93a386Sopenharmony_ci ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); 664cb93a386Sopenharmony_ci ALLOCATE_ARRAY (int, advances, glyphs_size); 665cb93a386Sopenharmony_ci ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); 666cb93a386Sopenharmony_ci ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); 667cb93a386Sopenharmony_ci 668cb93a386Sopenharmony_ci /* Note: 669cb93a386Sopenharmony_ci * We can't touch the contents of glyph_props. Our fallback 670cb93a386Sopenharmony_ci * implementations of Shape and Place functions use that buffer 671cb93a386Sopenharmony_ci * by casting it to a different type. It works because they 672cb93a386Sopenharmony_ci * both agree about it, but if we want to access it here we 673cb93a386Sopenharmony_ci * need address that issue first. 674cb93a386Sopenharmony_ci */ 675cb93a386Sopenharmony_ci 676cb93a386Sopenharmony_ci#undef ALLOCATE_ARRAY 677cb93a386Sopenharmony_ci 678cb93a386Sopenharmony_ci#define MAX_ITEMS 256 679cb93a386Sopenharmony_ci 680cb93a386Sopenharmony_ci SCRIPT_ITEM items[MAX_ITEMS + 1]; 681cb93a386Sopenharmony_ci SCRIPT_CONTROL bidi_control = {0}; 682cb93a386Sopenharmony_ci SCRIPT_STATE bidi_state = {0}; 683cb93a386Sopenharmony_ci ULONG script_tags[MAX_ITEMS]; 684cb93a386Sopenharmony_ci int item_count; 685cb93a386Sopenharmony_ci 686cb93a386Sopenharmony_ci /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */ 687cb93a386Sopenharmony_ci //bidi_control.fMergeNeutralItems = true; 688cb93a386Sopenharmony_ci *(uint32_t*)&bidi_control |= 1u<<24; 689cb93a386Sopenharmony_ci 690cb93a386Sopenharmony_ci bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 691cb93a386Sopenharmony_ci bidi_state.fOverrideDirection = 1; 692cb93a386Sopenharmony_ci 693cb93a386Sopenharmony_ci hr = funcs->ScriptItemizeOpenType (pchars, 694cb93a386Sopenharmony_ci chars_len, 695cb93a386Sopenharmony_ci MAX_ITEMS, 696cb93a386Sopenharmony_ci &bidi_control, 697cb93a386Sopenharmony_ci &bidi_state, 698cb93a386Sopenharmony_ci items, 699cb93a386Sopenharmony_ci script_tags, 700cb93a386Sopenharmony_ci &item_count); 701cb93a386Sopenharmony_ci if (unlikely (FAILED (hr))) 702cb93a386Sopenharmony_ci FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr); 703cb93a386Sopenharmony_ci 704cb93a386Sopenharmony_ci#undef MAX_ITEMS 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_ci hb_tag_t lang_tag; 707cb93a386Sopenharmony_ci unsigned int lang_count = 1; 708cb93a386Sopenharmony_ci hb_ot_tags_from_script_and_language (buffer->props.script, 709cb93a386Sopenharmony_ci buffer->props.language, 710cb93a386Sopenharmony_ci nullptr, nullptr, 711cb93a386Sopenharmony_ci &lang_count, &lang_tag); 712cb93a386Sopenharmony_ci OPENTYPE_TAG language_tag = hb_uint32_swap (lang_count ? lang_tag : HB_TAG_NONE); 713cb93a386Sopenharmony_ci 714cb93a386Sopenharmony_ci /* 715cb93a386Sopenharmony_ci * Set up features. 716cb93a386Sopenharmony_ci */ 717cb93a386Sopenharmony_ci static_assert ((sizeof (TEXTRANGE_PROPERTIES) == sizeof (hb_ms_features_t)), ""); 718cb93a386Sopenharmony_ci static_assert ((sizeof (OPENTYPE_FEATURE_RECORD) == sizeof (hb_ms_feature_t)), ""); 719cb93a386Sopenharmony_ci hb_vector_t<hb_ms_feature_t> feature_records; 720cb93a386Sopenharmony_ci hb_vector_t<hb_ms_range_record_t> range_records; 721cb93a386Sopenharmony_ci bool has_features = false; 722cb93a386Sopenharmony_ci if (num_features) 723cb93a386Sopenharmony_ci has_features = hb_ms_setup_features (features, 724cb93a386Sopenharmony_ci num_features, 725cb93a386Sopenharmony_ci feature_records, 726cb93a386Sopenharmony_ci range_records); 727cb93a386Sopenharmony_ci 728cb93a386Sopenharmony_ci hb_vector_t<hb_ms_features_t*> range_properties; 729cb93a386Sopenharmony_ci hb_vector_t<uint32_t> range_char_counts; 730cb93a386Sopenharmony_ci 731cb93a386Sopenharmony_ci unsigned int glyphs_offset = 0; 732cb93a386Sopenharmony_ci unsigned int glyphs_len; 733cb93a386Sopenharmony_ci bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 734cb93a386Sopenharmony_ci for (int i = 0; i < item_count; i++) 735cb93a386Sopenharmony_ci { 736cb93a386Sopenharmony_ci unsigned int chars_offset = items[i].iCharPos; 737cb93a386Sopenharmony_ci unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; 738cb93a386Sopenharmony_ci 739cb93a386Sopenharmony_ci if (has_features) 740cb93a386Sopenharmony_ci hb_ms_make_feature_ranges (feature_records, 741cb93a386Sopenharmony_ci range_records, 742cb93a386Sopenharmony_ci item_chars_len, 743cb93a386Sopenharmony_ci chars_offset, 744cb93a386Sopenharmony_ci log_clusters, 745cb93a386Sopenharmony_ci range_properties, 746cb93a386Sopenharmony_ci range_char_counts); 747cb93a386Sopenharmony_ci 748cb93a386Sopenharmony_ci /* Asking for glyphs in logical order circumvents at least 749cb93a386Sopenharmony_ci * one bug in Uniscribe. */ 750cb93a386Sopenharmony_ci items[i].a.fLogicalOrder = true; 751cb93a386Sopenharmony_ci 752cb93a386Sopenharmony_ci retry_shape: 753cb93a386Sopenharmony_ci hr = funcs->ScriptShapeOpenType (font_data->hdc, 754cb93a386Sopenharmony_ci &font_data->script_cache, 755cb93a386Sopenharmony_ci &items[i].a, 756cb93a386Sopenharmony_ci script_tags[i], 757cb93a386Sopenharmony_ci language_tag, 758cb93a386Sopenharmony_ci (int *) range_char_counts.arrayZ, 759cb93a386Sopenharmony_ci (TEXTRANGE_PROPERTIES**) range_properties.arrayZ, 760cb93a386Sopenharmony_ci range_properties.length, 761cb93a386Sopenharmony_ci pchars + chars_offset, 762cb93a386Sopenharmony_ci item_chars_len, 763cb93a386Sopenharmony_ci glyphs_size - glyphs_offset, 764cb93a386Sopenharmony_ci /* out */ 765cb93a386Sopenharmony_ci log_clusters + chars_offset, 766cb93a386Sopenharmony_ci char_props + chars_offset, 767cb93a386Sopenharmony_ci glyphs + glyphs_offset, 768cb93a386Sopenharmony_ci glyph_props + glyphs_offset, 769cb93a386Sopenharmony_ci (int *) &glyphs_len); 770cb93a386Sopenharmony_ci 771cb93a386Sopenharmony_ci if (unlikely (items[i].a.fNoGlyphIndex)) 772cb93a386Sopenharmony_ci FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); 773cb93a386Sopenharmony_ci if (unlikely (hr == E_OUTOFMEMORY || hr == E_NOT_SUFFICIENT_BUFFER)) 774cb93a386Sopenharmony_ci { 775cb93a386Sopenharmony_ci if (unlikely (!buffer->ensure (buffer->allocated * 2))) 776cb93a386Sopenharmony_ci FAIL ("Buffer resize failed"); 777cb93a386Sopenharmony_ci goto retry; 778cb93a386Sopenharmony_ci } 779cb93a386Sopenharmony_ci if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT)) 780cb93a386Sopenharmony_ci { 781cb93a386Sopenharmony_ci if (items[i].a.eScript == SCRIPT_UNDEFINED) 782cb93a386Sopenharmony_ci FAIL ("ScriptShapeOpenType() failed: Font doesn't support script"); 783cb93a386Sopenharmony_ci items[i].a.eScript = SCRIPT_UNDEFINED; 784cb93a386Sopenharmony_ci goto retry_shape; 785cb93a386Sopenharmony_ci } 786cb93a386Sopenharmony_ci if (unlikely (FAILED (hr))) 787cb93a386Sopenharmony_ci { 788cb93a386Sopenharmony_ci FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr); 789cb93a386Sopenharmony_ci } 790cb93a386Sopenharmony_ci 791cb93a386Sopenharmony_ci for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) 792cb93a386Sopenharmony_ci log_clusters[j] += glyphs_offset; 793cb93a386Sopenharmony_ci 794cb93a386Sopenharmony_ci hr = funcs->ScriptPlaceOpenType (font_data->hdc, 795cb93a386Sopenharmony_ci &font_data->script_cache, 796cb93a386Sopenharmony_ci &items[i].a, 797cb93a386Sopenharmony_ci script_tags[i], 798cb93a386Sopenharmony_ci language_tag, 799cb93a386Sopenharmony_ci (int *) range_char_counts.arrayZ, 800cb93a386Sopenharmony_ci (TEXTRANGE_PROPERTIES**) range_properties.arrayZ, 801cb93a386Sopenharmony_ci range_properties.length, 802cb93a386Sopenharmony_ci pchars + chars_offset, 803cb93a386Sopenharmony_ci log_clusters + chars_offset, 804cb93a386Sopenharmony_ci char_props + chars_offset, 805cb93a386Sopenharmony_ci item_chars_len, 806cb93a386Sopenharmony_ci glyphs + glyphs_offset, 807cb93a386Sopenharmony_ci glyph_props + glyphs_offset, 808cb93a386Sopenharmony_ci glyphs_len, 809cb93a386Sopenharmony_ci /* out */ 810cb93a386Sopenharmony_ci advances + glyphs_offset, 811cb93a386Sopenharmony_ci offsets + glyphs_offset, 812cb93a386Sopenharmony_ci nullptr); 813cb93a386Sopenharmony_ci if (unlikely (FAILED (hr))) 814cb93a386Sopenharmony_ci FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr); 815cb93a386Sopenharmony_ci 816cb93a386Sopenharmony_ci if (DEBUG_ENABLED (UNISCRIBE)) 817cb93a386Sopenharmony_ci fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n", 818cb93a386Sopenharmony_ci i, 819cb93a386Sopenharmony_ci items[i].a.fRTL, 820cb93a386Sopenharmony_ci items[i].a.fLayoutRTL, 821cb93a386Sopenharmony_ci items[i].a.fLogicalOrder, 822cb93a386Sopenharmony_ci HB_UNTAG (hb_uint32_swap (script_tags[i]))); 823cb93a386Sopenharmony_ci 824cb93a386Sopenharmony_ci glyphs_offset += glyphs_len; 825cb93a386Sopenharmony_ci } 826cb93a386Sopenharmony_ci glyphs_len = glyphs_offset; 827cb93a386Sopenharmony_ci 828cb93a386Sopenharmony_ci /* Ok, we've got everything we need, now compose output buffer, 829cb93a386Sopenharmony_ci * very, *very*, carefully! */ 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_ci /* Calculate visual-clusters. That's what we ship. */ 832cb93a386Sopenharmony_ci for (unsigned int i = 0; i < glyphs_len; i++) 833cb93a386Sopenharmony_ci vis_clusters[i] = (uint32_t) -1; 834cb93a386Sopenharmony_ci for (unsigned int i = 0; i < buffer->len; i++) { 835cb93a386Sopenharmony_ci uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; 836cb93a386Sopenharmony_ci *p = hb_min (*p, buffer->info[i].cluster); 837cb93a386Sopenharmony_ci } 838cb93a386Sopenharmony_ci for (unsigned int i = 1; i < glyphs_len; i++) 839cb93a386Sopenharmony_ci if (vis_clusters[i] == (uint32_t) -1) 840cb93a386Sopenharmony_ci vis_clusters[i] = vis_clusters[i - 1]; 841cb93a386Sopenharmony_ci 842cb93a386Sopenharmony_ci#undef utf16_index 843cb93a386Sopenharmony_ci 844cb93a386Sopenharmony_ci if (unlikely (!buffer->ensure (glyphs_len))) 845cb93a386Sopenharmony_ci FAIL ("Buffer in error"); 846cb93a386Sopenharmony_ci 847cb93a386Sopenharmony_ci#undef FAIL 848cb93a386Sopenharmony_ci 849cb93a386Sopenharmony_ci /* Set glyph infos */ 850cb93a386Sopenharmony_ci buffer->len = 0; 851cb93a386Sopenharmony_ci for (unsigned int i = 0; i < glyphs_len; i++) 852cb93a386Sopenharmony_ci { 853cb93a386Sopenharmony_ci hb_glyph_info_t *info = &buffer->info[buffer->len++]; 854cb93a386Sopenharmony_ci 855cb93a386Sopenharmony_ci info->codepoint = glyphs[i]; 856cb93a386Sopenharmony_ci info->cluster = vis_clusters[i]; 857cb93a386Sopenharmony_ci 858cb93a386Sopenharmony_ci /* The rest is crap. Let's store position info there for now. */ 859cb93a386Sopenharmony_ci info->mask = advances[i]; 860cb93a386Sopenharmony_ci info->var1.i32 = offsets[i].du; 861cb93a386Sopenharmony_ci info->var2.i32 = offsets[i].dv; 862cb93a386Sopenharmony_ci } 863cb93a386Sopenharmony_ci 864cb93a386Sopenharmony_ci /* Set glyph positions */ 865cb93a386Sopenharmony_ci buffer->clear_positions (); 866cb93a386Sopenharmony_ci double x_mult = font_data->x_mult, y_mult = font_data->y_mult; 867cb93a386Sopenharmony_ci for (unsigned int i = 0; i < glyphs_len; i++) 868cb93a386Sopenharmony_ci { 869cb93a386Sopenharmony_ci hb_glyph_info_t *info = &buffer->info[i]; 870cb93a386Sopenharmony_ci hb_glyph_position_t *pos = &buffer->pos[i]; 871cb93a386Sopenharmony_ci 872cb93a386Sopenharmony_ci /* TODO vertical */ 873cb93a386Sopenharmony_ci pos->x_advance = x_mult * (int32_t) info->mask; 874cb93a386Sopenharmony_ci pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32); 875cb93a386Sopenharmony_ci pos->y_offset = y_mult * info->var2.i32; 876cb93a386Sopenharmony_ci } 877cb93a386Sopenharmony_ci 878cb93a386Sopenharmony_ci if (backward) 879cb93a386Sopenharmony_ci hb_buffer_reverse (buffer); 880cb93a386Sopenharmony_ci 881cb93a386Sopenharmony_ci buffer->unsafe_to_break_all (); 882cb93a386Sopenharmony_ci 883cb93a386Sopenharmony_ci /* Wow, done! */ 884cb93a386Sopenharmony_ci return true; 885cb93a386Sopenharmony_ci} 886cb93a386Sopenharmony_ci 887cb93a386Sopenharmony_ci 888cb93a386Sopenharmony_ci#endif 889