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