nsresult GDIFontEntry::ReadCMAP() { // skip non-SFNT fonts completely if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE && mFontType != GFX_FONT_TYPE_TT_OPENTYPE && mFontType != GFX_FONT_TYPE_TRUETYPE) { return NS_ERROR_FAILURE; } // attempt this once, if errors occur leave a blank cmap if (mCmapInitialized) return NS_OK; mCmapInitialized = PR_TRUE; const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p'); AutoFallibleTArray<PRUint8,16384> buffer; if (GetFontTable(kCmapTag, buffer) != NS_OK) return NS_ERROR_FAILURE; PRUint8 *cmap = buffer.Elements(); PRPackedBool unicodeFont = PR_FALSE, symbolFont = PR_FALSE; nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(), mCharacterMap, mUVSOffset, unicodeFont, symbolFont); mSymbolFont = symbolFont; mHasCmapTable = NS_SUCCEEDED(rv); #ifdef PR_LOGGING LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n", NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize())); #endif return rv; }
nsresult FT2FontEntry::ReadCMAP() { if (mCharacterMap) { return NS_OK; } nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(); AutoFallibleTArray<PRUint8,16384> buffer; nsresult rv = GetFontTable(TTAG_cmap, buffer); if (NS_SUCCEEDED(rv)) { bool unicodeFont; bool symbolFont; rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(), *charmap, mUVSOffset, unicodeFont, symbolFont); } mHasCmapTable = NS_SUCCEEDED(rv); if (mHasCmapTable) { gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); mCharacterMap = pfl->FindCharMap(charmap); } else { // if error occurred, initialize to null cmap mCharacterMap = new gfxCharacterMap(); } return rv; }
bool gfxDWriteFontEntry::IsCJKFont() { if (mIsCJK != UNINITIALIZED_VALUE) { return mIsCJK; } mIsCJK = false; const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2'); AutoFallibleTArray<uint8_t,128> buffer; if (CopyFontTable(kOS2Tag, buffer) != NS_OK) { return mIsCJK; } // ulCodePageRange bit definitions for the CJK codepages, // from http://www.microsoft.com/typography/otspec/os2.htm#cpr const uint32_t CJK_CODEPAGE_BITS = (1 << 17) | // codepage 932 - JIS/Japan (1 << 18) | // codepage 936 - Chinese (simplified) (1 << 19) | // codepage 949 - Korean Wansung (1 << 20) | // codepage 950 - Chinese (traditional) (1 << 21); // codepage 1361 - Korean Johab if (buffer.Length() >= offsetof(OS2Table, sxHeight)) { const OS2Table* os2 = reinterpret_cast<const OS2Table*>(buffer.Elements()); if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) { mIsCJK = true; } } return mIsCJK; }
void nsSVGGeometryFrame::SetupCairoStrokeHitGeometry(gfxContext *aContext) { SetupCairoStrokeGeometry(aContext); AutoFallibleTArray<gfxFloat, 10> dashes; gfxFloat dashOffset; if (GetStrokeDashData(dashes, &dashOffset)) { aContext->SetDash(dashes.Elements(), dashes.Length(), dashOffset); } }
nsresult FT2FontEntry::ReadCMAP(FontInfoData *aFontInfoData) { if (mCharacterMap) { return NS_OK; } nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(); AutoFallibleTArray<uint8_t,16384> buffer; nsresult rv = CopyFontTable(TTAG_cmap, buffer); if (NS_SUCCEEDED(rv)) { bool unicodeFont; bool symbolFont; rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(), *charmap, mUVSOffset, unicodeFont, symbolFont); } if (NS_SUCCEEDED(rv) && !HasGraphiteTables()) { // We assume a Graphite font knows what it's doing, // and provides whatever shaping is needed for the // characters it supports, so only check/clear the // complex-script ranges for non-Graphite fonts // for layout support, check for the presence of opentype layout tables bool hasGSUB = HasFontTable(TRUETYPE_TAG('G','S','U','B')); for (const ScriptRange* sr = gfxPlatformFontList::sComplexScriptRanges; sr->rangeStart; sr++) { // check to see if the cmap includes complex script codepoints if (charmap->TestRange(sr->rangeStart, sr->rangeEnd)) { // We check for GSUB here, as GPOS alone would not be ok. if (hasGSUB && SupportsScriptInGSUB(sr->tags)) { continue; } charmap->ClearRange(sr->rangeStart, sr->rangeEnd); } } } mHasCmapTable = NS_SUCCEEDED(rv); if (mHasCmapTable) { gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); mCharacterMap = pfl->FindCharMap(charmap); } else { // if error occurred, initialize to null cmap mCharacterMap = new gfxCharacterMap(); } return rv; }
nsresult GDIFontEntry::ReadCMAP() { // skip non-SFNT fonts completely if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE && mFontType != GFX_FONT_TYPE_TT_OPENTYPE && mFontType != GFX_FONT_TYPE_TRUETYPE) { return NS_ERROR_FAILURE; } // attempt this once, if errors occur leave a blank cmap if (mCmapInitialized) return NS_OK; mCmapInitialized = true; const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p'); AutoFallibleTArray<PRUint8,16384> buffer; if (GetFontTable(kCmapTag, buffer) != NS_OK) return NS_ERROR_FAILURE; PRUint8 *cmap = buffer.Elements(); bool unicodeFont = false, symbolFont = false; nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(), mCharacterMap, mUVSOffset, unicodeFont, symbolFont); mSymbolFont = symbolFont; mHasCmapTable = NS_SUCCEEDED(rv); #ifdef PR_LOGGING LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n", NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of))); if (LOG_CMAPDATA_ENABLED()) { char prefix[256]; sprintf(prefix, "(cmapdata) name: %.220s", NS_ConvertUTF16toUTF8(mName).get()); mCharacterMap.Dump(prefix, eGfxLog_cmapdata); } #endif return rv; }
void MobileMessageCursorChild::DoNotifyResult(const nsTArray<ThreadData>& aDataArray) { const uint32_t length = aDataArray.Length(); MOZ_ASSERT(length); AutoFallibleTArray<nsISupports*, 1> autoArray; NS_ENSURE_TRUE_VOID(autoArray.SetCapacity(length)); AutoFallibleTArray<nsCOMPtr<nsISupports>, 1> threads; NS_ENSURE_TRUE_VOID(threads.SetCapacity(length)); for (uint32_t i = 0; i < length; i++) { nsCOMPtr<nsISupports> thread = new MobileMessageThread(aDataArray[i]); NS_ENSURE_TRUE_VOID(threads.AppendElement(thread)); NS_ENSURE_TRUE_VOID(autoArray.AppendElement(thread.get())); } mCursorCallback->NotifyCursorResult(autoArray.Elements(), length); }
nsresult FT2FontEntry::ReadCMAP() { if (mCmapInitialized) { return NS_OK; } // attempt this once, if errors occur leave a blank cmap mCmapInitialized = true; AutoFallibleTArray<PRUint8,16384> buffer; nsresult rv = GetFontTable(TTAG_cmap, buffer); if (NS_SUCCEEDED(rv)) { bool unicodeFont; bool symbolFont; rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(), mCharacterMap, mUVSOffset, unicodeFont, symbolFont); } mHasCmapTable = NS_SUCCEEDED(rv); return rv; }
gfxFontEntry* gfxGDIFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, const uint8_t *aFontData, uint32_t aLength) { // MakePlatformFont is responsible for deleting the font data with NS_Free // so we set up a stack object to ensure it is freed even if we take an // early exit struct FontDataDeleter { FontDataDeleter(const uint8_t *aFontData) : mFontData(aFontData) { } ~FontDataDeleter() { NS_Free((void*)mFontData); } const uint8_t *mFontData; }; FontDataDeleter autoDelete(aFontData); bool hasVertical; bool isCFF = gfxFontUtils::IsCffFont(aFontData, hasVertical); nsresult rv; HANDLE fontRef = nullptr; bool isEmbedded = false; nsAutoString uniqueName; rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName); if (NS_FAILED(rv)) return nullptr; // for TTF fonts, first try using the t2embed library if available if (!isCFF && TTLoadEmbeddedFontPtr && TTDeleteEmbeddedFontPtr) { // TrueType-style glyphs, use EOT library AutoFallibleTArray<uint8_t,2048> eotHeader; uint8_t *buffer; uint32_t eotlen; isEmbedded = true; uint32_t nameLen = NS_MIN<uint32_t>(uniqueName.Length(), LF_FACESIZE - 1); nsAutoString fontName(Substring(uniqueName, 0, nameLen)); FontDataOverlay overlayNameData = {0, 0, 0}; rv = gfxFontUtils::MakeEOTHeader(aFontData, aLength, &eotHeader, &overlayNameData); if (NS_SUCCEEDED(rv)) { // load in embedded font data eotlen = eotHeader.Length(); buffer = reinterpret_cast<uint8_t*> (eotHeader.Elements()); int32_t ret; ULONG privStatus, pulStatus; EOTFontStreamReader eotReader(aFontData, aLength, buffer, eotlen, &overlayNameData); ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &pulStatus, EOTFontStreamReader::ReadEOTStream, &eotReader, (PRUnichar*)(fontName.get()), 0, 0); if (ret != E_NONE) { fontRef = nullptr; char buf[256]; sprintf(buf, "font (%s) not loaded using TTLoadEmbeddedFont - error %8.8x", NS_ConvertUTF16toUTF8(aProxyEntry->Name()).get(), ret); NS_WARNING(buf); } } } // load CFF fonts or fonts that failed with t2embed loader if (fontRef == nullptr) { // Postscript-style glyphs, swizzle name table, load directly FallibleTArray<uint8_t> newFontData; isEmbedded = false; rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData); if (NS_FAILED(rv)) return nullptr; DWORD numFonts = 0; uint8_t *fontData = reinterpret_cast<uint8_t*> (newFontData.Elements()); uint32_t fontLength = newFontData.Length(); NS_ASSERTION(fontData, "null font data after renaming"); // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx // "A font that is added by AddFontMemResourceEx is always private // to the process that made the call and is not enumerable." fontRef = AddFontMemResourceEx(fontData, fontLength, 0 /* reserved */, &numFonts); if (!fontRef) return nullptr; // only load fonts with a single face contained in the data // AddFontMemResourceEx generates an additional face name for // vertical text if the font supports vertical writing if (fontRef && numFonts != 1 + !!hasVertical) { RemoveFontMemResourceEx(fontRef); return nullptr; } } // make a new font entry using the unique name WinUserFontData *winUserFontData = new WinUserFontData(fontRef, isEmbedded); uint16_t w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight); GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName, gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, uint32_t(aProxyEntry->mItalic ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL), w, aProxyEntry->mStretch, winUserFontData, false); if (!fe) return fe; fe->mIsUserFont = true; // Uniscribe doesn't place CFF fonts loaded privately // via AddFontMemResourceEx on XP/Vista if (isCFF && gfxWindowsPlatform::WindowsOSVersion() < gfxWindowsPlatform::kWindows7) { fe->mForceGDI = true; } return fe; }
nsresult GDIFontEntry::ReadCMAP() { // attempt this once, if errors occur leave a blank cmap if (mCharacterMap) { return NS_OK; } // skip non-SFNT fonts completely if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE && mFontType != GFX_FONT_TYPE_TT_OPENTYPE && mFontType != GFX_FONT_TYPE_TRUETYPE) { mCharacterMap = new gfxCharacterMap(); mCharacterMap->mBuildOnTheFly = true; return NS_ERROR_FAILURE; } nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(); uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p'); nsresult rv; AutoFallibleTArray<uint8_t,16384> cmap; rv = GetFontTable(kCMAP, cmap); bool unicodeFont = false, symbolFont = false; // currently ignored if (NS_SUCCEEDED(rv)) { rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(), *charmap, mUVSOffset, unicodeFont, symbolFont); } mSymbolFont = symbolFont; mHasCmapTable = NS_SUCCEEDED(rv); if (mHasCmapTable) { gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); mCharacterMap = pfl->FindCharMap(charmap); } else { // if error occurred, initialize to null cmap mCharacterMap = new gfxCharacterMap(); // For fonts where we failed to read the character map, // we can take a slow path to look up glyphs character by character mCharacterMap->mBuildOnTheFly = true; } #ifdef PR_LOGGING LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n", NS_ConvertUTF16toUTF8(mName).get(), charmap->SizeOfIncludingThis(moz_malloc_size_of), charmap->mHash, mCharacterMap == charmap ? " new" : "")); if (LOG_CMAPDATA_ENABLED()) { char prefix[256]; sprintf(prefix, "(cmapdata) name: %.220s", NS_ConvertUTF16toUTF8(mName).get()); charmap->Dump(prefix, eGfxLog_cmapdata); } #endif return rv; }
void gfxMacFont::InitMetrics() { mIsValid = false; ::memset(&mMetrics, 0, sizeof(mMetrics)); PRUint32 upem = 0; // try to get unitsPerEm from sfnt head table, to avoid calling CGFont // if possible (bug 574368) and because CGFontGetUnitsPerEm does not // return the true value for OpenType/CFF fonts (it normalizes to 1000, // which then leads to metrics errors when we read the 'hmtx' table to // get glyph advances for HarfBuzz, see bug 580863) const PRUint32 kHeadTableTag = TRUETYPE_TAG('h','e','a','d'); AutoFallibleTArray<PRUint8,sizeof(HeadTable)> headData; if (NS_SUCCEEDED(mFontEntry->GetFontTable(kHeadTableTag, headData)) && headData.Length() >= sizeof(HeadTable)) { HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements()); upem = head->unitsPerEm; } else { upem = ::CGFontGetUnitsPerEm(mCGFont); } if (upem < 16 || upem > 16384) { // See http://www.microsoft.com/typography/otspec/head.htm #ifdef DEBUG char warnBuf[1024]; sprintf(warnBuf, "Bad font metrics for: %s (invalid unitsPerEm value)", NS_ConvertUTF16toUTF8(mFontEntry->Name()).get()); NS_WARNING(warnBuf); #endif return; } mAdjustedSize = NS_MAX(mStyle.size, 1.0); mFUnitsConvFactor = mAdjustedSize / upem; // For CFF fonts, when scaling values read from CGFont* APIs, we need to // use CG's idea of unitsPerEm, which may differ from the "true" value in // the head table of the font (see bug 580863) gfxFloat cgConvFactor; if (static_cast<MacOSFontEntry*>(mFontEntry.get())->IsCFF()) { cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont); } else { cgConvFactor = mFUnitsConvFactor; } // Try to read 'sfnt' metrics; for local, non-sfnt fonts ONLY, fall back to // platform APIs. The InitMetrics...() functions will set mIsValid on success. if (!InitMetricsFromSfntTables(mMetrics) && (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) { InitMetricsFromPlatform(); } if (!mIsValid) { return; } if (mMetrics.xHeight == 0.0) { mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor; } if (mStyle.sizeAdjust != 0.0 && mStyle.size > 0.0 && mMetrics.xHeight > 0.0) { // apply font-size-adjust, and recalculate metrics gfxFloat aspect = mMetrics.xHeight / mStyle.size; mAdjustedSize = mStyle.GetAdjustedSize(aspect); mFUnitsConvFactor = mAdjustedSize / upem; if (static_cast<MacOSFontEntry*>(mFontEntry.get())->IsCFF()) { cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont); } else { cgConvFactor = mFUnitsConvFactor; } mMetrics.xHeight = 0.0; if (!InitMetricsFromSfntTables(mMetrics) && (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) { InitMetricsFromPlatform(); } if (!mIsValid) { // this shouldn't happen, as we succeeded earlier before applying // the size-adjust factor! But check anyway, for paranoia's sake. return; } if (mMetrics.xHeight == 0.0) { mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor; } } // Once we reach here, we've got basic metrics and set mIsValid = TRUE; // there should be no further points of actual failure in InitMetrics(). // (If one is introduced, be sure to reset mIsValid to FALSE!) mMetrics.emHeight = mAdjustedSize; // Measure/calculate additional metrics, independent of whether we used // the tables directly or ATS metrics APIs CFDataRef cmap = ::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('c','m','a','p')); PRUint32 glyphID; if (mMetrics.aveCharWidth <= 0) { mMetrics.aveCharWidth = GetCharWidth(cmap, 'x', &glyphID, cgConvFactor); if (glyphID == 0) { // we didn't find 'x', so use maxAdvance rather than zero mMetrics.aveCharWidth = mMetrics.maxAdvance; } } if (IsSyntheticBold()) { mMetrics.aveCharWidth += GetSyntheticBoldOffset(); mMetrics.maxAdvance += GetSyntheticBoldOffset(); } mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID, cgConvFactor); if (glyphID == 0) { // no space glyph?! mMetrics.spaceWidth = mMetrics.aveCharWidth; } mSpaceGlyph = glyphID; mMetrics.zeroOrAveCharWidth = GetCharWidth(cmap, '0', &glyphID, cgConvFactor); if (glyphID == 0) { mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth; } if (cmap) { ::CFRelease(cmap); } CalculateDerivedMetrics(mMetrics); SanitizeMetrics(&mMetrics, mFontEntry->mIsBadUnderlineFont); #if 0 fprintf (stderr, "Font: %p (%s) size: %f\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); // fprintf (stderr, " fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height); fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent); fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance); fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading); fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight); fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset); #endif }
int CALLBACK GDIFontInfo::EnumerateFontsForFamily( const ENUMLOGFONTEXW *lpelfe, const NEWTEXTMETRICEXW *nmetrics, DWORD fontType, LPARAM data) { EnumerateFontsForFamilyData *famData = reinterpret_cast<EnumerateFontsForFamilyData*>(data); HDC hdc = famData->mFontInfo.mHdc; LOGFONTW logFont = lpelfe->elfLogFont; const NEWTEXTMETRICW& metrics = nmetrics->ntmTm; AutoSelectFont font(hdc, &logFont); if (!font.IsValid()) { return 1; } FontFaceData fontData; nsDependentString fontName(lpelfe->elfFullName); // callback called for each style-charset so return if style already seen if (fontName.Equals(famData->mPreviousFontName)) { return 1; } famData->mPreviousFontName = fontName; famData->mFontInfo.mLoadStats.fonts++; // read name table info bool nameDataLoaded = false; if (famData->mFontInfo.mLoadFaceNames || famData->mFontInfo.mLoadOtherNames) { uint32_t kNAME = NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e')); uint32_t nameSize; AutoFallibleTArray<uint8_t, 1024> nameData; nameSize = ::GetFontData(hdc, kNAME, 0, nullptr, 0); if (nameSize != GDI_ERROR && nameSize > 0 && nameData.SetLength(nameSize, fallible)) { ::GetFontData(hdc, kNAME, 0, nameData.Elements(), nameSize); // face names if (famData->mFontInfo.mLoadFaceNames) { gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize, gfxFontUtils::NAME_ID_FULL, fontData.mFullName); gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize, gfxFontUtils::NAME_ID_POSTSCRIPT, fontData.mPostscriptName); nameDataLoaded = true; famData->mFontInfo.mLoadStats.facenames++; } // other family names if (famData->mFontInfo.mLoadOtherNames) { gfxFontFamily::ReadOtherFamilyNamesForFace(famData->mFamilyName, (const char*)(nameData.Elements()), nameSize, famData->mOtherFamilyNames, false); } } } // read cmap bool cmapLoaded = false; gfxWindowsFontType feType = GDIFontEntry::DetermineFontType(metrics, fontType); if (famData->mFontInfo.mLoadCmaps && (feType == GFX_FONT_TYPE_PS_OPENTYPE || feType == GFX_FONT_TYPE_TT_OPENTYPE || feType == GFX_FONT_TYPE_TRUETYPE)) { uint32_t kCMAP = NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p')); uint32_t cmapSize; AutoFallibleTArray<uint8_t, 1024> cmapData; cmapSize = ::GetFontData(hdc, kCMAP, 0, nullptr, 0); if (cmapSize != GDI_ERROR && cmapSize > 0 && cmapData.SetLength(cmapSize, fallible)) { ::GetFontData(hdc, kCMAP, 0, cmapData.Elements(), cmapSize); bool cmapLoaded = false; bool unicodeFont = false, symbolFont = false; RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(); uint32_t offset; if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData.Elements(), cmapSize, *charmap, offset, unicodeFont, symbolFont))) { fontData.mCharacterMap = charmap; fontData.mUVSOffset = offset; fontData.mSymbolFont = symbolFont; cmapLoaded = true; famData->mFontInfo.mLoadStats.cmaps++; } } } if (cmapLoaded || nameDataLoaded) { famData->mFontInfo.mFontFaceData.Put(fontName, fontData); } return 1; }
nsresult gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText, uint32_t aOffset, uint32_t aLength, CTRunRef aCTRun, int32_t aStringOffset) { // The word has been bidi-wrapped; aStringOffset is the number // of chars at the beginning of the CTLine that we should skip. // aCTRun is a glyph run from the CoreText layout process. int32_t direction = aShapedText->IsRightToLeft() ? -1 : 1; int32_t numGlyphs = ::CTRunGetGlyphCount(aCTRun); if (numGlyphs == 0) { return NS_OK; } int32_t wordLength = aLength; // character offsets get really confusing here, as we have to keep track of // (a) the text in the actual textRun we're constructing // (c) the string that was handed to CoreText, which contains the text of the font run // plus directional-override padding // (d) the CTRun currently being processed, which may be a sub-run of the CoreText line // (but may extend beyond the actual font run into the bidi wrapping text). // aStringOffset tells us how many initial characters of the line to ignore. // get the source string range within the CTLine's text CFRange stringRange = ::CTRunGetStringRange(aCTRun); // skip the run if it is entirely outside the actual range of the font run if (stringRange.location - aStringOffset + stringRange.length <= 0 || stringRange.location - aStringOffset >= wordLength) { return NS_OK; } // retrieve the laid-out glyph data from the CTRun UniquePtr<CGGlyph[]> glyphsArray; UniquePtr<CGPoint[]> positionsArray; UniquePtr<CFIndex[]> glyphToCharArray; const CGGlyph* glyphs = nullptr; const CGPoint* positions = nullptr; const CFIndex* glyphToChar = nullptr; // Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds, // and so allocating a new array and copying data with CTRunGetGlyphs // will be extremely rare. // If this were not the case, we could use an nsAutoTArray<> to // try and avoid the heap allocation for small runs. // It's possible that some future change to CoreText will mean that // CTRunGetGlyphsPtr fails more often; if this happens, nsAutoTArray<> // may become an attractive option. glyphs = ::CTRunGetGlyphsPtr(aCTRun); if (!glyphs) { glyphsArray = MakeUniqueFallible<CGGlyph[]>(numGlyphs); if (!glyphsArray) { return NS_ERROR_OUT_OF_MEMORY; } ::CTRunGetGlyphs(aCTRun, ::CFRangeMake(0, 0), glyphsArray.get()); glyphs = glyphsArray.get(); } positions = ::CTRunGetPositionsPtr(aCTRun); if (!positions) { positionsArray = MakeUniqueFallible<CGPoint[]>(numGlyphs); if (!positionsArray) { return NS_ERROR_OUT_OF_MEMORY; } ::CTRunGetPositions(aCTRun, ::CFRangeMake(0, 0), positionsArray.get()); positions = positionsArray.get(); } // Remember that the glyphToChar indices relate to the CoreText line, // not to the beginning of the textRun, the font run, // or the stringRange of the glyph run glyphToChar = ::CTRunGetStringIndicesPtr(aCTRun); if (!glyphToChar) { glyphToCharArray = MakeUniqueFallible<CFIndex[]>(numGlyphs); if (!glyphToCharArray) { return NS_ERROR_OUT_OF_MEMORY; } ::CTRunGetStringIndices(aCTRun, ::CFRangeMake(0, 0), glyphToCharArray.get()); glyphToChar = glyphToCharArray.get(); } double runWidth = ::CTRunGetTypographicBounds(aCTRun, ::CFRangeMake(0, 0), nullptr, nullptr, nullptr); nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs; gfxShapedText::CompressedGlyph *charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset; // CoreText gives us the glyphindex-to-charindex mapping, which relates each glyph // to a source text character; we also need the charindex-to-glyphindex mapping to // find the glyph for a given char. Note that some chars may not map to any glyph // (ligature continuations), and some may map to several glyphs (eg Indic split vowels). // We set the glyph index to NO_GLYPH for chars that have no associated glyph, and we // record the last glyph index for cases where the char maps to several glyphs, // so that our clumping will include all the glyph fragments for the character. // The charToGlyph array is indexed by char position within the stringRange of the glyph run. static const int32_t NO_GLYPH = -1; AutoFallibleTArray<int32_t,SMALL_GLYPH_RUN> charToGlyphArray; if (!charToGlyphArray.SetLength(stringRange.length, fallible)) { return NS_ERROR_OUT_OF_MEMORY; } int32_t *charToGlyph = charToGlyphArray.Elements(); for (int32_t offset = 0; offset < stringRange.length; ++offset) { charToGlyph[offset] = NO_GLYPH; } for (int32_t i = 0; i < numGlyphs; ++i) { int32_t loc = glyphToChar[i] - stringRange.location; if (loc >= 0 && loc < stringRange.length) { charToGlyph[loc] = i; } } // Find character and glyph clumps that correspond, allowing for ligatures, // indic reordering, split glyphs, etc. // // The idea is that we'll find a character sequence starting at the first char of stringRange, // and extend it until it includes the character associated with the first glyph; // we also extend it as long as there are "holes" in the range of glyphs. So we // will eventually have a contiguous sequence of characters, starting at the beginning // of the range, that map to a contiguous sequence of glyphs, starting at the beginning // of the glyph array. That's a clump; then we update the starting positions and repeat. // // NB: In the case of RTL layouts, we iterate over the stringRange in reverse. // // This may find characters that fall outside the range 0:wordLength, // so we won't necessarily use everything we find here. bool isRightToLeft = aShapedText->IsRightToLeft(); int32_t glyphStart = 0; // looking for a clump that starts at this glyph index int32_t charStart = isRightToLeft ? stringRange.length - 1 : 0; // and this char index (in the stringRange of the glyph run) while (glyphStart < numGlyphs) { // keep finding groups until all glyphs are accounted for bool inOrder = true; int32_t charEnd = glyphToChar[glyphStart] - stringRange.location; NS_WARN_IF_FALSE(charEnd >= 0 && charEnd < stringRange.length, "glyph-to-char mapping points outside string range"); // clamp charEnd to the valid range of the string charEnd = std::max(charEnd, 0); charEnd = std::min(charEnd, int32_t(stringRange.length)); int32_t glyphEnd = glyphStart; int32_t charLimit = isRightToLeft ? -1 : stringRange.length; do { // This is normally executed once for each iteration of the outer loop, // but in unusual cases where the character/glyph association is complex, // the initial character range might correspond to a non-contiguous // glyph range with "holes" in it. If so, we will repeat this loop to // extend the character range until we have a contiguous glyph sequence. NS_ASSERTION((direction > 0 && charEnd < charLimit) || (direction < 0 && charEnd > charLimit), "no characters left in range?"); charEnd += direction; while (charEnd != charLimit && charToGlyph[charEnd] == NO_GLYPH) { charEnd += direction; } // find the maximum glyph index covered by the clump so far if (isRightToLeft) { for (int32_t i = charStart; i > charEnd; --i) { if (charToGlyph[i] != NO_GLYPH) { // update extent of glyph range glyphEnd = std::max(glyphEnd, charToGlyph[i] + 1); } } } else { for (int32_t i = charStart; i < charEnd; ++i) { if (charToGlyph[i] != NO_GLYPH) { // update extent of glyph range glyphEnd = std::max(glyphEnd, charToGlyph[i] + 1); } } } if (glyphEnd == glyphStart + 1) { // for the common case of a single-glyph clump, we can skip the following checks break; } if (glyphEnd == glyphStart) { // no glyphs, try to extend the clump continue; } // check whether all glyphs in the range are associated with the characters // in our clump; if not, we have a discontinuous range, and should extend it // unless we've reached the end of the text bool allGlyphsAreWithinCluster = true; int32_t prevGlyphCharIndex = charStart; for (int32_t i = glyphStart; i < glyphEnd; ++i) { int32_t glyphCharIndex = glyphToChar[i] - stringRange.location; if (isRightToLeft) { if (glyphCharIndex > charStart || glyphCharIndex <= charEnd) { allGlyphsAreWithinCluster = false; break; } if (glyphCharIndex > prevGlyphCharIndex) { inOrder = false; } prevGlyphCharIndex = glyphCharIndex; } else { if (glyphCharIndex < charStart || glyphCharIndex >= charEnd) { allGlyphsAreWithinCluster = false; break; } if (glyphCharIndex < prevGlyphCharIndex) { inOrder = false; } prevGlyphCharIndex = glyphCharIndex; } } if (allGlyphsAreWithinCluster) { break; } } while (charEnd != charLimit); NS_WARN_IF_FALSE(glyphStart < glyphEnd, "character/glyph clump contains no glyphs!"); if (glyphStart == glyphEnd) { ++glyphStart; // make progress - avoid potential infinite loop charStart = charEnd; continue; } NS_WARN_IF_FALSE(charStart != charEnd, "character/glyph clump contains no characters!"); if (charStart == charEnd) { glyphStart = glyphEnd; // this is bad - we'll discard the glyph(s), // as there's nowhere to attach them continue; } // Now charStart..charEnd is a ligature clump, corresponding to glyphStart..glyphEnd; // Set baseCharIndex to the char we'll actually attach the glyphs to (1st of ligature), // and endCharIndex to the limit (position beyond the last char), // adjusting for the offset of the stringRange relative to the textRun. int32_t baseCharIndex, endCharIndex; if (isRightToLeft) { while (charEnd >= 0 && charToGlyph[charEnd] == NO_GLYPH) { charEnd--; } baseCharIndex = charEnd + stringRange.location - aStringOffset + 1; endCharIndex = charStart + stringRange.location - aStringOffset + 1; } else { while (charEnd < stringRange.length && charToGlyph[charEnd] == NO_GLYPH) { charEnd++; } baseCharIndex = charStart + stringRange.location - aStringOffset; endCharIndex = charEnd + stringRange.location - aStringOffset; } // Then we check if the clump falls outside our actual string range; if so, just go to the next. if (endCharIndex <= 0 || baseCharIndex >= wordLength) { glyphStart = glyphEnd; charStart = charEnd; continue; } // Ensure we won't try to go beyond the valid length of the word's text baseCharIndex = std::max(baseCharIndex, 0); endCharIndex = std::min(endCharIndex, wordLength); // Now we're ready to set the glyph info in the textRun; measure the glyph width // of the first (perhaps only) glyph, to see if it is "Simple" int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit(); double toNextGlyph; if (glyphStart < numGlyphs-1) { toNextGlyph = positions[glyphStart+1].x - positions[glyphStart].x; } else { toNextGlyph = positions[0].x + runWidth - positions[glyphStart].x; } int32_t advance = int32_t(toNextGlyph * appUnitsPerDevUnit); // Check if it's a simple one-to-one mapping int32_t glyphsInClump = glyphEnd - glyphStart; if (glyphsInClump == 1 && gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyphs[glyphStart]) && gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) && charGlyphs[baseCharIndex].IsClusterStart() && positions[glyphStart].y == 0.0) { charGlyphs[baseCharIndex].SetSimpleGlyph(advance, glyphs[glyphStart]); } else { // collect all glyphs in a list to be assigned to the first char; // there must be at least one in the clump, and we already measured its advance, // hence the placement of the loop-exit test and the measurement of the next glyph while (1) { gfxTextRun::DetailedGlyph *details = detailedGlyphs.AppendElement(); details->mGlyphID = glyphs[glyphStart]; details->mXOffset = 0; details->mYOffset = -positions[glyphStart].y * appUnitsPerDevUnit; details->mAdvance = advance; if (++glyphStart >= glyphEnd) { break; } if (glyphStart < numGlyphs-1) { toNextGlyph = positions[glyphStart+1].x - positions[glyphStart].x; } else { toNextGlyph = positions[0].x + runWidth - positions[glyphStart].x; } advance = int32_t(toNextGlyph * appUnitsPerDevUnit); } gfxTextRun::CompressedGlyph textRunGlyph; textRunGlyph.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(), true, detailedGlyphs.Length()); aShapedText->SetGlyphs(aOffset + baseCharIndex, textRunGlyph, detailedGlyphs.Elements()); detailedGlyphs.Clear(); } // the rest of the chars in the group are ligature continuations, no associated glyphs while (++baseCharIndex != endCharIndex && baseCharIndex < wordLength) { gfxShapedText::CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex]; NS_ASSERTION(!shapedTextGlyph.IsSimpleGlyph(), "overwriting a simple glyph"); shapedTextGlyph.SetComplex(inOrder && shapedTextGlyph.IsClusterStart(), false, 0); } glyphStart = glyphEnd; charStart = charEnd; } return NS_OK; }
bool PluginScriptableObjectParent::AnswerInvokeDefault(const InfallibleTArray<Variant>& aArgs, Variant* aResult, bool* aSuccess) { if (!mObject) { NS_WARNING("Calling AnswerInvoke with an invalidated object!"); *aResult = void_t(); *aSuccess = false; return true; } NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!"); NS_ASSERTION(mType == LocalObject, "Bad type!"); PluginInstanceParent* instance = GetInstance(); if (!instance) { NS_ERROR("No instance?!"); *aResult = void_t(); *aSuccess = false; return true; } const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); if (!npn) { NS_ERROR("No netscape funcs?!"); *aResult = void_t(); *aSuccess = false; return true; } AutoFallibleTArray<NPVariant, 10> convertedArgs; uint32_t argCount = aArgs.Length(); if (!convertedArgs.SetLength(argCount)) { *aResult = void_t(); *aSuccess = false; return true; } for (uint32_t index = 0; index < argCount; index++) { if (!ConvertToVariant(aArgs[index], convertedArgs[index], instance)) { // Don't leak things we've already converted! while (index-- > 0) { ReleaseVariant(convertedArgs[index], instance); } *aResult = void_t(); *aSuccess = false; return true; } } NPVariant result; bool success = npn->invokeDefault(instance->GetNPP(), mObject, convertedArgs.Elements(), argCount, &result); for (uint32_t index = 0; index < argCount; index++) { ReleaseVariant(convertedArgs[index], instance); } if (!success) { *aResult = void_t(); *aSuccess = false; return true; } Variant convertedResult; success = ConvertToRemoteVariant(result, convertedResult, GetInstance()); DeferNPVariantLastRelease(npn, &result); if (!success) { *aResult = void_t(); *aSuccess = false; return true; } *aResult = convertedResult; *aSuccess = true; return true; }
nsresult gfxDWriteFontEntry::ReadCMAP() { HRESULT hr; nsresult rv; // attempt this once, if errors occur leave a blank cmap if (mCmapInitialized) return NS_OK; mCmapInitialized = PR_TRUE; // if loading via GDI, just use GetFontTable if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) { const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p'); AutoFallibleTArray<PRUint8,16384> buffer; if (GetFontTable(kCmapTag, buffer) != NS_OK) return NS_ERROR_FAILURE; PRUint8 *cmap = buffer.Elements(); PRPackedBool unicodeFont = PR_FALSE, symbolFont = PR_FALSE; rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(), mCharacterMap, mUVSOffset, unicodeFont, symbolFont); mHasCmapTable = NS_SUCCEEDED(rv); return rv; } // loading using dwrite, don't use GetFontTable to avoid copy nsRefPtr<IDWriteFontFace> fontFace; rv = CreateFontFace(getter_AddRefs(fontFace)); if (NS_FAILED(rv)) { return rv; } PRUint8 *tableData; PRUint32 len; void *tableContext = NULL; BOOL exists; hr = fontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('c', 'm', 'a', 'p'), (const void**)&tableData, &len, &tableContext, &exists); if (FAILED(hr)) { return NS_ERROR_FAILURE; } PRPackedBool isSymbol = fontFace->IsSymbolFont(); PRPackedBool isUnicode = PR_TRUE; if (exists) { rv = gfxFontUtils::ReadCMAP(tableData, len, mCharacterMap, mUVSOffset, isUnicode, isSymbol); } fontFace->ReleaseFontTable(tableContext); #ifdef PR_LOGGING LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n", NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize())); #endif mHasCmapTable = NS_SUCCEEDED(rv); return rv; }
nsresult gfxDWriteFontEntry::ReadCMAP() { HRESULT hr; nsresult rv; // attempt this once, if errors occur leave a blank cmap if (mCharacterMap) { return NS_OK; } nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap(); // if loading via GDI, just use GetFontTable if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) { uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p'); AutoFallibleTArray<uint8_t,16384> cmap; rv = GetFontTable(kCMAP, cmap); bool unicodeFont = false, symbolFont = false; // currently ignored if (NS_SUCCEEDED(rv)) { rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(), *charmap, mUVSOffset, unicodeFont, symbolFont); } } else { // loading using dwrite, don't use GetFontTable to avoid copy nsRefPtr<IDWriteFontFace> fontFace; rv = CreateFontFace(getter_AddRefs(fontFace)); if (NS_SUCCEEDED(rv)) { const uint32_t kCmapTag = DWRITE_MAKE_OPENTYPE_TAG('c', 'm', 'a', 'p'); uint8_t *tableData; uint32_t len; void *tableContext = NULL; BOOL exists; hr = fontFace->TryGetFontTable(kCmapTag, (const void**)&tableData, &len, &tableContext, &exists); if (SUCCEEDED(hr)) { bool isSymbol = fontFace->IsSymbolFont(); bool isUnicode = true; if (exists) { rv = gfxFontUtils::ReadCMAP(tableData, len, *charmap, mUVSOffset, isUnicode, isSymbol); } fontFace->ReleaseFontTable(tableContext); } else { rv = NS_ERROR_FAILURE; } } } mHasCmapTable = NS_SUCCEEDED(rv); if (mHasCmapTable) { gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); mCharacterMap = pfl->FindCharMap(charmap); } else { // if error occurred, initialize to null cmap mCharacterMap = new gfxCharacterMap(); } #ifdef PR_LOGGING LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n", NS_ConvertUTF16toUTF8(mName).get(), charmap->SizeOfIncludingThis(moz_malloc_size_of), charmap->mHash, mCharacterMap == charmap ? " new" : "")); if (LOG_CMAPDATA_ENABLED()) { char prefix[256]; sprintf(prefix, "(cmapdata) name: %.220s", NS_ConvertUTF16toUTF8(mName).get()); charmap->Dump(prefix, eGfxLog_cmapdata); } #endif return rv; }