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