📄 coretextcontroller.cpp
字号:
UChar c = *curr; bool forceSmallCaps = !isSurrogate && isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK); if (isSurrogate) { if (m_run.ltr()) { if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1])) return; nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false); } else { if (!U16_IS_TRAIL(curr[0]) || curr -1 == end || !U16_IS_SURROGATE_LEAD(curr[-1])) return; nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false); } } else nextGlyphData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps); if (!isSurrogate && m_font.isSmallCaps()) { nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c; if (nextIsSmallCaps) m_smallCapsBuffer[index] = forceSmallCaps ? c : newC; } if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) { int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition; int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition; collectCoreTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0); indexOfFontTransition = index; } } int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition - (hasTrailingSoftHyphen ? 1 : 0); if (itemLength) { int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; collectCoreTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); } if (hasTrailingSoftHyphen && m_run.ltr()) collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);}void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer){ // FIXME: For offsets falling inside a ligature, we should advance only as far as the appropriate "ligature caret" // or divide the width of the ligature by the number of offsets it encompasses and make an advance proportional // to the offsets into the ligature. However, Core Text does not expose a low-level API for // directly finding out how many characters a ligature encompasses (the "attachment count"). if (static_cast<int>(offset) > m_end) offset = m_end; if (offset <= m_currentCharacter) return; m_currentCharacter = offset; size_t runCount = m_coreTextRuns.size(); bool ltr = m_run.ltr(); unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar; while (m_currentRun < runCount) { const CoreTextRun& coreTextRun = m_coreTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun]; size_t glyphCount = coreTextRun.glyphCount(); unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun; while (m_glyphInCurrentRun < glyphCount) { if (coreTextRun.indexAt(g) + coreTextRun.stringLocation() >= m_currentCharacter) return; CGSize adjustedAdvance = m_adjustedAdvances[k]; if (glyphBuffer) glyphBuffer->add(m_adjustedGlyphs[k], coreTextRun.fontData(), adjustedAdvance); m_runWidthSoFar += adjustedAdvance.width; m_numGlyphsSoFar++; m_glyphInCurrentRun++; if (ltr) { g++; k++; } else { g--; k--; } } m_currentRun++; m_glyphInCurrentRun = 0; } if (!ltr && m_numGlyphsSoFar == m_adjustedAdvances.size()) m_runWidthSoFar += m_finalRoundingWidth;}void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData){ if (!fontData) { // Create a run of missing glyphs from the primary font. m_coreTextRuns.append(CoreTextRun(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); return; } RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes())); RetainPtr<CTTypesetterRef> typesetter; if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) { static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; static const void* ltrOptionValues[] = { kCFBooleanFalse }; static const void* rtlOptionValues[] = { kCFBooleanTrue }; static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); } else typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); CFIndex runCount = CFArrayGetCount(runArray); for (CFIndex r = 0; r < runCount; r++) { CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); m_coreTextRuns.append(CoreTextRun(ctRun, fontData, cp, stringLocation, length)); }}void CoreTextController::adjustGlyphsAndAdvances(){ size_t runCount = m_coreTextRuns.size(); for (size_t r = 0; r < runCount; ++r) { const CoreTextRun& coreTextRun = m_coreTextRuns[r]; unsigned glyphCount = coreTextRun.glyphCount(); const SimpleFontData* fontData = coreTextRun.fontData(); Vector<CGGlyph, 256> glyphsVector; const CGGlyph* glyphs; Vector<CGSize, 256> advancesVector; const CGSize* advances; if (coreTextRun.ctRun()) { glyphs = CTRunGetGlyphsPtr(coreTextRun.ctRun()); if (!glyphs) { glyphsVector.grow(glyphCount); CTRunGetGlyphs(coreTextRun.ctRun(), CFRangeMake(0, 0), glyphsVector.data()); glyphs = glyphsVector.data(); } advances = CTRunGetAdvancesPtr(coreTextRun.ctRun()); if (!advances) { advancesVector.grow(glyphCount); CTRunGetAdvances(coreTextRun.ctRun(), CFRangeMake(0, 0), advancesVector.data()); advances = advancesVector.data(); } } else { // Synthesize a run of missing glyphs. glyphsVector.fill(0, glyphCount); glyphs = glyphsVector.data(); advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), glyphCount); advances = advancesVector.data(); } bool lastRun = r + 1 == runCount; const UChar* cp = coreTextRun.characters(); CGFloat roundedSpaceWidth = roundCGFloat(fontData->m_spaceWidth); bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled(); for (unsigned i = 0; i < glyphCount; i++) { CFIndex characterIndex = coreTextRun.indexAt(i); UChar ch = *(cp + characterIndex); bool lastGlyph = lastRun && i + 1 == glyphCount; UChar nextCh; if (lastGlyph) nextCh = ' '; else if (i + 1 < glyphCount) nextCh = *(cp + coreTextRun.indexAt(i + 1)); else nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0)); bool treatAsSpace = Font::treatAsSpace(ch); CGGlyph glyph = treatAsSpace ? fontData->m_spaceGlyph : glyphs[i]; CGSize advance = treatAsSpace ? CGSizeMake(fontData->m_spaceWidth, advances[i].height) : advances[i]; if (ch == '\t' && m_run.allowTabs()) { float tabWidth = m_font.tabWidth(); advance.width = tabWidth - fmodf(m_run.xPos() + m_totalWidth, tabWidth); } else if (ch == zeroWidthSpace || Font::treatAsZeroWidthSpace(ch) && !treatAsSpace) { advance.width = 0; glyph = fontData->m_spaceGlyph; } float roundedAdvanceWidth = roundf(advance.width); if (roundsAdvances) advance.width = roundedAdvanceWidth; advance.width += fontData->m_syntheticBoldOffset; // We special case spaces in two ways when applying word rounding. // First, we round spaces to an adjusted width in all fonts. // Second, in fixed-pitch fonts we ensure that all glyphs that // match the width of the space glyph have the same width as the space glyph. if (roundedAdvanceWidth == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) advance.width = fontData->m_adjustedSpaceWidth; if (hasExtraSpacing) { // If we're a glyph with an advance, go ahead and add in letter-spacing. // That way we weed out zero width lurkers. This behavior matches the fast text code path. if (advance.width && m_font.letterSpacing()) advance.width += m_font.letterSpacing(); // Handle justification and word-spacing. if (glyph == fontData->m_spaceGlyph) { // Account for padding. WebCore uses space padding to justify text. // We distribute the specified padding over the available spaces in the run. if (m_padding) { // Use leftover padding if not evenly divisible by number of spaces. if (m_padding < m_padPerSpace) { advance.width += m_padding; m_padding = 0; } else { advance.width += m_padPerSpace; m_padding -= m_padPerSpace; } } // Account for word-spacing. if (treatAsSpace && characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing()) advance.width += m_font.wordSpacing(); } } // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters // followed by a character defined by isRoundingHackCharacter()) are always an integer width. // We adjust the width of the last character of a "word" to ensure an integer width. // Force characters that are used to determine word boundaries for the rounding hack // to be integer width, so the following words will start on an integer boundary. if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(ch)) advance.width = ceilCGFloat(advance.width); // Check to see if the next character is a "rounding hack character", if so, adjust the // width so that the total run width will be on an integer boundary. if (m_run.applyWordRounding() && !lastGlyph && Font::isRoundingHackCharacter(nextCh) || m_run.applyRunRounding() && lastGlyph) { CGFloat totalWidth = m_totalWidth + advance.width; CGFloat extraWidth = ceilCGFloat(totalWidth) - totalWidth; if (m_run.ltr()) advance.width += extraWidth; else { m_totalWidth += extraWidth; if (m_lastRoundingGlyph) m_adjustedAdvances[m_lastRoundingGlyph - 1].width += extraWidth; else m_finalRoundingWidth = extraWidth; m_lastRoundingGlyph = m_adjustedAdvances.size() + 1; } } m_totalWidth += advance.width; advance.height *= -1; m_adjustedAdvances.append(advance); m_adjustedGlyphs.append(glyph); } }}} // namespace WebCore#endif // USE(CORE_TEXT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -