static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); unsigned codepoints = 0; for (hb_uint32 i = 0; i < length; i++) { if (!SkUTF16_IsHighSurrogate(characters[i])) codepoints++; if (codepoints > *glyphsSize) return 0; } int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs)); // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our // |glyphs| array needs to be converted. for (int i = numGlyphs - 1; i >= 0; --i) { uint16_t value; // We use a memcpy to avoid breaking strict aliasing rules. memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t)); glyphs[i] = value; } *glyphsSize = numGlyphs; return 1; }
Font::Font(const FontPlatformData& platformData, bool isCustomFont, bool isLoading, bool isTextOrientationFallback) : m_maxCharWidth(-1) , m_avgCharWidth(-1) , m_platformData(platformData) , m_treatAsFixedPitch(false) , m_isCustomFont(isCustomFont) , m_isLoading(isLoading) , m_isTextOrientationFallback(isTextOrientationFallback) , m_isBrokenIdeographFallback(false) , m_mathData(nullptr) #if ENABLE(OPENTYPE_VERTICAL) , m_verticalData(0) #endif , m_hasVerticalGlyphs(false) { platformInit(); platformGlyphInit(); platformCharWidthInit(); #if ENABLE(OPENTYPE_VERTICAL) if (platformData.orientation() == Vertical && !isTextOrientationFallback) { m_verticalData = platformData.verticalData(); m_hasVerticalGlyphs = m_verticalData.get() && m_verticalData->hasVerticalMetrics(); } #endif }
SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) : m_maxCharWidth(-1) , m_avgCharWidth(-1) , m_unitsPerEm(defaultUnitsPerEm) , m_platformData(f) , m_treatAsFixedPitch(false) #if ENABLE(SVG_FONTS) , m_svgFontData(svgFontData) #endif , m_isCustomFont(customFont) , m_isLoading(loading) , m_smallCapsFontData(0) #if (PLATFORM(WKC)) , m_lineSpacing(0) #endif { #if !ENABLE(SVG_FONTS) UNUSED_PARAM(svgFontData); #else if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) { m_unitsPerEm = svgFontFaceElement->unitsPerEm(); double scale = f.size(); if (m_unitsPerEm) scale /= m_unitsPerEm; m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); m_lineGap = 0.1f * f.size(); m_lineSpacing = m_ascent + m_descent + m_lineGap; SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); Vector<SVGGlyphIdentifier> spaceGlyphs; associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale); Vector<SVGGlyphIdentifier> numeralZeroGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale); Vector<SVGGlyphIdentifier> letterWGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale); // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? m_spaceGlyph = 0; determinePitch(); m_adjustedSpaceWidth = roundf(m_spaceWidth); m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; return; } #endif platformInit(); platformGlyphInit(); platformCharWidthInit(); }
static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; if (flags & HB_ShaperFlag_UseDesignMetrics) return HB_Err_Invalid_Argument; // This is requesting pre-hinted positions. We can't support this. font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkPath path; paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); int numPoints = path.getPoints(0, 0); if (point >= static_cast<unsigned>(numPoints)) return HB_Err_Invalid_SubTable; SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1))); if (!points) return HB_Err_Invalid_SubTable; // Skia does let us get a single point from the path. path.getPoints(points, point + 1); *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX); *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY); *resultingNumPoints = numPoints; fastFree(points); return HB_Err_Ok; }
static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); OwnArrayPtr<uint16_t> glyphs16(new uint16_t[numGlyphs]); if (!glyphs16.get()) return; for (unsigned i = 0; i < numGlyphs; ++i) glyphs16[i] = glyphs[i]; paint.getTextWidths(glyphs16.get(), numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances)); // The |advances| values which Skia outputs are SkScalars, which are floats // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format. // These two formats are both 32-bits long. for (unsigned i = 0; i < numGlyphs; ++i) { float value; // We use a memcpy to avoid breaking strict aliasing rules. memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(float)); advances[i] = SkiaScalarToHarfbuzzFixed(value); } }
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) { // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm) // says that we must find an exact match for font family, slant (italic or oblique can be used) // and font weight (we only match bold/non-bold here). RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate()); String familyNameString(getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family)); if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data()))) return 0; bool italic = fontDescription.italic(); if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN)) return 0; if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, fontWeightToFontconfigWeight(fontDescription.weight()))) return 0; if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize())) return 0; // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp): // Allow Fontconfig to do pre-match substitution. Unless we are accessing a "fallback" // family like "sans," this is the only time we allow Fontconfig to substitute one // family name for another (i.e. if the fonts are aliased to each other). FcConfigSubstitute(0, pattern.get(), FcMatchPattern); FcDefaultSubstitute(pattern.get()); FcChar8* fontConfigFamilyNameAfterConfiguration; FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration); String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration)); FcResult fontConfigResult; RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult)); if (!resultPattern) // No match. return 0; FcChar8* fontConfigFamilyNameAfterMatching; FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching); String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching)); // If Fontconfig gave use a different font family than the one we requested, we should ignore it // and allow WebCore to give us the next font on the CSS fallback list. The only exception is if // this family name is a commonly used generic family. if (!equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching) && !(equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif") || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace") || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive"))) return 0; // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman. // If this font doesn't have one of these three encodings, don't select it. FontPlatformData* platformData = new FontPlatformData(resultPattern.get(), fontDescription); if (!platformData->hasCompatibleCharmap()) { delete platformData; return 0; } return platformData; }
void paintSkiaText(GraphicsContext* context, const FontPlatformData& data, int numGlyphs, const WORD* glyphs, const int* advances, const GOFFSET* offsets, const SkPoint* origin) { paintSkiaText(context, data.hfont(), data.typeface(), data.size(), data.lfQuality(), numGlyphs, glyphs, advances, offsets, origin); }
std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) { FontPlatformData* ret = new FontPlatformData(fontDescription, family); if (!ret || !ret->font() || !ret->font()->font()) { delete ret; return nullptr; } return std::unique_ptr<FontPlatformData>(ret); }
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; }
void paintSkiaText(GraphicsContext* context, const FontPlatformData& data, int numGlyphs, const WORD* glyphs, const int* advances, const GOFFSET* offsets, const SkPoint& origin, const SkRect& textRect) { paintSkiaText(context, data.hfont(), data.typeface(), data.size(), data.paintTextFlags(), numGlyphs, glyphs, advances, offsets, origin, textRect); }
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; }
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) { bool isLucidaGrande = false; static AtomicString lucidaStr("Lucida Grande"); if (equalIgnoringCase(family, lucidaStr)) isLucidaGrande = true; bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande; // The logical size constant is 32. We do this for subpixel precision when rendering using Uniscribe. // This masks rounding errors related to the HFONT metrics being different from the CGFont metrics. // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't // look as nice. That may be solvable though. #if PLATFORM(CG) bool canCreateCGFontWithLOGFONT = wkCanCreateCGFontWithLOGFONT(); #else bool canCreateCGFontWithLOGFONT = true; #endif LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family); HFONT hfont = createGDIFont(family, weight, fontDescription.italic(), fontDescription.computedPixelSize() * (useGDI ? 1 : 32), useGDI && canCreateCGFontWithLOGFONT); if (!hfont) return 0; if (isLucidaGrande) useGDI = false; // Never use GDI for Lucida Grande. LOGFONT logFont; GetObject(hfont, sizeof(LOGFONT), &logFont); bool synthesizeBold = isGDIFontWeightBold(weight) && !isGDIFontWeightBold(logFont.lfWeight); bool synthesizeItalic = fontDescription.italic() && !logFont.lfItalic; FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI); #if PLATFORM(CG) bool fontCreationFailed = !result->cgFont(); #elif PLATFORM(CAIRO) bool fontCreationFailed = !result->fontFace(); #endif if (fontCreationFailed) { // The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next // font. delete result; DeleteObject(hfont); return 0; } return result; }
Font::Font(const FontPlatformData& platformData, bool isCustomFont, bool isLoading, bool isTextOrientationFallback) : Font(platformData, std::unique_ptr<SVGData>(), isCustomFont, isLoading, isTextOrientationFallback) { platformInit(); platformGlyphInit(); platformCharWidthInit(); #if ENABLE(OPENTYPE_VERTICAL) if (platformData.orientation() == Vertical && !isTextOrientationFallback) { m_verticalData = platformData.verticalData(); m_hasVerticalGlyphs = m_verticalData.get() && m_verticalData->hasVerticalMetrics(); } #endif }
PassRefPtr<Font> Font::platformCreateScaledFont(const FontDescription& orig, float scaleFactor) const { FontDescription d(orig); d.setComputedSize(orig.computedSize() * scaleFactor); d.setSpecifiedSize(orig.specifiedSize() * scaleFactor); FontPlatformData* ret = new FontPlatformData(d, m_platformData.font()->familyName().data()); if (!ret || !ret->font() || !ret->font()->font()) { delete ret; return adoptRef((Font *)0); } return Font::create(*ret); }
static int substituteWithVerticalGlyphs(const FontPlatformData& platformData, uint16_t* glyphs, unsigned bufferLength) { HB_FaceRec_* hbFace = platformData.harfbuzzFace(); if (!hbFace->gsub) { // if there is no GSUB table, treat it as not covered return 0Xffff; } HB_Buffer buffer; hb_buffer_new(&buffer); for (unsigned i = 0; i < bufferLength; ++i) hb_buffer_add_glyph(buffer, glyphs[i], 0, i); HB_UShort scriptIndex; HB_UShort featureIndex; HB_GSUB_Select_Script(hbFace->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &scriptIndex); HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'e', 'r', 't'), scriptIndex, 0xffff, &featureIndex); HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1); HB_GSUB_Select_Feature(hbFace->gsub, HB_MAKE_TAG('v', 'r', 't', '2'), scriptIndex, 0xffff, &featureIndex); HB_GSUB_Add_Feature(hbFace->gsub, featureIndex, 1); int error = HB_GSUB_Apply_String(hbFace->gsub, buffer); if (!error) { for (unsigned i = 0; i < bufferLength; ++i) glyphs[i] = static_cast<Glyph>(buffer->out_string[i].gindex); } return error; }
SimpleFontData::SimpleFontData(const FontPlatformData& platformData, PassRefPtr<CustomFontData> customData, bool isTextOrientationFallback) : m_maxCharWidth(-1) , m_avgCharWidth(-1) , m_platformData(platformData) , m_isTextOrientationFallback(isTextOrientationFallback) , m_verticalData(nullptr) , m_hasVerticalGlyphs(false) , m_customFontData(customData) { platformInit(); platformGlyphInit(); if (platformData.isVerticalAnyUpright() && !isTextOrientationFallback) { m_verticalData = platformData.verticalData(); m_hasVerticalGlyphs = m_verticalData.get() && m_verticalData->hasVerticalMetrics(); } }
static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask) { HFONT mlangFont; LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont); return result == S_OK ? mlangFont : 0; }
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize) { ASSERT(creationParams.creationType() == CreateFontByFamily); CString name; RefPtr<SkTypeface> tf = createTypeface(fontDescription, creationParams, name); if (!tf) return 0; // Windows will always give us a valid pointer here, even if the face name // is non-existent. We have to double-check and see if the family name was // really used. // FIXME: Do we need to use predefined fonts "guaranteed" to exist // when we're running in layout-test mode? if (!typefacesMatchesFamily(tf.get(), creationParams.family())) { return 0; } FontPlatformData* result = new FontPlatformData(tf, name.data(), fontSize, fontDescription.weight() >= FontWeightBold && !tf->isBold() || fontDescription.isSyntheticBold(), fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(), fontDescription.orientation(), s_useSubpixelPositioning); struct FamilyMinSize { const wchar_t* family; unsigned minSize; }; const static FamilyMinSize minAntiAliasSizeForFont[] = { { L"simsun", 16 }, { L"dotum", 12 }, { L"gulim", 12 }, { L"pmingliu", 11 } }; size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont); for (size_t i = 0; i < numFonts; i++) { FamilyMinSize entry = minAntiAliasSizeForFont[i]; if (typefacesMatchesFamily(tf.get(), entry.family)) { result->setMinSizeForAntiAlias(entry.minSize); break; } } return result; }
static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); SkPaint::FontMetrics skiaMetrics; paint.getFontMetrics(&skiaMetrics); switch (metric) { case HB_FontAscent: return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent); // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them. default: return 0; } }
PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*) { // First try the specified font with standard style & weight. if (fontDescription.style() == FontStyleItalic || fontDescription.weight() >= FontWeight600) { RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle( fontDescription, c); if (fontData) return fontData; } FontCache::PlatformFallbackFont fallbackFont; FontCache::getFontForCharacter(c, fontDescription.locale().ascii().data(), &fallbackFont); if (fallbackFont.name.isEmpty()) return nullptr; FontFaceCreationParams creationParams; creationParams = FontFaceCreationParams(fallbackFont.filename, fallbackFont.fontconfigInterfaceId, fallbackFont.ttcIndex); // Changes weight and/or italic of given FontDescription depends on // the result of fontconfig so that keeping the correct font mapping // of the given character. See http://crbug.com/32109 for details. bool shouldSetSyntheticBold = false; bool shouldSetSyntheticItalic = false; FontDescription description(fontDescription); if (fallbackFont.isBold && description.weight() < FontWeightBold) description.setWeight(FontWeightBold); if (!fallbackFont.isBold && description.weight() >= FontWeightBold) { shouldSetSyntheticBold = true; description.setWeight(FontWeightNormal); } if (fallbackFont.isItalic && description.style() == FontStyleNormal) description.setStyle(FontStyleItalic); if (!fallbackFont.isItalic && description.style() == FontStyleItalic) { shouldSetSyntheticItalic = true; description.setStyle(FontStyleNormal); } FontPlatformData* substitutePlatformData = getFontPlatformData(description, creationParams); if (!substitutePlatformData) return nullptr; FontPlatformData platformData = FontPlatformData(*substitutePlatformData); platformData.setSyntheticBold(shouldSetSyntheticBold); platformData.setSyntheticItalic(shouldSetSyntheticItalic); return fontDataFromFontPlatformData(&platformData, DoNotRetain); }
bool FontPlatformData::operator==(const FontPlatformData& a) const { // If either of the typeface pointers are null then we test for pointer // equality. Otherwise, we call SkTypeface::Equal on the valid pointers. bool typefacesEqual = false; if (!typeface() || !a.typeface()) typefacesEqual = typeface() == a.typeface(); else typefacesEqual = SkTypeface::Equal(typeface(), a.typeface()); return typefacesEqual && m_textSize == a.m_textSize && m_isHashTableDeletedValue == a.m_isHashTableDeletedValue && m_syntheticBold == a.m_syntheticBold && m_syntheticItalic == a.m_syntheticItalic #if OS(LINUX) || OS(ANDROID) && m_style == a.m_style #endif && m_orientation == a.m_orientation; }
HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(voidface); const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag); if (!tableSize) return HB_Err_Invalid_Argument; // If Harfbuzz specified a NULL buffer then it's asking for the size of the table. if (!buffer) { *len = tableSize; return HB_Err_Ok; } if (*len < tableSize) return HB_Err_Invalid_Argument; SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer); return HB_Err_Ok; }
static hb_blob_t* harfbuzzSkiaGetTable(hb_face_t* face, hb_tag_t tag, void* userData) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(userData); const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag); if (!tableSize) return 0; char* buffer = reinterpret_cast<char*>(fastMalloc(tableSize)); if (!buffer) return 0; size_t actualSize = SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer); if (tableSize != actualSize) { fastFree(buffer); return 0; } return hb_blob_create(const_cast<char*>(buffer), tableSize, HB_MEMORY_MODE_WRITABLE, buffer, fastFree); }
void FontPlatformData::platformDataInit(const FontPlatformData& source) { m_harfbuzzFace = source.m_harfbuzzFace; m_scaledFont = 0; if (source.m_font && source.m_font != hashTableDeletedFontValue()) { m_font = FS_new_client(source.m_font, 0); m_name = fastStrDup(source.name()); bool ret = applyState(m_font); ASSERT_UNUSED(ret, ret); } else m_font = source.m_font; }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const { if (run.length() == 0) return run.padding(); const FontPlatformData& fontPlatformData = primaryFont()->platformData(); const float scaleFactor = fontPlatformData.scaleFactor(); Olympia::Platform::Text::Font* font = fontPlatformData.font(); Olympia::Platform::Text::DrawParam drawParam; String sanitized = setupTextDrawing(this, run, &drawParam); // WebKit calls us with plain spaces almost half of the time. // Exit early with a cached value to avoid lots of calls into Text API. if (sanitized.length() == 1 && sanitized[0] == ' ') return primaryFont()->spaceWidth(); #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif Olympia::Platform::Text::TextMetrics metrics; FontPlatformData::engine()->drawText(0 /* no drawing, only measuring */, *font, sanitized.characters(), sanitized.length(), 0 /*x*/, 0 /*y*/, 0 /* no wrap */, &drawParam, &metrics); if (fallbackFonts && primaryFont()->lineSpacing() < metrics.m_ascent + metrics.m_descent) { FontPlatformData tallerFontPlatformData = fontPlatformData; tallerFontPlatformData.setLineSpacingOverride(metrics.m_ascent, metrics.m_descent); // HACK: We can't generate a cached SimpleFontData from outside of FontCache, // so instead we abuse FontCache::getFontDataForCharacters() to do that. // Safe to use this way because we also pass 0 as string length, // which avoids clashes with possible regular calls of that method. fallbackFonts->add(fontCache()->getFontDataForCharacters(*this, reinterpret_cast<const UChar*>(&tallerFontPlatformData), 0)); } return metrics.m_linearAdvance * scaleFactor; }
bool HarfBuzzShaper::shapeHarfBuzzRuns() { HarfBuzzScopedPtr<hb_buffer_t> harfbuzzBuffer(hb_buffer_create(), hb_buffer_destroy); hb_buffer_set_unicode_funcs(harfbuzzBuffer.get(), hb_icu_get_unicode_funcs()); if (m_run.rtl() || m_run.directionalOverride()) hb_buffer_set_direction(harfbuzzBuffer.get(), m_run.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); 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 (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()); HarfBuzzNGFace* face = platformData->harfbuzzFace(); if (!face) return false; 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()); if (m_run.rtl() || m_run.directionalOverride()) hb_buffer_set_direction(harfbuzzBuffer.get(), m_run.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); } return true; }
SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) : m_unitsPerEm(defaultUnitsPerEm) , m_font(f) , m_treatAsFixedPitch(false) #if ENABLE(SVG_FONTS) , m_svgFontData(svgFontData) #endif , m_isCustomFont(customFont) , m_isLoading(loading) , m_smallCapsFontData(0) { #if ENABLE(SVG_FONTS) if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) { m_unitsPerEm = svgFontFaceElement->unitsPerEm(); double scale = f.size(); if (m_unitsPerEm) scale /= m_unitsPerEm; m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); m_lineGap = 0.1f * f.size(); m_lineSpacing = m_ascent + m_descent + m_lineGap; m_spaceGlyph = 0; m_spaceWidth = 0; m_adjustedSpaceWidth = 0; determinePitch(); m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; return; } #endif platformInit(); platformGlyphInit(); }
static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkScalar width; SkRect bounds; paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds); metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft); metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop); metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width()); metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height()); metrics->xOffset = SkiaScalarToHarfbuzzFixed(width); // We can't actually get the |y| correct because Skia doesn't export // the vertical advance. However, nor we do ever render vertical text at // the moment so it's unimportant. metrics->yOffset = 0; }
static HFONT createMLangFont(IMLangFontLinkType* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask, UChar character = 0) { HFONT mlangFont; #if USE(IMLANG_FONT_LINK2) HRESULT result = langFontLink->MapFont(hdc, codePageMask, character, &mlangFont); #else HRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont); #endif if (SUCCEEDED(result)) return mlangFont; return 0; }
PassRefPtr<SimpleFontData> FontCache::fallbackOnStandardFontStyle( const FontDescription& fontDescription, UChar32 character) { FontDescription substituteDescription(fontDescription); substituteDescription.setStyle(FontStyleNormal); substituteDescription.setWeight(FontWeightNormal); FontFaceCreationParams creationParams( substituteDescription.family().family()); FontPlatformData* substitutePlatformData = getFontPlatformData(substituteDescription, creationParams); if (substitutePlatformData && substitutePlatformData->fontContainsCharacter(character)) { FontPlatformData platformData = FontPlatformData(*substitutePlatformData); platformData.setSyntheticBold(fontDescription.weight() >= FontWeight600); platformData.setSyntheticItalic( fontDescription.style() == FontStyleItalic || fontDescription.style() == FontStyleOblique); return fontDataFromFontPlatformData(&platformData, DoNotRetain); } return nullptr; }