Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
    }
  }
  
}
Exemplo n.º 5
0
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;
    }
Exemplo n.º 7
0
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);
    }
}
Exemplo n.º 9
0
/*************************************************************
 *    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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
0
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;

}