BOOL doScriptShape(struct scriptShapeParams *p) { HRESULT hr; hr = ScriptShape(p->hdc, p->psc, p->pwcChars, p->cChars, p->cMaxGlyphs, p->psa, p->pwOutGlyphs, p->pwLogClust, p->psva, p->pcGlyphs); if (hr == S_OK) return TRUE; if (hr != E_OUTOFMEMORY) die("error calling ScriptShape()", hr); return FALSE; }
static HRESULT shape_run( ME_Context *c, ME_Run *run ) { HRESULT hr; HFONT old_font; int i; if (!run->glyphs) { run->max_glyphs = 1.5 * run->len + 16; /* This is suggested in the uniscribe documentation */ run->max_glyphs = (run->max_glyphs + 7) & ~7; /* Keep alignment simple */ get_run_glyph_buffers( run ); } if (run->max_clusters < run->len) { heap_free( run->clusters ); run->max_clusters = run->len * 2; run->clusters = heap_alloc( run->max_clusters * sizeof(WORD) ); } old_font = ME_SelectStyleFont( c, run->style ); while (1) { hr = ScriptShape( c->hDC, &run->style->script_cache, get_text( run, 0 ), run->len, run->max_glyphs, &run->script_analysis, run->glyphs, run->clusters, run->vis_attrs, &run->num_glyphs ); if (hr != E_OUTOFMEMORY) break; if (run->max_glyphs > 10 * run->len) break; /* something has clearly gone wrong */ run->max_glyphs *= 2; get_run_glyph_buffers( run ); } if (SUCCEEDED(hr)) hr = ScriptPlace( c->hDC, &run->style->script_cache, run->glyphs, run->num_glyphs, run->vis_attrs, &run->script_analysis, run->advances, run->offsets, NULL ); if (SUCCEEDED(hr)) { for (i = 0, run->nWidth = 0; i < run->num_glyphs; i++) run->nWidth += run->advances[i]; } ME_UnselectStyleFont( c, run->style, old_font ); return hr; }
bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, const Font* fontData, Vector<WORD>& glyphs, Vector<WORD>& clusters, Vector<SCRIPT_VISATTR>& visualAttributes) { HWndDC hdc; HFONT oldFont = 0; HRESULT shapeResult = E_PENDING; int glyphCount = 0; if (!fontData) return false; do { shapeResult = ScriptShape(hdc, fontData->scriptCache(), str, len, glyphs.size(), &item.a, glyphs.data(), clusters.data(), visualAttributes.data(), &glyphCount); if (shapeResult == E_PENDING) { // The script cache isn't primed with enough info yet. We need to select our HFONT into // a DC and pass the DC in to ScriptShape. ASSERT(!hdc); hdc.setHWnd(0); HFONT hfont = fontData->platformData().hfont(); oldFont = (HFONT)SelectObject(hdc, hfont); } else if (shapeResult == E_OUTOFMEMORY) { // Need to resize our buffers. glyphs.resize(glyphs.size() * 2); visualAttributes.resize(glyphs.size()); } } while (shapeResult == E_PENDING || shapeResult == E_OUTOFMEMORY); if (hdc) SelectObject(hdc, oldFont); if (FAILED(shapeResult)) return false; glyphs.shrink(glyphCount); visualAttributes.shrink(glyphCount); return true; }
HRESULT Shape() { HRESULT rv; HDC shapeDC = nullptr; const PRUnichar *str = mAlternativeString ? mAlternativeString : mItemString; mScriptItem->a.fLogicalOrder = true; SCRIPT_ANALYSIS sa = mScriptItem->a; while (true) { rv = ScriptShape(shapeDC, mShaper->ScriptCache(), str, mItemLength, mMaxGlyphs, &sa, mGlyphs.Elements(), mClusters.Elements(), mAttr.Elements(), &mNumGlyphs); if (rv == E_OUTOFMEMORY) { mMaxGlyphs *= 2; if (!mGlyphs.SetLength(mMaxGlyphs) || !mAttr.SetLength(mMaxGlyphs)) { return E_OUTOFMEMORY; } continue; } // Uniscribe can't do shaping with some fonts, so it sets the // fNoGlyphIndex flag in the SCRIPT_ANALYSIS structure to indicate // this. This occurs with CFF fonts loaded with // AddFontMemResourceEx but it's not clear what the other cases // are. We return an error so our caller can try fallback shaping. // see http://msdn.microsoft.com/en-us/library/ms776520(VS.85).aspx if (sa.fNoGlyphIndex) { return GDI_ERROR; } if (rv == E_PENDING) { if (shapeDC == mDC) { // we already tried this once, something failed, give up return E_PENDING; } SelectFont(); shapeDC = mDC; continue; } // http://msdn.microsoft.com/en-us/library/dd368564(VS.85).aspx: // Uniscribe will return this if "the font corresponding to the // DC does not support the script required by the run...". // In this case, we'll set the script code to SCRIPT_UNDEFINED // and try again, so that we'll at least get glyphs even though // they won't necessarily have proper shaping. // (We probably shouldn't have selected this font at all, // but it's too late to fix that here.) if (rv == USP_E_SCRIPT_NOT_IN_FONT) { sa.eScript = SCRIPT_UNDEFINED; NS_WARNING("Uniscribe says font does not support script needed"); continue; } // Prior to Windows 7, Uniscribe didn't support Ideographic Variation // Selectors. Replace the UVS glyph manually. if (mIVS) { uint32_t lastChar = str[mItemLength - 1]; if (NS_IS_LOW_SURROGATE(lastChar) && NS_IS_HIGH_SURROGATE(str[mItemLength - 2])) { lastChar = SURROGATE_TO_UCS4(str[mItemLength - 2], lastChar); } uint16_t glyphId = mShaper->GetFont()->GetUVSGlyph(lastChar, mIVS); if (glyphId) { mGlyphs[mNumGlyphs - 1] = glyphId; } } return rv; } }
bool UniscribeHelper::shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, Shaping& shaping) { HFONT hfont = m_hfont; SCRIPT_CACHE* scriptCache = m_scriptCache; SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; int ascent = m_ascent; HDC tempDC = 0; HGDIOBJ oldFont = 0; HRESULT hr; // When used to fill up glyph pages for simple scripts in non-BMP, // we don't want any font fallback in this class. The simple script // font path can take care of font fallback. bool lastFallbackTried = m_disableFontFallback; bool result; int generatedGlyphs = 0; // In case HFONT passed in ctor cannot render this run, we have to scan // other fonts from the beginning of the font list. resetFontIndex(); // Compute shapes. while (true) { shaping.m_logs.resize(itemLength); shaping.m_glyphs.resize(numGlyphs); shaping.m_visualAttributes.resize(numGlyphs); #ifdef PURIFY // http://code.google.com/p/chromium/issues/detail?id=5309 // Purify isn't able to track the assignments that ScriptShape makes to // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it // writes, will be considered un-initialized data. // // This hack avoid the false-positive UMRs by marking the buffer as // initialized. // // FIXME: A better solution would be to use Purify's API and mark only // the populated range as initialized: // // PurifyMarkAsInitialized( // &shaping.m_glyphs[0], // sizeof(shaping.m_glyphs[0] * generatedGlyphs); ZeroMemory(&shaping.m_glyphs[0], sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size()); #endif // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true // here. Is that what we want? It will display control characters. hr = ScriptShape(tempDC, scriptCache, input, itemLength, numGlyphs, &run.a, &shaping.m_glyphs[0], &shaping.m_logs[0], &shaping.m_visualAttributes[0], &generatedGlyphs); if (hr == E_PENDING) { // Allocate the DC. tempDC = GetDC(0); oldFont = SelectObject(tempDC, hfont); continue; } else if (hr == E_OUTOFMEMORY) { numGlyphs *= 2; continue; } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties))) break; // The current font can't render this run. clear DC and try // next font. if (tempDC) { SelectObject(tempDC, oldFont); ReleaseDC(0, tempDC); tempDC = 0; } if (!m_disableFontFallback && nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) { // The primary font does not support this run. Try next font. // In case of web page rendering, they come from fonts specified in // CSS stylesheets. continue; } else if (!lastFallbackTried) { lastFallbackTried = true; // Generate a last fallback font based on the script of // a character to draw while inheriting size and styles // from the primary font if (!m_logfont.lfFaceName[0]) setLogFontAndStyle(m_hfont, &m_logfont, &m_style); // TODO(jungshik): generic type should come from webkit for // UniscribeHelperTextRun (a derived class used in webkit). const UChar *family = getFallbackFamily(input, itemLength, FontDescription::StandardFamily, 0, 0); bool fontOk = getDerivedFontData(family, m_style, &m_logfont, &ascent, &hfont, &scriptCache); if (!fontOk) { // If this GetDerivedFontData is called from the renderer it // might fail because the sandbox is preventing it from opening // the font files. If we are running in the renderer, // TryToPreloadFont is overridden to ask the browser to preload // the font for us so we can access it. tryToPreloadFont(hfont); // Try again. fontOk = getDerivedFontData(family, m_style, &m_logfont, &ascent, &hfont, &scriptCache); ASSERT(fontOk); } // TODO(jungshik) : Currently GetDerivedHFont always returns a // a valid HFONT, but in the future, I may change it to return 0. ASSERT(hfont); // We don't need a font_properties for the last resort fallback font // because we don't have anything more to try and are forced to // accept empty glyph boxes. If we tried a series of fonts as // 'last-resort fallback', we'd need it, but currently, we don't. continue; } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { run.a.eScript = SCRIPT_UNDEFINED; continue; } else if (FAILED(hr)) { // Error shaping. generatedGlyphs = 0; result = false; goto cleanup; } } // Sets Windows font data for this run to those corresponding to // a font supporting this run. we don't need to store font_properties // because it's not used elsewhere. shaping.m_hfont = hfont; shaping.m_scriptCache = scriptCache; // The ascent of a font for this run can be different from // that of the primary font so that we need to keep track of // the difference per run and take that into account when calling // ScriptTextOut in |draw|. Otherwise, different runs rendered by // different fonts would not be aligned vertically. shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0; result = true; cleanup: shaping.m_glyphs.resize(generatedGlyphs); shaping.m_visualAttributes.resize(generatedGlyphs); shaping.m_advance.resize(generatedGlyphs); shaping.m_offsets.resize(generatedGlyphs); if (tempDC) { SelectObject(tempDC, oldFont); ReleaseDC(0, tempDC); } // On failure, our logs don't mean anything, so zero those out. if (!result) shaping.m_logs.clear(); return result; }
/************************************************************* * BIDI_Reorder * * Returns TRUE if reordering was required and done. */ BOOL BIDI_Reorder( HDC hDC, /*[in] Display DC */ LPCWSTR lpString, /* [in] The string for which information is to be returned */ INT uCount, /* [in] Number of WCHARs in string. */ DWORD dwFlags, /* [in] GetCharacterPlacement compatible flags specifying how to process the string */ DWORD dwWineGCP_Flags, /* [in] Wine internal flags - Force paragraph direction */ LPWSTR lpOutString, /* [out] Reordered string */ INT uCountOut, /* [in] Size of output buffer */ UINT *lpOrder, /* [out] Logical -> Visual order map */ WORD **lpGlyphs, /* [out] reordered, mirrored, shaped glyphs to display */ INT *cGlyphs /* [out] number of glyphs generated */ ) { WORD *chartype; BYTE *levels; unsigned i, done, glyph_i; BOOL is_complex; int maxItems; int nItems; SCRIPT_CONTROL Control; SCRIPT_STATE State; SCRIPT_ITEM *pItems; HRESULT res; SCRIPT_CACHE psc = NULL; WORD *run_glyphs = NULL; WORD *pwLogClust = NULL; SCRIPT_VISATTR *psva = NULL; DWORD cMaxGlyphs = 0; BOOL doGlyphs = TRUE; TRACE("%s, %d, 0x%08x lpOutString=%p, lpOrder=%p\n", debugstr_wn(lpString, uCount), uCount, dwFlags, lpOutString, lpOrder); memset(&Control, 0, sizeof(Control)); memset(&State, 0, sizeof(State)); if (lpGlyphs) *lpGlyphs = NULL; if (!(dwFlags & GCP_REORDER)) { FIXME("Asked to reorder without reorder flag set\n"); return FALSE; } if (lpOutString && uCountOut < uCount) { FIXME("lpOutString too small\n"); return FALSE; } chartype = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD)); if (!chartype) { WARN("Out of memory\n"); return FALSE; } if (lpOutString) memcpy(lpOutString, lpString, uCount * sizeof(WCHAR)); is_complex = FALSE; for (i = 0; i < uCount && !is_complex; i++) { if ((lpString[i] >= 0x900 && lpString[i] <= 0xfff) || (lpString[i] >= 0x1cd0 && lpString[i] <= 0x1cff) || (lpString[i] >= 0xa840 && lpString[i] <= 0xa8ff)) is_complex = TRUE; } /* Verify reordering will be required */ if ((WINE_GCPW_FORCE_RTL == (dwWineGCP_Flags&WINE_GCPW_DIR_MASK)) || ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL)) State.uBidiLevel = 1; else if (!is_complex) { done = 1; classify(lpString, chartype, uCount); for (i = 0; i < uCount; i++) switch (chartype[i]) { case R: case AL: case RLE: case RLO: done = 0; break; } if (done) { HeapFree(GetProcessHeap(), 0, chartype); if (lpOrder) { for (i = 0; i < uCount; i++) lpOrder[i] = i; } return TRUE; } } levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(BYTE)); if (!levels) { WARN("Out of memory\n"); HeapFree(GetProcessHeap(), 0, chartype); return FALSE; } maxItems = 5; pItems = HeapAlloc(GetProcessHeap(),0, maxItems * sizeof(SCRIPT_ITEM)); if (!pItems) { WARN("Out of memory\n"); HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, levels); return FALSE; } if (lpGlyphs) { cMaxGlyphs = 1.5 * uCount + 16; run_glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * cMaxGlyphs); if (!run_glyphs) { WARN("Out of memory\n"); HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, levels); HeapFree(GetProcessHeap(), 0, pItems); return FALSE; } pwLogClust = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * uCount); if (!pwLogClust) { WARN("Out of memory\n"); HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, levels); HeapFree(GetProcessHeap(), 0, pItems); HeapFree(GetProcessHeap(), 0, run_glyphs); return FALSE; } psva = HeapAlloc(GetProcessHeap(),0,sizeof(SCRIPT_VISATTR) * uCount); if (!psva) { WARN("Out of memory\n"); HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, levels); HeapFree(GetProcessHeap(), 0, pItems); HeapFree(GetProcessHeap(), 0, run_glyphs); HeapFree(GetProcessHeap(), 0, pwLogClust); return FALSE; } } done = 0; glyph_i = 0; while (done < uCount) { unsigned j; classify(lpString + done, chartype, uCount - done); /* limit text to first block */ i = resolveParagraphs(chartype, uCount - done); for (j = 0; j < i; ++j) switch(chartype[j]) { case B: case S: case WS: case ON: chartype[j] = N; default: continue; } if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL) State.uBidiLevel = 1; else if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_LTR) State.uBidiLevel = 0; if (dwWineGCP_Flags & WINE_GCPW_LOOSE_MASK) { for (j = 0; j < i; ++j) if (chartype[j] == L) { State.uBidiLevel = 0; break; } else if (chartype[j] == R || chartype[j] == AL) { State.uBidiLevel = 1; break; } } res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems); while (res == E_OUTOFMEMORY) { maxItems = maxItems * 2; pItems = HeapReAlloc(GetProcessHeap(), 0, pItems, sizeof(SCRIPT_ITEM) * maxItems); if (!pItems) { WARN("Out of memory\n"); HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, levels); return FALSE; } res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems); } if (lpOutString || lpOrder) for (j = 0; j < nItems; j++) { int k; for (k = pItems[j].iCharPos; k < pItems[j+1].iCharPos; k++) levels[k] = pItems[j].a.s.uBidiLevel; } if (lpOutString) { /* assign directional types again, but for WS, S this time */ classify(lpString + done, chartype, i); BidiLines(State.uBidiLevel, lpOutString + done, lpString + done, chartype, levels, i, 0); } if (lpOrder) { int k, lastgood; for (j = lastgood = 0; j < i; ++j) if (levels[j] != levels[lastgood]) { --j; if (odd(levels[lastgood])) for (k = j; k >= lastgood; --k) lpOrder[done + k] = done + j - k; else for (k = lastgood; k <= j; ++k) lpOrder[done + k] = done + k; lastgood = ++j; } if (odd(levels[lastgood])) for (k = j - 1; k >= lastgood; --k) lpOrder[done + k] = done + j - 1 - k; else for (k = lastgood; k < j; ++k) lpOrder[done + k] = done + k; } if (lpGlyphs && doGlyphs) { int j; BYTE runOrder[maxItems]; int visOrder[maxItems]; SCRIPT_ITEM *curItem; for (j = 0; j < nItems; j++) runOrder[j] = pItems[j].a.s.uBidiLevel; ScriptLayout(nItems, runOrder, visOrder, NULL); for (j = 0; j < nItems; j++) { int k; int cChars,cOutGlyphs; curItem = &pItems[visOrder[j]]; cChars = pItems[visOrder[j]+1].iCharPos - curItem->iCharPos; res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs); while (res == E_OUTOFMEMORY) { cMaxGlyphs *= 2; run_glyphs = HeapReAlloc(GetProcessHeap(), 0, run_glyphs, sizeof(WORD) * cMaxGlyphs); if (!run_glyphs) { WARN("Out of memory\n"); HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, levels); HeapFree(GetProcessHeap(), 0, pItems); HeapFree(GetProcessHeap(), 0, psva); HeapFree(GetProcessHeap(), 0, pwLogClust); HeapFree(GetProcessHeap(), 0, *lpGlyphs); ScriptFreeCache(&psc); *lpGlyphs = NULL; return FALSE; } res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs); } if (res) { if (res == USP_E_SCRIPT_NOT_IN_FONT) TRACE("Unable to shape with currently selected font\n"); else FIXME("Unable to shape string (%x)\n",res); j = nItems; doGlyphs = FALSE; HeapFree(GetProcessHeap(), 0, *lpGlyphs); *lpGlyphs = NULL; } else { if (*lpGlyphs) *lpGlyphs = HeapReAlloc(GetProcessHeap(), 0, *lpGlyphs, sizeof(WORD) * (glyph_i + cOutGlyphs)); else *lpGlyphs = HeapAlloc(GetProcessHeap(), 0, sizeof(WORD) * (glyph_i + cOutGlyphs)); for (k = 0; k < cOutGlyphs; k++) (*lpGlyphs)[glyph_i+k] = run_glyphs[k]; glyph_i += cOutGlyphs; } } } done += i; } if (cGlyphs) *cGlyphs = glyph_i; HeapFree(GetProcessHeap(), 0, chartype); HeapFree(GetProcessHeap(), 0, levels); HeapFree(GetProcessHeap(), 0, pItems); HeapFree(GetProcessHeap(), 0, run_glyphs); HeapFree(GetProcessHeap(), 0, pwLogClust); HeapFree(GetProcessHeap(), 0, psva); ScriptFreeCache(&psc); return TRUE; }
static bool MCTextLayoutShapeItem(MCTextLayoutState& self, SCRIPT_ANALYSIS p_analysis, const unichar_t *p_chars, uint32_t p_char_count, MCTextLayoutFont *p_font, bool* p_try) { bool t_success; t_success = true; // We do everything in logical order, doing any swizzling of glyphs at the // end. p_analysis . fLogicalOrder = true; // We start off by using the given font, however if this causes an issue // with shaping we fall back to the primary font. MCTextLayoutFont *t_layout_font; t_layout_font = p_font; // If the initial font is nil, then we use the primary font and undefined // script. if (t_layout_font == nil) { p_analysis . eScript = SCRIPT_UNDEFINED; t_layout_font = self . primary_font; } // Allocate a big enough cluster array for the item WORD *t_clusters; uint32_t t_cluster_limit; t_clusters = nil; t_cluster_limit = 0; if (t_success) t_success = MCMemoryResizeArray(p_char_count, t_clusters, t_cluster_limit); // Loop until we succeed in generating some glyphs - note that this loop // is a little hairy. It loops until we don't get E_OUTOFMEMORY, but // additionally, may loop with USP_E_SCRIPT_NOT_IN_FONT, in which case // t_script_font will have changed, as might p_analysis. WORD *t_glyphs; SCRIPT_VISATTR *t_attrs; uint32_t t_glyph_limit, t_attr_limit, t_glyph_count; t_glyphs = nil; t_attrs = nil; t_glyph_limit = 0; t_attr_limit = 0; t_glyph_count = 0; while(t_success) { // Make sure we have enough room in the glyph buffer uint32_t t_new_glyph_limit; t_new_glyph_limit = (t_glyph_limit == 0 ? p_char_count + p_char_count / 2 + 16 : t_glyph_limit + p_char_count / 2); t_success = MCMemoryResizeArray(t_new_glyph_limit, t_glyphs, t_glyph_limit) && MCMemoryResizeArray(t_new_glyph_limit, t_attrs, t_attr_limit); // Now try to shape HRESULT t_result; if (t_success) { SelectObject(self . dc, t_layout_font -> handle); t_result = ScriptShape(self . dc, &t_layout_font -> cache, p_chars, p_char_count, t_glyph_limit, &p_analysis, t_glyphs, t_clusters, t_attrs, (int *)&t_glyph_count); if (t_result != S_OK && t_result != E_OUTOFMEMORY && t_result != USP_E_SCRIPT_NOT_IN_FONT) t_success = false; } // If the result was 'script not in font' then reprocess with the undefined // script with the primary font. if (t_success && t_result == USP_E_SCRIPT_NOT_IN_FONT) { // If we are just testing for shaping success, break on no font. if (p_try != nil) break; t_layout_font = self . primary_font; p_analysis . eScript = SCRIPT_UNDEFINED; continue; } // If the result is S_OK, we can break if (t_success && t_result == S_OK) break; } // Assuming nothing failed, we now have a sequence of glyphs to place (only // if we aren't just testing for shaping success). if (t_success && p_try == nil) t_success = MCTextLayoutPlaceItem(self, p_analysis, p_chars, p_char_count, t_clusters, t_glyphs, t_attrs, t_glyph_count, t_layout_font); // If we are testing for shaping success then scan the glyph buffer for // undefined glyphs. if (t_success && p_try != nil) { uint32_t t_undefined; t_undefined = 0; for(uint32_t i = 0; i < t_glyph_count; i++) if (t_glyphs[i] == t_layout_font -> default_glyph) t_undefined += 1; // We use the following heuristic - if the first glyph is undefined // then shaping failed, otherwise shaping only fails if *all* the // glyphs are undefined. *p_try = t_glyph_count != 0 && t_undefined != t_glyph_count && t_glyphs[0] != t_layout_font -> default_glyph; } // Free up the arrays we allocated - placing causes the contents to be // copied/processed into separate run buffers. MCMemoryDeleteArray(t_clusters); MCMemoryDeleteArray(t_glyphs); MCMemoryDeleteArray(t_attrs); return t_success; }
static gboolean itemize_shape_and_place (PangoFont *font, HDC hdc, wchar_t *wtext, int wlen, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { int i; int item, nitems, item_step; int itemlen, glyphix, nglyphs; SCRIPT_CONTROL control; SCRIPT_STATE state; SCRIPT_ITEM items[100]; double scale = pango_win32_font_get_metrics_factor (font); HFONT hfont = _pango_win32_font_get_hfont (font); static GHashTable *script_cache_hash = NULL; if (!script_cache_hash) script_cache_hash = g_hash_table_new (g_int64_hash, g_int64_equal); memset (&control, 0, sizeof (control)); memset (&state, 0, sizeof (state)); control.uDefaultLanguage = make_langid (analysis->language); state.uBidiLevel = analysis->level; #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (G_STRLOC ": ScriptItemize: uDefaultLanguage:%04x uBidiLevel:%d\n", control.uDefaultLanguage, state.uBidiLevel); #endif if (ScriptItemize (wtext, wlen, G_N_ELEMENTS (items), &control, NULL, items, &nitems)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("ScriptItemize failed\n"); #endif return FALSE; } #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("%d items:\n", nitems); #endif if (analysis->level % 2) { item = nitems - 1; item_step = -1; } else { item = 0; item_step = 1; } for (i = 0; i < nitems; i++, item += item_step) { WORD iglyphs[1000]; WORD log_clusters[1000]; SCRIPT_VISATTR visattrs[1000]; int advances[1000]; GOFFSET offsets[1000]; ABC abc; gint32 script = items[item].a.eScript; int ng; int char_offset; SCRIPT_CACHE *script_cache; gint64 font_and_script_key; memset (advances, 0, sizeof (advances)); memset (offsets, 0, sizeof (offsets)); memset (&abc, 0, sizeof (abc)); /* Note that itemlen is number of wchar_t's i.e. surrogate pairs * count as two! */ itemlen = items[item+1].iCharPos - items[item].iCharPos; char_offset = items[item].iCharPos; #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (" Item %d: iCharPos=%d eScript=%d (%s) %s%s%s%s%s%s%s wchar_t %d--%d (%d)\n", item, items[item].iCharPos, script, lang_name (scripts[script]->langid), scripts[script]->fComplex ? "complex" : "simple", items[item].a.fRTL ? " fRTL" : "", items[item].a.fLayoutRTL ? " fLayoutRTL" : "", items[item].a.fLinkBefore ? " fLinkBefore" : "", items[item].a.fLinkAfter ? " fLinkAfter" : "", items[item].a.fLogicalOrder ? " fLogicalOrder" : "", items[item].a.fNoGlyphIndex ? " fNoGlyphIndex" : "", items[item].iCharPos, items[item+1].iCharPos-1, itemlen); #endif /* Create a hash key based on hfont and script engine */ font_and_script_key = (((gint64) ((gint32) hfont)) << 32) | script; /* Get the script cache for this hfont and script */ script_cache = g_hash_table_lookup (script_cache_hash, &font_and_script_key); if (!script_cache) { gint64 *key_n; SCRIPT_CACHE *new_script_cache; key_n = g_new (gint64, 1); *key_n = font_and_script_key; new_script_cache = g_new0 (SCRIPT_CACHE, 1); script_cache = new_script_cache; /* Insert the new value */ g_hash_table_insert (script_cache_hash, key_n, new_script_cache); #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (" New SCRIPT_CACHE for font %p and script %d\n", hfont, script); #endif } items[item].a.fRTL = analysis->level % 2; if (ScriptShape (hdc, script_cache, wtext + items[item].iCharPos, itemlen, G_N_ELEMENTS (iglyphs), &items[item].a, iglyphs, log_clusters, visattrs, &nglyphs)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("pango-basic-win32: ScriptShape failed\n"); #endif return FALSE; } #ifdef BASIC_WIN32_DEBUGGING dump_glyphs_and_log_clusters (items[item].a.fRTL, itemlen, items[item].iCharPos, log_clusters, iglyphs, nglyphs); #endif ng = glyphs->num_glyphs; pango_glyph_string_set_size (glyphs, ng + nglyphs); set_up_pango_log_clusters (wtext + items[item].iCharPos, items[item].a.fRTL, itemlen, log_clusters, nglyphs, glyphs->log_clusters + ng, char_offset); if (ScriptPlace (hdc, script_cache, iglyphs, nglyphs, visattrs, &items[item].a, advances, offsets, &abc)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("pango-basic-win32: ScriptPlace failed\n"); #endif return FALSE; } for (glyphix = 0; glyphix < nglyphs; glyphix++) { if (iglyphs[glyphix] != 0) { glyphs->glyphs[ng+glyphix].glyph = iglyphs[glyphix]; glyphs->glyphs[ng+glyphix].geometry.width = floor (0.5 + scale * advances[glyphix]); glyphs->glyphs[ng+glyphix].geometry.x_offset = floor (0.5 + scale * offsets[glyphix].du); glyphs->glyphs[ng+glyphix].geometry.y_offset = floor (0.5 + scale * offsets[glyphix].dv); } else { PangoRectangle logical_rect; /* Should pass actual char that was not found to * PANGO_GET_UNKNOWN_GLYPH(), but a bit hard to * find out that at this point, so cheat and use 0. */ PangoGlyph unk = PANGO_GET_UNKNOWN_GLYPH (0); glyphs->glyphs[ng+glyphix].glyph = unk; pango_font_get_glyph_extents (font, unk, NULL, &logical_rect); glyphs->glyphs[ng+glyphix].geometry.width = logical_rect.width; glyphs->glyphs[ng+glyphix].geometry.x_offset = 0; glyphs->glyphs[ng+glyphix].geometry.y_offset = 0; } } } #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) { g_print (" Pango log_clusters (level:%d), char index:", analysis->level); for (glyphix = 0; glyphix < glyphs->num_glyphs; glyphix++) g_print ("%d ", glyphs->log_clusters[glyphix]); g_print ("\n"); } #endif return TRUE; }