Imported Upstream version 1.7.6
[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 #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 though.
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
883   if (isRightToLeft)
884     hb_buffer_reverse (buffer);
885
886   free (clusterMap);
887   free (glyphIndices);
888   free (textProperties);
889   free (glyphProperties);
890   free (glyphAdvances);
891   free (glyphOffsets);
892
893   if (num_features)
894     free (singleFeatures.features);
895
896   /* Wow, done! */
897   return true;
898 }
899
900 hb_bool_t
901 _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
902   hb_font_t          *font,
903   hb_buffer_t        *buffer,
904   const hb_feature_t *features,
905   unsigned int        num_features)
906 {
907   return _hb_directwrite_shape_full(shape_plan, font, buffer,
908     features, num_features, 0);
909 }
910
911 /*
912  * Public [experimental] API
913  */
914
915 hb_bool_t
916 hb_directwrite_shape_experimental_width(hb_font_t          *font,
917   hb_buffer_t        *buffer,
918   const hb_feature_t *features,
919   unsigned int        num_features,
920   float               width)
921 {
922   static char *shapers = "directwrite";
923   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
924     &buffer->props, features, num_features, &shapers);
925   hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
926     features, num_features, width);
927
928   buffer->unsafe_to_break_all ();
929
930   return res;
931 }