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(); }
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(); }