Ошибка смещения таблицы в шрифте OpenType

Пример: у нас есть 2 класса Client и Service. Client будет использовать Service

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

Без инъекции зависимостей

Способ 1)

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

Способ 2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Способ 3)

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1) 2) 3) Использование

Client client = new Client();
client.doSomeThingInService();

Преимущества

  • Простой

Недостатки

  • Жесткий для теста Client класс
  • Когда мы меняем конструктор Service, нам нужно изменить код на месте create Service object

Использовать инжекцию зависимостей

Способ 1) Инъекция конструктора

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Использование

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

Способ 2) Узел установки

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Использование

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

Способ 3) Инъекция интерфейса

Проверить https://en.wikipedia.org/wiki/Dependency_injection

===

Теперь этот код уже выполняется Dependency Injection и это легче для класса Client. Тем не менее, мы все еще используем new Service() много раз, и это не хорошо, когда конструктор изменения Service. Чтобы предотвратить это, мы можем использовать DI-инжектор, например: 1) Простая инструкция Injector

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

Использование

Service service = Injector.provideService();

2) Использование библиотеки: для Android dagger2

Преимущества

  • Сделать тест легче
  • Когда вы меняете Service, вам нужно только изменить его в классе Инжектор
  • g12]
  • Если вы используете Constructor Injection, когда вы смотрите на конструктор Client, вы увидите, сколько зависимостей Client класса

Недостатки

  • Если вы используете use Constructor Injection, объект Service создается, когда Client создан, когда-то мы используем функцию в классе Client без использования Service, поэтому созданный Service теряется

Определение зависимостей впрыска

https://en.wikipedia.org/wiki/Dependency_injection

A зависимость - это объект, который можно использовать (Service). Инъекция - это передача зависимости (Service) к зависимому объекту (Client), который будет использовать его

1
задан user10869858 16 January 2019 в 19:17
поделиться

1 ответ

При отладке вывода может оказаться полезным использовать формат шестнадцатеричного дампа, который показывает ASCII-представление байтов в правом столбце. Я использую xxd для этого и рекомендую вам сделать то же самое. В частности, для шрифтов OpenType этот формат дампа очень удобен для выявления проблем с выравниванием, особенно в заголовке шрифта.

Чтобы понять, что я имею в виду: вот первый раздел одного из ваших дампов:

00000000: 4f54 544f 0009 0008 0003 0001 4346 4620  OTTO........CFF 
00000010: 0000 0000 0000 00c2 9c00 0000 0563 6d61  .............cma
00000020: 7000 0000 0000 0000 c2a4 0000 0024 6865  p............$he
00000030: 6164 0000 0000 0000 00c3 8800 0000 3668  ad............6h
00000040: 6865 6100 0000 0000 0001 0000 0000 2468  hea...........$h
00000050: 6d74 7800 0000 0000 0001 2400 0000 006d  mtx.......$....m
00000060: 6178 7000 0000 0000 0001 2400 0000 066e  axp.......$....n
00000070: 616d 6500 0000 0000 0001 2c00 0000 064f  ame.......,....O
00000080: 532f 3200 0000 0000 0001 3400 0000 6470  S/2.......4...dp
00000090: 6f73 7400 0000 0000 0001 c298 0000 0020  ost............ 

Вы можете видеть, что первая запись tableDirectory для таблицы CFF - тег ('CFF') ) начинается как последние 4 байта первой строки (4346 4620, что в ASCII - «CFF»), и это правильное выравнивание. Поскольку длина строки hexdump составляет ровно 16 байтов, а каждая запись в tableDirectory составляет 16 байтов, должным образом выровненный tableDirectory будет иметь теги для каждой таблицы как последние 4 байта строки. Но, как вы можете видеть, у вас есть некоторое смещение ... 'c' (0x63) для 'cmap' находится на один байт слишком далеко вправо, и последующие записи tableDirectory также сдвигаются. Он должен выглядеть примерно так:

00000000: 4f54 544f 0009 0008 0003 0001 4346 4620  OTTO........CFF 
00000010: ???? ???? ???? ???? ???? ???? 636d 6170  ............cmap
00000020: ???? ???? ???? ???? ???? ???? 6865 6164  ............head
00000030: ???? ???? ???? ???? ???? ???? 6868 6561  ............hhea
[...]

Так что похоже на некоторые ваших записей в tableDirectory, в конце добавляется дополнительный байт. Поэтому вам нужно выполнить резервное копирование и проверить этот код, чтобы он сначала работал правильно, а затем позаботиться о searchRange, rangeShift и entrySelector (который, предполагая, что ваш шрифт содержит 9 таблиц, как объявлено, должен быть: 0080 0003 0010 (hex)).

0
ответ дан djangodude 16 January 2019 в 19:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: