Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
  }
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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);
}
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;
}
Esempio n. 11
0
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
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
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;
}
Esempio n. 16
0
nsresult
gfxGraphiteShaper::SetGlyphsFromSegment(gfxContext      *aContext,
                                        gfxShapedText   *aShapedText,
                                        uint32_t         aOffset,
                                        uint32_t         aLength,
                                        const char16_t *aText,
                                        gr_segment      *aSegment)
{
    int32_t dev2appUnits = aShapedText->GetAppUnitsPerDevUnit();
    bool rtl = aShapedText->IsRightToLeft();

    uint32_t glyphCount = gr_seg_n_slots(aSegment);

    // identify clusters; graphite may have reordered/expanded/ligated glyphs.
    AutoFallibleTArray<Cluster,SMALL_GLYPH_RUN> clusters;
    AutoFallibleTArray<uint16_t,SMALL_GLYPH_RUN> gids;
    AutoFallibleTArray<float,SMALL_GLYPH_RUN> xLocs;
    AutoFallibleTArray<float,SMALL_GLYPH_RUN> yLocs;

    if (!clusters.SetLength(aLength, fallible) ||
        !gids.SetLength(glyphCount, fallible) ||
        !xLocs.SetLength(glyphCount, fallible) ||
        !yLocs.SetLength(glyphCount, fallible))
    {
        return NS_ERROR_OUT_OF_MEMORY;
    }

    // walk through the glyph slots and check which original character
    // each is associated with
    uint32_t gIndex = 0; // glyph slot index
    uint32_t cIndex = 0; // current cluster index
    for (const gr_slot *slot = gr_seg_first_slot(aSegment);
         slot != nullptr;
         slot = gr_slot_next_in_segment(slot), gIndex++)
    {
        uint32_t before =
            gr_cinfo_base(gr_seg_cinfo(aSegment, gr_slot_before(slot)));
        uint32_t after =
            gr_cinfo_base(gr_seg_cinfo(aSegment, gr_slot_after(slot)));
        gids[gIndex] = gr_slot_gid(slot);
        xLocs[gIndex] = gr_slot_origin_X(slot);
        yLocs[gIndex] = gr_slot_origin_Y(slot);

        // if this glyph has a "before" character index that precedes the
        // current cluster's char index, we need to merge preceding
        // clusters until it gets included
        while (before < clusters[cIndex].baseChar && cIndex > 0) {
            clusters[cIndex-1].nChars += clusters[cIndex].nChars;
            clusters[cIndex-1].nGlyphs += clusters[cIndex].nGlyphs;
            --cIndex;
        }

        // if there's a gap between the current cluster's base character and
        // this glyph's, extend the cluster to include the intervening chars
        if (gr_slot_can_insert_before(slot) && clusters[cIndex].nChars &&
            before >= clusters[cIndex].baseChar + clusters[cIndex].nChars)
        {
            NS_ASSERTION(cIndex < aLength - 1, "cIndex at end of word");
            Cluster& c = clusters[cIndex + 1];
            c.baseChar = clusters[cIndex].baseChar + clusters[cIndex].nChars;
            c.nChars = before - c.baseChar;
            c.baseGlyph = gIndex;
            c.nGlyphs = 0;
            ++cIndex;
        }

        // increment cluster's glyph count to include current slot
        NS_ASSERTION(cIndex < aLength, "cIndex beyond word length");
        ++clusters[cIndex].nGlyphs;

        // extend cluster if necessary to reach the glyph's "after" index
        if (clusters[cIndex].baseChar + clusters[cIndex].nChars < after + 1) {
            clusters[cIndex].nChars = after + 1 - clusters[cIndex].baseChar;
        }
    }

    bool roundX;
    bool roundY;
    aContext->GetRoundOffsetsToPixels(&roundX, &roundY);

    gfxShapedText::CompressedGlyph *charGlyphs =
        aShapedText->GetCharacterGlyphs() + aOffset;

    // now put glyphs into the textrun, one cluster at a time
    for (uint32_t i = 0; i <= cIndex; ++i) {
        const Cluster& c = clusters[i];

        float adv; // total advance of the cluster
        if (rtl) {
            if (i == 0) {
                adv = gr_seg_advance_X(aSegment) - xLocs[c.baseGlyph];
            } else {
                adv = xLocs[clusters[i-1].baseGlyph] - xLocs[c.baseGlyph];
            }
        } else {
            if (i == cIndex) {
                adv = gr_seg_advance_X(aSegment) - xLocs[c.baseGlyph];
            } else {
                adv = xLocs[clusters[i+1].baseGlyph] - xLocs[c.baseGlyph];
            }
        }

        // Check for default-ignorable char that didn't get filtered, combined,
        // etc by the shaping process, and skip it.
        uint32_t offs = c.baseChar;
        NS_ASSERTION(offs < aLength, "unexpected offset");
        if (c.nGlyphs == 1 && c.nChars == 1 &&
            aShapedText->FilterIfIgnorable(aOffset + offs, aText[offs])) {
            continue;
        }

        uint32_t appAdvance = roundX ? NSToIntRound(adv) * dev2appUnits :
                                       NSToIntRound(adv * dev2appUnits);
        if (c.nGlyphs == 1 &&
            gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
            gfxShapedText::CompressedGlyph::IsSimpleAdvance(appAdvance) &&
            charGlyphs[offs].IsClusterStart() &&
            yLocs[c.baseGlyph] == 0)
        {
            charGlyphs[offs].SetSimpleGlyph(appAdvance, gids[c.baseGlyph]);
        } else {
            // not a one-to-one mapping with simple metrics: use DetailedGlyph
            nsAutoTArray<gfxShapedText::DetailedGlyph,8> details;
            float clusterLoc;
            for (uint32_t j = c.baseGlyph; j < c.baseGlyph + c.nGlyphs; ++j) {
                gfxShapedText::DetailedGlyph* d = details.AppendElement();
                d->mGlyphID = gids[j];
                d->mYOffset = roundY ? NSToIntRound(-yLocs[j]) * dev2appUnits :
                              -yLocs[j] * dev2appUnits;
                if (j == c.baseGlyph) {
                    d->mXOffset = 0;
                    d->mAdvance = appAdvance;
                    clusterLoc = xLocs[j];
                } else {
                    float dx = rtl ? (xLocs[j] - clusterLoc) :
                                     (xLocs[j] - clusterLoc - adv);
                    d->mXOffset = roundX ? NSToIntRound(dx) * dev2appUnits :
                                           dx * dev2appUnits;
                    d->mAdvance = 0;
                }
            }
            gfxShapedText::CompressedGlyph g;
            g.SetComplex(charGlyphs[offs].IsClusterStart(),
                         true, details.Length());
            aShapedText->SetGlyphs(aOffset + offs, g, details.Elements());
        }

        for (uint32_t j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) {
            NS_ASSERTION(j < aLength, "unexpected offset");
            gfxShapedText::CompressedGlyph &g = charGlyphs[j];
            NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
            g.SetComplex(g.IsClusterStart(), false, 0);
        }
    }

    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;
}