! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays alien alien.c-types alien.syntax kernel
-destructors accessors fry words hashtables strings
-sequences memoize assocs math math.functions locals init
-namespaces combinators fonts colors core-foundation
-core-foundation.strings core-foundation.attributed-strings
-core-foundation.utilities core-graphics core-graphics.types
-core-text.fonts core-text.utilities ;
+USING: arrays alien alien.c-types alien.data alien.syntax kernel
+destructors accessors fry words hashtables strings sequences
+memoize assocs math math.order math.vectors math.rectangles
+math.functions locals init namespaces combinators fonts colors
+cache core-foundation core-foundation.strings
+core-foundation.attributed-strings core-foundation.utilities
+core-graphics core-graphics.types core-text.fonts ;
IN: core-text
TYPEDEF: void* CTLineRef
-C-GLOBAL: kCTFontAttributeName
-C-GLOBAL: kCTKernAttributeName
-C-GLOBAL: kCTLigatureAttributeName
-C-GLOBAL: kCTForegroundColorAttributeName
-C-GLOBAL: kCTParagraphStyleAttributeName
-C-GLOBAL: kCTUnderlineStyleAttributeName
-C-GLOBAL: kCTVerticalFormsAttributeName
-C-GLOBAL: kCTGlyphInfoAttributeName
+C-GLOBAL: CFStringRef kCTFontAttributeName
+C-GLOBAL: CFStringRef kCTKernAttributeName
+C-GLOBAL: CFStringRef kCTLigatureAttributeName
+C-GLOBAL: CFStringRef kCTForegroundColorAttributeName
+C-GLOBAL: CFStringRef kCTParagraphStyleAttributeName
+C-GLOBAL: CFStringRef kCTUnderlineStyleAttributeName
+C-GLOBAL: CFStringRef kCTVerticalFormsAttributeName
+C-GLOBAL: CFStringRef kCTGlyphInfoAttributeName
FUNCTION: CTLineRef CTLineCreateWithAttributedString ( CFAttributedStringRef string ) ;
CTLineCreateWithAttributedString
] with-destructors ;
-TUPLE: line font line metrics dim bitmap age refs disposed ;
+TUPLE: line < disposable line metrics image loc dim ;
-: compute-line-metrics ( line -- line-metrics )
- 0 <CGFloat> 0 <CGFloat> 0 <CGFloat>
- [ CTLineGetTypographicBounds ] 3keep [ *CGFloat ] tri@
- metrics boa ;
+: typographic-bounds ( line -- width ascent descent leading )
+ { CGFloat CGFloat CGFloat }
+ [ CTLineGetTypographicBounds ] [ ] with-out-parameters ; inline
-: bounds>dim ( bounds -- dim )
+: store-typographic-bounds ( metrics width ascent descent leading -- metrics )
+ {
+ [ >>width ]
+ [ >>ascent ]
+ [ >>descent ]
+ [ >>leading ]
+ } spread ; inline
+
+: compute-font-metrics ( metrics font -- metrics )
+ [ CTFontGetCapHeight >>cap-height ]
+ [ CTFontGetXHeight >>x-height ]
+ bi ; inline
+
+: compute-line-metrics ( open-font line -- line-metrics )
+ [ metrics new ] 2dip
+ [ compute-font-metrics ]
+ [ typographic-bounds store-typographic-bounds ] bi*
+ compute-height ;
+
+: metrics>dim ( bounds -- dim )
[ width>> ] [ [ ascent>> ] [ descent>> ] bi + ] bi
- [ ceiling >fixnum ]
+ [ ceiling >integer ]
bi@ 2array ;
: fill-background ( context font dim -- )
: selection-rect ( dim line selection -- rect )
[ start>> ] [ end>> ] bi
- [ f CTLineGetOffsetForStringIndex ] bi-curry@ bi
+ [ f CTLineGetOffsetForStringIndex round ] bi-curry@ bi
[ drop nip 0 ] [ swap - swap second ] 3bi <CGRect> ;
-:: fill-selection-background ( context dim line string -- )
+: CGRect-translate-x ( CGRect x -- CGRect' )
+ [ dup CGRect-x ] dip - over set-CGRect-x ;
+
+:: fill-selection-background ( context loc dim line string -- )
string selection? [
context string color>> >rgba-components CGContextSetRGBFillColor
- context dim line string selection-rect CGContextFillRect
+ context dim line string selection-rect
+ loc first CGRect-translate-x
+ CGContextFillRect
] when ;
-: set-text-position ( context metrics -- )
- [ 0 ] dip descent>> ceiling CGContextSetTextPosition ;
+: line-rect ( line -- rect )
+ dummy-context CTLineGetImageBounds ;
+
+: set-text-position ( context loc -- )
+ first2 [ neg ] bi@ CGContextSetTextPosition ;
+
+:: line-loc ( metrics loc dim -- loc )
+ loc first
+ metrics ascent>> ceiling dim second loc second + - 2array ;
:: <line> ( font string -- line )
[
- [let* | open-font [ font cache-font CFRetain |CFRelease ]
- line [ string open-font font foreground>> <CTLine> |CFRelease ]
- metrics [ line compute-line-metrics ]
- dim [ metrics bounds>dim ] |
- dim [
- {
- [ font dim fill-background ]
- [ dim line string fill-selection-background ]
- [ metrics set-text-position ]
- [ [ line ] dip CTLineDraw ]
- } cleave
- ] with-bitmap-context
- [ open-font line metrics dim ] dip 0 0 f
- ]
- line boa
- ] with-destructors ;
+ line new-disposable
-M: line dispose* [ font>> CFRelease ] [ line>> CFRelease ] bi ;
+ font cache-font :> open-font
+ string open-font font foreground>> <CTLine> |CFRelease :> line
-: ref/unref-line ( line n -- )
- '[ _ + ] change-refs 0 >>age drop ;
+ line line-rect :> rect
+ rect origin>> CGPoint>loc :> (loc)
+ rect size>> CGSize>dim :> (dim)
+ (loc) (dim) v+ :> (ext)
+ (loc) [ floor ] map :> loc
+ (loc) (dim) [ + ceiling ] 2map :> ext
+ ext loc [ - >integer 1 max ] 2map :> dim
+ open-font line compute-line-metrics :> metrics
-: ref-line ( line -- ) 1 ref/unref-line ;
-: unref-line ( line -- ) -1 ref/unref-line ;
+ line >>line
-SYMBOL: cached-lines
+ metrics >>metrics
-: cached-line ( font string -- line )
- cached-lines get [ <line> ] 2cache ;
+ dim [
+ {
+ [ font dim fill-background ]
+ [ loc dim line string fill-selection-background ]
+ [ loc set-text-position ]
+ [ [ line ] dip CTLineDraw ]
+ } cleave
+ ] make-bitmap-image >>image
-CONSTANT: max-line-age 10
+ metrics loc dim line-loc >>loc
-: age ( obj -- ? )
- [ 1+ ] change-age age>> max-line-age >= ;
+ metrics metrics>dim >>dim
+ ] with-destructors ;
-: age-line ( line -- ? )
- #! Outputs t whether the line is dead.
- dup refs>> 0 = [ age ] [ drop f ] if ;
+M: line dispose* line>> CFRelease ;
-: age-assoc ( assoc quot -- assoc' )
- '[ nip @ ] assoc-partition
- [ values dispose-each ] dip ; inline
+SYMBOL: cached-lines
-: age-lines ( -- )
- cached-lines global [ [ age-line ] age-assoc ] change-at ;
+: cached-line ( font string -- line )
+ cached-lines get [ <line> ] 2cache ;
-[ H{ } clone cached-lines set-global ] "core-text" add-init-hook
\ No newline at end of file
+[ <cache-assoc> cached-lines set-global ] "core-text" add-startup-hook