1 pontos por GN⁺ 4 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • A tipografia árabe na web é um problema de infraestrutura de renderização em que se entrelaçam conexão entre letras, texto bidirecional, tratamento de números e pontuação, e alinhamento de linhas, sendo difícil tratá-lo como um simples bug de CSS
  • A composição árabe clássica implementava o alinhamento justificado não aumentando o espaço entre palavras, mas sim com o kashida, alongando traços internos das letras; já o text-align: justify dos navegadores modernos aumenta principalmente o espaço entre palavras
  • Em árabe, um único codepoint armazenado muda conforme o contexto para formas isolada, inicial, medial e final, e sem recursos OpenType e um motor de shaping, as letras são renderizadas separadas
  • Arabic Presentation Forms no Unicode, sistemas numéricos, o algoritmo bidirecional UAX #9 e caracteres de controle invisíveis levam a problemas reais de produto, como falhas de busca, números de telefone invertidos e confusão no movimento do cursor
  • Fundamentos essenciais como HarfBuzz, Amiri e os W3C Arabic Layout Requirements já foram construídos, mas o alinhamento árabe nos navegadores e o uso de jstf continuam sendo lacunas de implementação

Ponto de partida: o problema de composição árabe que parecia um “bug de CSS”

  • Em um dashboard voltado a clientes, parágrafos em árabe com conteúdo misto não eram renderizados com alinhamento justificado como no layout aprovado pelo design, e a borda esquerda ficava irregular
  • A versão em caracteres latinos do mesmo bloco parecia “fine”, mas no árabe as linhas começam pela direita, então a borda irregular aparece à esquerda
  • Mesmo aplicando text-align: justify, não era possível preencher a linha alongando traços dentro das palavras como no formato aprovado pela equipe de design
  • No mesmo produto, já haviam ocorrido antes problemas com separação de letras em nomes em PDFs, falhas de indexação de busca e codepoints Unicode legados em árabe
  • A essência do problema não está em um defeito de uma folha de estilo específica, mas sim no estado da tipografia árabe na web

O problema que a tradição manuscrita resolvia

  • A tradição clássica de manuscritos árabes justificava a linha não aumentando o espaço entre palavras, mas alongando os traços de conexão dentro da forma das letras
  • Esse método é chamado de taṭwīl ou, no termo técnico moderno, kashida, e consiste em estender o traço de ligação entre determinados pares de letras
  • Uma página bem composta em Naskh do século XVII alinha as duas margens e cria uma textura densa e regular sem ampliar o espaçamento entre palavras
  • O al-khaṭṭ al-mansūb, sistematizado por Ibn Muqla, organizava as formas das letras com base em elementos como o ponto em forma de losango da ponta do cálamo, a altura do alif e proporções de arcos
  • Nessa tradição, o alinhamento de linhas não era um problema de distribuir espaços, mas um problema de shaping que escolhia formas de letras e glifos alternativos

Uma letra, quatro formas

  • O árabe é uma escrita sempre conectada, como a cursiva, sem a distinção entre letras de forma e manuscritas
  • Cada letra muda para forma isolada, inicial, medial ou final conforme as letras vizinhas, e seis letras não se conectam à frente, interrompendo o fluxo dentro da palavra
  • O Unicode armazena letras abstratas, a fonte fornece glifos posicionais e o motor de shaping aplica recursos OpenType como isol, init, medi, fina, rlig, mark e mkmk
  • Uma palavra como محمد ocupa quatro codepoints no armazenamento, mas na renderização passa por várias seleções de glifos e consultas OpenType para aparecer como um único traço contínuo
  • Sem um motor de shaping como o HarfBuzz, ou quando um gerador de PDF não passa por ele, os mesmos codepoints são renderizados como letras isoladas e separadas

Os fósseis do Unicode: Arabic Presentation Forms

  • Nos code pages de 8 bits da era DOS e do início do Windows, codificavam-se não letras abstratas, mas as próprias formas como inicial e medial como caracteres separados
  • O Unicode aceitou isso por compatibilidade de ida e volta, e isso permanece nos blocos Arabic Presentation Forms de U+FB50 até U+FEFF
  • Esses codepoints não deveriam aparecer em documentos novos, mas extratores de texto de PDF ainda podem emiti-los hoje
  • Se o mesmo nome for armazenado uma vez em Unicode moderno e outra em Presentation Forms, ele parecerá igual na tela, mas comparação de strings e busca o tratarão como diferente
  • Aplicar normalização NFKC pode reduzir falhas de busca ao converter Presentation Forms em letras abstratas

Software que pulou shaping e tratamento bidirecional

  • Softwares que ignoram o motor de shaping e o algoritmo bidirecional desenham as letras uma por uma em forma isolada e dispõem a linha da esquerda para a direita
  • Esse tipo de saída é algo que leitores de árabe realmente encontram em letreiros de lojas, cartões de embarque, marcas d’água e legendas árabes em filmes antigos
  • Versões antigas do Photoshop, a configuração padrão do matplotlib, vários geradores de PDF no npm e impressoras de recibo podem produzir esse problema
  • Soluções alternativas comuns em Python, como arabic_reshaper e python-bidi, usam o bloco Presentation Forms para embutir no texto uma forma já “moldada” antecipadamente
  • Esse desvio coloca dentro da string um trabalho que deveria ser feito pelo renderizador, revelando assim uma falha fundamental da pilha de texto

Três tipos de números e o problema da pontuação

  • Os dígitos 0–9 que o mundo chama de “Arabic numerals” não são, para a maioria dos leitores de árabe, a forma de número usada no dia a dia
  • Egito, Sudão, Levante, Iraque e países do Golfo usam os ARABIC-INDIC DIGITS do Unicode: ٠١٢٣٤٥٦٧٨٩
  • A região do Magrebe usa glifos de números latinos, e Irã, Afeganistão e Paquistão usam os EXTENDED ARABIC-INDIC DIGITS: ۰۱۲۳۴۵۶۷۸۹
  • Em UAX #9, números não são tratados como caracteres fortes, mas fracos, e são reclassificados como números europeus ou árabes conforme a direcionalidade do caractere forte anterior
  • Um número de telefone como 010-1234-5678 após uma palavra em árabe pode ter a ordem exibida como 5678-1234-010, porque o hífen é tratado como neutro
  • A solução oferecida pelas plataformas é isolar a direcionalidade envolvendo o número com ou <bdi>
  • Os separadores decimal e de milhar no mundo árabe são U+066B ٫ e U+066C ٬; eles parecem quase iguais ao ASCII . e ,, mas têm codepoints e propriedades bidirecionais diferentes

Desvios e simplificações do impresso à web

  • O Kitāb Ṣalāt al-Sawāʿī, impresso em Fano em 1514, foi o primeiro livro árabe em tipos móveis e mostra casos de letras desconectadas e erros na posição dos pontos
  • O Qurʾān de Paganini, impresso em Veneza em 1537, acumulou erros de composição e erros de texto, fracassou comercialmente e um exemplar foi encontrado em 1987 na biblioteca de um mosteiro em Veneza
  • A história da proibição otomana da impressão tem o problema de que os textos originais dos decretos de Bayezid II e Selim I não sobreviveram, e ela depende de relatos de viajantes europeus
  • A Bulaq Press, no Cairo, foi fundada por Muhammad Ali em 1820 e elevou a qualidade dos tipos metálicos árabes com centenas de peças de tipo e muita paciência
  • O Qurʾān do Cairo de 1924 foi produzido em tipos metálicos na Amiria Press e contribuiu para a padronização textual e tipográfica do século XX
  • No fim dos anos 1950, Kamel Mrowa e a Linotype criaram o Simplified Arabic para se adequar a revistas de 90 canais, fundindo formas iniciais com mediais, finais com isoladas e reduzindo ligaturas
  • O Simplified Arabic tornou possível uma produção de jornais barata e rápida e, em uma geração, dominou as redações árabes

O kashida que a web ainda não consegue desenhar

  • Rascunhos iniciais do CSS Text Module Level 3 incluíam o valor kashida para text-justify, e o Internet Explorer 5.5 implementou isso em 2000
  • O IE 5.5 também oferecia a propriedade text-kashida-space, mas, como nenhum outro navegador a implementou, esse valor acabou saindo da especificação
  • No Chrome, Firefox e Safari atuais, text-align: justify em árabe funciona ampliando o espaço entre palavras
  • A issue sobre alinhamento árabe no CSS Working Group está aberta pelo menos desde 2015, e o trabalho do W3C Arabic Layout Requirements também começou naquele ano
  • O alinhamento com kashida exige que shaping e layout renegociem iterativamente em nível de linha, porque glifos alongados mudam a largura, essa mudança altera as quebras de linha e isso muda novamente o alongamento necessário
  • O OpenType já tinha desde os anos 1990 a tabela jstf, pela qual fontes poderiam informar prioridades de justificação, mas motores de shaping quase nunca a leem e criadores de fontes quase nunca a fornecem
  • Microsoft Word e InDesign Middle East Edition oferecem alinhamento com kashida, mas o conjunto de renderizadores de navegador em que as pessoas mais leem ainda não consegue alongar as letras

O hack com Tatweel e os problemas de ligaturas e diacríticos

  • Um desvio comum na web é inserir no próprio texto o caractere U+0640 TATWEEL para fazê-lo parecer um traço alongado
  • Como o Tatweel altera o conteúdo, ele causa problemas em correspondência de busca, copiar e colar, leitores de tela e refluxo de colunas
  • O traço desenhado por Tatweel não é um kashida posicionado segundo as regras da fonte e dos caracteres, mas uma barra de estilo máquina de escrever inserida por tentativa do autor
  • As ligaturas OpenType se dividem em rlig, liga e dlig, e se uma ligatura obrigatória como lām-alif quebra, o texto deixa de estar apenas feio: ele fica errado
  • Inserir U+200C ZERO WIDTH NON-JOINER entre letras preserva os caracteres armazenados, mas força a renderização de cada letra em forma isolada
  • O Safari ignora "rlig" 0 e "liga" 0, então demos para desativar ligaturas obrigatórias não têm efeito nele
  • Amiri é uma fonte Naskh lançada por Khaled Hosny em 2011 sob a SIL Open Font License e, após a reescrita 1.0 em 2022, passou a oferecer kashidas curvos e empilhamento refinado de diacríticos
  • Componentes de cartão com line-height: 1 e overflow: hidden podem cortar os diacríticos superiores de árabe totalmente vocalizado

O algoritmo bidirecional e o cursor que mente

  • Números de versão, identificadores em inglês, URLs e palavras em francês dentro de um parágrafo em árabe acionam o UAX #9, o Unicode Bidirectional Algorithm
  • Letras árabes são tratadas como caracteres fortes da direita para a esquerda, letras latinas como fortes da esquerda para a direita, números como fracos dependentes do contexto e espaços e pontuação como neutros
  • O algoritmo atribui uma classe direcional a cada caractere, interpreta progressivamente caracteres fracos e neutros, depois atribui níveis de embedding e inverte runs com o mesmo nível
  • Como a ordem visual na tela difere da ordem lógica na memória, mover o cursor, clicar com o mouse e selecionar texto exige tradução contínua entre essas duas ordens
  • Nas fronteiras entre runs existem duas posições legítimas de cursor, uma lógica e outra visual, e Chrome, Firefox, Qt e Outlook podem tratá-las de formas diferentes
  • Escrever texto misto árabe-inglês continua sendo, mesmo em 2026, uma experiência com alto custo cognitivo por padrão em editores importantes, clientes de e-mail e aplicativos de chat
  • Um intervalo como الصفحات 10-20 pode parecer “de 20 a 10” por causa da regra W2 e do tratamento neutro do hífen, e isso pode ser corrigido colocando U+200E LEFT-TO-RIGHT MARK antes

A base que funciona e as lacunas restantes

  • Khaled Hosny criou a Amiri, escreveu a ferramenta de linha de comando hb-shape do HarfBuzz e também atua como co-mantenedor do HarfBuzz
  • Behdad Esfahbod escreveu grande parte do HarfBuzz antes de Hosny e contribuiu para o motor de shaping que hoje desenha corretamente letras árabes nos navegadores
  • A Brill encomendou a John Hudson a fonte Brill para incluir todos os caracteres de transliteração necessários ao catálogo Semitics e a lançou gratuitamente para uso não comercial em 2011
  • O Sakhr AX-170 era um computador MSX saudita-kuwaitiano que exibia árabe em ROM por volta de 1984 e suportava identificadores em Arabic BASIC escritos da direita para a esquerda
  • HarfBuzz, Amiri, Scheherazade, o suporte a Presentation Forms no GNU Unifont, Noto Arabic e a documentação do W3C Arabic Layout dependem fortemente do esforço de poucas pessoas, organizações e voluntários
  • Os fornecedores de navegadores adotaram o HarfBuzz depois que ele ficou pronto e gratuito, mas contribuíram muito pouco para o loop de layout que implementaria na tela o método de alinhamento da tradição manuscrita
  • A lacuna restante é um algoritmo bem compreendido que precisa ser implementado em alguns motores de layout, e a margem esquerda irregular no dashboard do cliente é a forma visível para o usuário dessa falta de investimento

1 comentários

 
GN⁺ 4 시간 전
Comentários do Lobste.rs
  • Texto realmente impressionante
    E eu gosto do fato de que este caractere é um único code point. É curioso copiar e testar
    Dizem que significa “Em nome de Alá, o mais misericordioso, o mais compassivo”

    • Sobre , esta frase do texto é poética
      “Um monumento de uma época em que ninguém confiava nos motores de renderização, então a renderização era embutida na codificação. Como uma mosca recitadora preservada para sempre dentro do âmbar”
    • Esse caractere Unicode também foi discutido aqui: https://lobste.rs/s/7s4sjp
      Foi divertido seguir as referências do link da Wikipedia citado aqui: https://lobste.rs/c/dq2ucz
      Resumindo, esse caractere entrou no Unicode porque estava em uma code page do Paquistão, e entrou lá porque havia uma exigência legal de incluir essa frase em documentos jurídicos. Como o urdu é uma língua indo-europeia, com a tecnologia da época provavelmente era difícil “fazer uma chamada externa” para uma code page árabe só para escrever a Basmallah
      Infelizmente, nem todos os comentários mostram o melhor daquela comunidade
  • Meta: este é mais um ótimo exemplo de que textos assim precisam da tag typography

    • Não entendo por que precisaria. O assunto parece bem popular; existe mesmo uma demanda forte para esconder esse tipo de conteúdo?
      No lobste.rs, as tags servem principalmente para filtragem
  • A propriedade text-justify do IE, nossa, havia muitas coisas interessantes naquela época. Também existia text-justify: newspaper, e décadas depois alguns passaram a descrever isso como Knuth-Plass ou algo parecido, mas não acredito que fosse isso de fato
    https://mediumwell.com/wp-content/uploads/… mostra um comportamento que na época era apresentado como text-justify: newspaper e que bate com o text-justify: inter-character da especificação atual
    O IE realmente tinha muitos recursos legais bem cedo, e outros navegadores deixaram esse tipo de recurso na cesta do “difícil demais”. No fim, alguns nunca voltaram, e outros só voltaram 15 ou 30 anos depois. O Firefox ganhou text-justify: inter-character em 2017, o Chromium só implementou essa parte há alguns meses, e o Safari ainda não tem isso

  • Artigo incrivelmente excelente e informativo. Gostei especialmente do contexto histórico, que deu uma visão ampla para toda a história
    Como alguém com formação em história e também carreira em TI, este texto acertou em cheio nos meus dois interesses

  • Há algo no texto que faz meu detector de LLM apitar, o que é uma pena. Isso porque ele tem profundidade e trata de partes menos documentadas da stack tecnológica moderna
    Um exemplo de trecho que soa como LLM é este, e senti isso ao longo do texto:
    “A razão pela qual nenhum navegador oferece isso é estrutural, e como obstáculo essa estrutura é bastante elegante. A justificação latina trata o texto já modelado como algo fixo, mede as palavras, despeja o espaço restante nos espaçamentos e termina. Shaping e layout ficam cada um em sua própria caixa, e toda stack de texto em operação é projetada em torno dessa separação. A justificação com Kashida abre essa caixa à força.”
    Eu gostaria de perguntar ao @lr0 se o corpo deste texto foi gerado, refinado ou traduzido com LLM. Se sim, talvez valha a pena ajustar o nível de controle que o LLM tem sobre a saída final. Posts antigos do blog, por exemplo https://lr0.org/blog/p/gpt/ e https://lr0.org/blog/p/linux_new_users/ , pareciam muito mais humanos