harfbuzz / harfbuzzjs

Providing HarfBuzz shaping library for client/server side JavaScript projects
https://harfbuzz.github.io/harfbuzzjs/
Other
204 stars 35 forks source link

The name table needs to retain the nameID referenced in the STAT table #84

Closed yisibl closed 1 year ago

yisibl commented 1 year ago

harfbuzzjs removes nameID >= 256, which causes ttx and OTS to report errors.

The hb-subset command line, on the other hand, does not create such a problem, and I'm not sure what function needs to be called to handle it.

ttx -t name -t STAT examples/NotoSansThai-Bold-hb-subset.ttf

See also: https://github.com/yisibl/harfbuzzjs/pull/1

<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.39">

  <name>
    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
      Copyright 2022 The Noto Project Authors (https://github.com/notofonts/thai)
    </namerecord>
    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
      Noto Sans Thai
    </namerecord>
    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
      Bold
    </namerecord>
    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
      2.001;GOOG;NotoSansThai-Bold
    </namerecord>
    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
      Noto Sans Thai Bold
    </namerecord>
    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
      Version 2.001
    </namerecord>
    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
      NotoSansThai-Bold
    </namerecord>
    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
      Weight
    </namerecord>
    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
      Width
    </namerecord>
    <namerecord nameID="264" platformID="3" platEncID="1" langID="0x409">
      Bold
    </namerecord>
    <namerecord nameID="330" platformID="3" platEncID="1" langID="0x409">
      Normal
    </namerecord>
  </name>

  <STAT>
    <Version value="0x00010001"/>
    <DesignAxisRecordSize value="8"/>
    <!-- DesignAxisCount=2 -->
    <DesignAxisRecord>
      <Axis index="0">
        <AxisTag value="wdth"/>
        <AxisNameID value="257"/>  <!-- Width -->
        <AxisOrdering value="0"/>
      </Axis>
      <Axis index="1">
        <AxisTag value="wght"/>
        <AxisNameID value="256"/>  <!-- Weight -->
        <AxisOrdering value="1"/>
      </Axis>
    </DesignAxisRecord>
    <!-- AxisValueCount=2 -->
    <AxisValueArray>
      <AxisValue index="0" Format="1">
        <AxisIndex value="0"/>
        <Flags value="2"/>  <!-- ElidableAxisValueName -->
        <ValueNameID value="330"/>  <!-- Normal -->
        <Value value="100.0"/>
      </AxisValue>
      <AxisValue index="1" Format="1">
        <AxisIndex value="1"/>
        <Flags value="0"/>
        <ValueNameID value="264"/>  <!-- Bold -->
        <Value value="700.0"/>
      </AxisValue>
    </AxisValueArray>
    <ElidedFallbackNameID value="2"/>  <!-- Bold -->
  </STAT>

</ttFont>
yisibl commented 1 year ago

@garretrieger Can you help with this issue?

garretrieger commented 1 year ago

What's the specific hb-subset command line you're using?

yisibl commented 1 year ago

@garretrieger This is almost the default output of the hb-subset used.

hb-subset test/fonts/noto/NotoSansThai-Bold.ttf --text='abc' -o examples/NotoSansThai-Bold-hb-subset.ttf
hb-subset --version
hb-subset (HarfBuzz) 7.1.0
Available shapers: graphite2,ot,coretext,fallback

The original ttf file of the font can be seen here.

CGQAQ commented 1 year ago
#include <stdio.h>
#include <stdlib.h>

#include "../../src/hb.h"
#include "../../src/hb-subset.h"

int main() {
    const char* font_path = "/Users/cgqaq/code/repo/harfbuzzjs/test/fonts/noto/NotoSansThai-Bold.ttf";

    FILE* font_file = fopen(font_path, "r");

    if (font_file == NULL) {
        printf("Error: font file not found\n");
        return 1;
    }

    // read all into memory
    fseek(font_file, 0, SEEK_END);
    long font_file_size = ftell(font_file);
    fseek(font_file, 0, SEEK_SET);

    char* font_file_data = (char*) malloc(font_file_size);
    fread(font_file_data, 1, font_file_size, font_file);
    fclose(font_file);

    hb_blob_t* blob = hb_blob_create_or_fail(
        font_file_data,
        font_file_size,
        HB_MEMORY_MODE_WRITABLE,
        NULL,
        NULL
    );

    hb_face_t* face = hb_face_create(blob, 0);

    hb_subset_input_t* input = hb_subset_input_create_or_fail();
    hb_set_t* unicodes = hb_subset_input_unicode_set(input);

    hb_set_add(unicodes, 0x61); // a
    hb_set_add(unicodes, 0x62); // b
    hb_set_add(unicodes, 0x63); // c

    // hb_subset_input_set_drop_hints(input, true);
    hb_face_t* subset = hb_subset_or_fail(face, input);

    hb_blob_t* subset_blob = hb_face_reference_blob(subset);

    const char* base = hb_blob_get_data(subset_blob, NULL);
    const unsigned int length = hb_blob_get_length(subset_blob);

    FILE* subset_file = fopen("/Users/cgqaq/code/repo/harfbuzzjs/test/fonts/noto/NotoSansThai-Bold.subset.ttf", "w");
    fwrite(base, 1, length, subset_file);
    fclose(subset_file);

    hb_blob_destroy(subset_blob);
    hb_face_destroy(subset);
    hb_subset_input_destroy(input);
    hb_face_destroy(face);
    hb_blob_destroy(blob);
    free(font_file_data);
    return 0;
}

Here is what I found, same API, using C to call will work

C version

``` Copyright 2022 The Noto Project Authors (https://github.com/notofonts/thai) Noto Sans Thai Bold 2.001;GOOG;NotoSansThai-Bold Noto Sans Thai Bold Version 2.001 NotoSansThai-Bold Weight Width Bold Normal ```

js/wasm version

``` Copyright 2022 The Noto Project Authors (https://github.com/notofonts/thai) Noto Sans Thai Bold 2.001;GOOG;NotoSansThai-Bold Noto Sans Thai Bold Version 2.001 NotoSansThai-Bold ```

behdad commented 1 year ago

cc @qxliu76

yisibl commented 1 year ago

Hi @qxliu76 Do you have time to help look at it? It's really quite important for building subset fonts in a production environment.

qxliu76 commented 1 year ago

js version is configured with HB_NO_STYLE enabled. So name_ids from STAT table are not collected, see below:

#ifndef HB_NO_STYLE
  plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
#endif

Need comments from @behdad @garretrieger to see if we can remove this wrapper from harfbuzz code.

behdad commented 1 year ago

If HB_NO_STYLE is defined then face->table.STAT will not be present.

I suggest adding a more complete build of HarfBuzz to hbjs...

yisibl commented 1 year ago

Thanks @qxliu76 @behdad, I've verified PR #91 and it's finally good.

There is also a HB_NO_COLOR, do we need to set it to undefine? https://github.com/harfbuzz/harfbuzz/blob/c7f2d440f463be31ae24cbae7ceb6ea72a15e990/src/hb-subset-plan.cc#L682-L685

#ifndef HB_NO_COLOR
  if (!drop_tables->has (HB_OT_TAG_CPAL))
    plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
#endif

Where should I check to get all the parameter differences between harfbuzzjs and hb-subset?

qxliu76 commented 1 year ago

Yeah seems we might need to undef HB_NO_COLOR as well. You can find configurations in build scripts and hb-config.hh