Kelvin Ma | 2 Jul 01:18 2016
Picon

Re: HarfBuzz Digest, Vol 121, Issue 4



On 02.07.2016 1:02, Kelvin Ma wrote:
> So that’s what the value member does. thanks! Will it always be either 0
> or 1?

0 means disabled, 1 means enabled, >1 means enabled with specific value.
According to msdn 'salt' feature could use that to pick a specific
alternate glyph.

So it’s not boolean okay. Right now I have opentype features as a font styling attribute, which means that there is always an explicit ON/OFF value computed for every feature in every style. So it’s important to have good hardcoded defaults for the base class fontstyle. But seeing as it varies by script, and the font styles are not aware of script that makes it a lot more problematic…
 

> && what does .tag do?

It identifies a feature.

>
> On Fri, Jul 1, 2016 at 5:51 PM, Simon Cozens <simon-eH/WZUpBTt7sazjREg0tEA@public.gmane.org
> <mailto:simon <at> simon-cozens.org>> wrote:
>
>     On 02/07/2016 07:34, Kelvin Ma wrote:
>     > So I think I figured out how to turn on font features, but how do I turn
>     > ones off that are enabled by default? Like liga or kern?
>
>     Just set the value to 0 in the features array.
>     See
>     https://github.com/simoncozens/sile/blob/master/src/justenoughharfbuzz.c#L78
>
>     Simon
>
>
>
>
> _______________________________________________
> HarfBuzz mailing list
> HarfBuzz-PD4FTy7X32mMSPqsTGOZug@public.gmane.orgesktop.org
> https://lists.freedesktop.org/mailman/listinfo/harfbuzz
>

_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Kelvin Ma | 2 Jul 01:11 2016
Picon

Re: Turning off ligatures and kerning

How can I tell if a feature is enabled by default? Is it constant across scripts? And are feature values always True/False

On Fri, Jul 1, 2016 at 6:34 PM, Ebrahim Byagowi <ebraminio-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
By passing a list of opentype features to harfbuzz, it just modifies the default status of them but still has knows which ones should be enabled or disabled in case user didn't explicitly set them.

Because i can turn off LIGA by passing a LIGA feature with value=0 and nothing will happen to arabic but CALT with value=1 changes it
In case of LIGA and CALT difference, that depends on that specific font you are using whether it has marked which feature by which tag. An identical stylic operation can have two different tag on different fonts.

On Sat, Jul 2, 2016 at 2:58 AM, Kelvin Ma <kelvinsthirteen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
Now I’m even more confused, will harfbuzz override the features in the features array if it’s setting arabic? Because i can turn off LIGA by passing a LIGA feature with value=0 and nothing will happen to arabic but CALT with value=1 changes it

On Fri, Jul 1, 2016 at 6:24 PM, Ebrahim Byagowi <ebraminio <at> gmail.com> wrote:
Different and essential operations of a shaper are divided and marked by features and some features are enabled by default per the specification, for example on Arabic https://www.microsoft.com/typography/OpenTypeDev/arabic/intro.htm#features

On Sat, Jul 2, 2016 at 2:33 AM, Kelvin Ma <kelvinsthirteen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
&& why does harfbuzz still use features if I pass it an empty list? How does it know whether to turn them on or off?

On Fri, Jul 1, 2016 at 6:02 PM, Kelvin Ma <kelvinsthirteen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
So that’s what the value member does. thanks! Will it always be either 0 or 1?
&& what does .tag do?

On Fri, Jul 1, 2016 at 5:51 PM, Simon Cozens <simon-eH/WZUpBTt7sazjREg0tEA@public.gmane.org> wrote:
On 02/07/2016 07:34, Kelvin Ma wrote:
> So I think I figured out how to turn on font features, but how do I turn
> ones off that are enabled by default? Like liga or kern?

Just set the value to 0 in the features array.
See
https://github.com/simoncozens/sile/blob/master/src/justenoughharfbuzz.c#L78

Simon




_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz





_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Kelvin Ma | 1 Jul 23:34 2016
Picon

Turning off ligatures and kerning

So I think I figured out how to turn on font features, but how do I turn ones off that are enabled by default? Like liga or kern?
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Kelvin Ma | 1 Jul 21:02 2016
Picon

Opentype features

so if this isn’t lying then it looks like i gotta do

otint = hb.tag_from_string(list(map(ord, 'onum')))
otfeature = [' ', ' ', ' ', ' ']
hb.tag_to_string(otint, otfeature)
print(otfeature)


to round-trip a opentype feature through harfbuzz…
and of course

>>> Segmentation fault (core dumped)

Why not just

otint = hb.tag_from_string('onum')
otfeature = hb.tag_to_string(otint)
print(otfeature)


?
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Behdad Esfahbod | 1 Jul 20:45 2016
Picon

Re: Clear buffer contents without clearing direction or script

On Jul 1, 2016 11:37 AM, "Kelvin Ma" <kelvinsthirteen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
> Is there a way to remove all the codepoints from a buffer object while leaving the direction, script, and language intact?

No.  Those properties depend on buffer text, si it doesn't make sense to clear text but not those.  It's two lines to capture them and set them back.  HarfBuzz is a library, it provides building blocks that enable what people need to do, not every imaginable combination of lines of code someone might need...

> buffer_clear_contents() clears that data too.
>
> _______________________________________________
> HarfBuzz mailing list
> HarfBuzz-PD4FTy7X32mMSPqsTGOZug@public.gmane.orgesktop.org
> https://lists.freedesktop.org/mailman/listinfo/harfbuzz
>

_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Kelvin Ma | 1 Jul 20:37 2016
Picon

Clear buffer contents without clearing direction or script

Is there a way to remove all the codepoints from a buffer object while leaving the direction, script, and language intact? buffer_clear_contents() clears that data too.
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Kelvin Ma | 1 Jul 05:31 2016
Picon

Can I only reshape broken clusters?

If I have the string A = 'affifibcd' and the master list of shaped glyphs

[a 0] [ffi 1] [fi 4] [b 6] [c 7] [d 8]

and I wanted to shape the substring A[2:] ('fifibcd'), could I simply take my preshaped glyphs after the cluster at or above (ceiling) i = 2 and only reshape the segment A[2:6]?

So I would reuse the glyphs

[fi 4] [b 6] [c 7] [d 8]

and reshape the segment A[2:6] = 'fifi' to get

[fi 2] [fi 4]

and add them together (dropping the last glyph in the reshaped segment) to get

[fi 2]  [fi 4] [b 6] [c 7] [d 8]

?
Would this be the same result as reshaping the entire segment A[2:]? Would this still work for RTL text, or a substring that’s on the left-hand side of the parent string like A[:5] = 'affif'?
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Behdad Esfahbod | 30 Jun 20:01 2016

harfbuzz: Branch 'master' - 2 commits

 src/hb-coretext.cc |   18 +++++++++---------
 src/sample.py      |   22 +++++++++++++++++++++-
 2 files changed, 30 insertions(+), 10 deletions(-)

New commits:
commit d3e2a06b0f2587e913a9c3ff1a20c187f260db80
Author: Behdad Esfahbod <behdad <at> behdad.org>
Date:   Thu Jun 30 11:01:22 2016 -0700

    [python] Use utf-32 / utf-16 based on build of Python

    Fixes https://github.com/behdad/harfbuzz/pull/271

diff --git a/src/sample.py b/src/sample.py
index 19a4fdc..c2cb94d 100755
--- a/src/sample.py
+++ b/src/sample.py
 <at>  <at>  -3,6 +3,7  <at>  <at> 

 from __future__ import print_function
 import sys
+import array
 from gi.repository import HarfBuzz as hb
 from gi.repository import GLib

 <at>  <at>  -39,7 +40,26  <at>  <at>  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)
+
+##
+## Add text to buffer
+##
+#
+# See https://github.com/behdad/harfbuzz/pull/271
+#
+if False:
+	# If you do not care about cluster values reflecting Python
+	# string indices, then this is quickest way to add text to
+	# buffer:
+	hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
+	# Otherwise, then following handles both narrow and wide
+	# Python builds:
+elif sys.maxunicode == 0x10FFFF:
+	hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32')), 0, -1)
+else:
+	hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16')), 0, -1)
+
+
 hb.buffer_guess_segment_properties (buf)

 hb.shape (font, buf, [])
commit fc9de44a03a97f6e93bd98d804596cb1f9f4b5fd
Author: Behdad Esfahbod <behdad <at> behdad.org>
Date:   Thu Jun 30 09:46:52 2016 -0700

    Comments

diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 98592af..db6d2aa 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
 <at>  <at>  -155,15 +155,15  <at>  <at>  create_ct_font (CGFontRef cg_font, CGFloat font_size)
     CFRelease (last_resort_font_desc);
     if (new_ct_font)
     {
-      // The CTFontCreateCopyWithAttributes call fails to stay on the same font
-      // when reconfiguring the cascade list and may switch to a different font
-      // when there are fonts that go by the same name, since the descriptor is
-      // just name and size.
-
-      // Avoid reconfiguring the cascade lists if the new font is outside the
-      // system locations that we cannot access from the sandboxed renderer
-      // process in Blink. This can be detected by the new file URL location
-      // that the newly found font points to.
+      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
+       * when reconfiguring the cascade list and may switch to a different font
+       * when there are fonts that go by the same name, since the descriptor is
+       * just name and size.
+       *
+       * Avoid reconfiguring the cascade lists if the new font is outside the
+       * system locations that we cannot access from the sandboxed renderer
+       * process in Blink. This can be detected by the new file URL location
+       * that the newly found font points to. */
       CFURLRef new_url = (CFURLRef)CTFontCopyAttribute(new_ct_font, kCTFontURLAttribute);
       if (CFEqual(original_url, new_url)) {
         CFRelease (ct_font);
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Behdad Esfahbod | 30 Jun 18:41 2016

harfbuzz: Branch 'master' - 5 commits

 src/hb-coretext.cc |   24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

New commits:
commit 46809dee30232d493539519b1bb527fa816c37db
Merge: 70e72e5 1bea49e
Author: Behdad Esfahbod <behdad@...>
Date:   Thu Jun 30 09:41:03 2016 -0700

    Merge pull request #268 from drott/conflictingFontFix

    Discard reconfigured CTFont if URL changes

commit 1bea49eb4b7a94ab6222f9c3c40320cbdb247b2d
Merge: 7aa3631 70e72e5
Author: Dominik Röttsches <d-r@...>
Date:   Wed Jun 29 12:10:41 2016 +0200

    Merge branch 'master' into conflictingFontFix

commit 7aa3631dd06af74a1fa9f0bfaa5f721876be817f
Merge: f7da048 abae93f
Author: Dominik Röttsches <d-r@...>
Date:   Tue Jun 28 09:52:18 2016 +0200

    Merge branch 'master' into conflictingFontFix

commit f7da0486ed8884481d477ce08fcf928c4da9a0a3
Merge: a022327 07461d0
Author: Dominik Röttsches <d-r@...>
Date:   Mon Jun 20 10:25:43 2016 +0300

    Merge branch 'master' into conflictingFontFix

commit a0223274b97e82fe02730fd45729172511fec459
Author: Dominik Röttsches <drott@...>
Date:   Thu Jun 16 14:19:39 2016 +0200

    Discard reconfigured CTFont if URL changes

    Fixes https://github.com/behdad/harfbuzz/issues/267

diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index e64d265..98592af 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
 <at>  <at>  -145,6 +145,7  <at>  <at>  create_ct_font (CGFontRef cg_font, CGFloat font_size)
     DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
     return NULL;
   }
+  CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);

   /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
    * font fallback which we don't need anyway. */
 <at>  <at>  -154,14 +155,31  <at>  <at>  create_ct_font (CGFontRef cg_font, CGFloat font_size)
     CFRelease (last_resort_font_desc);
     if (new_ct_font)
     {
-      CFRelease (ct_font);
-      ct_font = new_ct_font;
+      // The CTFontCreateCopyWithAttributes call fails to stay on the same font
+      // when reconfiguring the cascade list and may switch to a different font
+      // when there are fonts that go by the same name, since the descriptor is
+      // just name and size.
+
+      // Avoid reconfiguring the cascade lists if the new font is outside the
+      // system locations that we cannot access from the sandboxed renderer
+      // process in Blink. This can be detected by the new file URL location
+      // that the newly found font points to.
+      CFURLRef new_url = (CFURLRef)CTFontCopyAttribute(new_ct_font, kCTFontURLAttribute);
+      if (CFEqual(original_url, new_url)) {
+        CFRelease (ct_font);
+        ct_font = new_ct_font;
+      } else {
+        CFRelease(new_ct_font);
+        DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
+      }
+      CFRelease(new_url);
     }
     else
       DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
   }

- return ct_font;
+  CFRelease(original_url);
+  return ct_font;
 }

 struct hb_coretext_shaper_face_data_t {
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Behdad Esfahbod | 29 Jun 06:15 2016

harfbuzz: Branch 'master' - 3 commits

 src/hb-buffer.cc         |    2 +-
 src/hb-gobject-structs.h |   12 ++++++++++++
 src/hb-shape.cc          |    2 --
 src/hb-unicode.h         |   15 ---------------
 src/sample.py            |    3 +--
 5 files changed, 14 insertions(+), 20 deletions(-)

New commits:
commit 70e72e5f61d73c33d3c8f3bf07f5a9afd0db046a
Author: Behdad Esfahbod <behdad <at> behdad.org>
Date:   Tue Jun 28 21:00:37 2016 -0700

    [gobject] Fix a few warnings

    Part of https://github.com/behdad/harfbuzz/issues/277

diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 406db9c..4552d15 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
 <at>  <at>  -52,7 +52,7  <at>  <at> 
  *
  * Checks the equality of two #hb_segment_properties_t's.
  *
- * Return value: (transfer full):
+ * Return value:
  * %true if all properties of  <at> a equal those of  <at> b, false otherwise.
  *
  * Since: 0.9.7
diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h
index 0ea3b12..1c30321 100644
--- a/src/hb-gobject-structs.h
+++ b/src/hb-gobject-structs.h
 <at>  <at>  -41,30 +41,40  <at>  <at>  HB_BEGIN_DECLS
 /* Object types */

 /**
+ * hb_gobject_blob_get_type:
+ *
  * Since: 0.9.2
  **/
 HB_EXTERN GType hb_gobject_blob_get_type (void);
 #define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())

 /**
+ * hb_gobject_buffer_get_type:
+ *
  * Since: 0.9.2
  **/
 HB_EXTERN GType hb_gobject_buffer_get_type (void);
 #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())

 /**
+ * hb_gobject_face_get_type:
+ *
  * Since: 0.9.2
  **/
 HB_EXTERN GType hb_gobject_face_get_type (void);
 #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())

 /**
+ * hb_gobject_font_get_type:
+ *
  * Since: 0.9.2
  **/
 HB_EXTERN GType hb_gobject_font_get_type (void);
 #define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())

 /**
+ * hb_gobject_font_funcs_get_type:
+ *
  * Since: 0.9.2
  **/
 HB_EXTERN GType hb_gobject_font_funcs_get_type (void);
 <at>  <at>  -77,6 +87,8  <at>  <at>  HB_EXTERN GType hb_gobject_shape_plan_get_type (void);
 #define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())

 /**
+ * hb_gobject_unicode_funcs_get_type:
+ *
  * Since: 0.9.2
  **/
 HB_EXTERN GType hb_gobject_unicode_funcs_get_type (void);
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 352d42c..41a4fc5 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
 <at>  <at>  -394,8 +394,6  <at>  <at>  hb_shape_full (hb_font_t          *font,
  * positioned glyphs. If  <at> features is not %NULL, it will be used to control the
  * features applied during shaping.
  *
- * Return value: %FALSE if all shapers failed, %TRUE otherwise
- *
  * Since: 0.9.2
  **/
 void
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 6a15cb0..2657f48 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
 <at>  <at>  -449,33 +449,18  <at>  <at>  HB_EXTERN hb_script_t
 hb_unicode_script (hb_unicode_funcs_t *ufuncs,
 		   hb_codepoint_t unicode);

-/**
- * hb_unicode_compose:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN hb_bool_t
 hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
 		    hb_codepoint_t      a,
 		    hb_codepoint_t      b,
 		    hb_codepoint_t     *ab);

-/**
- * hb_unicode_decompose:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN hb_bool_t
 hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
 		      hb_codepoint_t      ab,
 		      hb_codepoint_t     *a,
 		      hb_codepoint_t     *b);

-/**
- * hb_unicode_decompose_compatibility:
- *
- * Since: 0.9.2
- **/
 HB_EXTERN unsigned int
 hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
 				    hb_codepoint_t      u,
commit d8273aac19771033c5064a2f079c29d09a86e7c0
Merge: abae93f ae9054c
Author: Behdad Esfahbod <behdad <at> behdad.org>
Date:   Tue Jun 28 21:15:28 2016 -0700

    Merge pull request #280 from behdad/revert-271-patch-2

    Revert "use utf32"

commit ae9054c740631e36b7582b44c5afb42ff4509461
Author: Behdad Esfahbod <behdad <at> behdad.org>
Date:   Tue Jun 28 21:14:38 2016 -0700

    Revert "use utf32"

diff --git a/src/sample.py b/src/sample.py
index cfbc122..19a4fdc 100755
--- a/src/sample.py
+++ b/src/sample.py
 <at>  <at>  -20,7 +20,6  <at>  <at>  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))
 <at>  <at>  -40,7 +39,7  <at>  <at>  class Debugger(object):
 		return True
 debugger = Debugger()
 hb.buffer_set_message_func (buf, debugger.message, 1, 0)
