resume in layout-engine, ot-layout-engine

main
Matthew Butterick 7 years ago
parent 3aba76f338
commit 1f2e685e8b

@ -0,0 +1,43 @@
#lang fontkit/racket
(provide (all-defined-out))
(define VARIATION_FEATURES '(rvrn))
(define COMMON_FEATURES '(ccmp locl rlig mark mkmk))
(define FRACTIONAL_FEATURES '(frac numr dnom))
(define HORIZONTAL_FEATURES '(calt clig liga rclt curs kern))
(define VERTICAL_FEATURES '(vert))
(define DIRECTIONAL_FEATURES (mhasheq
'ltr '(ltra ltrm)
'rtl '(rtla rtlm)))
(define zeroMarkWidths 'AFTER_GPOS)
(define-subclass object% (DefaultShaper)
(define/public (plan plan_ glyphs features)
;; Plan the features we want to apply
(planPreprocessing plan_)
(planFeatures plan_)
(planPostprocessing plan_ features)
;; Assign the global features to all the glyphs
(send plan_ assignGlobalFeatures glyphs)
;; Assign local features to glyphs
(assignFeatures plan_ glyphs))
(define/public (planPreprocessing plan)
(send plan add (mhasheq
'global (append VARIATION_FEATURES (dict-ref DIRECTIONAL_FEATURES (· plan direction)))
'local FRACTIONAL_FEATURES)))
(define/public (planFeatures plan)
;; Do nothing by default. Let subclasses override this.
(void))
(define/public (planPostprocessing plan userFeatures)
(send plan add (append COMMON_FEATURES HORIZONTAL_FEATURES userFeatures)))
(define/public (assignFeatures plan glyphs)
;; todo: Enable contextual fractions
(void)))

@ -236,7 +236,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js
((string?) ((option/c (listof symbol?)) (option/c symbol?) (option/c symbol?)) . ->*m . GlyphRun?)
(unless (· this _layoutEngine)
(set-field! _layoutEngine this (+LayoutEngine this)))
(report* 'in-layout (· this _layoutEngine))
(report*/file 'in-layout (· this _layoutEngine))
(send (· this _layoutEngine) layout string userFeatures script language))

@ -0,0 +1,24 @@
#lang fontkit/racket
(provide (all-defined-out))
(define-subclass object% (GlyphInfo font-in id-in [codePoints-in empty] [features-in (mhasheq)])
(field [_font font-in]
[codePoints codePoints-in]
[id id-in]
[features (mhasheq)])
(cond
[(list? features-in)
(for ([feature (in-list features-in)])
(hash-set! features feature #t))]
[(object? features-in)
(hash-set! features (· features-in features))])
(field [ligatureID #f]
[ligatureComponent #f]
[ligated #f]
[cursiveAttachment #f]
[markattachment #f]
[shaperInfo #f]
[substituted #f]))

@ -6,31 +6,5 @@
;; Returned by the font layout method.
(define-subclass object% (GlyphRun
glyphs ; An array of Glyph objects in the run
features-in
script ; The script that was requested for shaping. This was either passed in or detected automatically.
language) ; The language requested for shaping, as passed in. If `null`, the default language for the script was used.
;; An array of GlyphPosition objects for each glyph in the run
(field [positions #f])
;; The directionality of the requested script (either ltr or rtl).
(field [direction (Script-direction script)])
;; The features requested during shaping. This is a combination of user
;; specified features and features chosen by the shaper.
(field [features (cond
[(hash? features-in) features-in]
;; Convert features to an object
[(list? features-in)
(define f (mhash))
(for ([tag (in-list features)])
(hash-set! f tag #t))
f]
[(not features-in) (mhash)]
[else (error 'glyphrun:unknown-features-type)])])
)
positions) ; An array of GlyphPosition objects for each glyph in the run
)

@ -31,53 +31,55 @@ https://github.com/mbutterick/fontkit/blob/master/src/layout/LayoutEngine.js
(define/contract (layout this str-or-glyphs [features #f]
;; Attempt to detect the script if not provided.
[script (report (if (string? str-or-glyphs)
[script (if (string? str-or-glyphs)
(Script-forString str-or-glyphs)
(Script-forCodePoints (append-map (λ (g) (· g codePoints)) str-or-glyphs))))]
(Script-forCodePoints (append-map (λ (g) (· g codePoints)) str-or-glyphs)))]
[language #f])
(((or/c string? (listof Glyph?))) ((option/c list?) (option/c symbol?) (option/c symbol?)) . ->*m . GlyphRun?)
(define glyphs
;; Map string to glyphs if needed
(if (string? str-or-glyphs)
(send (· this font) glyphsForString str-or-glyphs)
str-or-glyphs))
(define glyphRun (make-object GlyphRun glyphs features script language))
(report*/file 'starting-layout-in-layout-engine glyphs)
(cond
[(empty? glyphs) (+GlyphRun glyphs empty)] ; Return early if there are no glyphs
[else
;; Setup the advanced layout engine
(when (and (· this engine) #;(·? engine setup))
(send (· this engine) setup glyphs features script language))
(if (empty? glyphs)
(set-field! positions glyphRun empty)
(begin
;; Setup the advanced layout engine ; todo
;; Substitute and position the glyphs
(set! glyphs (send this substitute glyphs features script language))
(define positions (send this position glyphs features script language))
;; Substitute and position the glyphs
(send this substitute glyphRun)
(send this position glyphRun)
(send this hideDefaultIgnorables glyphRun)
;; Let the layout engine clean up any state it might have
(and (· this engine) (· this engine cleanup))))
glyphRun)
;; Let the layout engine clean up any state it might have
(when (and (· this engine) #;(·? this engine cleanup))
(· this engine cleanup))
(+GlyphRun glyphs positions)]))
(define/contract (substitute this glyphRun)
((is-a?/c GlyphRun) . ->m . void?)
(define (substitute this glyphs features script language)
#;((is-a?/c GlyphRun) . ->m . void?)
;; Call the advanced layout engine to make substitutions
(when (and (· this engine) (· this engine substitute))
(send (· this engine) substitute glyphRun)))
(when (and (· this engine) #;(· this engine substitute))
(send (· this engine) substitute glyphs features script language))
glyphs)
(define/contract (position this glyphRun)
((is-a?/c GlyphRun) . ->m . void?)
(define (position this glyphs features script language)
((listof Glyph?) (option/c list?) (option/c symbol?) (option/c symbol?) . ->m . (listof GlyphPosition?))
(define positions (for/list ([g (in-list (· glyphRun glyphs))])
(make-object GlyphPosition (· g advanceWidth))))
(set-field! positions glyphRun positions)
(define positions (for/list ([glyph (in-list glyphs)])
(make-object GlyphPosition (· glyph advanceWidth))))
#|
;; Call the advanced layout engine. Returns the features applied.
(define positioned
(and (· this engine) (· this engine position)
(send (· this engine) position glyphRun)))
(and (· this engine) #;(· this engine position)
(send (· this engine) position glyphs positions features script language)))
;; if there is no GPOS table, use unicode properties to position marks.
;; todo: implement unicodelayoutengine
@ -85,7 +87,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/layout/LayoutEngine.js
;; if kerning is not supported by GPOS, do kerning with the TrueType/AAT kern table
;; todo: implement kerning
(void)
|#
positions
)
@ -94,15 +97,15 @@ https://github.com/mbutterick/fontkit/blob/master/src/layout/LayoutEngine.js
(define space (send (· this font) glyphForCodePoint #x20))
(define-values (new-glyphs new-positions)
(for/lists (ngs nps)
([glyph (in-list (· glyphRun glyphs))]
[pos (in-list (· glyphRun positions))])
(cond
[(send this isDefaultIgnorable (car (· glyph codePoints)))
(define new-pos pos)
(set-field! xAdvance new-pos 0)
(set-field! yAdvance new-pos 0)
(values space new-pos)]
[else (values glyph pos)])))
([glyph (in-list (· glyphRun glyphs))]
[pos (in-list (· glyphRun positions))])
(cond
[(send this isDefaultIgnorable (car (· glyph codePoints)))
(define new-pos pos)
(set-field! xAdvance new-pos 0)
(set-field! yAdvance new-pos 0)
(values space new-pos)]
[else (values glyph pos)])))
(set-field! glyphs glyphRun new-glyphs)
(set-field! positions glyphRun new-positions))

@ -1,5 +1,5 @@
#lang fontkit/racket
(require "gsub-processor.rkt" "gpos-processor.rkt")
(require "gsub-processor.rkt" "gpos-processor.rkt" "glyphinfo.rkt" (prefix-in Shapers- "shapers.rkt") "shaping-plan.rkt")
(provide (all-defined-out))
#|
@ -8,6 +8,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/OTLayoutEngine.js
(define-subclass object% (OTLayoutEngine font)
(field [glyphInfos #f]
[shaper #f]
[plan #f]
[GSUBProcessor #f]
[GPOSProcessor #f])
@ -18,10 +19,18 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/OTLayoutEngine.js
(set-field! GSUBProcessor this (+GSUBProcessor font (· font GSUB))))
(report* 'starting-gpos-dingdong)
(report* 'dingdong!-starting-gpos)
(when (· font has-gpos-table?)
(set-field! GPOSProcessor this (+GPOSProcessor font (· font GPOS))))
(define/public (setup glyphs features script language)
;; Map glyphs to GlyphInfo objects so data can be passed between
;; GSUB and GPOS without mutating the real (shared) Glyph objects.
(set! glyphInfos (map (λ (glyph) (+GlyphInfo (· this font) (· glyph id) (· glyph codePoints))) glyphs))
)
;; Choose a shaper based on the script, and setup a shaping plan.
;; This determines which features to apply to which glyphs.
(set! shaper (Shapers-choose script))
#;(set! plan (+ShapingPlan (· this font) script language))
(send (· this shaper) plan (· this plan) (· this glyphInfos) features)))

@ -0,0 +1,68 @@
#lang fontkit/racket
(require "default-shaper.rkt")
(provide (all-defined-out))
;; todo: alternative shapers
(define SHAPERS
(hasheq
; 'arab ArabicShaper ;; Arabic
; 'mong ArabicShaper ;; Mongolian
; 'syrc ArabicShaper ;; Syriac
; '|nko | ArabicShaper ;; N'Ko
; 'phag ArabicShaper ;; Phags Pa
; 'mand ArabicShaper ;; Mandaic
; 'mani ArabicShaper ;; Manichaean
; 'phlp ArabicShaper ;; Psalter Pahlavi
;
; 'hang HangulShaper ;; Hangul
;
; 'bali UniversalShaper ;; Balinese
; 'batk UniversalShaper ;; Batak
; 'brah UniversalShaper ;; Brahmi
; 'bugi UniversalShaper ;; Buginese
; 'buhd UniversalShaper ;; Buhid
; 'cakm UniversalShaper ;; Chakma
; 'cham UniversalShaper ;; Cham
; 'dupl UniversalShaper ;; Duployan
; 'egyp UniversalShaper ;; Egyptian Hieroglyphs
; 'gran UniversalShaper ;; Grantha
; 'hano UniversalShaper ;; Hanunoo
; 'java UniversalShaper ;; Javanese
; 'kthi UniversalShaper ;; Kaithi
; 'kali UniversalShaper ;; Kayah Li
; 'khar UniversalShaper ;; Kharoshthi
; 'khoj UniversalShaper ;; Khojki
; 'sind UniversalShaper ;; Khudawadi
; 'lepc UniversalShaper ;; Lepcha
; 'limb UniversalShaper ;; Limbu
; 'mahj UniversalShaper ;; Mahajani
; ';; mand UniversalShaper ;; Mandaic
; ';; mani UniversalShaper ;; Manichaean
; 'mtei UniversalShaper ;; Meitei Mayek
; 'modi UniversalShaper ;; Modi
; ';; mong UniversalShaper ;; Mongolian
; ';; 'nko ' UniversalShaper ;; NKo
; 'hmng UniversalShaper ;; Pahawh Hmong
; ';; phag UniversalShaper ;; Phags-pa
; ';; phlp UniversalShaper ;; Psalter Pahlavi
; 'rjng UniversalShaper ;; Rejang
; 'saur UniversalShaper ;; Saurashtra
; 'shrd UniversalShaper ;; Sharada
; 'sidd UniversalShaper ;; Siddham
; 'sinh UniversalShaper ;; Sinhala
; 'sund UniversalShaper ;; Sundanese
; 'sylo UniversalShaper ;; Syloti Nagri
; 'tglg UniversalShaper ;; Tagalog
; 'tagb UniversalShaper ;; Tagbanwa
; 'tale UniversalShaper ;; Tai Le
; 'lana UniversalShaper ;; Tai Tham
; 'tavt UniversalShaper ;; Tai Viet
; 'takr UniversalShaper ;; Takri
; 'tibt UniversalShaper ;; Tibetan
; 'tfng UniversalShaper ;; Tifinagh
; 'tirh UniversalShaper ;; Tirhuta
'latn DefaultShaper ;; Latin
'DFLT DefaultShaper)) ;; Default
(define (choose script)
(dict-ref SHAPERS script DefaultShaper))

@ -0,0 +1,9 @@
#lang fontkit/racket
(provide (all-defined-out))
; * ShapingPlans are used by the OpenType shapers to store which
; * features should by applied, and in what order to apply them.
; * The features are applied in groups called stages. A feature
; * can be applied globally to all glyphs, or locally to only
; * specific glyphs.

@ -12417,6 +12417,9 @@ var TTFFont = (_class = function () {
* @return {GlyphRun}
*/
TTFFont.prototype.layout = function layout(string, userFeatures, script, language) {
console.log("userFeatures="+userFeatures);
console.log("script="+script);
console.log("language="+language);
return this._layoutEngine.layout(string, userFeatures, script, language);
};

@ -37,7 +37,7 @@
return null;
}
relative = (function() {
console.log("pointer-scope="+this.options.type)
//console.log("pointer-scope="+this.options.type)
switch (this.options.type) {
case 'local':
return ctx._startOffset;
@ -56,13 +56,13 @@
if (this.options.relativeTo) {
relative += this.relativeToGetter(ctx);
}
console.log("this._startOffset= "+this._startOffset);
console.log("ctx= "+ctx);
console.log("ctx._startOffset= "+ctx._startOffset);
console.log("offset= "+ offset)
console.log("relative= "+ relative)
//console.log("this._startOffset= "+this._startOffset);
//console.log("ctx= "+ctx);
//console.log("ctx._startOffset= "+ctx._startOffset);
//console.log("offset= "+ offset)
//console.log("relative= "+ relative)
ptr = offset + relative;
console.log("ptr="+ptr+" size="+this.offsetType.size());
//console.log("ptr="+ptr+" size="+this.offsetType.size());
if (this.type != null) {
val = null;
decodeValue = (function(_this) {

@ -48,7 +48,7 @@
for (key in fields) {
type = fields[key];
console.log("key= " + key );
//console.log("key= " + key );
if (typeof type === 'function') {
val = type.call(res, res);
} else {

@ -14,6 +14,7 @@
pitfall/test/test11
pitfall/test/test12 ; ttf subset
pitfall/test/test13 ; subset with composites
pitfall/test/test14 ; Fira ttf with GPOS
pitfall/test/test14 ; Fira ttf with GPOS (no kerning)
;pitfall/test/test15 ; Fira ttf with GPOS kerning
pitfall/page-test
(submod pitfall/zlib test)))

@ -43,11 +43,13 @@ https://github.com/mbutterick/pdfkit/blob/master/lib/font/embedded.coffee
(define/contract (encode this text [features #f])
((string?) ((option/c list?)) . ->*m .
(list/c (listof string?) (listof GlyphPosition?)))
(report*/file 'starting-layout-in-embedded (description (· this font)))
(define glyphRun (send (· this font) layout text features))
(define glyphs (· glyphRun glyphs))
(for ([g (in-list glyphs)])
(· g id))
(define positions (· glyphRun positions))
(report positions)
(define-values (subset-idxs new-positions)
(for/lists (idxs posns)
([(glyph i) (in-indexed glyphs)]

@ -24,7 +24,8 @@
sugar/dict
sugar/stub
sugar/port
sugar/contract)
sugar/contract
describe)
(module reader syntax/module-reader
#:language 'pitfall/racket

Binary file not shown.

@ -1,5 +1,7 @@
#lang pitfall/pdftest
;; test kerning from GPOS
(define-runtime-path ttf-path "assets/fira.ttf")
(define (proc doc)
@ -12,7 +14,7 @@
[fontSize 25]
[text "ATAVATA" 100 100 (hash 'width #f)]))
;; test against non-subsetted font version
(define-runtime-path this "test15rkt.pdf")
(make-doc this #f proc #:test #f)

@ -2,6 +2,11 @@
(require sugar/list)
(provide text-mixin)
#|
approximates
https://github.com/mbutterick/pdfkit/blob/master/lib/mixins/text.coffee
|#
(define (text-mixin [% mixin-tester%])
(class %
(super-new)

Loading…
Cancel
Save