コード例 #1
0
ファイル: gfxDWriteShaper.cpp プロジェクト: lofter2011/Icefox
bool
gfxDWriteShaper::ShapeWord(gfxContext *aContext,
                           gfxShapedWord *aShapedWord,
                           const PRUnichar *aString)
{
    HRESULT hr;
    // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES

    DWRITE_READING_DIRECTION readingDirection = 
        aShapedWord->IsRightToLeft()
            ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
            : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;

    gfxDWriteFont *font = static_cast<gfxDWriteFont*>(mFont);

    gfxShapedWord::CompressedGlyph g;

    IDWriteTextAnalyzer *analyzer =
        gfxWindowsPlatform::GetPlatform()->GetDWriteAnalyzer();
    if (!analyzer) {
        return false;
    }

    /**
     * There's an internal 16-bit limit on some things inside the analyzer,
     * but we never attempt to shape a word longer than 64K characters
     * in a single gfxShapedWord, so we cannot exceed that limit.
     */
    UINT32 length = aShapedWord->Length();

    TextAnalysis analysis(aString, length, NULL, readingDirection);
    TextAnalysis::Run *runHead;
    hr = analysis.GenerateResults(analyzer, &runHead);

    if (FAILED(hr)) {
        NS_WARNING("Analyzer failed to generate results.");
        return false;
    }

    PRUint32 appUnitsPerDevPixel = aShapedWord->AppUnitsPerDevUnit();

    UINT32 maxGlyphs = 0;
trymoreglyphs:
    if ((PR_UINT32_MAX - 3 * length / 2 + 16) < maxGlyphs) {
        // This isn't going to work, we're going to cross the UINT32 upper
        // limit. Give up.
        NS_WARNING("Shaper needs to generate more than 2^32 glyphs?!");
        return false;
    }
    maxGlyphs += 3 * length / 2 + 16;

    nsAutoTArray<UINT16, 400> clusters;
    nsAutoTArray<UINT16, 400> indices;
    nsAutoTArray<DWRITE_SHAPING_TEXT_PROPERTIES, 400> textProperties;
    nsAutoTArray<DWRITE_SHAPING_GLYPH_PROPERTIES, 400> glyphProperties;
    if (!clusters.SetLength(length) ||
        !indices.SetLength(maxGlyphs) || 
        !textProperties.SetLength(maxGlyphs) ||
        !glyphProperties.SetLength(maxGlyphs)) {
        NS_WARNING("Shaper failed to allocate memory.");
        return false;
    }

    UINT32 actualGlyphs;

    hr = analyzer->GetGlyphs(aString, length,
            font->GetFontFace(), FALSE, 
            readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
            &runHead->mScript, NULL, NULL, NULL, NULL, 0,
            maxGlyphs, clusters.Elements(), textProperties.Elements(),
            indices.Elements(), glyphProperties.Elements(), &actualGlyphs);

    if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
        // We increase the amount of glyphs and try again.
        goto trymoreglyphs;
    }
    if (FAILED(hr)) {
        NS_WARNING("Analyzer failed to get glyphs.");
        return false;
    }

    WORD gID = indices[0];
    nsAutoTArray<FLOAT, 400> advances;
    nsAutoTArray<DWRITE_GLYPH_OFFSET, 400> glyphOffsets;
    if (!advances.SetLength(actualGlyphs) || 
        !glyphOffsets.SetLength(actualGlyphs)) {
        NS_WARNING("Shaper failed to allocate memory.");
        return false;
    }

    if (!static_cast<gfxDWriteFont*>(mFont)->mUseSubpixelPositions) {
        hr = analyzer->GetGdiCompatibleGlyphPlacements(
                                          aString,
                                          clusters.Elements(),
                                          textProperties.Elements(),
                                          length,
                                          indices.Elements(),
                                          glyphProperties.Elements(),
                                          actualGlyphs,
                                          font->GetFontFace(),
                                          font->GetAdjustedSize(),
                                          1.0,
                                          nsnull,
                                          FALSE,
                                          FALSE,
                                          FALSE,
                                          &runHead->mScript,
                                          NULL,
                                          NULL,
                                          NULL,
                                          0,
                                          advances.Elements(),
                                          glyphOffsets.Elements());
    } else {
        hr = analyzer->GetGlyphPlacements(aString,
                                          clusters.Elements(),
                                          textProperties.Elements(),
                                          length,
                                          indices.Elements(),
                                          glyphProperties.Elements(),
                                          actualGlyphs,
                                          font->GetFontFace(),
                                          font->GetAdjustedSize(),
                                          FALSE,
                                          FALSE,
                                          &runHead->mScript,
                                          NULL,
                                          NULL,
                                          NULL,
                                          0,
                                          advances.Elements(),
                                          glyphOffsets.Elements());
    }
    if (FAILED(hr)) {
        NS_WARNING("Analyzer failed to get glyph placements.");
        return false;
    }

    nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;

    for (unsigned int c = 0; c < length; c++) {
        PRUint32 k = clusters[c];
        PRUint32 absC = c;

        if (c > 0 && k == clusters[c - 1]) {
            g.SetComplex(aShapedWord->IsClusterStart(absC), false, 0);
            aShapedWord->SetGlyphs(absC, g, nsnull);
            // This is a cluster continuation. No glyph here.
            continue;
        }

        // Count glyphs for this character
        PRUint32 glyphCount = actualGlyphs - k;
        PRUint32 nextClusterOffset;
        for (nextClusterOffset = c + 1; 
            nextClusterOffset < length; ++nextClusterOffset) {
            if (clusters[nextClusterOffset] > k) {
                glyphCount = clusters[nextClusterOffset] - k;
                break;
            }
        }
        PRInt32 advance = (PRInt32)(advances[k] * appUnitsPerDevPixel);
        if (glyphCount == 1 && advance >= 0 &&
            glyphOffsets[k].advanceOffset == 0 &&
            glyphOffsets[k].ascenderOffset == 0 &&
            aShapedWord->IsClusterStart(absC) &&
            gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advance) &&
            gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
              aShapedWord->SetSimpleGlyph(absC, 
                                          g.SetSimpleGlyph(advance, 
                                                           indices[k]));
        } else {
            if (detailedGlyphs.Length() < glyphCount) {
                if (!detailedGlyphs.AppendElements(
                    glyphCount - detailedGlyphs.Length())) {
                    continue;
                }
            }
            float totalAdvance = 0;
            for (unsigned int z = 0; z < glyphCount; z++) {
                detailedGlyphs[z].mGlyphID = indices[k + z];
                detailedGlyphs[z].mAdvance = 
                    (PRInt32)(advances[k + z]
                       * appUnitsPerDevPixel);
                if (readingDirection == 
                    DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) {
                    detailedGlyphs[z].mXOffset = 
                        (totalAdvance + 
                          glyphOffsets[k + z].advanceOffset)
                        * appUnitsPerDevPixel;
                } else {
                    detailedGlyphs[z].mXOffset = 
                        glyphOffsets[k + z].advanceOffset *
                        appUnitsPerDevPixel;
                }
                detailedGlyphs[z].mYOffset = 
                    -glyphOffsets[k + z].ascenderOffset *
                    appUnitsPerDevPixel;
                totalAdvance += advances[k + z];
            }
            aShapedWord->SetGlyphs(
                absC,
                g.SetComplex(aShapedWord->IsClusterStart(absC),
                             true,
                             glyphCount),
                detailedGlyphs.Elements());
        }
    }

    return true;
}
コード例 #2
0
void directwriteAnalyzerTest(IDWriteFontFace *fontFace, WCHAR *string, int len, featurePreparer *features)
{
	IDWriteTextAnalyzer *analyzer;
	analysisSourceSink *ss;
	const DWRITE_TYPOGRAPHIC_FEATURES **dwfeatures;
	UINT32 *dwfeatureRangeLengths;
	UINT32 dwfeatureRanges;
	std::vector<UINT16> glyphs;
	HRESULT hr;

	hr = dwfactory->CreateTextAnalyzer(&analyzer);
	if (hr != S_OK)
		die("error creating IDWriteTextAnalyzer", hr);
	ss = new analysisSourceSink(string, len);

	dwfeatures = NULL;
	dwfeatureRangeLengths = NULL;
	dwfeatureRanges = 0;
	if (features != NULL) {
		// TODO WTF IS THIS C++? or is this the DirectWrite devs failing?
		dwfeatures = (const DWRITE_TYPOGRAPHIC_FEATURES **) (features->dwFeatures);
		dwfeatureRangeLengths = features->dwFeatureRangeLengths;
		dwfeatureRanges = features->dwFeatureRanges;
	}

	hr = analyzer->AnalyzeScript(ss, 0, len, ss);
	if (hr != S_OK)
		die("error analyzing scripts for DirectWrite", hr);
	ss->processResults([&](DWRITE_SCRIPT_ANALYSIS scriptAnalysis, UINT32 start, UINT32 end) {
		UINT16 *clusterMap;
		DWRITE_SHAPING_TEXT_PROPERTIES *textProps;
		UINT16 *glyphIndices;
		DWRITE_SHAPING_GLYPH_PROPERTIES *glyphProps;
		UINT32 nGlyphs, nActualGlyphs;
		UINT32 i;

		clusterMap = new UINT16[end - start];
		textProps = new DWRITE_SHAPING_TEXT_PROPERTIES[end - start];
		nGlyphs = (3 * (end - start) / 2 + 16);
		for (;;) {
			glyphIndices = new UINT16[nGlyphs];
			glyphProps = new DWRITE_SHAPING_GLYPH_PROPERTIES[nGlyphs];
			ZeroMemory(clusterMap, (end - start) * sizeof (UINT16));
			ZeroMemory(textProps, (end - start) * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
			ZeroMemory(glyphIndices, nGlyphs * sizeof (UINT16));
			ZeroMemory(glyphProps, nGlyphs * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
			hr = analyzer->GetGlyphs(string + start, end - start,
				fontFace, FALSE, FALSE,
				&scriptAnalysis, NULL, NULL,
				dwfeatures, dwfeatureRangeLengths, dwfeatureRanges,
				nGlyphs, clusterMap, textProps,
				glyphIndices, glyphProps, &nActualGlyphs);
			if (hr == S_OK)
				break;
			if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
				die("error analyzing text with DirectWrite", hr);
			delete[] glyphProps;
			delete[] glyphIndices;
			nGlyphs *= 2;
		}
		for (i = 0; i < nActualGlyphs; i++)
			glyphs.push_back(glyphIndices[i]);
		delete[] glyphProps;
		delete[] glyphIndices;
		delete[] textProps;
		delete[] clusterMap;
	});
	printGlyphs("DirectWrite IDWriteTextAnalyzer", glyphs);

	delete ss;
	analyzer->Release();
}