inline bool HarfBuzzShaper::shapeRange(hb_buffer_t* harfBuzzBuffer, unsigned startIndex, unsigned numCharacters, const SimpleFontData* currentFont, PassRefPtr<UnicodeRangeSet> currentFontRangeSet, UScriptCode currentRunScript, hb_language_t language) { const FontPlatformData* platformData = &(currentFont->platformData()); HarfBuzzFace* face = platformData->harfBuzzFace(); if (!face) { DLOG(ERROR) << "Could not create HarfBuzzFace from FontPlatformData."; return false; } hb_buffer_set_language(harfBuzzBuffer, language); hb_buffer_set_script(harfBuzzBuffer, ICUScriptToHBScript(currentRunScript)); hb_buffer_set_direction(harfBuzzBuffer, TextDirectionToHBDirection(m_textRun.direction(), m_font->getFontDescription().orientation(), currentFont)); hb_font_t* hbFont = face->getScaledFont(currentFontRangeSet); hb_shape(hbFont, harfBuzzBuffer, m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); return true; }
bool FontPlatformData::hasSpaceInLigaturesOrKerning( TypesettingFeatures features) const { HarfBuzzFace* hbFace = harfBuzzFace(); if (!hbFace) return false; hb_font_t* font = hbFace->getScaledFont(); ASSERT(font); hb_face_t* face = hb_font_get_face(font); ASSERT(face); hb_codepoint_t space; // If the space glyph isn't present in the font then each space character // will be rendering using a fallback font, which grantees that it cannot // affect the shape of the preceding word. if (!hb_font_get_glyph(font, spaceCharacter, 0, &space)) return false; if (!hb_ot_layout_has_substitution(face) && !hb_ot_layout_has_positioning(face)) { return false; } bool foundSpaceInTable = false; hb_set_t* glyphs = hb_set_create(); if (features & Kerning) foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GPOS, space); if (!foundSpaceInTable && (features & Ligatures)) foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GSUB, space); hb_set_destroy(glyphs); return foundSpaceInTable; }
bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection) { HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy); hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_funcs()); for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); const SimpleFontData* currentFontData = currentRun->fontData(); if (currentFontData->isSVGFont()) return false; hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); if (shouldSetDirection) hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); else // Leaving direction to HarfBuzz to guess is *really* bad, but will do for now. hb_buffer_guess_segment_properties(harfBuzzBuffer.get()); // Add a space as pre-context to the buffer. This prevents showing dotted-circle // for combining marks at the beginning of runs. static const uint16_t preContext = ' '; hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) { String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()); upperText.makeUpper(); currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData; hb_buffer_add_utf16(harfBuzzBuffer.get(), upperText.characters(), currentRun->numCharacters(), 0, currentRun->numCharacters()); } else hb_buffer_add_utf16(harfBuzzBuffer.get(), m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters(), 0, currentRun->numCharacters()); FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tFontData->platformData()); HarfBuzzFace* face = platformData->harfBuzzFace(); if (!face) return false; if (m_font->fontDescription().orientation() == Vertical) face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy); hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); currentRun->applyShapeResult(harfBuzzBuffer.get()); setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get()); hb_buffer_reset(harfBuzzBuffer.get()); } return true; }
bool HarfBuzzShaper::shapeHarfBuzzRun() { FontPlatformData* platformData = const_cast<FontPlatformData*>(&m_currentFontData->platformData()); HarfBuzzFace* face = platformData->harfbuzzFace(); if (!face) return false; hb_font_t* harfbuzzFont = face->createFont(); hb_shape(harfbuzzFont, m_harfbuzzBuffer, m_features.size() > 0 ? m_features.data() : 0, m_features.size()); hb_font_destroy(harfbuzzFont); m_harfbuzzRuns.append(HarfBuzzRun::create(m_numCharactersOfCurrentRun, m_run.direction(), m_harfbuzzBuffer)); return true; }