📄 uniscribehelper.cpp
字号:
if (shaping.charLength() == 0 || fromChar >= shaping.charLength() || toChar <= 0) { // No chars in this item to display. curX += advanceForItem(itemIndex); continue; } // Compute the starting glyph within this span. |from| and |to| are // global offsets that may intersect arbitrarily with our local run. int fromGlyph, afterGlyph; if (item.a.fRTL) { // To compute the first glyph when going RTL, we use |to|. if (toChar >= shaping.charLength()) // The end of the text is after (to the left) of us. fromGlyph = 0; else { // Since |to| is exclusive, the first character we draw on the // left is actually the one right before (to the right) of // |to|. fromGlyph = shaping.m_logs[toChar - 1]; } // The last glyph is actually the first character in the range. if (fromChar <= 0) { // The first character to draw is before (to the right) of this // span, so draw all the way to the end. afterGlyph = shaping.glyphLength(); } else { // We want to draw everything up until the character to the // right of |from|. To the right is - 1, so we look that up // (remember our character could be more than one glyph, so we // can't look up our glyph and add one). afterGlyph = shaping.m_logs[fromChar - 1]; } } else { // Easy case, everybody agrees about directions. We only need to // handle boundary conditions to get a range inclusive at the // beginning, and exclusive at the ending. We have to do some // computation to see the glyph one past the end. fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar]; if (toChar >= shaping.charLength()) afterGlyph = shaping.glyphLength(); else afterGlyph = shaping.m_logs[toChar]; } // Account for the characters that were skipped in this run. When // WebKit asks us to draw a subset of the run, it actually tells us // to draw at the X offset of the beginning of the run, since it // doesn't know the internal position of any of our characters. const int* effectiveAdvances = shaping.effectiveAdvances(); int innerOffset = 0; for (int i = 0; i < fromGlyph; i++) innerOffset += effectiveAdvances[i]; // Actually draw the glyphs we found. int glyphCount = afterGlyph - fromGlyph; if (fromGlyph >= 0 && glyphCount > 0) { // Account for the preceding space we need to add to this run. We // don't need to count for the following space because that will be // counted in advanceForItem below when we move to the next run. innerOffset += shaping.m_prePadding; // Pass 0 in when there is no justification. const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph]; if (firstRun) { oldFont = SelectObject(dc, shaping.m_hfont); firstRun = false; } else SelectObject(dc, shaping.m_hfont); // Fonts with different ascents can be used to render different // runs. 'Across-runs' y-coordinate correction needs to be // adjusted for each font. bool textOutOk = false; for (int executions = 0; executions < 2; ++executions) { if (useWindowsDrawing) { HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache, curX + innerOffset, y - shaping.m_ascentOffset, 0, 0, &item.a, 0, 0, &shaping.m_glyphs[fromGlyph], glyphCount, &shaping.m_advance[fromGlyph], justify, &shaping.m_offsets[fromGlyph]); ASSERT(S_OK == hr); textOutOk = (hr == S_OK); } else { SkPoint origin; origin.fX = curX + + innerOffset; origin.fY = y + m_ascent - shaping.m_ascentOffset; textOutOk = paintSkiaText(graphicsContext, shaping.m_hfont, glyphCount, &shaping.m_glyphs[fromGlyph], &shaping.m_advance[fromGlyph], &shaping.m_offsets[fromGlyph], &origin); } if (!textOutOk && 0 == executions) { // If TextOut 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(shaping.m_hfont); continue; } break; } } curX += advanceForItem(itemIndex); } if (oldFont) SelectObject(dc, oldFont);}WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const{ // Find the run for the given character. for (int i = 0; i < static_cast<int>(m_runs.size()); i++) { int firstChar = m_runs[i].iCharPos; const Shaping& shaping = m_shapes[i]; int localOffset = charOffset - firstChar; if (localOffset >= 0 && localOffset < shaping.charLength()) { // The character is in this run, return the first glyph for it // (should generally be the only glyph). It seems Uniscribe gives // glyph 0 for empty, which is what we want to return in the // "missing" case. size_t glyphIndex = shaping.m_logs[localOffset]; if (glyphIndex >= shaping.m_glyphs.size()) { // The glyph should be in this run, but the run has too few // actual characters. This can happen when shaping the run // fails, in which case, we should have no data in the logs at // all. ASSERT(shaping.m_glyphs.size() == 0); return 0; } return shaping.m_glyphs[glyphIndex]; } } return 0;}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); }}bool UniscribeHelper::shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, Shaping& shaping){ HFONT hfont = m_hfont; SCRIPT_CACHE* scriptCache = m_scriptCache; SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; int ascent = m_ascent; HDC tempDC = 0; HGDIOBJ oldFont = 0; HRESULT hr; // When used to fill up glyph pages for simple scripts in non-BMP, // we don't want any font fallback in this class. The simple script // font path can take care of font fallback. bool lastFallbackTried = m_disableFontFallback; bool result; int generatedGlyphs = 0; // In case HFONT passed in ctor cannot render this run, we have to scan // other fonts from the beginning of the font list. resetFontIndex(); // Compute shapes. while (true) { shaping.m_logs.resize(itemLength); shaping.m_glyphs.resize(numGlyphs); shaping.m_visualAttributes.resize(numGlyphs);#ifdef PURIFY // http://code.google.com/p/chromium/issues/detail?id=5309 // Purify isn't able to track the assignments that ScriptShape makes to // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it // writes, will be considered un-initialized data. // // This hack avoid the false-positive UMRs by marking the buffer as // initialized. // // FIXME: A better solution would be to use Purify's API and mark only // the populated range as initialized: // // PurifyMarkAsInitialized( // &shaping.m_glyphs[0], // sizeof(shaping.m_glyphs[0] * generatedGlyphs); ZeroMemory(&shaping.m_glyphs[0], sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());#endif // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true // here. Is that what we want? It will display control characters. hr = ScriptShape(tempDC, scriptCache, input, itemLength, numGlyphs, &run.a, &shaping.m_glyphs[0], &shaping.m_logs[0], &shaping.m_visualAttributes[0], &generatedGlyphs); if (hr == E_PENDING) { // Allocate the DC. tempDC = GetDC(0); oldFont = SelectObject(tempDC, hfont); continue; } else if (hr == E_OUTOFMEMORY) { numGlyphs *= 2; continue; } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties))) break; // The current font can't render this run. clear DC and try // next font. if (tempDC) { SelectObject(tempDC, oldFont); ReleaseDC(0, tempDC); tempDC = 0; } if (!m_disableFontFallback && nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) { // The primary font does not support this run. Try next font. // In case of web page rendering, they come from fonts specified in // CSS stylesheets. continue; } else if (!lastFallbackTried) { lastFallbackTried = true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -