void Font::platformInit() { if (!m_platformData.size()) return; ASSERT(m_platformData.scaledFont()); cairo_font_extents_t fontExtents; cairo_scaled_font_extents(m_platformData.scaledFont(), &fontExtents); float ascent = narrowPrecisionToFloat(fontExtents.ascent); float descent = narrowPrecisionToFloat(fontExtents.descent); float capHeight = narrowPrecisionToFloat(fontExtents.height); float lineGap = narrowPrecisionToFloat(fontExtents.height - fontExtents.ascent - fontExtents.descent); { CairoFtFaceLocker cairoFtFaceLocker(m_platformData.scaledFont()); // If the USE_TYPO_METRICS flag is set in the OS/2 table then we use typo metrics instead. FT_Face freeTypeFace = cairoFtFaceLocker.ftFace(); TT_OS2* OS2Table = freeTypeFace ? static_cast<TT_OS2*>(FT_Get_Sfnt_Table(freeTypeFace, ft_sfnt_os2)) : nullptr; if (OS2Table) { const FT_Short kUseTypoMetricsMask = 1 << 7; if (OS2Table->fsSelection & kUseTypoMetricsMask) { // FT_Size_Metrics::y_scale is in 16.16 fixed point format. // Its (fractional) value is a factor that converts vertical metrics from design units to units of 1/64 pixels. double yscale = (freeTypeFace->size->metrics.y_scale / 65536.0) / 64.0; ascent = narrowPrecisionToFloat(yscale * OS2Table->sTypoAscender); descent = -narrowPrecisionToFloat(yscale * OS2Table->sTypoDescender); lineGap = narrowPrecisionToFloat(yscale * OS2Table->sTypoLineGap); } } } m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); m_fontMetrics.setCapHeight(capHeight); #if PLATFORM(EFL) m_fontMetrics.setLineSpacing(ascent + descent + lineGap); #else // Match CoreGraphics metrics. m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); #endif m_fontMetrics.setLineGap(lineGap); cairo_text_extents_t textExtents; cairo_scaled_font_text_extents(m_platformData.scaledFont(), "x", &textExtents); m_fontMetrics.setXHeight(narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.height : textExtents.width)); cairo_scaled_font_text_extents(m_platformData.scaledFont(), " ", &textExtents); m_spaceWidth = narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.x_advance : -textExtents.y_advance); if ((platformData().orientation() == Vertical) && !isTextOrientationFallback()) { CairoFtFaceLocker cairoFtFaceLocker(m_platformData.scaledFont()); FT_Face freeTypeFace = cairoFtFaceLocker.ftFace(); m_fontMetrics.setUnitsPerEm(freeTypeFace->units_per_EM); } m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; }
CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures, FontOrientation orientation) const { unsigned key = typesettingFeatures + 1; HashMap<unsigned, RetainPtr<CFDictionaryRef>>::AddResult addResult = m_CFStringAttributes.add(key, RetainPtr<CFDictionaryRef>()); RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.iterator->value; if (!addResult.isNewEntry) return attributesDictionary.get(); attributesDictionary = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFMutableDictionaryRef mutableAttributes = (CFMutableDictionaryRef)attributesDictionary.get(); CFDictionarySetValue(mutableAttributes, kCTFontAttributeName, platformData().ctFont()); if (!(typesettingFeatures & Kerning)) { const float zero = 0; static CFNumberRef zeroKerningValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &zero); CFDictionarySetValue(mutableAttributes, kCTKernAttributeName, zeroKerningValue); } bool allowLigatures = (orientation == Horizontal && platformData().allowsLigatures()) || (typesettingFeatures & Ligatures); if (!allowLigatures) { const int zero = 0; static CFNumberRef essentialLigaturesValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero); CFDictionarySetValue(mutableAttributes, kCTLigatureAttributeName, essentialLigaturesValue); } if (orientation == Vertical) CFDictionarySetValue(mutableAttributes, kCTVerticalFormsAttributeName, kCFBooleanTrue); return attributesDictionary.get(); }
js::detail::MutexImpl::~MutexImpl() { if (!platformData_) return; TRY_CALL_PTHREADS(pthread_mutex_destroy(&platformData()->ptMutex), "js::detail::MutexImpl::~MutexImpl: pthread_mutex_destroy failed"); js_delete(platformData()); }
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { if (!glyph || !platformData().size()) return 0; QVector<quint32> glyphIndexes; glyphIndexes.append(glyph); QVector<QPointF> advances = platformData().rawFont().advancesForGlyphIndexes(glyphIndexes); ASSERT(!advances.isEmpty()); return advances.at(0).x(); }
bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const { if (U16_IS_LEAD(buffer[bufferLength-1])) { DLOG(ERROR) << "Last UTF-16 code unit is high-surrogate."; return false; } SkTypeface* typeface = platformData().typeface(); if (!typeface) { DLOG(ERROR) << "fillGlyphPage called on an empty Skia typeface."; return false; } SkAutoSTMalloc<GlyphPage::size, uint16_t> glyphStorage(length); uint16_t* glyphs = glyphStorage.get(); typeface->charsToGlyphs(buffer, SkTypeface::kUTF16_Encoding, glyphs, length); bool haveGlyphs = false; for (unsigned i = 0; i < length; i++) { if (glyphs[i]) { pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this); haveGlyphs = true; } } return haveGlyphs; }
SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const { FontDescription desc = FontDescription(fontDescription); desc.setSpecifiedSize(scaleFactor * fontDescription.computedSize()); FontPlatformData platformData(desc, desc.family().family()); return new SimpleFontData(platformData, isCustomFont(), false); }
bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const { if (U16_IS_LEAD(buffer[bufferLength - 1])) { SkDebugf("%s last char is high-surrogate", __FUNCTION__); return false; } SkAutoSTMalloc<GlyphPage::size, uint16_t> glyphStorage(length); uint16_t* glyphs = glyphStorage.get(); SkTypeface* typeface = platformData().typeface(); typeface->charsToGlyphs(buffer, SkTypeface::kUTF16_Encoding, glyphs, length); bool haveGlyphs = false; for (unsigned i = 0; i < length; i++) { if (glyphs[i]) { pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this); haveGlyphs = true; } } return haveGlyphs; }
Glyph SimpleFontData::glyphForCharacter(UChar32 codepoint) const { uint16_t glyph; SkTypeface* typeface = platformData().typeface(); RELEASE_ASSERT(typeface); typeface->charsToGlyphs(&codepoint, SkTypeface::kUTF32_Encoding, &glyph, 1); return glyph; }
js::detail::MutexImpl::MutexImpl() { AutoEnterOOMUnsafeRegion oom; platformData_ = js_new<PlatformData>(); if (!platformData_) oom.crash("js::detail::MutexImpl::MutexImpl"); pthread_mutexattr_t* attrp = nullptr; #ifdef DEBUG pthread_mutexattr_t attr; TRY_CALL_PTHREADS(pthread_mutexattr_init(&attr), "js::detail::MutexImpl::MutexImpl: pthread_mutexattr_init failed"); TRY_CALL_PTHREADS(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK), "js::detail::MutexImpl::MutexImpl: pthread_mutexattr_settype failed"); attrp = &attr; #endif TRY_CALL_PTHREADS(pthread_mutex_init(&platformData()->ptMutex, attrp), "js::detail::MutexImpl::MutexImpl: pthread_mutex_init failed"); #ifdef DEBUG TRY_CALL_PTHREADS(pthread_mutexattr_destroy(&attr), "js::detail::MutexImpl::MutexImpl: pthread_mutexattr_destroy failed"); #endif }
bool RendererGlLinux::initialize( void *window, RendererRef sharedRenderer ) { mContext = reinterpret_cast<GLFWwindow*>( window ); ::glfwMakeContextCurrent( mContext ); #if defined( CINDER_GL_ES ) gl::Environment::setEs(); #else gl::Environment::setCore(); #endif gl::env()->initializeFunctionPointers(); std::shared_ptr<gl::PlatformDataLinux> platformData( new gl::PlatformDataLinux( mContext ) ); platformData->mDebug = mRenderer->getOptions().getDebug(); platformData->mDebugLogSeverity = mRenderer->getOptions().getDebugLogSeverity(); platformData->mDebugBreakSeverity = mRenderer->getOptions().getDebugBreakSeverity(); platformData->mObjectTracking = mRenderer->getOptions().getObjectTracking(); mCinderContext = gl::Context::createFromExisting( platformData ); mCinderContext->makeCurrent(); ::glfwSwapInterval( 1 ); return true; }
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { Olympia::Platform::Text::Font* font = platformData().font(); ASSERT(font); const Olympia::Platform::Text::Utf16Char characters[] = { glyph }; Olympia::Platform::Text::TextMetrics metrics; #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif FontPlatformData::engine()->drawText(0 /* no drawing, only measuring */, *font, characters, 1 /* number of characters */, 0 /*x*/, 0 /*y*/, 0 /* no wrap */, 0 /* draw params */, &metrics); return metrics.m_linearAdvance * platformData().scaleFactor(); }
bool js::Thread::Id::operator==(const Id& aOther) const { const PlatformData& self = *platformData(); const PlatformData& other = *aOther.platformData(); return (!self.hasThread && !other.hasThread) || (self.hasThread == other.hasThread && pthread_equal(self.ptThread, other.ptThread)); }
String Font::description() const { if (isSVGFont()) return "[SVG font]"; if (isCustomFont()) return "[custom font]"; return platformData().description(); }
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { if (!glyph || !platformData().size()) return 0; float escapements[1]; CString encoded = UTF8Encoding().encode((UChar *)&glyph, 1, URLEncodedEntitiesForUnencodables); m_platformData.font()->GetEscapements(encoded.data(), 1, escapements); return escapements[0] * m_platformData.font()->Size(); }
SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { if (!m_smallCapsFontData) { FontDescription desc = FontDescription(fontDescription); desc.setSpecifiedSize(0.70f * fontDescription.computedSize()); FontPlatformData platformData(desc, desc.family().family()); m_smallCapsFontData = new SimpleFontData(platformData); } return m_smallCapsFontData; }
const char* SharedBuffer::data() const { if (hasPlatformData()) return platformData(); if (m_purgeableBuffer) return m_purgeableBuffer->data(); return buffer().data(); }
SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& desc) const { if (m_smallCapsFontData) return m_smallCapsFontData; FontDescription smallCapsDesc = desc; smallCapsDesc.setSmallCaps(true); FontPlatformData smallCapsPlatformFont(smallCapsDesc, platformData().fontFamily()); m_smallCapsFontData = new SimpleFontData(smallCapsPlatformFont); return m_smallCapsFontData; }
void SimpleFontData::platformInit() { if (!m_platformData.m_size) return; ASSERT(m_platformData.scaledFont()); cairo_font_extents_t fontExtents; cairo_scaled_font_extents(m_platformData.scaledFont(), &fontExtents); float ascent = narrowPrecisionToFloat(fontExtents.ascent); float descent = narrowPrecisionToFloat(fontExtents.descent); float lineGap = narrowPrecisionToFloat(fontExtents.height - fontExtents.ascent - fontExtents.descent); m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); #if PLATFORM(EFL) m_fontMetrics.setLineSpacing(ascent + descent + lineGap); #else // Match CoreGraphics metrics. m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); #endif m_fontMetrics.setLineGap(lineGap); cairo_text_extents_t textExtents; cairo_scaled_font_text_extents(m_platformData.scaledFont(), "x", &textExtents); m_fontMetrics.setXHeight(narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.height : textExtents.width)); cairo_scaled_font_text_extents(m_platformData.scaledFont(), " ", &textExtents); m_spaceWidth = narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.x_advance : -textExtents.y_advance); if ((platformData().orientation() == Vertical) && !isTextOrientationFallback()) { FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); m_fontMetrics.setUnitsPerEm(freeTypeFace->units_per_EM); cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); } m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; }
const char* SharedBuffer::data() const { if (hasPlatformData()) return platformData(); #if USE(NETWORK_CFDATA_ARRAY_CALLBACK) if (const char* buffer = singleDataArrayBuffer()) return buffer; #endif return this->buffer().data(); }
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { if (!m_platformData.size()) return 0; if (cairo_scaled_font_status(m_platformData.scaledFont()) != CAIRO_STATUS_SUCCESS) return m_spaceWidth; cairo_glyph_t cairoGlyph = { glyph, 0, 0 }; cairo_text_extents_t extents; cairo_scaled_font_glyph_extents(m_platformData.scaledFont(), &cairoGlyph, 1, &extents); float width = platformData().orientation() == Horizontal ? extents.x_advance : -extents.y_advance; return width ? width : m_spaceWidth; }
FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const { Olympia::Platform::Text::Font* font = platformData().font(); ASSERT(font); const Olympia::Platform::Text::Utf16Char characters[] = { glyph }; Olympia::Platform::Text::TextMetrics metrics; #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif FontPlatformData::engine()->drawText(0 /* no drawing, only measuring */, *font, characters, 1 /* number of characters */, 0 /*x*/, 0 /*y*/, 0 /* no wrap */, 0 /* draw params */, &metrics); const float scaleFactor = platformData().scaleFactor(); float boundLeft = metrics.m_boundsLeft * scaleFactor; float boundTop = metrics.m_boundsTop * scaleFactor; float boundRight = metrics.m_boundsRight * scaleFactor; float boundBottom = metrics.m_boundsBottom * scaleFactor; return FloatRect(boundLeft, boundTop, boundRight - boundLeft, boundBottom - boundTop); }
CFDictionaryRef Font::getCFStringAttributes(bool enableKerning, FontOrientation orientation) const { auto& attributesDictionary = enableKerning ? m_kernedCFStringAttributes : m_nonKernedCFStringAttributes; if (attributesDictionary) return attributesDictionary.get(); attributesDictionary = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFMutableDictionaryRef mutableAttributes = (CFMutableDictionaryRef)attributesDictionary.get(); CFDictionarySetValue(mutableAttributes, kCTFontAttributeName, platformData().ctFont()); if (!enableKerning) { const float zero = 0; static CFNumberRef zeroKerningValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &zero); CFDictionarySetValue(mutableAttributes, kCTKernAttributeName, zeroKerningValue); } if (orientation == Vertical) CFDictionarySetValue(mutableAttributes, kCTVerticalFormsAttributeName, kCFBooleanTrue); return attributesDictionary.get(); }
const char* SharedBuffer::data() const { #if ENABLE(DISK_IMAGE_CACHE) if (isMemoryMapped()) return static_cast<const char*>(diskImageCache().dataForItem(m_diskImageCacheId)); #endif if (hasPlatformData()) return platformData(); #if USE(NETWORK_CFDATA_ARRAY_CALLBACK) if (const char* buffer = singleDataArrayBuffer()) return buffer; #endif createPurgeableBuffer(); if (m_purgeableBuffer) return m_purgeableBuffer->data(); return this->buffer().data(); }
void SimpleFontData::platformGlyphInit() { SkTypeface* typeface = platformData().typeface(); if (!typeface->countGlyphs()) { m_spaceGlyph = 0; m_spaceWidth = 0; m_zeroGlyph = 0; m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; return; } // Nasty hack to determine if we should round or ceil space widths. // If the font is monospace or fake monospace we ceil to ensure that // every character and the space are the same width. Otherwise we round. m_spaceGlyph = glyphForCharacter(' '); float width = widthForGlyph(m_spaceGlyph); m_spaceWidth = width; m_zeroGlyph = glyphForCharacter('0'); m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph)); m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; }
void SimpleFontData::platformInit() { if (platformData().isValid()) { Olympia::Platform::Text::Font* font = platformData().font(); const float scaleFactor = platformData().scaleFactor(); ASSERT(font); Olympia::Platform::Text::FontMetrics fontMetrics; font->getFontMetrics(fontMetrics); m_ascent = fontMetrics.m_ascent * scaleFactor + 0.9; m_descent = fontMetrics.m_descent * scaleFactor + 0.9; m_lineGap = (fontMetrics.m_leadingAbove + fontMetrics.m_leadingBelow) * scaleFactor + 0.9; m_lineSpacing = m_ascent + m_descent + m_lineGap; m_maxCharWidth = fontMetrics.m_maxCharWidth * scaleFactor; m_unitsPerEm = fontMetrics.m_height * scaleFactor; static const Olympia::Platform::Text::Utf16Char characters[] = { 'x' }; Olympia::Platform::Text::TextMetrics metrics; #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif FontPlatformData::engine()->drawText(0 /* no drawing, only measuring */, *font, characters, 1 /* number of characters */, 0 /*x*/, 0 /*y*/, 0 /* no wrap */, 0 /* draw params */, &metrics); if (platformData().hasLineSpacingOverride()) { m_ascent = platformData().ascentOverride(); m_descent = platformData().descentOverride(); m_lineSpacing = platformData().lineSpacingOverride(); m_lineGap = 0; } m_xHeight = (metrics.m_boundsBottom - metrics.m_boundsTop) * scaleFactor; m_avgCharWidth = metrics.m_linearAdvance * scaleFactor; } }
CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures) const { unsigned key = typesettingFeatures + 1; pair<HashMap<unsigned, RetainPtr<CFDictionaryRef> >::iterator, bool> addResult = m_CFStringAttributes.add(key, RetainPtr<CFDictionaryRef>()); RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.first->second; if (!addResult.second) return attributesDictionary.get(); bool allowLigatures = platformData().allowsLigatures() || (typesettingFeatures & Ligatures); static const int ligaturesNotAllowedValue = 0; static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue); static const int ligaturesAllowedValue = 1; static CFNumberRef ligaturesAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesAllowedValue); if (!(typesettingFeatures & Kerning)) { static const float kerningAdjustmentValue = 0; static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue); static const void* keysWithKerningDisabled[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName }; const void* valuesWithKerningDisabled[] = { getCTFont(), kerningAdjustment, allowLigatures ? ligaturesAllowed : ligaturesNotAllowed }; attributesDictionary.adoptCF(CFDictionaryCreate(0, keysWithKerningDisabled, valuesWithKerningDisabled, sizeof(keysWithKerningDisabled) / sizeof(*keysWithKerningDisabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); } else { // By omitting the kCTKernAttributeName attribute, we get Core Text's standard kerning. static const void* keysWithKerningEnabled[] = { kCTFontAttributeName, kCTLigatureAttributeName }; const void* valuesWithKerningEnabled[] = { getCTFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed }; attributesDictionary.adoptCF(CFDictionaryCreate(0, keysWithKerningEnabled, valuesWithKerningEnabled, sizeof(keysWithKerningEnabled) / sizeof(*keysWithKerningEnabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); } return attributesDictionary.get(); }
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; }
void SimpleFontData::platformInit(bool subpixelAscentDescent) { if (!m_platformData.size()) { m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; return; } SkPaint::FontMetrics metrics; m_platformData.setupPaint(&m_paint); m_paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); m_paint.getFontMetrics(&metrics); SkTypeface* face = m_paint.getTypeface(); ASSERT(face); int vdmxAscent = 0, vdmxDescent = 0; bool isVDMXValid = false; #if OS(LINUX) || OS(ANDROID) // Manually digging up VDMX metrics is only applicable when bytecode hinting // using FreeType. With DirectWrite or CoreText, no bytecode hinting is ever // done. This code should be pushed into FreeType (hinted font metrics). static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); int pixelSize = m_platformData.size() + 0.5; if (!m_paint.isAutohinted() && (m_paint.getHinting() == SkPaint::kFull_Hinting || m_paint.getHinting() == SkPaint::kNormal_Hinting)) { size_t vdmxSize = face->getTableSize(vdmxTag); if (vdmxSize && vdmxSize < maxVDMXTableSize) { uint8_t* vdmxTable = (uint8_t*)WTF::Partitions::fastMalloc( vdmxSize, WTF_HEAP_PROFILER_TYPE_NAME(SimpleFontData)); if (vdmxTable && face->getTableData(vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) isVDMXValid = true; WTF::Partitions::fastFree(vdmxTable); } } #endif float ascent; float descent; // Beware those who step here: This code is designed to match Win32 font // metrics *exactly* except: // - the adjustment of ascent/descent on Linux/Android // - metrics.fAscent and .fDesscent are not rounded to int for tiny fonts if (isVDMXValid) { ascent = vdmxAscent; descent = -vdmxDescent; } else { // For tiny fonts, the rounding of fAscent and fDescent results in equal // baseline for different types of text baselines (crbug.com/338908). // Please see CanvasRenderingContext2D::getFontBaseline for the heuristic. if (subpixelAscentDescent && (-metrics.fAscent < 3 || -metrics.fAscent + metrics.fDescent < 2)) { ascent = -metrics.fAscent; descent = metrics.fDescent; } else { ascent = SkScalarRoundToScalar(-metrics.fAscent); descent = SkScalarRoundToScalar(metrics.fDescent); } #if OS(LINUX) || OS(ANDROID) // When subpixel positioning is enabled, if the descent is rounded down, the // descent part of the glyph may be truncated when displayed in a 'overflow: // hidden' container. To avoid that, borrow 1 unit from the ascent when // possible. // FIXME: This can be removed if sub-pixel ascent/descent is supported. if (platformData().getFontRenderStyle().useSubpixelPositioning && descent < SkScalarToFloat(metrics.fDescent) && ascent >= 1) { ++descent; --ascent; } #endif } #if OS(MACOSX) // We are preserving this ascent hack to match Safari's ascent adjustment // in their SimpleFontDataMac.mm, for details see crbug.com/445830. // We need to adjust Times, Helvetica, and Courier to closely match the // vertical metrics of their Microsoft counterparts that are the de facto // web standard. The AppKit adjustment of 20% is too big and is // incorrectly added to line spacing, so we use a 15% adjustment instead // and add it to the ascent. DEFINE_STATIC_LOCAL(AtomicString, timesName, ("Times")); DEFINE_STATIC_LOCAL(AtomicString, helveticaName, ("Helvetica")); DEFINE_STATIC_LOCAL(AtomicString, courierName, ("Courier")); String familyName = m_platformData.fontFamilyName(); if (familyName == timesName || familyName == helveticaName || familyName == courierName) ascent += floorf(((ascent + descent) * 0.15f) + 0.5f); #endif m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); float xHeight; if (metrics.fXHeight) { xHeight = metrics.fXHeight; #if OS(MACOSX) // Mac OS CTFontGetXHeight reports the bounding box height of x, // including parts extending below the baseline and apparently no x-height // value from the OS/2 table. However, the CSS ex unit // expects only parts above the baseline, hence measuring the glyph: // http://www.w3.org/TR/css3-values/#ex-unit const Glyph xGlyph = glyphForCharacter('x'); if (xGlyph) { FloatRect glyphBounds(boundsForGlyph(xGlyph)); // SkGlyph bounds, y down, based on rendering at (0,0). xHeight = -glyphBounds.y(); } #endif m_fontMetrics.setXHeight(xHeight); } else { xHeight = ascent * 0.56; // Best guess from Windows font metrics. m_fontMetrics.setXHeight(xHeight); m_fontMetrics.setHasXHeight(false); } float lineGap = SkScalarToFloat(metrics.fLeading); m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); if (platformData().isVerticalAnyUpright() && !isTextOrientationFallback()) { static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a'); static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G'); size_t vheaSize = face->getTableSize(vheaTag); size_t vorgSize = face->getTableSize(vorgTag); if ((vheaSize > 0) || (vorgSize > 0)) m_hasVerticalGlyphs = true; } // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is // calculated for us, but we need to calculate m_maxCharWidth and // m_avgCharWidth in order for text entry widgets to be sized correctly. #if OS(WIN) m_maxCharWidth = SkScalarRoundToInt(metrics.fMaxCharWidth); // Older version of the DirectWrite API doesn't implement support for max // char width. Fall back on a multiple of the ascent. This is entirely // arbitrary but comes pretty close to the expected value in most cases. if (m_maxCharWidth < 1) m_maxCharWidth = ascent * 2; #elif OS(MACOSX) // FIXME: The current avg/max character width calculation is not ideal, // it should check either the OS2 table or, better yet, query FontMetrics. // Sadly FontMetrics provides incorrect data on Mac at the moment. // https://crbug.com/420901 m_maxCharWidth = std::max(m_avgCharWidth, m_fontMetrics.floatAscent()); #else // Better would be to rely on either fMaxCharWidth or fAveCharWidth. // skbug.com/3087 m_maxCharWidth = SkScalarRoundToInt(metrics.fXMax - metrics.fXMin); #endif #if !OS(MACOSX) if (metrics.fAvgCharWidth) { m_avgCharWidth = SkScalarRoundToInt(metrics.fAvgCharWidth); } else { #endif m_avgCharWidth = xHeight; const Glyph xGlyph = glyphForCharacter('x'); if (xGlyph) { m_avgCharWidth = widthForGlyph(xGlyph); } #if !OS(MACOSX) } #endif if (int unitsPerEm = face->getUnitsPerEm()) m_fontMetrics.setUnitsPerEm(unitsPerEm); }
void SimpleFontData::platformInit() { if (!m_platformData.size()) { m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; return; } SkPaint paint; SkPaint::FontMetrics metrics; m_platformData.setupPaint(&paint); paint.getFontMetrics(&metrics); const SkFontID fontID = m_platformData.uniqueID(); static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); int pixelSize = m_platformData.size() + 0.5; int vdmxAscent, vdmxDescent; bool isVDMXValid = false; size_t vdmxSize = SkFontHost::GetTableSize(fontID, vdmxTag); if (vdmxSize && vdmxSize < maxVDMXTableSize) { uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize); if (vdmxTable && SkFontHost::GetTableData(fontID, vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) isVDMXValid = true; fastFree(vdmxTable); } float ascent; float descent; // Beware those who step here: This code is designed to match Win32 font // metrics *exactly*. if (isVDMXValid) { ascent = vdmxAscent; descent = -vdmxDescent; } else { SkScalar height = -metrics.fAscent + metrics.fDescent + metrics.fLeading; ascent = SkScalarRound(-metrics.fAscent); descent = SkScalarRound(height) - ascent; } m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); float xHeight; if (metrics.fXHeight) xHeight = metrics.fXHeight; else { // hack taken from the Windows port xHeight = ascent * 0.56f; } float lineGap = SkScalarToFloat(metrics.fLeading); m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setXHeight(xHeight); m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); if (platformData().orientation() == Vertical && !isTextOrientationFallback()) { static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a'); static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G'); size_t vheaSize = SkFontHost::GetTableSize(fontID, vheaTag); size_t vorgSize = SkFontHost::GetTableSize(fontID, vorgTag); if ((vheaSize > 0) || (vorgSize > 0)) m_hasVerticalGlyphs = true; } // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is // calculated for us, but we need to calculate m_maxCharWidth and // m_avgCharWidth in order for text entry widgets to be sized correctly. SkScalar xRange = metrics.fXMax - metrics.fXMin; m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size())); if (metrics.fAvgCharWidth) m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); else { m_avgCharWidth = xHeight; GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); if (glyphPageZero) { static const UChar32 x_char = 'x'; const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(x_char).glyph; if (xGlyph) m_avgCharWidth = widthForGlyph(xGlyph); } } }
void SimpleFontData::determinePitch() { m_treatAsFixedPitch = platformData().isFixedPitch(); }