-hb.buffer_add_utf32 (buf, codepoints, 0, len(codepoints))
+hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
 hb.buffer_guess_segment_properties (buf)

 hb.shape (font, buf, [])
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz
Behdad Esfahbod | 29 Jun 05:54 2016

harfbuzz: Branch 'master' - 9 commits

 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@...>
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@...>
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
 <at>  <at>  -664,11 +664,11  <at>  <at>  _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));

 <at>  <at>  -679,9 +679,7  <at>  <at>  retry_getglyphs:

   if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
   {
-    free (clusterMap);
     free (glyphIndices);
-    free (textProperties);
     free (glyphProperties);

     maxGlyphCount *= 2;
 <at>  <at>  -779,10 +777,10  <at>  <at>  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;
 <at>  <at>  -795,7 +793,6  <at>  <at>  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@...>
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
 <at>  <at>  -130,11 +130,12  <at>  <at>  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 *
 <at>  <at>  -195,6 +196,7  <at>  <at>  _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;
 <at>  <at>  -205,10 +207,23  <at>  <at>  _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@...>
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
 <at>  <at>  -134,6 +134,7  <at>  <at>  struct hb_directwrite_shaper_face_data_t {
   IDWriteFontFile* fontFile;
   IDWriteFontFileLoader* fontFileLoader;
   IDWriteFontFace* fontFace;
+  hb_blob_t* faceBlob;
 };

 hb_directwrite_shaper_face_data_t *
 <at>  <at>  -153,7 +154,7  <at>  <at>  _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));

 <at>  <at>  -196,6 +197,7  <at>  <at>  _hb_directwrite_shaper_face_data_create(hb_face_t *face)
   data->fontFile = fontFile;
   data->fontFileLoader = fontFileLoader;
   data->fontFace = fontFace;
+  data->faceBlob = blob;

   return data;
 }
 <at>  <at>  -205,6 +207,7  <at>  <at>  _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@...>
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
 <at>  <at>  -25,11 +25,7  <at>  <at> 
 #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"

 <at>  <at>  -156,7 +152,6  <at>  <at>  _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 (
 <at>  <at>  -377,7 +372,8  <at>  <at>  public:

   IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
     uint32_t* textLength,
-    wchar_t const** localeName) {
+    wchar_t const** localeName)
+  {
     return S_OK;
   }

 <at>  <at>  -402,7 +398,8  <at>  <at>  public:
   {
     SetCurrentRun(textPosition);
     SplitCurrentRun(textPosition);
-    while (textLength > 0) {
+    while (textLength > 0)
+    {
       Run *run = FetchNextRun(&textLength);
       run->mScript = *scriptAnalysis;
     }
 <at>  <at>  -435,10 +432,12  <at>  <at>  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;
     }
 <at>  <at>  -455,12 +454,14  <at>  <at>  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;
       }
 <at>  <at>  -471,13 +472,15  <at>  <at>  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;
 <at>  <at>  -514,9 +517,9  <at>  <at>  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); }

 /*
 <at>  <at>  -536,14 +539,8  <at>  <at>  _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);
 <at>  <at>  -717,106 +714,110  <at>  <at>  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@...>
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
 <at>  <at>  -45,176 +45,172  <at>  <at> 
 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);
 }

 
 <at>  <at>  -223,90 +219,27  <at>  <at> 
_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
 <at>  <at>  -327,7 +260,7  <at>  <at>  _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
 <at>  <at>  -581,9 +514,9  <at>  <at>  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); }

 /*
 <at>  <at>  -600,23 +533,8  <at>  <at>  _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;
 <at>  <at>  -672,7 +590,6  <at>  <at>  _hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
     }
   }

-  HRESULT hr;
   // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES

   DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? 
 <at>  <at>  -688,6 +605,7  <at>  <at>  _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
 <at>  <at>  -31,4 +31,4  <at>  <at>  HB_BEGIN_DECLS

 HB_END_DECLS

-#endif /* HB_UNISCRIBE_H */
+#endif /* HB_DIRECTWRITE_H */
commit 07461d06d242cd5cfda7ccb891189f074a89b460
Author: Kelvin <kelvinsthirteen@...>
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
 <at>  <at>  -20,6 +20,7  <at>  <at>  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))
 <at>  <at>  -39,7 +40,7  <at>  <at>  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@...>
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@...>
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
 <at>  <at>  -7,7 +7,43  <at>  <at>  from itertools import *
 diff_symbols = "-+=*&^%$# <at> !~/"
 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:
_______________________________________________
HarfBuzz mailing list
HarfBuzz <at> lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/harfbuzz

Gmane