static HRESULT itemize(WCHAR *msg, size_t len, SCRIPT_ITEM **out, int *outn) { SCRIPT_CONTROL sc; SCRIPT_STATE ss; SCRIPT_ITEM *items; size_t maxItems; int n; HRESULT hr; // make sure these are zero-initialized to avoid mangling the text ZeroMemory(&sc, sizeof (SCRIPT_CONTROL)); ZeroMemory(&ss, sizeof (SCRIPT_STATE)); maxItems = len + 2; for (;;) { items = new SCRIPT_ITEM[maxItems]; hr = ScriptItemize(msg, len, maxItems, &sc, &ss, items, &n); if (hr == S_OK) break; // otherwise either an error or not enough room delete[] items; if (hr != E_OUTOFMEMORY) return hr; maxItems *= 2; // add some more and try again } *out = items; *outn = n; return S_OK; }
BOOL doScriptItemize(struct scriptItemizeParams *p) { HRESULT hr; hr = ScriptItemize(p->pwcInChars, p->cInChars, p->cMaxItems, p->psControl, p->psState, p->pItems, p->pcItems); if (hr == S_OK) return TRUE; if (hr != E_OUTOFMEMORY) die("error calling ScriptItemize()", hr); return FALSE; }
void NS_GetComplexLineBreaks(const char16_t* aText, uint32_t aLength, uint8_t* aBreakBefore) { NS_ASSERTION(aText, "aText shouldn't be null"); int outItems = 0; HRESULT result; AutoTArray<SCRIPT_ITEM, 64> items; char16ptr_t text = aText; memset(aBreakBefore, false, aLength); if (!items.AppendElements(64)) return; do { result = ScriptItemize(text, aLength, items.Length(), nullptr, nullptr, items.Elements(), &outItems); if (result == E_OUTOFMEMORY) { if (!items.AppendElements(items.Length())) return; } } while (result == E_OUTOFMEMORY); for (int iItem = 0; iItem < outItems; ++iItem) { uint32_t endOffset = (iItem + 1 == outItems ? aLength : items[iItem + 1].iCharPos); uint32_t startOffset = items[iItem].iCharPos; AutoTArray<SCRIPT_LOGATTR, 64> sla; if (!sla.AppendElements(endOffset - startOffset)) return; if (ScriptBreak(text + startOffset, endOffset - startOffset, &items[iItem].a, sla.Elements()) < 0) return; for (uint32_t j=0; j+startOffset < endOffset; ++j) { aBreakBefore[j+startOffset] = sla[j].fSoftBreak; } } }
void NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength, PRPackedBool* aBreakBefore) { NS_ASSERTION(aText, "aText shouldn't be null"); int outItems = 0; HRESULT result; nsAutoTArray<SCRIPT_ITEM, 64> items; memset(aBreakBefore, PR_FALSE, aLength); if (!items.AppendElements(64)) return; do { result = ScriptItemize(aText, aLength, items.Length(), NULL, NULL, items.Elements(), &outItems); if (result == E_OUTOFMEMORY) { if (!items.AppendElements(items.Length())) return; } } while (result == E_OUTOFMEMORY); for (int iItem = 0; iItem < outItems; ++iItem) { PRUint32 endOffset = (iItem + 1 == outItems ? aLength : items[iItem + 1].iCharPos); PRUint32 startOffset = items[iItem].iCharPos; nsAutoTArray<SCRIPT_LOGATTR, 64> sla; if (!sla.AppendElements(endOffset - startOffset)) return; if (ScriptBreak(aText + startOffset, endOffset - startOffset, &items[iItem].a, sla.Elements()) < 0) return; for (PRUint32 j=0; j+startOffset < endOffset; ++j) { aBreakBefore[j+startOffset] = sla[j].fSoftBreak; } } }
void UniscribeController::itemizeShapeAndPlace(const UChar* cp, unsigned length, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer) { // ScriptItemize (in Windows XP versions prior to SP2) can overflow by 1. This is why there is an extra empty item // hanging out at the end of the array m_items.resize(6); int numItems = 0; while (ScriptItemize(cp, length, m_items.size() - 1, &m_control, &m_state, m_items.data(), &numItems) == E_OUTOFMEMORY) { m_items.resize(m_items.size() * 2); resetControlAndState(); } m_items.resize(numItems + 1); if (m_run.rtl()) { for (int i = m_items.size() - 2; i >= 0; i--) { if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer)) return; } } else { for (unsigned i = 0; i < m_items.size() - 1; i++) { if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer)) return; } } }
int Itemize() { HRESULT rv; int maxItems = 5; Init(); // Allocate space for one more item than expected, to handle a rare // overflow in ScriptItemize (pre XP SP2). See bug 366643. if (!mItems.SetLength(maxItems + 1)) { return 0; } while ((rv = ScriptItemize(mString, mLength, maxItems, &mControl, &mState, mItems.Elements(), &mNumItems)) == E_OUTOFMEMORY) { maxItems *= 2; if (!mItems.SetLength(maxItems + 1)) { return 0; } Init(); } return mNumItems; }
static HRESULT itemize_para( ME_Context *c, ME_DisplayItem *p ) { ME_Paragraph *para = &p->member.para; ME_Run *run; ME_DisplayItem *di; SCRIPT_ITEM buf[16], *items = buf; int items_passed = sizeof( buf ) / sizeof( buf[0] ), num_items, cur_item; SCRIPT_CONTROL control = { LANG_USER_DEFAULT, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0 }; SCRIPT_STATE state = { 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, 0 }; HRESULT hr; assert( p->type == diParagraph ); while (1) { hr = ScriptItemize( para->text->szData, para->text->nLen, items_passed, &control, &state, items, &num_items ); if (hr != E_OUTOFMEMORY) break; /* may not be enough items if hr == E_OUTOFMEMORY */ if (items_passed > para->text->nLen + 1) break; /* something else has gone wrong */ items_passed *= 2; if (items == buf) items = heap_alloc( items_passed * sizeof( *items ) ); else items = heap_realloc( items, items_passed * sizeof( *items ) ); if (!items) break; } if (FAILED( hr )) goto end; if (TRACE_ON( richedit )) { TRACE( "got items:\n" ); for (cur_item = 0; cur_item < num_items; cur_item++) { TRACE( "\t%d - %d RTL %d bidi level %d\n", items[cur_item].iCharPos, items[cur_item+1].iCharPos - 1, items[cur_item].a.fRTL, items[cur_item].a.s.uBidiLevel ); } TRACE( "before splitting runs into ranges\n" ); for (di = p->next; di != p->member.para.next_para; di = di->next) { if (di->type != diRun) continue; TRACE( "\t%d: %s\n", di->member.run.nCharOfs, debugstr_run( &di->member.run ) ); } } /* split runs into ranges at item boundaries */ for (di = p->next, cur_item = 0; di != p->member.para.next_para; di = di->next) { if (di->type != diRun) continue; run = &di->member.run; if (run->nCharOfs == items[cur_item+1].iCharPos) cur_item++; items[cur_item].a.fLogicalOrder = TRUE; run->script_analysis = items[cur_item].a; if (run->nFlags & MERF_ENDPARA) break; /* don't split eop runs */ if (run->nCharOfs + run->len > items[cur_item+1].iCharPos) { ME_Cursor cursor = {p, di, items[cur_item+1].iCharPos - run->nCharOfs}; ME_SplitRunSimple( c->editor, &cursor ); } } if (TRACE_ON( richedit )) { TRACE( "after splitting into ranges\n" ); for (di = p->next; di != p->member.para.next_para; di = di->next) { if (di->type != diRun) continue; TRACE( "\t%d: %s\n", di->member.run.nCharOfs, debugstr_run( &di->member.run ) ); } } para->nFlags |= MEPF_COMPLEX; end: if (items != buf) heap_free( items ); return hr; }
void UniscribeHelper::fillRuns() { HRESULT hr; m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS); SCRIPT_STATE inputState; inputState.uBidiLevel = m_isRtl; inputState.fOverrideDirection = m_directionalOverride; inputState.fInhibitSymSwap = false; inputState.fCharShape = false; // Not implemented in Uniscribe inputState.fDigitSubstitute = false; // Do we want this for Arabic? inputState.fInhibitLigate = m_inhibitLigate; inputState.fDisplayZWG = false; // Don't draw control characters. inputState.fArabicNumContext = m_isRtl; // Do we want this for Arabic? inputState.fGcpClusters = false; inputState.fReserved = 0; inputState.fEngineReserved = 0; // The psControl argument to ScriptItemize should be non-0 for RTL text, // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a // SCRIPT_CONTROL that is set to all zeros. Zero as a locale ID means the // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage :16; 0, // fContextDigits :1; 0, // fInvertPreBoundDir :1; 0, // fInvertPostBoundDir :1; 0, // fLinkStringBefore :1; 0, // fLinkStringAfter :1; 0, // fNeutralOverride :1; 0, // fNumericOverride :1; 0, // fLegacyBidiClass :1; 0, // fMergeNeutralItems :1; 0};// fReserved :7; // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState) // here would be appropriate if we wanted to set the language ID, and get // local digit substitution behavior. For now, don't do it. while (true) { int numberOfItems = 0; // Ideally, we would have a way to know the runs before and after this // one, and put them into the control parameter of ScriptItemize. This // would allow us to shape characters properly that cross style // boundaries (WebKit bug 6148). // // We tell ScriptItemize that the output list of items is one smaller // than it actually is. According to Mozilla bug 366643, if there is // not enough room in the array on pre-SP2 systems, ScriptItemize will // write one past the end of the buffer. // // ScriptItemize is very strange. It will often require a much larger // ITEM buffer internally than it will give us as output. For example, // it will say a 16-item buffer is not big enough, and will write // interesting numbers into all those items. But when we give it a 32 // item buffer and it succeeds, it only has one item output. // // It seems to be doing at least two passes, the first where it puts a // lot of intermediate data into our items, and the second where it // collates them. hr = ScriptItemize(m_input, m_inputLength, static_cast<int>(m_runs.size()) - 1, &inputControl, &inputState, &m_runs[0], &numberOfItems); if (SUCCEEDED(hr)) { m_runs.resize(numberOfItems); break; } if (hr != E_OUTOFMEMORY) { // Some kind of unexpected error. m_runs.resize(0); break; } // There was not enough items for it to write into, expand. m_runs.resize(m_runs.size() * 2); } }
/************************************************************* * 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; }
bool MCTextLayout(const unichar_t *p_chars, uint32_t p_char_count, MCFontStruct *p_font, MCTextLayoutCallback p_callback, void *p_context) { bool t_success; t_success = true; // The state structure we use to record the list of runs and the dc we use // for processing. MCTextLayoutState self; MCMemoryClear(&self, sizeof(MCTextLayoutState)); if (t_success) { self . dc = CreateCompatibleDC(nil); if (self . dc == nil) t_success = false; } // Fetch a layout font for the provided HFONT. if (t_success) t_success = MCTextLayoutFontFromHFONT(p_font -> fid, self . primary_font); // First thing we need to do is itemize the input string. The ScriptItemize // function splits up the chars into runs, each run being potentially // processed differently by Uniscribe. // Unfortunately, there is no way to predict for an arbitrary string how // many items might be generated, nor is the ScriptItemize function // incremental, thus we must loop with an every increasing buffer until // we have enough room. SCRIPT_ITEM *t_items; uint32_t t_item_limit, t_item_count; SCRIPT_STATE t_script_state; SCRIPT_CONTROL t_script_control; t_items = nil; t_item_limit = 0; t_item_count = 0; MCMemoryClear(&t_script_state, sizeof(SCRIPT_STATE)); MCMemoryClear(&t_script_control, sizeof(SCRIPT_CONTROL)); while(t_success) { // Increase the item array by 32 each time if (t_success) t_success = MCMemoryResizeArray(t_item_limit + 32, t_items, t_item_limit); // Attempt to itemize HRESULT t_result; if (t_success) { t_result = ScriptItemize(p_chars, p_char_count, t_item_limit, &t_script_control, &t_script_state, t_items, (int *)&t_item_count); if (t_result != S_OK && t_result != E_OUTOFMEMORY) t_success = false; } if (t_success && t_result == S_OK) break; } // Next we loop through the items one by one, processing them as we go, this // process is slightly recursive - LayoutItem may recurse to fill in any // 'holes' caused by glyphs not in the primary font. for(uint32_t i = 0; i < t_item_count && t_success; i++) t_success = MCTextLayoutStyleItem( self, t_items[i] . a, p_chars + t_items[i] . iCharPos, t_items[i + 1] . iCharPos - t_items[i] . iCharPos, self . primary_font); // At this point we should have an array of runs to render. First though we // need to compute the visual to logical mapping. uint8_t *t_levels; int *t_map; t_levels = nil; t_map = nil; if (t_success) t_success = MCMemoryNewArray(self . run_count, t_levels) && MCMemoryNewArray(self . run_count, t_map); // Work out the run mapping, but only if we have runs to map! if (t_success && self . run_count > 0) { for(uint32_t i = 0; i < self . run_count; i++) t_levels[i] = self . runs[i] . embedding_level; if (ScriptLayout(self . run_count, t_levels, t_map, nil) != S_OK) t_success = false; } // Now we have the mapping we loop through the runs in the correct order // dispatching them to the callback. if (t_success && p_callback != nil) { double t_x; t_x = 0.0; for(uint32_t i = 0; i < self . run_count && t_success; i++) { MCTextLayoutRun *t_run; t_run = &self . runs[t_map[i]]; // Allocate a temporary array for the glyph structures MCTextLayoutGlyph *t_glyphs; t_glyphs = nil; if (t_success) t_success = MCMemoryNewArray(t_run -> glyph_count, t_glyphs); if (t_success) { // Compute the position for each glyph, keeping a running // total of the advance width. for(uint32_t i = 0; i < t_run -> glyph_count; i++) { t_glyphs[i] . index = t_run -> glyphs[i]; t_glyphs[i] . x = t_x + t_run -> goffsets[i] . du; t_glyphs[i] . y = t_run -> goffsets[i] . dv; t_x += t_run -> advances[i]; } // Dispatch the span to the callback. MCTextLayoutSpan t_span; t_span . chars = t_run -> chars; t_span . clusters = t_run -> clusters; t_span . char_count = t_run -> char_count; t_span . glyphs = t_glyphs; t_span . glyph_count = t_run -> glyph_count; t_span . font = t_run -> font -> handle; t_success = p_callback(p_context, &t_span); } // Free the temporary array. MCMemoryDeleteArray(t_glyphs); } } // Free all the arrays and other resources that have been allocated. MCMemoryDeleteArray(t_map); MCMemoryDeleteArray(t_levels); for(uint32_t i = 0; i < self . run_count; i++) { MCMemoryDeallocate(self . runs[i] . chars); MCMemoryDeallocate(self . runs[i] . clusters); MCMemoryDeallocate(self . runs[i] . glyphs); MCMemoryDeallocate(self . runs[i] . advances); MCMemoryDeallocate(self . runs[i] . goffsets); } MCMemoryDeleteArray(self . runs); MCMemoryDeleteArray(t_items); if (self . dc != nil) DeleteDC(self . dc); 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; }
void GenUsp10DllData() { WCHAR *text = new WCHAR[0xFFFF]; SCRIPT_ITEM *si = new SCRIPT_ITEM[0x0ffff]; for(int i = 0; i < 0xffff; ++i) { text[i] = i + 1; } int item_count = 0 ; HRESULT hr = ScriptItemize(text, 0xffff, 0x0fffff, NULL, NULL, si, &item_count); wprintf(L"#,code range,scriptId\n"); if(hr == S_OK) { WCHAR out_str[200]; for(int j = 0; j<item_count; ++j) { wsprintf(out_str, L"%d,U%04X-U%04X,%d\n",j,text[si[j].iCharPos], text[si[j+1].iCharPos - 1],si[j].a.eScript); //OutputDebugString(out_str); wprintf(out_str); } } wprintf(L"\n**********************************************\n"); wprintf(L"Script Property List:\n\n"); WCHAR out_str[1000]; wprintf(L"id,");//, //:16; // Primary and sublanguage associated with script wprintf(L"Name,");//, wprintf(L"langid,");//, //:16; // Primary and sublanguage associated with script wprintf(L"Numeric,");//, //:1; wprintf(L"Complex,");//, //:1; // Script requires special shaping or layout wprintf(L"NeedsWordBreaking,");//, //:1; // Requires ScriptBreak for word breaking information wprintf(L"NeedsCaretInfo,");//, //:1; // Requires caret restriction to cluster boundaries wprintf(L"CharSet,");//, //:8; // Charset to use when creating font wprintf(L"Control,");//, //:1; // Contains only control characters wprintf(L"PrivateUseArea,");//, //:1; // This item is from the Unicode range U+E000 through U+F8FF wprintf(L"NeedsCharacterJustify,");//, //:1; // Requires inter-character justification wprintf(L"InvalidGlyph,");//, //:1; // Invalid combinations generate glyph wgInvalid in the glyph buffer wprintf(L"InvalidLogAttr,");//, //:1; // Invalid combinations are marked by fInvalid in the logical attributes wprintf(L"CDM,");// //:1; // Contains Combining Diacritical Marks wprintf(L"AmbiguousCharSet,");//, //:1; // Script does not correspond 1:1 with a charset wprintf(L"ClusterSizeVaries,");//, //:1; // Measured cluster width depends on adjacent clusters wprintf(L"RejectInvalid\n");//, //:1; // Invalid combinations rejected,// const SCRIPT_PROPERTIES **propList = NULL; int propCount = 0; ScriptGetProperties(&propList, &propCount); for (int i = 0; i < propCount; i++) { wprintf(L"%2d,", i); wprintf(L"%s,", GetLangName(propList[i]->langid)); wprintf(L"0x%04X,", propList[i]->langid); //:16; // Primary and sublanguage associated with script wprintf(L"%d,", propList[i]->fNumeric); //:1; wprintf(L"%d,", propList[i]->fComplex); //:1; // Script requires special shaping or layout wprintf(L"%d,", propList[i]->fNeedsWordBreaking); //:1; // Requires ScriptBreak for word breaking information wprintf(L"%d,", propList[i]->fNeedsCaretInfo); //:1; // Requires caret restriction to cluster boundaries wprintf(L"0x%02X,", propList[i]->bCharSet); //:8; // Charset to use when creating font wprintf(L"%d,", propList[i]->fControl); //:1; // Contains only control characters wprintf(L"%d,", propList[i]->fPrivateUseArea); //:1; // This item is from the Unicode range U+E000 through U+F8FF wprintf(L"%d,", propList[i]->fNeedsCharacterJustify); //:1; // Requires inter-character justification wprintf(L"%d,", propList[i]->fInvalidGlyph); //:1; // Invalid combinations generate glyph wgInvalid in the glyph buffer wprintf(L"%d,", propList[i]->fInvalidLogAttr); //:1; // Invalid combinations are marked by fInvalid in the logical attributes wprintf(L"%d,", propList[i]->fCDM); //:1; // Contains Combining Diacritical Marks wprintf(L"%d,", propList[i]->fAmbiguousCharSet); //:1; // Script does not correspond 1:1 with a charset wprintf(L"%d,", propList[i]->fClusterSizeVaries); //:1; // Measured cluster width depends on adjacent clusters wprintf(L"%d\n", propList[i]->fRejectInvalid); //:1; // Invalid combinations should be rejected } delete[] si; delete[] text; }