/** * SECTION:hb-directwrite * @title: hb-directwrite * @short_description: DirectWrite integration * @include: hb-directwrite.h * * Functions for using HarfBuzz with DirectWrite fonts.
**/
/* Declare object creator for dynamic support of DWRITE */ typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
);
/* * DirectWrite font stream helpers
*/
// This is a font loader which provides only one font (unlike its original design). // For a better implementation which was also source of this // and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla class DWriteFontFileLoader : public IDWriteFontFileLoader
{ private:
IDWriteFontFileStream *mFontFileStream; public:
DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream)
{ mFontFileStream = fontFileStream; }
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project // but now is relicensed to MIT for HarfBuzz use class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
{ public:
// A single contiguous run of characters containing the same analysis // results. struct Run
{
uint32_t mTextStart; // starting text position of this run
uint32_t mTextLength; // number of contiguous code units covered
uint32_t mGlyphStart; // starting glyph in the glyphs array
uint32_t mGlyphCount; // number of glyphs associated with this run // text
DWRITE_SCRIPT_ANALYSIS mScript;
uint8_t mBidiLevel; bool mIsSideways;
public:
TextAnalysis (constwchar_t* text, uint32_t textLength, constwchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
: mTextLength (textLength), mText (text), mLocaleName (localeName),
mReadingDirection (readingDirection), mCurrentRun (nullptr) {}
~TextAnalysis ()
{ // delete runs, except mRunHead which is part of the TextAnalysis object for (Run *run = mRunHead.nextRun; run;)
{
Run *origRun = run;
run = run->nextRun; delete origRun;
}
}
STDMETHODIMP
GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
{ // Analyzes the text using the script analyzer and returns // the result as a series of runs.
HRESULT hr = S_OK;
// Initially start out with one result that covers the entire range. // This result will be subdivided by the analysis processes.
mRunHead.mTextStart = 0;
mRunHead.mTextLength = mTextLength;
mRunHead.mBidiLevel =
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
mRunHead.nextRun = nullptr;
mCurrentRun = &mRunHead;
// Call each of the analyzers in sequence, recording their results. if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
*runHead = &mRunHead;
return hr;
}
// IDWriteTextAnalysisSource implementation
IFACEMETHODIMP
GetTextAtPosition (uint32_t textPosition,
OUT wchar_tconst** textString,
OUT uint32_t* textLength)
{ if (textPosition >= mTextLength)
{ // No text at this position, valid query though.
*textString = nullptr;
*textLength = 0;
} else
{
*textString = mText + textPosition;
*textLength = mTextLength - textPosition;
} return S_OK;
}
IFACEMETHODIMP
GetTextBeforePosition (uint32_t textPosition,
OUT wchar_tconst** textString,
OUT uint32_t* textLength)
{ if (textPosition == 0 || textPosition > mTextLength)
{ // Either there is no text before here (== 0), or this // is an invalid position. The query is considered valid though.
*textString = nullptr;
*textLength = 0;
} else
{
*textString = mText;
*textLength = textPosition;
} return S_OK;
}
IFACEMETHODIMP
GetNumberSubstitution (uint32_t textPosition,
OUT uint32_t* textLength,
OUT IDWriteNumberSubstitution** numberSubstitution)
{ // We do not support number substitution.
*numberSubstitution = nullptr;
*textLength = mTextLength - textPosition;
protected:
Run *FetchNextRun (IN OUT uint32_t* textLength)
{ // Used by the sink setters, this returns a reference to the next run. // Position and length are adjusted to now point after the current run // being returned.
Run *origRun = mCurrentRun; // Split the tail if needed (the length remaining is less than the // current run's size). if (*textLength < mCurrentRun->mTextLength)
SplitCurrentRun (mCurrentRun->mTextStart + *textLength); else // Just advance the current run.
mCurrentRun = mCurrentRun->nextRun;
*textLength -= origRun->mTextLength;
// Return a reference to the run that was just current. return origRun;
}
void SetCurrentRun (uint32_t textPosition)
{ // Move the current run to the given position. // Since the analyzers generally return results in a forward manner, // this will usually just return early. If not, find the // corresponding run for the text position.
if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition)) return;
for (Run *run = &mRunHead; run; run = run->nextRun) if (run->ContainsTextPosition (textPosition))
{
mCurrentRun = run; return;
}
assert (0); // We should always be able to find the text position in one of our runs
}
void SplitCurrentRun (uint32_t splitPosition)
{ if (!mCurrentRun)
{
assert (0); // SplitCurrentRun called without current run // Shouldn't be calling this when no current run is set! return;
} // Split the current run. if (splitPosition <= mCurrentRun->mTextStart)
{ // No need to split, already the start of a run // or before it. Usually the first. return;
}
Run *newRun = new Run;
*newRun = *mCurrentRun;
// Insert the new run in our linked list.
newRun->nextRun = mCurrentRun->nextRun;
mCurrentRun->nextRun = newRun;
protected: // Input // (weak references are fine here, since this class is a transient // stack-based helper that doesn't need to copy data)
uint32_t mTextLength; constwchar_t* mText; constwchar_t* mLocaleName;
DWRITE_READING_DIRECTION mReadingDirection;
// Current processing state.
Run *mCurrentRun;
// Output is a list of runs starting here
Run mRunHead;
};
/* * 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_t textLength = chars_len;
goto retry_getglyphs;
} if (FAILED (hr))
FAIL ("Analyzer failed to get glyphs.");
float* glyphAdvances = newfloat[maxGlyphCount];
DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
/* The -2 in the following is to compensate for possible
* alignment needed after the WORD array. sizeof (WORD) == 2. */ unsignedint glyphs_size = (scratch_size * sizeof (int) - 2)
/ (sizeof (WORD) + sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) + sizeof (int) + sizeof (DWRITE_GLYPH_OFFSET) + sizeof (uint32_t));
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
#undef ALLOCATE_ARRAY
int fontEmSize = font->face->get_upem (); if (fontEmSize < 0) fontEmSize = -fontEmSize;
/* The rest is crap. Let's store position info there for now. */
info->mask = glyphAdvances[i];
info->var1.i32 = glyphOffsets[i].advanceOffset;
info->var2.i32 = glyphOffsets[i].ascenderOffset;
}
/* Set glyph positions */
buffer->clear_positions (); for (unsignedint i = 0; i < glyphCount; i++)
{
hb_glyph_info_t *info = &buffer->info[i];
hb_glyph_position_t *pos = &buffer->pos[i];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.