void UniscribeHelper::fillShapes()
{
    m_shapes.resize(m_runs.size());
    for (size_t i = 0; i < m_runs.size(); i++) {
        int startItem = m_runs[i].iCharPos;
        int itemLength = m_inputLength - startItem;
        if (i < m_runs.size() - 1)
            itemLength = m_runs[i + 1].iCharPos - startItem;

        int numGlyphs;
        if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) {
            // We'll start our buffer sizes with the current stack space
            // available in our buffers if the current input fits. As long as
            // it doesn't expand past that we'll save a lot of time mallocing.
            numGlyphs = UNISCRIBE_HELPER_STACK_CHARS;
        } else {
            // When the input doesn't fit, give up with the stack since it will
            // almost surely not be enough room (unless the input actually
            // shrinks, which is unlikely) and just start with the length
            // recommended by the Uniscribe documentation as a "usually fits"
            // size.
            numGlyphs = itemLength * 3 / 2 + 16;
        }

        // Convert a string to a glyph string trying the primary font, fonts in
        // the fallback list and then script-specific last resort font.
        Shaping& shaping = m_shapes[i];
        if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
            continue;

        // At the moment, the only time m_disableFontFallback is set is
        // when we look up glyph indices for non-BMP code ranges. So,
        // we can skip the glyph placement. When that becomes not the case
        // any more, we have to add a new flag to control glyph placement.
        if (m_disableFontFallback)
          continue;

        // Compute placements. Note that offsets is documented incorrectly
        // and is actually an array.

        // DC that we lazily create if Uniscribe commands us to.
        // (this does not happen often because scriptCache is already
        //  updated when calling ScriptShape).
        HDC tempDC = 0;
        HGDIOBJ oldFont = 0;
        HRESULT hr;
        while (true) {
            shaping.m_prePadding = 0;
            hr = ScriptPlace(tempDC, shaping.m_scriptCache,
                             &shaping.m_glyphs[0],
                             static_cast<int>(shaping.m_glyphs.size()),
                             &shaping.m_visualAttributes[0], &m_runs[i].a,
                             &shaping.m_advance[0], &shaping.m_offsets[0],
                             &shaping.m_abc);
            if (hr != E_PENDING)
                break;

            // Allocate the DC and run the loop again.
            tempDC = GetDC(0);
            oldFont = SelectObject(tempDC, shaping.m_hfont);
        }

        if (FAILED(hr)) {
            // Some error we don't know how to handle. Nuke all of our data
            // since we can't deal with partially valid data later.
            m_runs.clear();
            m_shapes.clear();
            m_screenOrder.clear();
        }

        if (tempDC) {
            SelectObject(tempDC, oldFont);
            ReleaseDC(0, tempDC);
        }
    }

    adjustSpaceAdvances();

    if (m_letterSpacing != 0 || m_wordSpacing != 0)
        applySpacing();
}
Пример #2
0
void UniscribeHelper::fillShapes()
{
    m_shapes.resize(m_runs.size());
    for (size_t i = 0; i < m_runs.size(); i++) {
        int startItem = m_runs[i].iCharPos;
        int itemLength = m_inputLength - startItem;
        if (i < m_runs.size() - 1)
            itemLength = m_runs[i + 1].iCharPos - startItem;

        int numGlyphs;
        if (itemLength < cUniscribeHelperStackChars) {
            // We'll start our buffer sizes with the current stack space
            // available in our buffers if the current input fits. As long as
            // it doesn't expand past that we'll save a lot of time mallocing.
            numGlyphs = cUniscribeHelperStackChars;
        } else {
            // When the input doesn't fit, give up with the stack since it will
            // almost surely not be enough room (unless the input actually
            // shrinks, which is unlikely) and just start with the length
            // recommended by the Uniscribe documentation as a "usually fits"
            // size.
            numGlyphs = itemLength * 3 / 2 + 16;
        }

        // Convert a string to a glyph string trying the primary font, fonts in
        // the fallback list and then script-specific last resort font.
        Shaping& shaping = m_shapes[i];
        if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], m_scriptTags[i], shaping))
            continue;

        // At the moment, the only time m_disableFontFallback is set is
        // when we look up glyph indices for non-BMP code ranges. So,
        // we can skip the glyph placement. When that becomes not the case
        // any more, we have to add a new flag to control glyph placement.
        if (m_disableFontFallback)
          continue;

        // Compute placements. Note that offsets is documented incorrectly
        // and is actually an array.
        EnsureCachedDCCreated();
        SelectObject(m_cachedDC, shaping.m_hfont);
        shaping.m_prePadding = 0;
        if (FAILED(ScriptPlace(m_cachedDC, shaping.m_scriptCache,
                               &shaping.m_glyphs[0],
                               static_cast<int>(shaping.m_glyphs.size()),
                               &shaping.m_visualAttributes[0], &m_runs[i].a,
                               &shaping.m_advance[0], &shaping.m_offsets[0],
                               &shaping.m_abc))) {
            // Some error we don't know how to handle. Nuke all of our data
            // since we can't deal with partially valid data later.
            m_runs.clear();
            m_scriptTags.clear();
            m_shapes.clear();
            m_screenOrder.clear();
        }
    }

    adjustSpaceAdvances();

    if (m_letterSpacing != 0 || m_wordSpacing != 0)
        applySpacing();
}