Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2015-2016  Ebrahim Byagowi
      3  *
      4  *  This is part of HarfBuzz, a text shaping library.
      5  *
      6  * Permission is hereby granted, without written agreement and without
      7  * license or royalty fees, to use, copy, modify, and distribute this
      8  * software and its documentation for any purpose, provided that the
      9  * above copyright notice and the following two paragraphs appear in
     10  * all copies of this software.
     11  *
     12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     16  * DAMAGE.
     17  *
     18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     23  */
     24 
     25 #include "hb-private.hh"
     26 #include "hb-debug.hh"
     27 #define HB_SHAPER directwrite
     28 #include "hb-shaper-impl-private.hh"
     29 
     30 #include <DWrite_1.h>
     31 
     32 #include "hb-directwrite.h"
     33 
     34 
     35 HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, face)
     36 HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, font)
     37 
     38 
     39 /*
     40  * DirectWrite font stream helpers
     41  */
     42 
     43 // This is a font loader which provides only one font (unlike its original design).
     44 // For a better implementation which was also source of this
     45 // and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
     46 class DWriteFontFileLoader : public IDWriteFontFileLoader
     47 {
     48 private:
     49   IDWriteFontFileStream *mFontFileStream;
     50 public:
     51   DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream) {
     52     mFontFileStream = fontFileStream;
     53   }
     54 
     55   // IUnknown interface
     56   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
     57   IFACEMETHOD_(ULONG, AddRef)() { return 1; }
     58   IFACEMETHOD_(ULONG, Release)() { return 1; }
     59 
     60   // IDWriteFontFileLoader methods
     61   virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
     62     UINT32 fontFileReferenceKeySize,
     63     OUT IDWriteFontFileStream** fontFileStream)
     64   {
     65     *fontFileStream = mFontFileStream;
     66     return S_OK;
     67   }
     68 };
     69 
     70 class DWriteFontFileStream : public IDWriteFontFileStream
     71 {
     72 private:
     73   uint8_t *mData;
     74   uint32_t mSize;
     75 public:
     76   DWriteFontFileStream(uint8_t *aData, uint32_t aSize)
     77   {
     78     mData = aData;
     79     mSize = aSize;
     80   }
     81 
     82   // IUnknown interface
     83   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
     84   IFACEMETHOD_(ULONG, AddRef)() { return 1; }
     85   IFACEMETHOD_(ULONG, Release)() { return 1; }
     86 
     87   // IDWriteFontFileStream methods
     88   virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
     89     UINT64 fileOffset,
     90     UINT64 fragmentSize,
     91     OUT void** fragmentContext)
     92   {
     93     // We are required to do bounds checking.
     94     if (fileOffset + fragmentSize > mSize) {
     95       return E_FAIL;
     96     }
     97 
     98     // truncate the 64 bit fileOffset to size_t sized index into mData
     99     size_t index = static_cast<size_t> (fileOffset);
    100 
    101     // We should be alive for the duration of this.
    102     *fragmentStart = &mData[index];
    103     *fragmentContext = nullptr;
    104     return S_OK;
    105   }
    106 
    107   virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext) { }
    108 
    109   virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize)
    110   {
    111     *fileSize = mSize;
    112     return S_OK;
    113   }
    114 
    115   virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime)
    116   {
    117     return E_NOTIMPL;
    118   }
    119 };
    120 
    121 
    122 /*
    123 * shaper face data
    124 */
    125 
    126 struct hb_directwrite_shaper_face_data_t {
    127   IDWriteFactory *dwriteFactory;
    128   IDWriteFontFile *fontFile;
    129   IDWriteFontFileStream *fontFileStream;
    130   IDWriteFontFileLoader *fontFileLoader;
    131   IDWriteFontFace *fontFace;
    132   hb_blob_t *faceBlob;
    133 };
    134 
    135 hb_directwrite_shaper_face_data_t *
    136 _hb_directwrite_shaper_face_data_create(hb_face_t *face)
    137 {
    138   hb_directwrite_shaper_face_data_t *data =
    139     (hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
    140   if (unlikely (!data))
    141     return nullptr;
    142 
    143   // TODO: factory and fontFileLoader should be cached separately
    144   IDWriteFactory* dwriteFactory;
    145   DWriteCreateFactory (
    146     DWRITE_FACTORY_TYPE_SHARED,
    147     __uuidof (IDWriteFactory),
    148     (IUnknown**) &dwriteFactory
    149   );
    150 
    151   HRESULT hr;
    152   hb_blob_t *blob = hb_face_reference_blob (face);
    153   IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
    154     (uint8_t*) hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob));
    155 
    156   IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
    157   dwriteFactory->RegisterFontFileLoader (fontFileLoader);
    158 
    159   IDWriteFontFile *fontFile;
    160   uint64_t fontFileKey = 0;
    161   hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
    162       fontFileLoader, &fontFile);
    163 
    164 #define FAIL(...) \
    165   HB_STMT_START { \
    166     DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
    167     return false; \
    168   } HB_STMT_END;
    169 
    170   if (FAILED (hr)) {
    171     FAIL ("Failed to load font file from data!");
    172     return false;
    173   }
    174 
    175   BOOL isSupported;
    176   DWRITE_FONT_FILE_TYPE fileType;
    177   DWRITE_FONT_FACE_TYPE faceType;
    178   UINT32 numberOfFaces;
    179   hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
    180   if (FAILED (hr) || !isSupported) {
    181     FAIL ("Font file is not supported.");
    182     return false;
    183   }
    184 
    185 #undef FAIL
    186 
    187   IDWriteFontFace *fontFace;
    188   dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
    189     DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
    190 
    191   data->dwriteFactory = dwriteFactory;
    192   data->fontFile = fontFile;
    193   data->fontFileStream = fontFileStream;
    194   data->fontFileLoader = fontFileLoader;
    195   data->fontFace = fontFace;
    196   data->faceBlob = blob;
    197 
    198   return data;
    199 }
    200 
    201 void
    202 _hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
    203 {
    204   if (data->fontFace)
    205     data->fontFace->Release ();
    206   if (data->fontFile)
    207     data->fontFile->Release ();
    208   if (data->dwriteFactory) {
    209     if (data->fontFileLoader)
    210       data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
    211     data->dwriteFactory->Release ();
    212   }
    213   if (data->fontFileLoader)
    214     delete data->fontFileLoader;
    215   if (data->fontFileStream)
    216     delete data->fontFileStream;
    217   if (data->faceBlob)
    218     hb_blob_destroy (data->faceBlob);
    219   if (data)
    220     free (data);
    221 }
    222 
    223 
    224 /*
    225  * shaper font data
    226  */
    227 
    228 struct hb_directwrite_shaper_font_data_t {
    229 };
    230 
    231 hb_directwrite_shaper_font_data_t *
    232 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
    233 {
    234   if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr;
    235 
    236   hb_directwrite_shaper_font_data_t *data =
    237     (hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
    238   if (unlikely (!data))
    239     return nullptr;
    240 
    241   return data;
    242 }
    243 
    244 void
    245 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
    246 {
    247   free (data);
    248 }
    249 
    250 
    251 /*
    252  * shaper shape_plan data
    253  */
    254 
    255 struct hb_directwrite_shaper_shape_plan_data_t {};
    256 
    257 hb_directwrite_shaper_shape_plan_data_t *
    258 _hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
    259 					       const hb_feature_t *user_features HB_UNUSED,
    260 					       unsigned int        num_user_features HB_UNUSED,
    261 					       const int          *coords HB_UNUSED,
    262 					       unsigned int        num_coords HB_UNUSED)
    263 {
    264   return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
    265 }
    266 
    267 void
    268 _hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
    269 {
    270 }
    271 
    272 // Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
    273 // but now is relicensed to MIT for HarfBuzz use
    274 class TextAnalysis
    275   : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
    276 {
    277 public:
    278 
    279   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
    280   IFACEMETHOD_(ULONG, AddRef)() { return 1; }
    281   IFACEMETHOD_(ULONG, Release)() { return 1; }
    282 
    283   // A single contiguous run of characters containing the same analysis
    284   // results.
    285   struct Run
    286   {
    287     uint32_t mTextStart;   // starting text position of this run
    288     uint32_t mTextLength;  // number of contiguous code units covered
    289     uint32_t mGlyphStart;  // starting glyph in the glyphs array
    290     uint32_t mGlyphCount;  // number of glyphs associated with this run of
    291     // text
    292     DWRITE_SCRIPT_ANALYSIS mScript;
    293     uint8_t mBidiLevel;
    294     bool mIsSideways;
    295 
    296     inline bool ContainsTextPosition(uint32_t aTextPosition) const
    297     {
    298       return aTextPosition >= mTextStart
    299         && aTextPosition <  mTextStart + mTextLength;
    300     }
    301 
    302     Run *nextRun;
    303   };
    304 
    305 public:
    306   TextAnalysis(const wchar_t* text,
    307     uint32_t textLength,
    308     const wchar_t* localeName,
    309     DWRITE_READING_DIRECTION readingDirection)
    310     : mText(text)
    311     , mTextLength(textLength)
    312     , mLocaleName(localeName)
    313     , mReadingDirection(readingDirection)
    314     , mCurrentRun(nullptr) { };
    315 
    316   ~TextAnalysis() {
    317     // delete runs, except mRunHead which is part of the TextAnalysis object
    318     for (Run *run = mRunHead.nextRun; run;) {
    319       Run *origRun = run;
    320       run = run->nextRun;
    321       free (origRun);
    322     }
    323   }
    324 
    325   STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
    326     Run **runHead) {
    327     // Analyzes the text using the script analyzer and returns
    328     // the result as a series of runs.
    329 
    330     HRESULT hr = S_OK;
    331 
    332     // Initially start out with one result that covers the entire range.
    333     // This result will be subdivided by the analysis processes.
    334     mRunHead.mTextStart = 0;
    335     mRunHead.mTextLength = mTextLength;
    336     mRunHead.mBidiLevel =
    337       (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
    338     mRunHead.nextRun = nullptr;
    339     mCurrentRun = &mRunHead;
    340 
    341     // Call each of the analyzers in sequence, recording their results.
    342     if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this))) {
    343       *runHead = &mRunHead;
    344     }
    345 
    346     return hr;
    347   }
    348 
    349   // IDWriteTextAnalysisSource implementation
    350 
    351   IFACEMETHODIMP GetTextAtPosition(uint32_t textPosition,
    352     OUT wchar_t const** textString,
    353     OUT uint32_t* textLength)
    354   {
    355     if (textPosition >= mTextLength) {
    356       // No text at this position, valid query though.
    357       *textString = nullptr;
    358       *textLength = 0;
    359     }
    360     else {
    361       *textString = mText + textPosition;
    362       *textLength = mTextLength - textPosition;
    363     }
    364     return S_OK;
    365   }
    366 
    367   IFACEMETHODIMP GetTextBeforePosition(uint32_t textPosition,
    368     OUT wchar_t const** textString,
    369     OUT uint32_t* textLength)
    370   {
    371     if (textPosition == 0 || textPosition > mTextLength) {
    372       // Either there is no text before here (== 0), or this
    373       // is an invalid position. The query is considered valid thouh.
    374       *textString = nullptr;
    375       *textLength = 0;
    376     }
    377     else {
    378       *textString = mText;
    379       *textLength = textPosition;
    380     }
    381     return S_OK;
    382   }
    383 
    384   IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
    385     GetParagraphReadingDirection() { return mReadingDirection; }
    386 
    387   IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
    388     uint32_t* textLength,
    389     wchar_t const** localeName)
    390   {
    391     return S_OK;
    392   }
    393 
    394   IFACEMETHODIMP
    395     GetNumberSubstitution(uint32_t textPosition,
    396     OUT uint32_t* textLength,
    397     OUT IDWriteNumberSubstitution** numberSubstitution)
    398   {
    399     // We do not support number substitution.
    400     *numberSubstitution = nullptr;
    401     *textLength = mTextLength - textPosition;
    402 
    403     return S_OK;
    404   }
    405 
    406   // IDWriteTextAnalysisSink implementation
    407 
    408   IFACEMETHODIMP
    409     SetScriptAnalysis(uint32_t textPosition,
    410     uint32_t textLength,
    411     DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
    412   {
    413     SetCurrentRun(textPosition);
    414     SplitCurrentRun(textPosition);
    415     while (textLength > 0)
    416     {
    417       Run *run = FetchNextRun(&textLength);
    418       run->mScript = *scriptAnalysis;
    419     }
    420 
    421     return S_OK;
    422   }
    423 
    424   IFACEMETHODIMP
    425     SetLineBreakpoints(uint32_t textPosition,
    426     uint32_t textLength,
    427     const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
    428 
    429   IFACEMETHODIMP SetBidiLevel(uint32_t textPosition,
    430     uint32_t textLength,
    431     uint8_t explicitLevel,
    432     uint8_t resolvedLevel) { return S_OK; }
    433 
    434   IFACEMETHODIMP
    435     SetNumberSubstitution(uint32_t textPosition,
    436     uint32_t textLength,
    437     IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
    438 
    439 protected:
    440   Run *FetchNextRun(IN OUT uint32_t* textLength)
    441   {
    442     // Used by the sink setters, this returns a reference to the next run.
    443     // Position and length are adjusted to now point after the current run
    444     // being returned.
    445 
    446     Run *origRun = mCurrentRun;
    447     // Split the tail if needed (the length remaining is less than the
    448     // current run's size).
    449     if (*textLength < mCurrentRun->mTextLength)
    450     {
    451       SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
    452     }
    453     else
    454     {
    455       // Just advance the current run.
    456       mCurrentRun = mCurrentRun->nextRun;
    457     }
    458     *textLength -= origRun->mTextLength;
    459 
    460     // Return a reference to the run that was just current.
    461     return origRun;
    462   }
    463 
    464   void SetCurrentRun(uint32_t textPosition)
    465   {
    466     // Move the current run to the given position.
    467     // Since the analyzers generally return results in a forward manner,
    468     // this will usually just return early. If not, find the
    469     // corresponding run for the text position.
    470 
    471     if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
    472     {
    473       return;
    474     }
    475 
    476     for (Run *run = &mRunHead; run; run = run->nextRun) {
    477       if (run->ContainsTextPosition (textPosition))
    478       {
    479         mCurrentRun = run;
    480         return;
    481       }
    482     }
    483     //NS_NOTREACHED("We should always be able to find the text position in one \
    484             //                of our runs");
    485   }
    486 
    487   void SplitCurrentRun(uint32_t splitPosition)
    488   {
    489     if (!mCurrentRun)
    490     {
    491       //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
    492       // Shouldn't be calling this when no current run is set!
    493       return;
    494     }
    495     // Split the current run.
    496     if (splitPosition <= mCurrentRun->mTextStart)
    497     {
    498       // No need to split, already the start of a run
    499       // or before it. Usually the first.
    500       return;
    501     }
    502     Run *newRun = (Run*) malloc (sizeof (Run));
    503 
    504     *newRun = *mCurrentRun;
    505 
    506     // Insert the new run in our linked list.
    507     newRun->nextRun = mCurrentRun->nextRun;
    508     mCurrentRun->nextRun = newRun;
    509 
    510     // Adjust runs' text positions and lengths.
    511     uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
    512     newRun->mTextStart += splitPoint;
    513     newRun->mTextLength -= splitPoint;
    514     mCurrentRun->mTextLength = splitPoint;
    515     mCurrentRun = newRun;
    516   }
    517 
    518 protected:
    519   // Input
    520   // (weak references are fine here, since this class is a transient
    521   //  stack-based helper that doesn't need to copy data)
    522   uint32_t mTextLength;
    523   const wchar_t* mText;
    524   const wchar_t* mLocaleName;
    525   DWRITE_READING_DIRECTION mReadingDirection;
    526 
    527   // Current processing state.
    528   Run *mCurrentRun;
    529 
    530   // Output is a list of runs starting here
    531   Run  mRunHead;
    532 };
    533 
    534 static inline uint16_t hb_uint16_swap (const uint16_t v)
    535 { return (v >> 8) | (v << 8); }
    536 static inline uint32_t hb_uint32_swap (const uint32_t v)
    537 { return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); }
    538 
    539 /*
    540  * shaper
    541  */
    542 
    543 static hb_bool_t
    544 _hb_directwrite_shape_full(hb_shape_plan_t    *shape_plan,
    545   hb_font_t          *font,
    546   hb_buffer_t        *buffer,
    547   const hb_feature_t *features,
    548   unsigned int        num_features,
    549   float               lineWidth)
    550 {
    551   hb_face_t *face = font->face;
    552   hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    553   hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
    554   IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
    555   IDWriteFontFace *fontFace = face_data->fontFace;
    556 
    557   IDWriteTextAnalyzer* analyzer;
    558   dwriteFactory->CreateTextAnalyzer(&analyzer);
    559 
    560   unsigned int scratch_size;
    561   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
    562 #define ALLOCATE_ARRAY(Type, name, len) \
    563   Type *name = (Type *) scratch; \
    564   { \
    565     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
    566     assert (_consumed <= scratch_size); \
    567     scratch += _consumed; \
    568     scratch_size -= _consumed; \
    569   }
    570 
    571 #define utf16_index() var1.u32
    572 
    573   ALLOCATE_ARRAY(wchar_t, textString, buffer->len * 2);
    574 
    575   unsigned int chars_len = 0;
    576   for (unsigned int i = 0; i < buffer->len; i++)
    577   {
    578     hb_codepoint_t c = buffer->info[i].codepoint;
    579     buffer->info[i].utf16_index() = chars_len;
    580     if (likely(c <= 0xFFFFu))
    581       textString[chars_len++] = c;
    582     else if (unlikely(c > 0x10FFFFu))
    583       textString[chars_len++] = 0xFFFDu;
    584     else {
    585       textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
    586       textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
    587     }
    588   }
    589 
    590   ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
    591   // if (num_features)
    592   {
    593     /* Need log_clusters to assign features. */
    594     chars_len = 0;
    595     for (unsigned int i = 0; i < buffer->len; i++)
    596     {
    597       hb_codepoint_t c = buffer->info[i].codepoint;
    598       unsigned int cluster = buffer->info[i].cluster;
    599       log_clusters[chars_len++] = cluster;
    600       if (hb_in_range(c, 0x10000u, 0x10FFFFu))
    601         log_clusters[chars_len++] = cluster; /* Surrogates. */
    602     }
    603   }
    604 
    605   // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
    606 
    607   DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ?
    608     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
    609     DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
    610 
    611   /*
    612   * There's an internal 16-bit limit on some things inside the analyzer,
    613   * but we never attempt to shape a word longer than 64K characters
    614   * in a single gfxShapedWord, so we cannot exceed that limit.
    615   */
    616   uint32_t textLength = buffer->len;
    617 
    618   TextAnalysis analysis(textString, textLength, nullptr, readingDirection);
    619   TextAnalysis::Run *runHead;
    620   HRESULT hr;
    621   hr = analysis.GenerateResults(analyzer, &runHead);
    622 
    623 #define FAIL(...) \
    624   HB_STMT_START { \
    625     DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
    626     return false; \
    627   } HB_STMT_END;
    628 
    629   if (FAILED (hr))
    630   {
    631     FAIL ("Analyzer failed to generate results.");
    632     return false;
    633   }
    634 
    635   uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
    636   uint32_t glyphCount;
    637   bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
    638 
    639   const wchar_t localeName[20] = {0};
    640   if (buffer->props.language != nullptr)
    641   {
    642     mbstowcs ((wchar_t*) localeName,
    643       hb_language_to_string (buffer->props.language), 20);
    644   }
    645 
    646   DWRITE_TYPOGRAPHIC_FEATURES singleFeatures;
    647   singleFeatures.featureCount = num_features;
    648   if (num_features)
    649   {
    650     DWRITE_FONT_FEATURE* dwfeatureArray = (DWRITE_FONT_FEATURE*)
    651       malloc (sizeof (DWRITE_FONT_FEATURE) * num_features);
    652     for (unsigned int i = 0; i < num_features; ++i)
    653     {
    654       dwfeatureArray[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
    655         hb_uint32_swap (features[i].tag);
    656       dwfeatureArray[i].parameter = features[i].value;
    657     }
    658     singleFeatures.features = dwfeatureArray;
    659   }
    660   const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures =
    661     (const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures;
    662   const uint32_t featureRangeLengths[] = { textLength };
    663 
    664   uint16_t* clusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
    665   DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
    666     malloc (textLength * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
    667 retry_getglyphs:
    668   uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
    669   DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
    670     malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
    671 
    672   hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
    673     isRightToLeft, &runHead->mScript, localeName, nullptr, &dwFeatures,
    674     featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
    675     glyphProperties, &glyphCount);
    676 
    677   if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
    678   {
    679     free (glyphIndices);
    680     free (glyphProperties);
    681 
    682     maxGlyphCount *= 2;
    683 
    684     goto retry_getglyphs;
    685   }
    686   if (FAILED (hr))
    687   {
    688     FAIL ("Analyzer failed to get glyphs.");
    689     return false;
    690   }
    691 
    692   float* glyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
    693   DWRITE_GLYPH_OFFSET* glyphOffsets = (DWRITE_GLYPH_OFFSET*)
    694     malloc(maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
    695 
    696   /* The -2 in the following is to compensate for possible
    697    * alignment needed after the WORD array.  sizeof(WORD) == 2. */
    698   unsigned int glyphs_size = (scratch_size * sizeof(int) - 2)
    699          / (sizeof(WORD) +
    700             sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES) +
    701             sizeof(int) +
    702             sizeof(DWRITE_GLYPH_OFFSET) +
    703             sizeof(uint32_t));
    704   ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
    705 
    706 #undef ALLOCATE_ARRAY
    707 
    708   int fontEmSize = font->face->get_upem();
    709   if (fontEmSize < 0)
    710     fontEmSize = -fontEmSize;
    711 
    712   if (fontEmSize < 0)
    713     fontEmSize = -fontEmSize;
    714   double x_mult = (double) font->x_scale / fontEmSize;
    715   double y_mult = (double) font->y_scale / fontEmSize;
    716 
    717   hr = analyzer->GetGlyphPlacements (textString,
    718     clusterMap, textProperties, textLength, glyphIndices,
    719     glyphProperties, glyphCount, fontFace, fontEmSize,
    720     false, isRightToLeft, &runHead->mScript, localeName,
    721     &dwFeatures, featureRangeLengths, 1,
    722     glyphAdvances, glyphOffsets);
    723 
    724   if (FAILED (hr))
    725   {
    726     FAIL ("Analyzer failed to get glyph placements.");
    727     return false;
    728   }
    729 
    730   IDWriteTextAnalyzer1* analyzer1;
    731   analyzer->QueryInterface (&analyzer1);
    732 
    733   if (analyzer1 && lineWidth)
    734   {
    735 
    736     DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
    737       (DWRITE_JUSTIFICATION_OPPORTUNITY*)
    738       malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
    739     hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize,
    740       runHead->mScript, textLength, glyphCount, textString, clusterMap,
    741       glyphProperties, justificationOpportunities);
    742 
    743     if (FAILED (hr))
    744     {
    745       FAIL ("Analyzer failed to get justification opportunities.");
    746       return false;
    747     }
    748 
    749     float* justifiedGlyphAdvances =
    750       (float*) malloc (maxGlyphCount * sizeof (float));
    751     DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
    752       malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
    753     hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
    754       glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
    755 
    756     if (FAILED (hr))
    757     {
    758       FAIL("Analyzer failed to get justified glyph advances.");
    759       return false;
    760     }
    761 
    762     DWRITE_SCRIPT_PROPERTIES scriptProperties;
    763     hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
    764     if (FAILED (hr))
    765     {
    766       FAIL("Analyzer failed to get script properties.");
    767       return false;
    768     }
    769     uint32_t justificationCharacter = scriptProperties.justificationCharacter;
    770 
    771     // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
    772     if (justificationCharacter != 32)
    773     {
    774       uint16_t* modifiedClusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
    775     retry_getjustifiedglyphs:
    776       uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
    777       float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
    778       DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
    779         malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
    780       uint32_t actualGlyphsCount;
    781       hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
    782         textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
    783         glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
    784         glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
    785         modifiedGlyphAdvances, modifiedGlyphOffsets);
    786 
    787       if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
    788       {
    789         maxGlyphCount = actualGlyphsCount;
    790         free (modifiedGlyphIndices);
    791         free (modifiedGlyphAdvances);
    792         free (modifiedGlyphOffsets);
    793 
    794         maxGlyphCount = actualGlyphsCount;
    795 
    796         goto retry_getjustifiedglyphs;
    797       }
    798       if (FAILED (hr))
    799       {
    800         FAIL ("Analyzer failed to get justified glyphs.");
    801         return false;
    802       }
    803 
    804       free (clusterMap);
    805       free (glyphIndices);
    806       free (glyphAdvances);
    807       free (glyphOffsets);
    808 
    809       glyphCount = actualGlyphsCount;
    810       clusterMap = modifiedClusterMap;
    811       glyphIndices = modifiedGlyphIndices;
    812       glyphAdvances = modifiedGlyphAdvances;
    813       glyphOffsets = modifiedGlyphOffsets;
    814 
    815       free (justifiedGlyphAdvances);
    816       free (justifiedGlyphOffsets);
    817     }
    818     else
    819     {
    820       free (glyphAdvances);
    821       free (glyphOffsets);
    822 
    823       glyphAdvances = justifiedGlyphAdvances;
    824       glyphOffsets = justifiedGlyphOffsets;
    825     }
    826 
    827     free (justificationOpportunities);
    828 
    829   }
    830 
    831   /* Ok, we've got everything we need, now compose output buffer,
    832    * very, *very*, carefully! */
    833 
    834   /* Calculate visual-clusters.  That's what we ship. */
    835   for (unsigned int i = 0; i < glyphCount; i++)
    836     vis_clusters[i] = -1;
    837   for (unsigned int i = 0; i < buffer->len; i++)
    838   {
    839     uint32_t *p =
    840       &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
    841     *p = MIN (*p, buffer->info[i].cluster);
    842   }
    843   for (unsigned int i = 1; i < glyphCount; i++)
    844     if (vis_clusters[i] == -1)
    845       vis_clusters[i] = vis_clusters[i - 1];
    846 
    847 #undef utf16_index
    848 
    849   if (unlikely (!buffer->ensure (glyphCount)))
    850     FAIL ("Buffer in error");
    851 
    852 #undef FAIL
    853 
    854   /* Set glyph infos */
    855   buffer->len = 0;
    856   for (unsigned int i = 0; i < glyphCount; i++)
    857   {
    858     hb_glyph_info_t *info = &buffer->info[buffer->len++];
    859 
    860     info->codepoint = glyphIndices[i];
    861     info->cluster = vis_clusters[i];
    862 
    863     /* The rest is crap.  Let's store position info there for now. */
    864     info->mask = glyphAdvances[i];
    865     info->var1.i32 = glyphOffsets[i].advanceOffset;
    866     info->var2.i32 = glyphOffsets[i].ascenderOffset;
    867   }
    868 
    869   /* Set glyph positions */
    870   buffer->clear_positions ();
    871   for (unsigned int i = 0; i < glyphCount; i++)
    872   {
    873     hb_glyph_info_t *info = &buffer->info[i];
    874     hb_glyph_position_t *pos = &buffer->pos[i];
    875 
    876     /* TODO vertical */
    877     pos->x_advance = x_mult * (int32_t) info->mask;
    878     pos->x_offset =
    879       x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
    880     pos->y_offset = y_mult * info->var2.i32;
    881 
    882     info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
    883   }
    884 
    885   if (isRightToLeft)
    886     hb_buffer_reverse (buffer);
    887 
    888   free (clusterMap);
    889   free (glyphIndices);
    890   free (textProperties);
    891   free (glyphProperties);
    892   free (glyphAdvances);
    893   free (glyphOffsets);
    894 
    895   if (num_features)
    896     free (singleFeatures.features);
    897 
    898   /* Wow, done! */
    899   return true;
    900 }
    901 
    902 hb_bool_t
    903 _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
    904   hb_font_t          *font,
    905   hb_buffer_t        *buffer,
    906   const hb_feature_t *features,
    907   unsigned int        num_features)
    908 {
    909   return _hb_directwrite_shape_full(shape_plan, font, buffer,
    910     features, num_features, 0);
    911 }
    912 
    913 /*
    914  * Public [experimental] API
    915  */
    916 
    917 hb_bool_t
    918 hb_directwrite_shape_experimental_width(hb_font_t          *font,
    919   hb_buffer_t        *buffer,
    920   const hb_feature_t *features,
    921   unsigned int        num_features,
    922   float               width)
    923 {
    924   static char *shapers = "directwrite";
    925   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
    926     &buffer->props, features, num_features, &shapers);
    927   hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
    928     features, num_features, width);
    929 
    930   buffer->unsafe_to_break_all ();
    931 
    932   return res;
    933 }
    934