Подтвердить что ты не робот

HTML как макет

Я пытаюсь реализовать свой собственный механизм макетирования на основе потока. Он должен имитировать поведение макета HTML, но только дерево рендеринга, а не часть DOM. Базовым классом для элементов в дереве рендеринга является класс Node. Он имеет:

  • Ссылка на элемент в DOM (для тех, которые создают дерево рендеринга с этой библиотекой)
  • Ссылка на него parent (который является экземпляром ContainerNode или None, см. ниже)
  • Ссылка на параметры компоновки
  • X, Y, ширина и высота (позиция вычисляется в layout(), после того, как размер был вычислен в compute_size(). Хотя позиция определяется методом layout() родителя, размер определяется например, с помощью ссылки на опции).

Его методы:

  • reflow() вызов compute_size() и layout()
  • compute_size(), который предназначен для вычисления ширины и высоты node.
  • layout(), который предназначен для размещения суб-узлов node, а не самого node.
  • paint(), который должен быть перезаписан пользователем библиотеки.

Класс ContainerNode реализует обработку под-узлов. Он предоставляет новый метод под названием add_node(), который добавляет прошедшие node к детям контейнеров. Функция также принимает силу параметра, которая по умолчанию имеет значение False, потому что контейнеру разрешено отклонить переданный node, за исключением того, что для силы установлено значение True.

Эти два класса не реализуют никакого алгоритма компоновки. Моя цель заключалась в создании разных классов для разных типов макетов (в CSS, в основном определяемых атрибутом display). Я провел несколько тестов с компоновкой текста прошлой ночью, и вы можете найти мой код с pastebin.com (требуется pygame). Вы можете сохранить его в файле python script и вызвать его следующим образом:

python text_test block -c -f "Georgia" -s 15

Примечание. Код действительно действительно дерьмовый. Я ценю комментарии к глубоким ложным заблуждениям.

Класс InlineNodeRow из упомянутого выше кода фактически представляет мою идею о том, как реализовать node, который отличается от атрибута display:inline (в сочетании с NodeBox).

Проблема 1 - Маржа и заполнение для встроенного текста

Вернуться к моему текущему подходу в библиотеке: одно слово из текста также будет представлено в виде единственного node (как в приведенном выше коде). Но я заметил две вещи о полях и paddings в теге <span>.

  • Когда задан край, учитывается только горизонтальный запас, вертикальное поле игнорируется.
  • Прокладка переполняет родительский контейнер и не "перемещает" диапазон node.

См. http://jsfiddle.net/CeRkT/1/.

Я вижу проблему здесь: когда я хочу вычислить размер InlineNodeBox, я запрашиваю для него текст node и добавляю его к размеру node. Но размер текстовых узлов включает в себя его margin и padding, которые не включены в позиционирование рендеринга HTML. Поэтому следующий код будет неправильным:

def compute_size(self):
    # Propagates the computation to the child-nodes.
    super(InlineNodeBox, self).compute_size()

    self.w = 0
    self.h = 0
    for node in self.nodes:
        self.w += node.w
        if self.h < node.h:
            self.h = node.h

node.w будет включать маржу и дополнение. Следующая проблема, которую я вижу, заключается в том, что я правильно определяю текстовые узлы, я хотел разбить их на одиночный TextNode для каждого слова, но маржа и дополнение будут применены ко всем этим узлам, тогда как маржа и отступы в HTML только тег <span>.

Я думаю, что моя нынешняя идея помещать каждое слово в отдельный node не идеальна. Как браузеры структурируют свое дерево рендеринга, или у вас есть идея?

Проблема 2 - Слишком длинное слово, поместите его в следующую строку.

Класс InlineNodeBox в настоящее время организует только одну строку. В приведенном выше примере кода я создал новый InlineNodeBox из NodeBox, когда первый отказался принять node (что означает, что он не вписывается). Я не могу этого с моим текущим подходом, так как я не хочу снова создавать дерево рендеринга. Когда a node был принят один раз, но превышает InlineNodeBox при следующем переплаве, как мне правильно поместить слово в следующую строку (предполагая, что я придерживаюсь идеи класса InlineNodeBox только для организации одной строки узлов)?


Я действительно надеюсь, что все это имеет смысл. Не стесняйтесь спрашивать, не понимаете ли вы мою концепцию. Я также очень открыт для критики и идей для других концепций, ссылок на ресурсы, документации, публикаций и т.д.

4b9b3361

Ответ 1

Проблема 2:

Вы можете сделать это, как рендеринги HTML, и сделать многострочный (например, проверить, добавляется ли новое слово, превышающее ширину, и добавлять новую строку, если это так). Вы можете сделать это в своем InlineNodeRow, также заботясь о высоте и обертывая слова, если они превышают максимальную ширину.

Проблема 1:

Если вы выясните проблему 2 для текста, вы можете поместить смещение (горизонтальное заполнение) только для первой строки.

Хотя <span> не учитывает height, он принимает line-height, поэтому ваш расчет может заключаться в том, что высота по умолчанию - это высота шрифта, если у вас нет опции line-height.

Помните, что если у вас есть два или более последовательных InlineNodeRow, представляющих промежутки, вам понадобится некоторая интеллектуальная логика, чтобы вторая продолжалась с того места, где закончилась первая:)

В качестве примечания. Из того, что я помню из Qt богатой текстовой метки, каждый набор слов с теми же свойствами рендеринга считается a node, и его функция render заботится о вычислении всего материала. Ваш подход немного более гранулирован, и его единственный недостаток от того, что я вижу, заключается в том, что вы не можете разделить слова.

НТН,