Apple Metin Düzenleyicisinin Teknik İç Yapısı
(papereditor.app)- Paper, Apple platformlarında TextKit 1 tabanlı bir
TextViewdüzenleyicisi olarak çalışır;NSTextStorage,NSTextContainer,NSLayoutManager,TextViewveScrollViewbirlikte düzenleme deneyimini oluşturur NSAttributedString, dizgeyi ve aralıklara göre öznitelikleri (attribute) kullanarak zengin metni temsil eder; Paper, Markdown yapısına yönelik meta öznitelikleri ekranda gösterime yönelik stil özniteliklerinden ayırır- Stil güncellemesi; belge açma, metin değişikliği ve ayar değişikliğine göre farklılaşır. Yerleşimi etkileyen öznitelikler transaction içinde gruplanır, dekorasyon öznitelikleri ise yerleşim yeniden hesaplanmadan güncellenir
- Giriş performansı, Markdown özel karakterlerinin çevresinde düzenleme yapılıp yapılmadığına bakarak tüm paragrafı yeniden ayrıştırmaktan kaçınan bir yöntemle iyileştirilir; ancak kod bloğu gibi belgenin tamamının stilini etkileyebilecek yapılar için istisna işleme gerekir
- Kopyala-yapıştır, UTI ve pasteboard’un birden fazla veri temsili üzerinde çalışır; Markdown gibi Apple’ın tanımlamadığı yarı açık UTI’ler, uygulamalar arası öncelik uyumsuzluğu nedeniyle RTF dönüşümü ve UX sorunları doğurabilir
Apple TextView düzenleme yığını
- Paper, eski TextKit 1 framework’ü üzerine inşa edilmiştir; aynı kavramlar ve soyutlamalar TextKit 2’de de aynen bulunur ya da daha iyi API’lerin altında yer alır
NSTextViewveUITextViewarasında farklar olsa da API’leri yeterince benzer olduğundan tek birTextViewailesi olarak ele alınabilirTextView, her OS sürümüyle daha karmaşık hâle gelen büyük bir bileşendir; TextEdit uygulaması neredeyse tek birTextView’dan oluşur-
Düzenleyiciyi oluşturan temel katmanlar
NSTextStorage- Orijinal metin dizgesini saklar
- Metin aralıklarına bağlı dizge-değer çiftlerinden oluşan öznitelikleri saklar
- Metin ve öznitelik değişikliği olayları üretir
NSTextContainer- Gliflerin yerleştirileceği alanın şeklini ve boyutunu tanımlar
- Çoğunlukla dikdörtgendir, ancak keyfi şekiller de mümkündür
NSLayoutManagerNSTextStorageiçindeki öznitelik aralıklarına bakarak glif boyutlarını ve aralıklarını hesaplar- Fonttan vektör glifleri çıkarır ve bir karakteri bir veya daha fazla glife dönüştürür
- Her satırın başlangıcını ve sonunu, satır sayısını ve toplam metin yüksekliğini hesaplar
TextViewNSLayoutManagertarafından oluşturulan glif yerleşimini çizer- Görünüm yüksekliğini mevcut metin yerleşimi yüksekliğiyle senkronize eder
- Giriş, seçim alanı, imleç, giriş öznitelikleri,
textContainerInset, dikte, kopyala-yapıştır, yazım denetimi vb. işlemleri yönetir
ScrollViewTextView’ın görünen bölümünü, kaydırmayı, kaydırma çubuklarını ve yakınlaştırmayı yönetirTextView’ıntextContainerInsetdeğerinden bağımsız olarakcontentInsetdeğerine sahip olabilir
-
AppKit ve UIKit’te kaydırma farkları
- AppKit’te
NSScrollView,NSClipViewve ikiNSScrolleriçerir;NSClipView,NSTextView’ı barındırır ve birden fazla sınıf birlikte kaydırma davranışını oluşturur - UIKit’te
UITextView,UIScrollView’dan kalıtım aldığı için kaydırma mantığını da doğrudan içerir - İmleç,
contentInsetile sınırlanan görünür alanın dışına çıkarsaUITextViewotomatik olarak kaydırır - iOS düzenleyicide imlecin klavyenin arkasına gittiğinde bir sonraki satıra kaydırılması, alt
contentInsetdeğerinin mevcut klavye yüksekliğine dinamik olarak ayarlanmasından kaynaklanır
- AppKit’te
NSAttributedString ve öznitelik sorgulama
NSAttributedString, Apple framework’lerinde zengin metin düzenleme temelidir ve iki unsurdan oluşur- Düz metin dizgesi
- Dizge içindeki metin aralıklarına bağlı dizge-değer öznitelik çiftleri
- Öznitelikler çoğunlukla stillendirme için kullanılır, ancak geliştirici ihtiyaç duyduğu keyfi dizge-değer çiftlerini de ekleyebilir
NSRange,locationvelengthdeğerlerinden oluşur;NSMakeRange(10, 5), 10 konumundan başlayan 5 karakterlik aralığı, yani 10~14 konumlarını ifade eder- Aynı konuma aynı öznitelik birden fazla aralıkta atanırsa en son uygulanan aralık önceliklidir
-
Belirli bir konumdaki özniteliği ve aralığı kontrol etme
- Belirli bir konumdaki öznitelik değeri
attribute:atIndex:effectiveRange:ile kontrol edilir - Dönen değer
nilise ilgili öznitelik yoktur; dönen değer varsa örnek bağlamındaNSFontveyaUIFontnesnesi gibi bir öznitelik değeridir - Son argüman olarak bir
NSRangepointer’ı verilirse aynı değere sahip özniteliğin devam ettiği aralık veya özniteliğin olmadığı boş aralık alınabilir - Dokümantasyona göre
effectiveRangemutlaka en büyük aralık değildir ve implementasyona bağlıdır - Garanti edilen en büyük aralık gerekiyorsa
attribute:atIndex:longestEffectiveRange:inRange:kullanılmalıdır - Belirli bir konumdaki tüm öznitelik kombinasyonlarını ve bu kombinasyonun devam ettiği aralığı döndüren bir metot da vardır
- Bir aralık içindeki öznitelikleri dolaşmak için
enumerateAttribute:inRange:options:usingBlock:kullanılabilir
- Belirli bir konumdaki öznitelik değeri
Paper’ın Markdown stillendirme hattı
- Paper’ın stillendirmesi, metin aralıklarına framework tarafından tanımlanan özel öznitelikler uygulama yöntemidir
- Stillendirme öncesinde metin yapısını belirlemek için özel meta öznitelikler de kullanılır
-
Meta öznitelikler ve stil öznitelikleri
- Meta öznitelikler
- Markdown ayrıştırıcısı tarafından Markdown sözdiziminin tekil bölümlerini tanımlamak için belirlenir
- Tamamen anlamsal bilgiye yönelik özel dizge-değer çiftleridir
- Metnin görsel görünümünü etkilemez
- Markdown için basitleştirilmiş bir AST gibi düşünülebilir
- Stil öznitelikleri
- Meta özniteliklerle işaretlenmiş bölümlerin üzerine uygulanan görsel özniteliklerdir
- AppKit ve UIKit tarafından tanımlanan yerleşik dizge-değer çiftleridir
- Meta öznitelikler
-
Öznitelik güncellemesini tetikleyen olaylar
- Öznitelikler,
NSTextStorageiçindeki Markdown metni ve metni etkileyen ayar değişiklikleriyle senkronize edilir - Belge açma sırasında meta öznitelikler ve stil öznitelikleri tamamen güncellenir
- Metin değişikliği sırasında etkilenen bölümün meta öznitelikleri ve stil öznitelikleri kısmen güncellenir
- Ayar değişikliği sırasında meta öznitelikler değiştirilmez, yalnızca stil öznitelikleri tamamen güncellenir
- Öznitelikler,
-
Güncelleme sırası ve yerleşim maliyeti
- Önce öznitelik değişikliklerini gruplamak için bir metin düzenleme transaction’ı başlatılır
- Transaction olmadan öznitelikler değiştirilirse her seferinde
NSLayoutManagertarafından pahalı yerleşim yeniden hesaplaması yapılır - Markdown dizgesi ayrıştırılarak meta özniteliklerle işaretlenen parçalara bölünür; ayar değişikliğinde Markdown yapısı değişmediği için bu adım atlanır
- Glif konumunu veya boyutunu etkileyebilecek görsel öznitelikler önce güncellenir;
NSParagraphStyle, satır ve paragraf yerleşimini etkileyen en önemli öznitelik olarak ele alınır - Transaction sonlandırıldıktan sonra yerleşimi etkilemeyen dekorasyon öznitelikleri güncellenir
- Dekorasyon öznitelikleri, Apple terminolojisinde rendering özniteliklerine karşılık gelir;
NSTextStorage’da değilNSLayoutManager’da bulunduğu için transaction’dan haberdar değildir
-
Giriş öznitelikleri
- Giriş öznitelikleri (typing attributes), boş seçim alanında imlecin önündeki konumun öznitelikleriyle; boş olmayan seçim alanında ise seçimin başlangıç noktasındaki özniteliklerle ilişkilidir
- Karakter girildiğinde giriş öznitelikleri yeni eklenen metne otomatik olarak uygulanır
- Markdown düzenleyicide stil Markdown sözdiziminden türetildiği için önemi daha düşüktür
- Zengin metin düzenleyicide ise stil kapatılana veya imleç başka bir konuma taşınana kadar stil imlece bağlı kaldığından daha önemlidir
- Paper’ın Preview Mode’u, Markdown düzenleyici içinde de açılıp kapatılabilen giriş özniteliklerinin öne çıktığı bir zengin metin düzenleme deneyimi sunar
Giriş performansı ve meta özniteliklerin kullanımı
- Meta, yerleşim ve dekorasyon özniteliklerinin ayrılması, bazı düzenleyici değişikliklerini hızlı işlemeye yardımcı olur
- Açık/koyu mod geçişi yalnızca dekorasyon özniteliklerini güncellediği için yerleşimi tetiklemez ve çok hızlıdır
- Metin boyutu ayarı gibi ayar değişiklikleri tüm belge yerleşiminin yeniden hesaplanmasını gerektirir, ancak tüm Markdown yapısını yeniden ayrıştırmaktan daha hızlıdır
-
Markdown girişi optimizasyonu
- Metin düzenleyicisinin en önemli performans unsuru giriş hızıdır
- Markdown’un yapısı gereği tek bir metin değişikliği tüm paragraf stilini etkileyebilir
- Her tuş girişinde tüm paragrafı yeniden ayrıştırıp yeniden stillendirmek teknik olarak en doğru yöntemdir, ancak uzun paragraflarda düzenleme hızını düşürebilir
- Paper, girilen bir sonraki karaktere ve çevresindeki karakterlere bakarak davranışı ayıran bir algoritma kullanır
- Özel Markdown sembolleri girildiğinde veya düzenleme konumunun çevresinde özel semboller varsa tüm paragraf güncellenir
- Aksi durumda giriş özniteliklerine dayanarak çoğu giriş senaryosunda düzenleyiciyi hızlandırır
-
Kod bloğu istisnası ve değer nesnesi önbelleği
- Kod bloğu, Paper’da çok paragraflı tek Markdown yapısıdır
- Kod bloğu bulunan bir belgede tek bir tuş girişi tüm belgenin stilini etkileyebilir
- Paper, belirli bir karakter sayısını aşan belgelerde kod bloğu işlemeyi yok sayarak kodla ilgilenmeyen çoğu kullanıcı için düzenleyiciyi hızlı tutar
- Bu tercih, geliştiricilere yakın kullanıcılar için de Paper’ı daha kullanışlı kılar
- Karmaşık öznitelik değer nesneleri her tuş girişinde yeniden ayrılır, ancak metni etkileyen ayarlar değişmediği sürece değişmedikleri için önbelleğe alınıp yeniden kullanılır
NSFont/UIFontNSColor/UIColorNSParagraphStyle
-
Meta özniteliklerin kullanıldığı özellikler
- Biçimlendirme kısayolları
- Geçiş yapılabilmesi için seçili Markdown metninin mevcut stil bilgisini bilmek gerekir
- Seçim alanı aynı stili tamamen kapsıyorsa ilgili stil kaldırılır
- Seçim alanında aynı stil yoksa stil eklenir
- Seçim alanı aynı stili yalnızca kısmen kapsıyorsa stil seçim alanına taşınır
- heading ve blockquote gibi paragraf tipini tanımlayan çakışan stiller karıştırılamaz; bu yüzden yeni stil eklenmeden önce kaldırılmaları gerekir
- Bölümde gezinme
- Önceki veya sonraki bölüm sınırına giderken imleç konumuna göre heading bulmak için meta öznitelikler kullanılır
- Outline
- Tüm heading’leri dolaşır; outline öğesine basıldığında imleç ilgili bölüme taşınır
- Bölüm yeniden düzenleme
- Outline’da bölümler yeniden sıralanabilir
- Biçim dönüştürme
- Markdown’u RTF, HTML, DOCX’e dönüştürmek için metin yapısının bilinmesi gerekir
- Paper harici kütüphane içermediği için önceden ayrıştırılmış metin modelini dolaşarak çıktı biçimini oluşturur
- Biçimlendirme kısayolları
Metin container matematiği ve seçim davranışı
-
Satır uzunluğu ve kenar boşluğu hesaplama
- Metin container’ının temel kuralı, tercih edilen satır uzunluğunu korumak ve kalan alanı iki taraftaki inset’lere bölmektir
- Heading etiketlerinin normal metin akışının dışında konumlandırıldığı durumlarda olduğu gibi simetriyi yapay olarak eşitlemek gereken durumlar da vardır
- Bu durumda metin container’ı sola taşınır ve paragraf
NSParagraphStyleile girintilenir - Yeterli alan varsa kenar boşlukları görsel olarak simetriye yakın tutulur
- Ek alan yoksa belirlenen satır uzunluğunu koruyacak şekilde simetri bozulur, ancak bu yalnızca sağ padding kaldığı sürece yapılır
- Padding kalmazsa tercih edilen satır genişliği yerine minimum kenar boşluğu öncelik kazanır
minvemaxkombinasyonuyla kademeli olarak katlanan kenar boşlukları uygulanabilir
-
Seçim ankrajı
- Metin seçiminde her zaman bir ankraj noktası vardır
- Mac’te tıklayıp sürüklerken tıklanan nokta referans olur; o noktayı geçince seçimin artma/azalma yönü tersine döner
- iOS’te bir seçim tutamacı sürüklendiğinde karşı taraf ankraj olur; tersi durumda da aynı şey geçerlidir
- Klavyeyle seçimi genişletirken de aynı mantık uygulanır
Option+sol/sağ ok ile kelime sınırına gidilir;Shiftde birlikte basılırsa kelime bazında seçim yapılır- Tıklayıp sürükleyerek seçim yaptıktan sonra klavyeyle genişletmeye veya daraltmaya devam edilse bile ilk tıklama noktası ankraj olarak kalır
-
Seçim affinity’si
- Seçim affinity’si, satır sonu sınırında ekleme noktasının önceki satırın son karakterinden sonra mı, yoksa sonraki satırın ilk karakterinden önce mi görüneceğini belirler
- İmleç ok tuşlarıyla hareket ettirildiğinde satır sonu noktasındaki boşluk çevresinde basitçe satır değiştirilir
- Kısayolla satır sonuna gidildiğinde imleç aynı satırda kalabilir ve satır sonu boşluğunun sağına yapışabilir
TextView, buna benzer seçim affinity davranışını başka durumlarda da gerçekleştirir
-
Undo coalescing
- Undo coalescing, girilen metnin ne zaman tek bir geri alınabilir işlem olarak gruplanacağını belirleyen algoritmadır
TextView, başka bir eylemle kesintiye uğramadan girilen içeriği birlikte gruplayan basit bir algoritma kullanıyor gibi görünür- Arada durup yazmaya devam edilse bile tek bir undo’da gruplanır; satır sonu da coalescing’i kesmez
- Sublime, yazım sırasında ayrı kelimeleri undo birimi olarak gruplamayı tercih eder; uzun bir kelime yazılırken bazen daha küçük undo birimlerine de böler
- Bu davranışın tek bir doğru cevabı yoktur ve düzenleyiciler farklı stratejilere sahip olabilir
UTI, pasteboard ve uygulamalar arası veri alışverişi
-
Uniform Type Identifiers
- UTI, veri tiplerinin üst veri tiplerinden kalıtım alır gibi
conform toettiği hiyerarşik bir sistemdir public.*tipleri Apple tarafından tanımlanır vepublic.html,public.jpeggibi yaygın kullanılan biçimleri tanımlar- Geliştiriciler çakışmaları önlemek için ters domain adı düzeniyle kendi tanımlayıcılarını oluşturabilir
- Hiyerarşik sistemin avantajı, bir uygulama tüm metin biçimlerini görebiliyorsa tek tek tüm biçimleri listelemek yerine yalnızca
public.textbildirebilmesidir - Paper tüm metin dosyalarını açabildiğini bildirir; highlighting olmasa bile
.html,.rtfgibi metin biçimlerini açabilir - Dosya, platformlar arası bir kavram olduğundan pratikte dosya uzantısı tanımlayıcı olarak kullanılır
- Uyumluluk için tüm UTI’ler ilişkili bir veya daha fazla dosya uzantısı tanımlayabilir
- Markdown yaygın kullanılsa da Apple’ın tanımlamadığı bir biçim olduğundan yarı açık UTI ile ilgili zorlu örnekler ortaya çıkar
- UTI, veri tiplerinin üst veri tiplerinden kalıtım alır gibi
-
Pasteboard ve birden fazla temsil
- Apple’ın pasteboard’u, UTI’leri serileştirilmiş metin veya ikili verilere eşleyen bir sözlüktür
- Xcode Additional Tools içindeki Clipboard Viewer ile pasteboard içeriği gerçek zamanlı olarak kontrol edilebilir
- Tek bir kopyalama eylemi aynı verinin birden fazla temsilini eş zamanlı olarak yazar
- Bazı uygulamalar geriye dönük uyumluluk için
NeXT Rich Text Format v1.0 pasteboard typegibi eski UTI dışı tanımlayıcılar da kullanır - Düzenleyici genellikle işleyebildiği en zengin biçimi seçer
- Zengin metin düzenleyicideki
Paste and Match StyleveyaPaste as Plain Text, pasteboard’daki düz metin biçiminin kullanılmasını sağlar - Yapıştırılan metne uygulanan stil genellikle giriş özniteliklerinden alınır
- Sürükle-bırak da başka bir pasteboard temelinde çalışır
- Standart copy-paste için general pasteboard kullanılır; özelleştirilmiş uygulamalar arası etkileşimler için özel pasteboard oluşturulabilir
-
RTF ve
NSAttributedString- RTF temelde
NSAttributedString’in serileştirilmiş biçimidir; tersinden bakıldığındaNSAttributedString, RTF’nin programlama arayüzüdür TextView,NSAttributedString’in alt sınıfı olanNSTextStorageüzerinde çalıştığı için pasteboard ile varsayılan olarak uyumludur- Ek kod yazmadan içerik pasteboard’a kopyalanabilir
- RTF temelde
-
Markdown UTI’sinin uygulamalar arası sorunları
- Markdown düzenleyiciler arasında kopyala-yapıştırda, iki uygulama standart protokolü uygulasa bile sorun çıkabilir
- İlk düzenleyici Markdown’u
public.text, zengin metin temsilinipublic.rtfolarak dışa aktarırsa ikinci düzenleyici bunun native Markdown olduğunu anlayamaz vepublic.rtf’yi seçebilir - Bu durumda gereksiz çift dönüşüm gerçekleşir; uygulamaların Markdown↔RTF dönüşüm yöntemleri farklı olduğundan ek satır sonları gibi küçük biçimlendirme sorunları ortaya çıkabilir
- Markdown ve RTF arasındaki temel stil farkları da görünür hâle gelebilir
- Doğal çalışması için iki uygulamanın da
net.daringfireball.markdownUTI’sini dışa aktarması ve bunupublic.rtf’den öncelikli tutması gerekir - Paper, Markdown UTI’sini dışa aktarmaya çalıştı, ancak diğer uygulamaların bunu zengin metinden daha öncelikli tutmadığı görüldü
- Pages,
net.daringfireball.markdown’upublic.rtf’den öncelikli tutar; ancak zengin metne dönüştürmeden orijinal Markdown dizgesini aynen ekleyen bir davranış gösterir - Bu nedenle Paper, Markdown UTI’sini kaldırdı
-
Paper’ın RTF sunma nedeni ve iOS paylaşımı
- Paper, zengin metin düzenleyicilerle doğal biçimde kopyala-yapıştır yapılabilmesi için RTF sunar
- İyi bir OS vatandaşı olarak, kopyalanan veriyi temsil eden birden fazla biçim sunmak gerekir; böylece alıcı uygulama işleyebildiği en zengin biçimi seçebilir
- Paper’da Markdown metni kopyalayıp Mail uygulamasına yapıştırdığınızda, Markdown varyantı olarak değil, güzel biçimlendirilmiş zengin metin olarak yapıştırılır
- iOS’in paylaşım özelliği, copy-paste’e benzer ancak üzerine UI eklenmiş bir biçimdir
- iOS paylaşımında uygulama veriyi birden fazla biçimde dışa aktarır ve alıcı uygulama istediği biçimi seçer
- Pasteboard’dan farklı olarak iOS paylaşımının üst uygulama listesinde görünmek için uygulamanın özel UI’ye sahip bir share extension’ı açıkça sağlaması gerekir
1 yorum
Hacker News yorumları
Gerçekten harika. Artık TextKit’e giriş materyali olarak sanırım https://www.objc.io/issues/5-ios7/getting-to-know-textkit/ yerine önce bu yazıya bakacağım
iOS ve MacOS’taki metin alanlarında varsayılan olarak kullanılan yeni yerleşim motoru bu; ileride tek seçenek haline gelme olasılığı yüksek
TextEdit uygulaması neredeyse tamamen tek bir TextView’dan oluşuyor
Windows tarafındaki karşılığı, RichEdit denetimi tabanlı WordPad sayılabilir. Bir başka ilginç nokta da RTF’nin fiilen NSAttributedString’in serileştirme biçimi olması
Windows’un RichEdit denetimi için de aynı durum geçerli; hatta Windows uygulaması daha önce çıkmış gibi görünüyor: https://en.wikipedia.org/wiki/Rich_Text_Format
Düzenleme işlemi dışında dekorasyon özniteliklerinin işlenmesi kısmı biraz kafamı karıştırdı. “NSLayoutManager’ın kendisinde bulunuyor ve NSTextStorage’da olmadığı için transaction’dan haberdar bile değil” diye bir açıklama vardı; oysa renk gibi dekorasyon öznitelikleri genellikle NSTextStorage’da yer alır
Yazarın Markdown karakterlerine uyguladığı rengi NSLayoutManager’ın geçici öznitelik desteğiyle işlediğini mi kastediyor? Normalde yazım hatası olan kelimeleri renklendirmek için kullanılan bir özellik; amacının ne olduğunu merak ediyorum
Geçici öznitelik kullanmanın avantajı, NSTextStorage’ın tüm transaction’ını çağırmaktan çok daha hızlı değişiklik yapılabilmesi. Örneğin Paper’da açık/koyu mod geçişi çok hızlı
Gerçekten iyi bir yazı; kişisel olarak ben de şu sıralar NSTextView ile uğraştığım için tam zamanında geldi
Böyle bir yazıyı yazmak için gereken bilgileri nasıl edindiğinizi merak ediyorum. Başkalarının kodlarından mı, sancılı deneyimlerden mi, developer.apple.com’dan mı?
DOM belgeleri çağında Notion veya GitBook’a bakarken bile, metin ayrıştırma ve manipülasyonda sihirli işler yapmak gerektiğinde sık sık öznitelikli string’lere geri dönüyorum
Gerçekten zarif bir yapı; neden bu kadar az bilindiğini anlayamıyorum. Yazı da inanılmaz derecede iyi
Daha önce tamamen sıfırdan kendi metin editörümü yapmayı denemiş biri olarak, o zaman böyle bir yazı olsaydı muazzam bir kaynak olurdu diye düşünüyorum
Bu uygulamayı gerçekten çok iyi kullanıyorum. Obsidian ve iA Writer dahil diğer tüm Markdown uygulamalarının yerini aldı
Daha fazla iOS bileşeni için böyle dokümantasyonlar olsa keşke
2024’te hâlâ birilerinin Cocoa ile uğraşıyor olması sevindirici
Uzun süredir Android uygulamaları geliştiren biri olarak, Apple’ın işleri biraz farklı ve daha dikkatli ele alış biçimi ilginç geldi
Android’de varsayılan olarak yerleşim ve rendering ile ilgili her şeyi Layout sınıfı ve alt sınıfları yürütür; TextView de düzenleme ve seçim mantığının bir kısmını uygular. EditText ile TextView arasındaki tek fark, EditText’in TextView içinde zaten bulunan düzenleme özelliklerini açık hale getirmesidir
Bu biraz tek parça yaklaşımın ve zayıf API’nin sorunu, uygulamanın metin rendering’i üzerinde daha ince denetim istediğinizde tıkanmanızdır. Örneğin yerleşim tamamlandıktan sonra tek tek gliflere erişmek isteseniz bile bu mümkün değildir