[HarfBuzz] harfbuzz: Branch 'master' - 9 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Jun 29 03:54:41 UTC 2016


 src/hb-directwrite.cc         |  568 ++++++++++++++++++------------------------
 src/hb-directwrite.h          |    2 
 src/sample.py                 |    3 
 test/shaping/hb_test_tools.py |   38 ++
 4 files changed, 291 insertions(+), 320 deletions(-)

New commits:
commit abae93faef32562f34a72981d252c848cc4f7565
Merge: 07461d0 8179ff5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Mon Jun 27 14:33:27 2016 -0400

    Merge pull request #273 from ebraminio/master
    
    	[dwrite] Use stream font loader instead GDI interop

commit 8179ff5d7ba4a140cf6743729a22072800e98a79
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Mon Jun 27 03:54:15 2016 +0430

    [dwrite] Don't allocate more than needed
    
    Addressing Nikolay Sivov reviews on harfbuzz mailing list

diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index 36b4d5d..09889d0 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -664,11 +664,11 @@ _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
     (const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures;
   const uint32_t featureRangeLengths[] = { textLength };
 
+  uint16_t* clusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
+  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+    malloc (textLength * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
 retry_getglyphs:
-  uint16_t* clusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
   uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
-  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
-    malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
   DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
     malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
 
@@ -679,9 +679,7 @@ retry_getglyphs:
 
   if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
   {
-    free (clusterMap);
     free (glyphIndices);
-    free (textProperties);
     free (glyphProperties);
 
     maxGlyphCount *= 2;
@@ -779,10 +777,10 @@ retry_getglyphs:
     // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
     if (justificationCharacter != 32)
     {
+      uint16_t* modifiedClusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
     retry_getjustifiedglyphs:
-      uint16_t* modifiedClusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof(uint16_t));
-      uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof(uint16_t));
-      float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof(float));
+      uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
+      float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
       DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
         malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
       uint32_t actualGlyphsCount;
@@ -795,7 +793,6 @@ retry_getglyphs:
       if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
       {
         maxGlyphCount = actualGlyphsCount;
-        free (modifiedClusterMap);
         free (modifiedGlyphIndices);
         free (modifiedGlyphAdvances);
         free (modifiedGlyphOffsets);
commit 07b724f3419a28c479cd8a75ae0eecb841a6d2f3
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Fri Jun 24 12:23:25 2016 +0430

    [dwrite] Delete remained objects
    
    No longer noticeable memory increase on create/destroy iterations,
    highly better than current state of uniscribe backend

diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index a74e318..36b4d5d 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -130,11 +130,12 @@ public:
 */
 
 struct hb_directwrite_shaper_face_data_t {
-  IDWriteFactory* dwriteFactory;
-  IDWriteFontFile* fontFile;
-  IDWriteFontFileLoader* fontFileLoader;
-  IDWriteFontFace* fontFace;
-  hb_blob_t* faceBlob;
+  IDWriteFactory *dwriteFactory;
+  IDWriteFontFile *fontFile;
+  IDWriteFontFileStream *fontFileStream;
+  IDWriteFontFileLoader *fontFileLoader;
+  IDWriteFontFace *fontFace;
+  hb_blob_t *faceBlob;
 };
 
 hb_directwrite_shaper_face_data_t *
@@ -195,6 +196,7 @@ _hb_directwrite_shaper_face_data_create(hb_face_t *face)
 
   data->dwriteFactory = dwriteFactory;
   data->fontFile = fontFile;
+  data->fontFileStream = fontFileStream;
   data->fontFileLoader = fontFileLoader;
   data->fontFace = fontFace;
   data->faceBlob = blob;
@@ -205,10 +207,23 @@ _hb_directwrite_shaper_face_data_create(hb_face_t *face)
 void
 _hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
 {
-  data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
-  delete data->fontFileLoader;
-  hb_blob_destroy (data->faceBlob);
-  free (data);
+  if (data->fontFace)
+    data->fontFace->Release ();
+  if (data->fontFile)
+    data->fontFile->Release ();
+  if (data->dwriteFactory) {
+    if (data->fontFileLoader)
+      data->dwriteFactory->UnregisterFontFileLoader(data->fontFileLoader);
+    data->dwriteFactory->Release();
+  }
+  if (data->fontFileLoader)
+    delete data->fontFileLoader;
+  if (data->fontFileStream)
+    delete data->fontFileStream;
+  if (data->faceBlob)
+    hb_blob_destroy (data->faceBlob);
+  if (data)
+    free (data);
 }
 
 
commit be565d17141818e006aa1e4582f3ae14c726fa85
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Fri Jun 24 11:42:01 2016 +0430

    [dwrite] Release allocated blob on face destroy
    
    This reduces memory consumption of my iterated font create/destroy cycle test
    significantly and makes it much better than uniscribe backend even

diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index c6fac4d..a74e318 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -134,6 +134,7 @@ struct hb_directwrite_shaper_face_data_t {
   IDWriteFontFile* fontFile;
   IDWriteFontFileLoader* fontFileLoader;
   IDWriteFontFace* fontFace;
+  hb_blob_t* faceBlob;
 };
 
 hb_directwrite_shaper_face_data_t *
@@ -153,7 +154,7 @@ _hb_directwrite_shaper_face_data_create(hb_face_t *face)
   );
 
   HRESULT hr;
-  hb_blob_t* blob = hb_face_reference_blob (face);
+  hb_blob_t *blob = hb_face_reference_blob (face);
   IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
     (uint8_t*) hb_blob_get_data (blob, NULL), hb_blob_get_length (blob));
 
@@ -196,6 +197,7 @@ _hb_directwrite_shaper_face_data_create(hb_face_t *face)
   data->fontFile = fontFile;
   data->fontFileLoader = fontFileLoader;
   data->fontFace = fontFace;
+  data->faceBlob = blob;
 
   return data;
 }
@@ -205,6 +207,7 @@ _hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data
 {
   data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
   delete data->fontFileLoader;
+  hb_blob_destroy (data->faceBlob);
   free (data);
 }
 
commit f3f0ea980a359343ac0e3d359a95855c2cf7be25
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Thu Jun 23 16:41:37 2016 +0430

    [dwrite] Remove ifdefs without breaking execution on old Windows versions

diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index f273f51..c6fac4d 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -25,11 +25,7 @@
 #define HB_SHAPER directwrite
 #include "hb-shaper-impl-private.hh"
 
-#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
-  #include <DWrite.h>
-#else
-  #include <DWrite_1.h>
-#endif
+#include <DWrite_1.h>
 
 #include "hb-directwrite.h"
 
@@ -156,7 +152,6 @@ _hb_directwrite_shaper_face_data_create(hb_face_t *face)
     (IUnknown**) &dwriteFactory
   );
 
-
   HRESULT hr;
   hb_blob_t* blob = hb_face_reference_blob (face);
   IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
@@ -377,7 +372,8 @@ public:
 
   IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
     uint32_t* textLength,
-    wchar_t const** localeName) {
+    wchar_t const** localeName)
+  {
     return S_OK;
   }
 
@@ -402,7 +398,8 @@ public:
   {
     SetCurrentRun(textPosition);
     SplitCurrentRun(textPosition);
-    while (textLength > 0) {
+    while (textLength > 0)
+    {
       Run *run = FetchNextRun(&textLength);
       run->mScript = *scriptAnalysis;
     }
@@ -435,10 +432,12 @@ protected:
     Run *origRun = mCurrentRun;
     // Split the tail if needed (the length remaining is less than the
     // current run's size).
-    if (*textLength < mCurrentRun->mTextLength) {
-      SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
+    if (*textLength < mCurrentRun->mTextLength)
+    {
+      SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
     }
-    else {
+    else
+    {
       // Just advance the current run.
       mCurrentRun = mCurrentRun->nextRun;
     }
@@ -455,12 +454,14 @@ protected:
     // this will usually just return early. If not, find the
     // corresponding run for the text position.
 
-    if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
+    if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
+    {
       return;
     }
 
     for (Run *run = &mRunHead; run; run = run->nextRun) {
-      if (run->ContainsTextPosition(textPosition)) {
+      if (run->ContainsTextPosition (textPosition))
+      {
         mCurrentRun = run;
         return;
       }
@@ -471,13 +472,15 @@ protected:
 
   void SplitCurrentRun(uint32_t splitPosition)
   {
-    if (!mCurrentRun) {
+    if (!mCurrentRun)
+    {
       //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
       // Shouldn't be calling this when no current run is set!
       return;
     }
     // Split the current run.
-    if (splitPosition <= mCurrentRun->mTextStart) {
+    if (splitPosition <= mCurrentRun->mTextStart)
+    {
       // No need to split, already the start of a run
       // or before it. Usually the first.
       return;
@@ -514,9 +517,9 @@ protected:
   Run  mRunHead;
 };
 
-static inline uint16_t hb_uint16_swap(const uint16_t v)
+static inline uint16_t hb_uint16_swap (const uint16_t v)
 { return (v >> 8) | (v << 8); }
-static inline uint32_t hb_uint32_swap(const uint32_t v)
+static inline uint32_t hb_uint32_swap (const uint32_t v)
 { return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); }
 
 /*
@@ -536,14 +539,8 @@ _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
   IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
   IDWriteFontFace *fontFace = face_data->fontFace;
 
-#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
   IDWriteTextAnalyzer* analyzer;
   dwriteFactory->CreateTextAnalyzer(&analyzer);
-#else
-  IDWriteTextAnalyzer* analyzer0;
-  dwriteFactory->CreateTextAnalyzer (&analyzer0);
-  IDWriteTextAnalyzer1* analyzer = (IDWriteTextAnalyzer1*) analyzer0;
-#endif
 
   unsigned int scratch_size;
   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
@@ -717,106 +714,110 @@ retry_getglyphs:
     return false;
   }
 
-#ifdef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
+  // TODO: get lineWith from somewhere
+  float lineWidth = 0;
 
-  DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
-    (DWRITE_JUSTIFICATION_OPPORTUNITY*)
-    malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
-  hr = analyzer->GetJustificationOpportunities (fontFace, fontEmSize,
-    runHead->mScript, textLength, glyphCount, textString, clusterMap,
-    glyphProperties, justificationOpportunities);
+  IDWriteTextAnalyzer1* analyzer1;
+  analyzer->QueryInterface (&analyzer1);
 
-  if (FAILED (hr))
+  if (analyzer1 && lineWidth)
   {
-    FAIL ("Analyzer failed to get justification opportunities.");
-    return false;
-  }
 
-  // TODO: get lineWith from somewhere
-  float lineWidth = 60000;
+    DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
+      (DWRITE_JUSTIFICATION_OPPORTUNITY*)
+      malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
+    hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize,
+      runHead->mScript, textLength, glyphCount, textString, clusterMap,
+      glyphProperties, justificationOpportunities);
 
-  float* justifiedGlyphAdvances =
-    (float*) malloc (maxGlyphCount * sizeof (float));
-  DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
-    malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
-  hr = analyzer->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
-    glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
+    if (FAILED (hr))
+    {
+      FAIL ("Analyzer failed to get justification opportunities.");
+      return false;
+    }
 
-  if (FAILED (hr))
-  {
-    FAIL ("Analyzer failed to get justified glyph advances.");
-    return false;
-  }
+    float* justifiedGlyphAdvances =
+      (float*) malloc (maxGlyphCount * sizeof (float));
+    DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
+      malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
+    hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
+      glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
 
-  DWRITE_SCRIPT_PROPERTIES scriptProperties;
-  hr = analyzer->GetScriptProperties (runHead->mScript, &scriptProperties);
-  if (FAILED (hr))
-  {
-    FAIL ("Analyzer failed to get script properties.");
-    return false;
-  }
-  uint32_t justificationCharacter = scriptProperties.justificationCharacter;
+    if (FAILED (hr))
+    {
+      FAIL("Analyzer failed to get justified glyph advances.");
+      return false;
+    }
 
-  // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
-  if (justificationCharacter != 32)
-  {
-retry_getjustifiedglyphs:
-    uint16_t* modifiedClusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
-    uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
-    float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
-    DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
-      malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
-    uint32_t actualGlyphsCount;
-    hr = analyzer->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
+    DWRITE_SCRIPT_PROPERTIES scriptProperties;
+    hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
+    if (FAILED (hr))
+    {
+      FAIL("Analyzer failed to get script properties.");
+      return false;
+    }
+    uint32_t justificationCharacter = scriptProperties.justificationCharacter;
+
+    // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
+    if (justificationCharacter != 32)
+    {
+    retry_getjustifiedglyphs:
+      uint16_t* modifiedClusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof(uint16_t));
+      uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof(uint16_t));
+      float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof(float));
+      DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
+        malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
+      uint32_t actualGlyphsCount;
+      hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
         textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
         glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
         glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
         modifiedGlyphAdvances, modifiedGlyphOffsets);
 
-    if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
-    {
-      maxGlyphCount = actualGlyphsCount;
-      free (modifiedClusterMap);
-      free (modifiedGlyphIndices);
-      free (modifiedGlyphAdvances);
-      free (modifiedGlyphOffsets);
+      if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
+      {
+        maxGlyphCount = actualGlyphsCount;
+        free (modifiedClusterMap);
+        free (modifiedGlyphIndices);
+        free (modifiedGlyphAdvances);
+        free (modifiedGlyphOffsets);
 
-      maxGlyphCount = actualGlyphsCount;
+        maxGlyphCount = actualGlyphsCount;
 
-      goto retry_getjustifiedglyphs;
-    }
-    if (FAILED (hr))
-    {
-      FAIL ("Analyzer failed to get justified glyphs.");
-      return false;
-    }
+        goto retry_getjustifiedglyphs;
+      }
+      if (FAILED (hr))
+      {
+        FAIL ("Analyzer failed to get justified glyphs.");
+        return false;
+      }
 
-    free (clusterMap);
-    free (glyphIndices);
-    free (glyphAdvances);
-    free (glyphOffsets);
+      free (clusterMap);
+      free (glyphIndices);
+      free (glyphAdvances);
+      free (glyphOffsets);
 
-    glyphCount = actualGlyphsCount;
-    clusterMap = modifiedClusterMap;
-    glyphIndices = modifiedGlyphIndices;
-    glyphAdvances = modifiedGlyphAdvances;
-    glyphOffsets = modifiedGlyphOffsets;
+      glyphCount = actualGlyphsCount;
+      clusterMap = modifiedClusterMap;
+      glyphIndices = modifiedGlyphIndices;
+      glyphAdvances = modifiedGlyphAdvances;
+      glyphOffsets = modifiedGlyphOffsets;
 
-    free(justifiedGlyphAdvances);
-    free(justifiedGlyphOffsets);
-  }
-  else
-  {
-    free(glyphAdvances);
-    free(glyphOffsets);
+      free (justifiedGlyphAdvances);
+      free (justifiedGlyphOffsets);
+    }
+    else
+    {
+      free (glyphAdvances);
+      free (glyphOffsets);
 
-    glyphAdvances = justifiedGlyphAdvances;
-    glyphOffsets = justifiedGlyphOffsets;
-  }
+      glyphAdvances = justifiedGlyphAdvances;
+      glyphOffsets = justifiedGlyphOffsets;
+    }
 
-  free(justificationOpportunities);
+    free (justificationOpportunities);
 
-#endif
+  }
 
   /* Ok, we've got everything we need, now compose output buffer,
    * very, *very*, carefully! */
commit 6b861dbd8b3662d0fa0e51fad1736d72192da868
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Tue Jun 21 13:57:26 2016 +0430

    [dwrite] Use stream font loader instead GDI interop
    
    With help of
    https://dxr.mozilla.org/mozilla-central/source/gfx/2d/NativeFontResourceDWrite.cpp

diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index 96d1870..f273f51 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -45,176 +45,172 @@
 HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
 HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
 
-/*
-* shaper face data
-*/
 
-struct hb_directwrite_shaper_face_data_t {
-  HANDLE fh;
-  wchar_t face_name[LF_FACESIZE];
-};
+/*
+ * DirectWrite font stream helpers
+ */
 
-/* face_name should point to a wchar_t[LF_FACESIZE] object. */
-static void
-_hb_generate_unique_face_name(wchar_t *face_name, unsigned int *plen)
+// This is a font loader which provides only one font (unlike its original design).
+// For a better implementation which was also source of this
+// and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
+class DWriteFontFileLoader : public IDWriteFontFileLoader
 {
-  /* We'll create a private name for the font from a UUID using a simple,
-  * somewhat base64-like encoding scheme */
-  const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
-  UUID id;
-  UuidCreate ((UUID*)&id);
-  ASSERT_STATIC (2 + 3 * (16 / 2) < LF_FACESIZE);
-  unsigned int name_str_len = 0;
-  face_name[name_str_len++] = 'F';
-  face_name[name_str_len++] = '_';
-  unsigned char *p = (unsigned char *)&id;
-  for (unsigned int i = 0; i < 16; i += 2)
-  {
-    /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
-    * using the bits in groups of 5,5,6 to select chars from enc.
-    * This will generate 24 characters; with the 'F_' prefix we already provided,
-    * the name will be 26 chars (plus the NUL terminator), so will always fit within
-    * face_name (LF_FACESIZE = 32). */
-    face_name[name_str_len++] = enc[p[i] >> 3];
-    face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
-    face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
-  }
-  face_name[name_str_len] = 0;
-  if (plen)
-    *plen = name_str_len;
-}
+private:
+  IDWriteFontFileStream *mFontFileStream;
+public:
+  DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream) {
+    mFontFileStream = fontFileStream;
+  }
 
-/* Destroys blob. */
-static hb_blob_t *
-_hb_rename_font(hb_blob_t *blob, wchar_t *new_name)
-{
-  /* Create a copy of the font data, with the 'name' table replaced by a
-   * table that names the font with our private F_* name created above.
-   * For simplicity, we just append a new 'name' table and update the
-   * sfnt directory; the original table is left in place, but unused.
-   *
-   * The new table will contain just 5 name IDs: family, style, unique,
-   * full, PS. All of them point to the same name data with our unique name.
-   */
+  // IUnknown interface
+  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
+  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
+  IFACEMETHOD_(ULONG, Release)() { return 1; }
 
-  blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
+  // IDWriteFontFileLoader methods
+  virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
+    UINT32 fontFileReferenceKeySize,
+    OUT IDWriteFontFileStream** fontFileStream)
+  {
+    *fontFileStream = mFontFileStream;
+    return S_OK;
+  }
+};
 
-  unsigned int length, new_length, name_str_len;
-  const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
+class DWriteFontFileStream : public IDWriteFontFileStream
+{
+private:
+  uint8_t *mData;
+  uint32_t mSize;
+public:
+  DWriteFontFileStream(uint8_t *aData, uint32_t aSize)
+  {
+    mData = aData;
+    mSize = aSize;
+  }
 
-  _hb_generate_unique_face_name (new_name, &name_str_len);
+  // IUnknown interface
+  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
+  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
+  IFACEMETHOD_(ULONG, Release)() { return 1; }
 
-  static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
+  // IDWriteFontFileStream methods
+  virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
+    UINT64 fileOffset,
+    UINT64 fragmentSize,
+    OUT void** fragmentContext)
+  {
+    // We are required to do bounds checking.
+    if (fileOffset + fragmentSize > mSize) {
+      return E_FAIL;
+    }
 
-  unsigned int name_table_length = OT::name::min_size +
-    ARRAY_LENGTH(name_IDs) * OT::NameRecord::static_size +
-    name_str_len * 2; /* for name data in UTF16BE form */
-  unsigned int name_table_offset = (length + 3) & ~3;
+    // truncate the 64 bit fileOffset to size_t sized index into mData
+    size_t index = static_cast<size_t> (fileOffset);
 
-  new_length = name_table_offset + ((name_table_length + 3) & ~3);
-  void *new_sfnt_data = calloc(1, new_length);
-  if (!new_sfnt_data)
-  {
-    hb_blob_destroy (blob);
-    return NULL;
+    // We should be alive for the duration of this.
+    *fragmentStart = &mData[index];
+    *fragmentContext = nullptr;
+    return S_OK;
   }
 
-  memcpy(new_sfnt_data, orig_sfnt_data, length);
+  virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext) { }
 
-  OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
-  name.format.set (0);
-  name.count.set (ARRAY_LENGTH (name_IDs));
-  name.stringOffset.set (name.get_size());
-  for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
+  virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize)
   {
-    OT::NameRecord &record = name.nameRecord[i];
-    record.platformID.set(3);
-    record.encodingID.set(1);
-    record.languageID.set(0x0409u); /* English */
-    record.nameID.set(name_IDs[i]);
-    record.length.set(name_str_len * 2);
-    record.offset.set(0);
-  }
-
-  /* Copy string data from new_name, converting wchar_t to UTF16BE. */
-  unsigned char *p = &OT::StructAfter<unsigned char>(name);
-  for (unsigned int i = 0; i < name_str_len; i++)
-  {
-    *p++ = new_name[i] >> 8;
-    *p++ = new_name[i] & 0xff;
+    *fileSize = mSize;
+    return S_OK;
   }
 
-  /* Adjust name table entry to point to new name table */
-  const OT::OpenTypeFontFile &file = *(OT::OpenTypeFontFile *) (new_sfnt_data);
-  unsigned int face_count = file.get_face_count ();
-  for (unsigned int face_index = 0; face_index < face_count; face_index++)
+  virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime)
   {
-    /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
-    * toe-stepping.  But we don't really care. */
-    const OT::OpenTypeFontFace &face = file.get_face (face_index);
-    unsigned int index;
-    if (face.find_table_index (HB_OT_TAG_name, &index))
-    {
-      OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
-      record.checkSum.set_for_data (&name, name_table_length);
-      record.offset.set (name_table_offset);
-      record.length.set (name_table_length);
-    }
-    else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
-    {
-      free (new_sfnt_data);
-      hb_blob_destroy (blob);
-      return NULL;
-    }
+    return E_NOTIMPL;
   }
+};
 
-  /* The checkSumAdjustment field in the 'head' table is now wrong,
-  * but that doesn't actually seem to cause any problems so we don't
-  * bother. */
 
-  hb_blob_destroy (blob);
-  return hb_blob_create ((const char *)new_sfnt_data, new_length,
-    HB_MEMORY_MODE_WRITABLE, NULL, free);
-}
+/*
+* shaper face data
+*/
+
+struct hb_directwrite_shaper_face_data_t {
+  IDWriteFactory* dwriteFactory;
+  IDWriteFontFile* fontFile;
+  IDWriteFontFileLoader* fontFileLoader;
+  IDWriteFontFace* fontFace;
+};
 
 hb_directwrite_shaper_face_data_t *
 _hb_directwrite_shaper_face_data_create(hb_face_t *face)
 {
   hb_directwrite_shaper_face_data_t *data =
-    (hb_directwrite_shaper_face_data_t *) calloc (1, sizeof (hb_directwrite_shaper_face_data_t));
+    (hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
   if (unlikely (!data))
     return NULL;
 
-  hb_blob_t *blob = hb_face_reference_blob (face);
-  if (unlikely (!hb_blob_get_length (blob)))
-    DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob");
+  // TODO: factory and fontFileLoader should be cached separately
+  IDWriteFactory* dwriteFactory;
+  DWriteCreateFactory (
+    DWRITE_FACTORY_TYPE_SHARED,
+    __uuidof (IDWriteFactory),
+    (IUnknown**) &dwriteFactory
+  );
+
 
-  blob = _hb_rename_font (blob, data->face_name);
-  if (unlikely (!blob))
-  {
-    free(data);
-    return NULL;
+  HRESULT hr;
+  hb_blob_t* blob = hb_face_reference_blob (face);
+  IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
+    (uint8_t*) hb_blob_get_data (blob, NULL), hb_blob_get_length (blob));
+
+  IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
+  dwriteFactory->RegisterFontFileLoader (fontFileLoader);
+
+  IDWriteFontFile *fontFile;
+  uint64_t fontFileKey = 0;
+  hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
+      fontFileLoader, &fontFile);
+
+#define FAIL(...) \
+  HB_STMT_START { \
+    DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
+    return false; \
+  } HB_STMT_END;
+
+  if (FAILED (hr)) {
+    FAIL ("Failed to load font file from data!");
+    return false;
   }
 
-  DWORD num_fonts_installed;
-  data->fh = AddFontMemResourceEx ((void *)hb_blob_get_data(blob, NULL),
-    hb_blob_get_length (blob),
-    0, &num_fonts_installed);
-  if (unlikely (!data->fh))
-  {
-    DEBUG_MSG (DIRECTWRITE, face, "Face AddFontMemResourceEx() failed");
-    free (data);
-    return NULL;
+  BOOL isSupported;
+  DWRITE_FONT_FILE_TYPE fileType;
+  DWRITE_FONT_FACE_TYPE faceType;
+  UINT32 numberOfFaces;
+  hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
+  if (FAILED (hr) || !isSupported) {
+    FAIL ("Font file is not supported.");
+    return false;
   }
 
+#undef FAIL
+
+  IDWriteFontFace *fontFace;
+  dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
+    DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
+
+  data->dwriteFactory = dwriteFactory;
+  data->fontFile = fontFile;
+  data->fontFileLoader = fontFileLoader;
+  data->fontFace = fontFace;
+
   return data;
 }
 
 void
 _hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
 {
-  RemoveFontMemResourceEx(data->fh);
-  free(data);
+  data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
+  delete data->fontFileLoader;
+  free (data);
 }
 
 
@@ -223,90 +219,27 @@ _hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data
  */
 
 struct hb_directwrite_shaper_font_data_t {
-  HDC hdc;
-  LOGFONTW log_font;
-  HFONT hfont;
 };
 
-static bool
-populate_log_font (LOGFONTW  *lf,
-       hb_font_t *font)
-{
-  memset (lf, 0, sizeof (*lf));
-  lf->lfHeight = -font->y_scale;
-  lf->lfCharSet = DEFAULT_CHARSET;
-
-  hb_face_t *face = font->face;
-  hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-
-  memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
-
-  return true;
-}
-
 hb_directwrite_shaper_font_data_t *
 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
 {
   if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
 
   hb_directwrite_shaper_font_data_t *data =
-    (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
+    (hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
   if (unlikely (!data))
     return NULL;
 
-  data->hdc = GetDC (NULL);
-
-  if (unlikely (!populate_log_font (&data->log_font, font)))
-  {
-    DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed");
-    _hb_directwrite_shaper_font_data_destroy (data);
-    return NULL;
-  }
-
-  data->hfont = CreateFontIndirectW (&data->log_font);
-  if (unlikely (!data->hfont))
-  {
-    DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed");
-    _hb_directwrite_shaper_font_data_destroy (data);
-     return NULL;
-  }
-
-  if (!SelectObject (data->hdc, data->hfont))
-  {
-    DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed");
-    _hb_directwrite_shaper_font_data_destroy (data);
-     return NULL;
-  }
-
   return data;
 }
 
 void
 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
 {
-  if (data->hdc)
-    ReleaseDC (NULL, data->hdc);
-  if (data->hfont)
-    DeleteObject (data->hfont);
   free (data);
 }
 
-LOGFONTW *
-hb_directwrite_font_get_logfontw (hb_font_t *font)
-{
-  if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
-  hb_directwrite_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
-  return &font_data->log_font;
-}
-
-HFONT
-hb_directwrite_font_get_hfont (hb_font_t *font)
-{
-  if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
-  hb_directwrite_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
-  return font_data->hfont;
-}
-
 
 /*
  * shaper shape_plan data
@@ -327,7 +260,7 @@ _hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan
 {
 }
 
-// Most of here TextAnalysis is originally written by Bas Schouten for Mozilla project
+// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
 // but now is relicensed to MIT for HarfBuzz use
 class TextAnalysis
   : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
@@ -581,9 +514,9 @@ protected:
   Run  mRunHead;
 };
 
-static inline uint16_t hb_uint16_swap (const uint16_t v)
+static inline uint16_t hb_uint16_swap(const uint16_t v)
 { return (v >> 8) | (v << 8); }
-static inline uint32_t hb_uint32_swap (const uint32_t v)
+static inline uint32_t hb_uint32_swap(const uint32_t v)
 { return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); }
 
 /*
@@ -600,23 +533,8 @@ _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
   hb_face_t *face = font->face;
   hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
-
-  // factory probably should be cached
-#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
-  IDWriteFactory* dwriteFactory;
-#else
-  IDWriteFactory1* dwriteFactory;
-#endif
-  DWriteCreateFactory (
-    DWRITE_FACTORY_TYPE_SHARED,
-    __uuidof (IDWriteFactory),
-    (IUnknown**) &dwriteFactory
-  );
-
-  IDWriteGdiInterop *gdiInterop;
-  dwriteFactory->GetGdiInterop (&gdiInterop);
-  IDWriteFontFace* fontFace;
-  gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace);
+  IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
+  IDWriteFontFace *fontFace = face_data->fontFace;
 
 #ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
   IDWriteTextAnalyzer* analyzer;
@@ -672,7 +590,6 @@ _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
     }
   }
 
-  HRESULT hr;
   // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
 
   DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? 
@@ -688,6 +605,7 @@ _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
 
   TextAnalysis analysis(textString, textLength, NULL, readingDirection);
   TextAnalysis::Run *runHead;
+  HRESULT hr;
   hr = analysis.GenerateResults(analyzer, &runHead);
 
 #define FAIL(...) \
diff --git a/src/hb-directwrite.h b/src/hb-directwrite.h
index adf33df..0e1b479 100644
--- a/src/hb-directwrite.h
+++ b/src/hb-directwrite.h
@@ -31,4 +31,4 @@ HB_BEGIN_DECLS
 
 HB_END_DECLS
 
-#endif /* HB_UNISCRIBE_H */
+#endif /* HB_DIRECTWRITE_H */
commit 07461d06d242cd5cfda7ccb891189f074a89b460
Author: Kelvin <kelvinsthirteen at gmail.com>
Date:   Sat Jun 18 22:46:38 2016 +0000

    Use UTF-32  in Python sample

diff --git a/src/sample.py b/src/sample.py
index 19a4fdc..cfbc122 100755
--- a/src/sample.py
+++ b/src/sample.py
@@ -20,6 +20,7 @@ def tounicode(s, encoding='utf-8'):
 
 fontdata = open (sys.argv[1], 'rb').read ()
 text = tounicode(sys.argv[2])
+codepoints = list(map(ord, text))
 # Need to create GLib.Bytes explicitly until this bug is fixed:
 # https://bugzilla.gnome.org/show_bug.cgi?id=729541
 blob = hb.glib_blob_create (GLib.Bytes.new (fontdata))
@@ -39,7 +40,7 @@ class Debugger(object):
 		return True
 debugger = Debugger()
 hb.buffer_set_message_func (buf, debugger.message, 1, 0)
-hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
+hb.buffer_add_utf32 (buf, codepoints, 0, len(codepoints))
 hb.buffer_guess_segment_properties (buf)
 
 hb.shape (font, buf, [])
commit fca0c61d67aa309fc824fb18f247493c2b7701ef
Merge: 4b8de1e 9883505
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Jun 19 00:08:51 2016 +0300

    Merge pull request #270 from khaledhosny/travis-failure
    
    Fix make check on Travis

commit 988350586f607c7a46bbb658a2abecfd004f41fb
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sat Jun 18 21:12:19 2016 +0200

    [tests] Workaround Python 2 “narrow” builds
    
    The so-called Python 2 “narrow” builds support UCS2 only, this is a
    workaround to allow unichr to work with any Unicode character in such
    builds. This fixes Travis-CI failure as it has narrow Python 2 builds.
    
    Copied from:
    https://github.com/behdad/fonttools/blob/master/Lib/fontTools/misc/py23.py

diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py
index 747699b..7473982 100644
--- a/test/shaping/hb_test_tools.py
+++ b/test/shaping/hb_test_tools.py
@@ -7,7 +7,43 @@ from itertools import *
 diff_symbols = "-+=*&^%$#@!~/"
 diff_colors = ['red', 'green', 'blue']
 
-if sys.version_info[0] >= 3:
+try:
+	unichr = unichr
+
+	if sys.maxunicode < 0x10FFFF:
+		# workarounds for Python 2 "narrow" builds with UCS2-only support.
+
+		_narrow_unichr = unichr
+
+		def unichr(i):
+			"""
+			Return the unicode character whose Unicode code is the integer 'i'.
+			The valid range is 0 to 0x10FFFF inclusive.
+
+			>>> _narrow_unichr(0xFFFF + 1)
+			Traceback (most recent call last):
+			  File "<stdin>", line 1, in ?
+			ValueError: unichr() arg not in range(0x10000) (narrow Python build)
+			>>> unichr(0xFFFF + 1) == u'\U00010000'
+			True
+			>>> unichr(1114111) == u'\U0010FFFF'
+			True
+			>>> unichr(0x10FFFF + 1)
+			Traceback (most recent call last):
+			  File "<stdin>", line 1, in ?
+			ValueError: unichr() arg not in range(0x110000)
+			"""
+			try:
+				return _narrow_unichr(i)
+			except ValueError:
+				try:
+					padded_hex_str = hex(i)[2:].zfill(8)
+					escape_str = "\\U" + padded_hex_str
+					return escape_str.decode("unicode-escape")
+				except UnicodeDecodeError:
+					raise ValueError('unichr() arg not in range(0x110000)')
+
+except NameError:
 	unichr = chr
 
 class ColorFormatter:


More information about the HarfBuzz mailing list