📄 uniscribehelper.cpp
字号:
// 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;}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::fillScreenOrder(){ m_screenOrder.resize(m_runs.size()); // We assume that the input has only one text direction in it. // TODO(brettw) are we sure we want to keep this restriction? if (m_isRtl) { for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i; } else { for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) m_screenOrder[i] = i; }}void UniscribeHelper::adjustSpaceAdvances(){ if (m_spaceWidth == 0) return; int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing; // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem. for (size_t run = 0; run < m_runs.size(); run++) { Shaping& shaping = m_shapes[run]; for (int i = 0; i < shaping.charLength(); i++) { if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) continue; int glyphIndex = shaping.m_logs[i]; int currentAdvance = shaping.m_advance[glyphIndex]; // currentAdvance does not include additional letter-spacing, but // space_width does. Here we find out how off we are from the // correct width for the space not including letter-spacing, then // just subtract that diff. int diff = currentAdvance - spaceWidthWithoutLetterSpacing; // The shaping can consist of a run of text, so only subtract the // difference in the width of the glyph. shaping.m_advance[glyphIndex] -= diff; shaping.m_abc.abcB -= diff; } }}void UniscribeHelper::applySpacing(){ for (size_t run = 0; run < m_runs.size(); run++) { Shaping& shaping = m_shapes[run]; bool isRtl = m_runs[run].a.fRTL; if (m_letterSpacing != 0) { // RTL text gets padded to the left of each character. We increment // the run's advance to make this happen. This will be balanced out // by NOT adding additional advance to the last glyph in the run. if (isRtl) shaping.m_prePadding += m_letterSpacing; // Go through all the glyphs in this run and increase the "advance" // to account for letter spacing. We adjust letter spacing only on // cluster boundaries. // // This works for most scripts, but may have problems with some // indic scripts. This behavior is better than Firefox or IE for // Hebrew. for (int i = 0; i < shaping.glyphLength(); i++) { if (shaping.m_visualAttributes[i].fClusterStart) { // Ick, we need to assign the extra space so that the glyph // comes first, then is followed by the space. This is // opposite for RTL. if (isRtl) { if (i != shaping.glyphLength() - 1) { // All but the last character just get the spacing // applied to their advance. The last character // doesn't get anything, shaping.m_advance[i] += m_letterSpacing; shaping.m_abc.abcB += m_letterSpacing; } } else { // LTR case is easier, we just add to the advance. shaping.m_advance[i] += m_letterSpacing; shaping.m_abc.abcB += m_letterSpacing; } } } } // Go through all the characters to find whitespace and insert the // extra wordspacing amount for the glyphs they correspond to. if (m_wordSpacing != 0) { for (int i = 0; i < shaping.charLength(); i++) { if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) continue; // The char in question is a word separator... int glyphIndex = shaping.m_logs[i]; // Spaces will not have a glyph in Uniscribe, it will just add // additional advance to the character to the left of the // space. The space's corresponding glyph will be the character // following it in reading order. if (isRtl) { // In RTL, the glyph to the left of the space is the same // as the first glyph of the following character, so we can // just increment it. shaping.m_advance[glyphIndex] += m_wordSpacing; shaping.m_abc.abcB += m_wordSpacing; } else { // LTR is actually more complex here, we apply it to the // previous character if there is one, otherwise we have to // apply it to the leading space of the run. if (glyphIndex == 0) shaping.m_prePadding += m_wordSpacing; else { shaping.m_advance[glyphIndex - 1] += m_wordSpacing; shaping.m_abc.abcB += m_wordSpacing; } } } } // m_wordSpacing != 0 // Loop for next run... }}// The advance is the ABC width of the runint UniscribeHelper::advanceForItem(int itemIndex) const{ int accum = 0; const Shaping& shaping = m_shapes[itemIndex]; if (shaping.m_justify.size() == 0) { // Easy case with no justification, the width is just the ABC width of // the run. (The ABC width is the sum of the advances). return shaping.m_abc.abcA + shaping.m_abc.abcB + shaping.m_abc.abcC + shaping.m_prePadding; } // With justification, we use the justified amounts instead. The // justification array contains both the advance and the extra space // added for justification, so is the width we want. int justification = 0; for (size_t i = 0; i < shaping.m_justify.size(); i++) justification += shaping.m_justify[i]; return shaping.m_prePadding + justification;}} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -