3 puan yazan GN⁺ 2024-03-22 | 3 yorum | WhatsApp'ta paylaş
  • Dropflow, temel CSS standartları olan inline, block, float, positioning ve gelecekte table’ları incelemek için geliştirilmiş bir CSS düzen motorudur; flexbox ve grid kapsam dışıdır
  • Node ve node-canvas ile arka uçta PDF/görsel üretimi için kullanılabilir; tarayıcıda ise canvas üzerinde satır sonlandırmalı zengin metin render edebilir
  • Metin düzeni çift yönlü ve RTL metin, grafem bazında font fallback, renkli aksan işaretleri, OpenType/TrueType font kaydı ve HarfBuzz tabanlı shaping destekler
  • CSS destek kapsamı 30’dan fazla özelliği içerir; float, clear, display: inline-block, position: relative, overflow, z-index, zoom gibi özellikler çalışır; table, absolute, fixed, transform gibi özellikler plan aşamasındadır
  • En yüksek performans, HTML/CSS ayrıştırmayı atlayan hyperscript API ve yeniden kullanılabilir style nesneleriyle elde edilir; 2019 MacBook Pro’da 500’den fazla paragraflık The Little Prince’i HTML’den görsele 160 ms’nin altında dönüştürür

Dropflow’un ele aldığı CSS düzen kapsamı

  • Dropflow, foundational CSS standards kapsamını incelemek için geliştirilmiş bir CSS düzen motorudur
    • Hedeflenenler inline, block, float, positioning ve gelecekte tables’tır
    • flexbox ve grid hedeflenmez
  • Yüksek kaliteli metin düzeni uygulamasına sahiptir ve dünyanın birçok dilini gösterebilir
  • İki kullanım alanı sunulur
    • Node ve node-canvas kullanarak arka uçta PDF veya görsel üretimi
    • Tarayıcıda canvas üzerinde satır sonlandırmalı zengin metin render etme

Başlıca özellikler

  • 30’dan fazla CSS özelliğini destekler; float gibi karmaşık özellikler de buna dahildir
  • Metinle ilgili özellikleri geniştir
    • Çift yönlü metin ve RTL metin
    • Grafem bazında font fallback
    • Renkli aksan işaretleri
    • Tercih edilen satır sonu işleme; örneğin başlangıç padding’ini sonraki satıra taşıma
    • Optimize edilmiş shaping
  • Girdi yöntemi olarak HTML/CSS’nin yanı sıra, stilleri nesne olarak ileten hyperscript h() API de desteklenir
  • OpenType/TrueType buffer’ları kaydedilebilir ve kayıt zorunludur
  • <img> JPEG, BMP, PNG ve GIF’i destekler; ancak destek arka uca göre değişebilir
  • Kalıtılan ve cascade edilmiş stiller iki kez hesaplanmaz
  • Tipleri eksiksizdir, çok sayıda testi vardır ve hızlı çalışmayı hedefler

CSS destek durumu

  • Inline formatting’de çalışan öğeler arasında color, direction, font-family, font-size, font-stretch, font-style, font-weight, line-height, text-align, vertical-align, white-space, word-break, overflow-wrap, word-wrap, word-spacing vb. bulunur
  • Inline formatting’de font-variant, letter-spacing, tab-size, text-decoration, unicode-bidi planlandı durumundadır
  • Block formatting’de clear ve float çalışır
    • writing-mode için horizontal-tb, vertical-lr, vertical-rl kısmen uygulanmış durumdadır
    • BFC’de uygulanmıştır, ancak IFC’de henüz uygulanmamıştır
  • Boxes and positioning’de birçok kutu ve yerleşim özelliği çalışır
    • background-clip, background-color, border-color, border-style, border-width
    • top, right, bottom, left
    • box-sizing
    • display: block, inline, inline-block, flow-root, none
    • height, margin, padding, overflow, width, z-index, zoom
    • position: relative
  • Boxes and positioning’de display: table, min/max-height, min/max-width, position: absolute, position: fixed, transform planlandı durumundadır

Temel kullanım akışı

  • Dropflow, tarayıcıyla aynı şekilde kalıtılmış ve hesaplanmış stillere sahip bir DOM temelinde çalışır
  • Tipik akış şöyledir
    • Düzen öncesinde FontFace ile font kaydı
    • flow.style() ile style nesnesi oluşturma
    • flow.h() ile DOM oluşturma
    • flow.dom() ile render edilecek ağacı hazırlama
    • renderToCanvas() ile canvas’ın tamamında layout ve paint işlemi yapma
  • HTML API de sağlanır; ancak yalnızca performans önemli değilse veya öğrenme amacıyla önerilir
    • Ayrıştırma ek süre yaratır ve bundle boyutunu ciddi ölçüde artırır
    • HTML ayrıştırmanın @fb55 sayesinde hızlı olduğu belirtilir
    • Şu anda yalnızca style HTML özelliği desteklenir; class henüz çalışmaz

Performans özellikleri

  • Performans en üst düzey hedeftir ve doğruluktan sonra gelir
  • Örneklere dayalı performans rakamları sunulur
    • Birden fazla inline span ve farklı fontlar içeren 8 paragrafı HTML’den görsele dönüştürme: 2019 MacBook Pro’da 9 ms, 2012 MacBook Pro’da 13 ms
    • 500’den fazla paragraflık The Little Prince’i HTML’den görsele dönüştürme: 2019 MacBook Pro’da 160 ms’nin altında, 2012 MacBook Pro’da 250 ms’nin altında
    • 10 karakterlik kelime oluşturup yalnızca layout yapma: 2019 MacBook Pro’da 25 µs’nin altında, 2012 MacBook Pro’da 50 µs’nin altında
  • En hızlı performans, DOM’u hyperscript API ile doğrudan oluşturup normal HTML/CSS ayrıştırma adımlarını atladığınızda elde edilir
  • style nesnelerini yeniden kullanmak daha fazla avantaj sağlar
  • Farklı genişliklerde reflow yapmak, layout tree’yi yeniden oluşturmaktan daha hızlıdır

API yapısı

  • Temel adımlar ikidir
    • Font kaydı
    • Hyperscript API veya Parse API ile DOM oluşturma
  • Basit kullanımda DOM doğrudan canvas’a render edilebilir
    • renderToCanvas(el, canvas), tüm layout’u render etmek için canvas’ın width ve height değerlerini viewport boyutu olarak kullanır
  • Daha düşük seviyeli API kullanıldığında layout korunabilir
    • Bağımlı kaynakları yükleme
    • DOM’un layout’unu oluşturma
    • layout reflow
    • HTML5 canvas gibi bir hedefe paint etme
  • Bu yöntem farklı boyutlara reflow yapmak, görünmeyen layout’u paint etmemek veya intrinsics elde etmek için kullanılabilir

Font işleme

  • Bir Dropflow programının ilk adımı, CSS font özellikleriyle seçilecek fontları kaydetmektir
  • Dropflow sistem fontlarını aramaz, bu nedenle en az bir kez FontFace oluşturup eklemek gerekir
  • Font kayıt API’si CSS Font Loading API’nin bir alt kümesini uygular ve standart dışı loadSync metodunu ekler
  • Sunucu tarafında file:/// URL’leri readFileSync ile senkron yüklenebilir
  • ArrayBuffer, tarayıcıdaki gibi constructor’da hemen yüklenir
  • registerNotoFonts, tüm Noto Sans font ailelerini kaydeder
    • Fontlar FontSource tarafından dağıtılır ve jsDelivr tarafından barındırılır
    • 200’den fazla Noto Sans fontu bulunduğu ve CJK fontlarının unicodeRange dizeleri büyük olduğu için büyük bir import’tur
    • Tarayıcıda production kullanımında tek tek fontları kaydetmenin daha iyi olduğu belirtilir
    • Latin için italic fontlar kaydedilir; tüm script’ler için normal 400 ve bold 700 kaydedilir
  • Çince, Korece ve Japonca ortak Unicode code point’leri paylaşır; ancak karakterler farklı render edilebildiğinden, mümkünse belirli dile ait font kullanmak daha iyidir

Layout, reflow, paint

  • layout(el), box tree, fragmentation tree ve glyph’leri içeren bir layout oluşturur
    • box tree genel olarak DOM tree ile eşleşir; ancak anonim metin içeriği nedeniyle daha fazla box oluşabilir veya display: none nedeniyle daha az olabilir
  • reflow(layout, width = 640, height = 480), box’ları yerleştirir, metni satırlara böler ve paint edilebilir hale getirir
    • block box’larda margin collapsing
    • Metni HarfBuzz’a aktarma
    • Font fallback yinelemesi
    • Satır sonu ve break point’lere göre reshaping
    • float yerleşimi ve clear işleme
    • direction ve metin yönüne göre shaped text span ve background yerleşimi
    • float, inline-block, absolute içeriklerinin intrinsics hesaplaması
    • normal flow sonrasında position işleme
  • Paint hedefleri şu anda Canvas ve SVG destekler
    • paintToCanvas, tarayıcı canvas’ına, node-canvas’a ve benzer standart uyumlu context’lere paint eder
    • paintToSvg, SVG string’i oluşturur ve FontFace’e verilen URL’lere referans veren @font-face kurallarını içerir
    • paintToSvgElements, mevcut bir SVG içine çizim yapmak için <svg> ve @font-face kurallarını eklemez
    • paintToHtml, mutlak konumlandırılmış öğelerden flat list oluşturur; kullanımı önerilmez ama geliştirme sırasında yararlı olabilir

DOM API ve ortam hook’ları

  • Hyperscript ve Parse API’den alınan kök HTMLElement, tarayıcının querySelector ailesine benzer şekilde tag name, id, class ile öğe bulma metotları sağlar
    • query(selector) tek bir HTMLElement veya null döndürür
    • queryAll(selector) HTMLElement[] döndürür
  • HTMLElement bağlı bir render box’a sahip olabilir
    • Genellikle birdir; ancak inline ve block içerikler karıştığında birden fazla olabilir
    • BlockContainer, absolute positioned element, floated element, inline-block ve block-level element için oluşturulur
    • ReplacedBox görseller için oluşturulur
  • Dropflow, çeşitli ortamlara uyarlanabilecek şekilde tasarlanmıştır
    • Tarayıcıda font ve görseller fetch ile yüklenir; font buffer’ları document.fonts içine kaydedilir
    • Nodejs’te fontlar fs.readFileSync ile senkron yüklenebilir
    • canvas arka ucu ve node-canvas varsa node-canvasın registerFont metodu çağrılır
    • node-canvas font buffer desteklemediğinden file:// URL kullanılmalıdır
  • @napi-rs/canvas veya skia-canvas kullanmak için flow.environment.registerFont’u ilgili font kayıt API’sine bağlayan birkaç satır kod gerekir
  • Ortamda 6 hook bulunur
    • wasmLocator
    • registerFont
    • resolveUrl
    • resolveUrlSync
    • createDecodedImage
    • destroyDecodedImage

HarfBuzz tabanlı metin shaping

  • Glyph layout, WebAssembly’ye derlenmiş HarfBuzz tarafından yapılır
  • measureText API ile metin span konumlandırma yaklaşımıyla elde edilmesi zor olan doğruluğu hedefler
  • Örnek olarak Google Sheets’te "AV" içindeki yalnızca "V" farklı renkle boyanırsa kerning kaybolur ve harfler normalden daha uzak görünür
    • Çünkü iki measureText ve fillText çağrısı karakter bazında gerçekleşir; bu da contextual glyph advance’i ortadan kaldırır
  • Dropflow, rengin değiştiği noktada değil, daha kaba shaping boundary’lerinde HarfBuzz kullanarak fontları daha doğru destekler
  • WebAssembly’ye derlenmiş HarfBuzz, CanvasRenderingContext2D’nin measureText metoduna benzer performans göstergeleri sunabilir
    • measureText kadar hızlı değildir, ama belirgin ölçüde yavaş da olmadığı belirtilir
    • İkisinin de metin düzeni yığınındaki baskın darboğaz olmadığı belirtilir
  • measureText tabanlı metin düzeninin hızlı çalışması için word cache gerekir; GSuite uygulamalarının bu yöntemi kullandığı belirtilir
    • word cache, boşlukları aşan etkileri olan fontları destekleyemez
    • Bu tür fontları desteklemek için paragrafın break index’lerinde ikili arama gerekir ve bunun tüm paragrafı HarfBuzz’a vermekten çok daha yavaş olduğu belirtilir
    • Renkli aksan işaretleri measureText ile mümkün değildir

Bağımlı projeler

  • Dropflow’un package.json bağımlılığı yoktur; ancak birçok projenin çalışmalarından yararlanır
  • JavaScript bağımlılıkları projeye check-in edilmiştir; odağı korumak ve dependency-of-dependency sorunlarından kaçınmak için çeşitli düzeylerde değiştirilmiştir
  • Başlıca projeler şunlardır

3 yorum

 
winterjung 2024-03-23

Orijinal başlık meğerse "Show HN: Dropflow, a CSS layout engine for node or <canvas>" imiş. Şu anda ise "GN⁺: HN Tanıtımı: Node veya <canvas> için CSS yerleşim motoru, Dropflow</canvas>" olarak girilmiş görünüyor.

 
dlehals2 2024-03-22

Başlıkta etiket olduğu için detay sayfasındaki başlık kısmı bozuluyor sanırım.. haha escape lazım..

 
GN⁺ 2024-03-22
Hacker News yorumları
  • Günümüzde backend'de güzel görünümlü PDF üretmenin temel yolu bir headless browser başlatıp tarayıcı API'siyle HTML/CSS'yi PDF'ye dönüştürmek; ancak sunucuda tarayıcı örnekleri çalıştırmanın ve büyük iş yüklerine göre ölçeklemenin maliyeti epey yüksek.
    Bu, oyunu değiştiren bir araç; artık tarayıcı ek yükü olmadan HTML/CSS ile PDF tasarlayıp üretebilirsiniz.

    • Web'in buraya kadar gelmiş olması şaşırtıcı. Güzel PDF belgeleri üretmenin en iyi yolunun sunucuda web tarayıcısını olduğu gibi çalıştırmak olması, 90'larda ya da 2000'lerde hayal etmesi zor bir şey olurdu.
    • Tarayıcı kullanmanın avantajı, üretilen PDF'nin vektörler ve fontlar kullanması. Canvas tabanlı yaklaşımda ise PDF içinde çoğu şey muhtemelen görüntü olur; yine de çoğu kullanım için bu büyük bir sorun olmayabilir.
    • https://ekoopmans.github.io/html2pdf.js/ kullandım ve oldukça iyi çalıştı.
    • Biraz kafam karıştı. Yan proje backend'imde PDF üretimi için uzun süredir Prawn kütüphanesini kullanıyorum: https://github.com/prawnpdf/prawn
      Yalnız benim ürettiğim PDF'ler kesinlikle pek güzel değil; fark bu olabilir.
    • Bazı müşteriler için PDF renderer'ları geliştirdim; PDF'lerde en büyük gereksinim erişilebilirlikti.
      Hepsinin ADA uyumlu olması gerekiyordu, bu yüzden Canvas renderer'a geçmek zor. Çünkü böyle olunca erişilebilirlik kayboluyor.
  • Gerçekten iyi görünüyor. Önceki işimde sürükleyici bir çevrimiçi öğrenme platformu geliştirmiştik; Oculus Quest 2 ile Savunma Bakanlığı personeline yabancı dil eğitimi veriyor, WebXR, Three.js vb. kullanıyorduk.
    Unity3D bir kez yeterliydi; app store incelemesinden geçmek de istemiyorduk. Kendi cihaz filomuz olduğu için sorun değildi.
    En büyük zorluklardan biri ders materyali içerik iş akışını oluşturmaktı ve bunu neredeyse tek başıma yapmam gerekti. Gerçek dil eğitmenleri PowerPoint ile PDF hazırlıyor, benim yaptığım özel editörle PDF'leri içerik veritabanına yüklüyor, eğitim ortamına yerleştiriyor, ardından PDFJS ile Canvas öğesine render edip 3D bir dikdörtgenin dokusu olarak kullanıyordum.
    Böyle bir araç olsaydı insanlar materyal hazırlamak için PowerPoint etrafından dolanmak zorunda kalmazdı. PowerPoint yöntemi, önceki denemede insanlara Photoshop ile görsel hazırlatmaktan çok daha hızlı bir iş akışı sağlamıştı; ama uygulamanın içine bir tabela editörü koyabilseydik “ortamda nasıl görüneceğini tahmin et → PDF olarak dışa aktar → DB'ye yükle → gerçek görünümü kontrol et” döngüsünü ortadan kaldıracağı için daha iyi olurdu.
    Gerçi ürün değil yalnızca hizmet satmayı bilen bir iş geliştirme ya da pazarlama ekibimiz olmadığı için bunun da pek anlamı olmazdı.

  • Kendi projem https://htwins.net/scale2 ve SVG ya da Canvas kullanan diğer çalışmalar için böyle bir şey arıyordum.

    • Bunu nasıl yaptığını anlatan yapım hikâyesini mutlaka okumak isterim.
  • Flexbox ile uğraşıyorsanız, responsive layout hazırlarken birden fazla özellikle ilgilenmemeniz için süreci sadeleştiren bir araç kullanabilirsiniz: https://flexboxcss.com

    • Gerçekten gördüğüm siteler arasında neumorphic design kullanan ilk örnek bu. Estetiği iyi; pratikte daha önce görmemiştim.
  • Harika. Bu tür araçlar, tarayıcı rendering engine denen sihirli kutuyu anlaşılır hale getirdiği için çok önemli.
    HTML ve CSS rendering hakkında tamamen makine tarafından okunabilir bir spesifikasyon oluşturulabilirse renderer üretmek mümkün olurdu. Tarayıcıya özgü tuhaf davranışlar bunun üzerinde extension olarak yer alabilir. https://github.com/tawesoft/html5spec gibi bir şeyin gerçek engine'lerde kullanılacak hale gelmesi güzel olurdu.

    • Bu bana Ladybird'ün sıfırdan yazılan bir tarayıcı olduğunu hatırlattı; ayrıca spesifikasyonlarda gerçekten hata olup olmadığını kontrol etmek için de epey yararlı olmuştu.
  • Son zamanlarda merak ettiğim şeye oldukça yakın. CSS ve SVG'nin, grafik ve UI kütüphanelerinin üzerinde bir soyutlama katmanı olarak kullanılıp kullanılamayacağını düşünüyordum.
    node-canvas'ı ilk kez duydum; bunun çizim tarafını tamamlıyor gibi görünüyor. Bu araç ise bir UI kütüphanesinden ihtiyaç duyduğum her şey olan layout kısmını üstlenebilir gibi.
    CSS implementasyonunun ne kadar zor olduğunu da merak ediyorum. Epey karmaşık olduğunu duymuştum.

    • CSS ile native grafik kütüphanelerini hedefleyen Sciter adlı başka bir proje de var: https://sciter.com
      CSS implementasyonu zordu, ama en büyük engel bilginin iyi görünür olmamasıydı.
      En zor kısım metin yerleşimi. Glyph'lerle uğraşmak ve RTL için geriye doğru dolaşmak baş ağrıtıcı; satır kırma da gerçekten karmaşık hale geliyor. Gerekli bilginin tek bir yerde toplanmamış olması işi daha da zorlaştırıyor.
      Başlarda block layout'u bitirdikten sonra birkaç yıl boyunca haftada yalnızca birkaç saat çalışarak text shaping ve itemization ayrıntılarını, yapılacakları ve kaçınılacakları öğrenmem gerekti. Birçok şeyi Pango [1] kaynak kodunu okuyarak öğrendim, kalanını da Google aramalarıyla bir araya getirdim.
      Bunun dışında W3C spesifikasyonları neredeyse her şeyi kapsıyor. CSS2 standardı [2], şimdiye kadar okuduğum en güzel belgelerden biriydi. İçsel olarak tutarlı ve öz; yıllar süren düşünme ve deneme-yanılmanın sonucu. CSS3 de harika ama CSS2 her şeyin temeli.
      [1] https://gitlab.gnome.org/GNOME/pango/
      [2] https://www.w3.org/TR/CSS22/
  • Dünyaya büyük bir katkı. Herkesin “birinin $X yapması lazım” diye düşündüğü ama kimsenin yapmadığı klasik örneklerden biri gibi görünüyor.
    Layout için CSS kullanmayı seven biri olarak bugünlerde çoğunlukla Flexbox ve Grid'e dayanıyorum. Henüz desteklememeniz tamamen anlaşılır; ama bir gün destekleme planınız olup olmadığını merak ediyorum. Varsa başkaları nasıl yardımcı olabilir?

  • Gerçekten müthiş. HTML'yi programatik olarak PNG'ye dönüştürmenin ne kadar zor olduğunu çoğu kişi muhtemelen bilmiyor.
    Node ile tarayıcı arasındaki farklar ya da HTML ile Canvas arasındaki farklar yüzünden sayısız küçük sorunla karşılaşıyorsunuz.

  • Yararlı görünüyor. Önce CSS'yi anlayıp onun üzerine bir layout engine inşa etmenin ne kadar çok iş gerektirdiğini hayal etmek zor.