GlyphData FontCascadeFonts::glyphDataForSystemFallback(UChar32 c, const FontCascadeDescription& description, FontVariant variant) { // System fallback is character-dependent. auto& primaryRanges = realizeFallbackRangesAt(description, 0); auto* originalFont = primaryRanges.fontForCharacter(c); if (!originalFont) originalFont = &primaryRanges.fontForFirstRange(); auto systemFallbackFont = originalFont->systemFallbackFontForCharacter(c, description, m_isForPlatformFont); if (!systemFallbackFont) return GlyphData(); if (systemFallbackFont->platformData().orientation() == Vertical && !systemFallbackFont->hasVerticalGlyphs() && FontCascade::isCJKIdeographOrSymbol(c)) variant = BrokenIdeographVariant; GlyphData fallbackGlyphData; if (variant == NormalVariant) fallbackGlyphData = systemFallbackFont->glyphDataForCharacter(c); else fallbackGlyphData = systemFallbackFont->variantFont(description, variant)->glyphDataForCharacter(c); if (fallbackGlyphData.font && fallbackGlyphData.font->platformData().orientation() == Vertical && !fallbackGlyphData.font->isTextOrientationFallback()) { if (variant == NormalVariant && !FontCascade::isCJKIdeographOrSymbol(c)) fallbackGlyphData = glyphDataForNonCJKCharacterWithGlyphOrientation(c, description.nonCJKGlyphOrientation(), fallbackGlyphData); #if PLATFORM(COCOA) || USE(CAIRO) if (fallbackGlyphData.font->platformData().syntheticOblique() && FontCascade::isCJKIdeographOrSymbol(c)) fallbackGlyphData = glyphDataForCJKCharacterWithoutSyntheticItalic(c, fallbackGlyphData); #endif } // Keep the system fallback fonts we use alive. if (fallbackGlyphData.glyph) m_systemFallbackFontSet.add(WTFMove(systemFallbackFont)); return fallbackGlyphData; }
bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const { bool haveGlyphs = false; Vector<CGGlyph, 512> glyphs(bufferLength); if (!shouldUseCoreText(buffer, bufferLength, this)) { CGFontGetGlyphsForUnichars(platformData().cgFont(), buffer, glyphs.data(), bufferLength); for (unsigned i = 0; i < length; ++i) { if (glyphs[i]) { pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this); haveGlyphs = true; } } } else if (!platformData().isCompositeFontReference() && platformData().widthVariant() != RegularWidth && CTFontGetGlyphsForCharacters(platformData().ctFont(), buffer, glyphs.data(), bufferLength)) { // When buffer consists of surrogate pairs, CTFontGetGlyphsForCharacters // places the glyphs at indices corresponding to the first character of each pair. unsigned glyphStep = bufferLength / length; for (unsigned i = 0; i < length; ++i) { if (glyphs[i * glyphStep]) { pageToFill->setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], this); haveGlyphs = true; } } } else { // We ask CoreText for possible vertical variant glyphs RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull)); RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), getCFStringAttributes(0, hasVerticalGlyphs() ? Vertical : Horizontal))); RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get())); CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); CFIndex runCount = CFArrayGetCount(runArray); Vector<CGGlyph, 512> glyphVector; Vector<CFIndex, 512> indexVector; bool done = false; // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may // be non-CFEqual to platformData().cgFont(). RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().ctFont(), 0)); for (CFIndex r = 0; r < runCount && !done ; ++r) { // CTLine could map characters over multiple fonts using its own font fallback list. // We need to pick runs that use the exact font we need, i.e., platformData().ctFont(). CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); CFDictionaryRef attributes = CTRunGetAttributes(ctRun); CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName)); RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0)); // Use CGFont here as CFEqual for CTFont counts all attributes for font. bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get()); if (gotBaseFont || platformData().isCompositeFontReference()) { // This run uses the font we want. Extract glyphs. CFIndex glyphCount = CTRunGetGlyphCount(ctRun); const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun); if (!glyphs) { glyphVector.resize(glyphCount); CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data()); glyphs = glyphVector.data(); } const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun); if (!stringIndices) { indexVector.resize(glyphCount); CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data()); stringIndices = indexVector.data(); } if (gotBaseFont) { for (CFIndex i = 0; i < glyphCount; ++i) { if (stringIndices[i] >= static_cast<CFIndex>(length)) { done = true; break; } if (glyphs[i]) { pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], this); haveGlyphs = true; } } } else { const SimpleFontData* runSimple = getCompositeFontReferenceFontData((NSFont *)runFont); if (runSimple) { for (CFIndex i = 0; i < glyphCount; ++i) { if (stringIndices[i] >= static_cast<CFIndex>(length)) { done = true; break; } if (glyphs[i]) { pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], runSimple); haveGlyphs = true; } } } } } } } return haveGlyphs; }