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