X11/XFT: Fixed a baaad bug in font caching causing horrible performance regression jv
authorJan Vrany <jan.vrany@fit.cvut.cz>
Mon, 29 Feb 2016 07:18:01 +0000
branchjv
changeset 7171 71c34a23762b
parent 7170 e5374bb05083
child 7177 03d926bea344
X11/XFT: Fixed a baaad bug in font caching causing horrible performance regression ...since fonts were not cached. The problem was that XftFontDescription>>#face and #style returned empty string if face or style was nil and therefore test in #sameDeviceFontAs: failed. Do not default to '' there!
FcConstants.st
FontDescription.st
XftFontDescription.st
--- a/FcConstants.st	Sun Feb 28 14:47:05 2016 +0000
+++ b/FcConstants.st	Mon Feb 29 07:18:01 2016 +0000
@@ -1,4 +1,4 @@
-'From Smalltalk/X jv-branch, Version:6.2.5.0 on 17-02-2016 at 10:52:35 AM'      !
+"{ Package: 'stx:libview' }"
 
 "{ NameSpace: Smalltalk }"
 
@@ -26,11 +26,13 @@
 		FC_CHARCELL FC_RGBA_UNKNOWN FC_RGBA_RGB FC_RGBA_BGR FC_RGBA_VRGB
 		FC_RGBA_VBGR FC_RGBA_NONE FC_HINT_NONE FC_HINT_SLIGHT
 		FC_HINT_MEDIUM FC_HINT_FULL FC_LCD_NONE FC_LCD_DEFAULT
-		FC_LCD_LIGHT FC_LCD_LEGACY StXFace2FCWeightMap StXStyle2FCSlantMap'
+		FC_LCD_LIGHT FC_LCD_LEGACY StXFace2FCWeightMap
+		StXStyle2FCSlantMap'
 	poolDictionaries:''
 	category:'Graphics-Support-FontConfig'
 !
 
+
 !FcConstants class methodsFor:'class initialization'!
 
 initialize
@@ -141,7 +143,8 @@
     FC_LCD_LEGACY           := 3.
 
     StXFace2FCWeightMap := Dictionary withKeysAndValues:{
-        '' . 	      FC_WEIGHT_NORMAL .
+        nil .         FC_WEIGHT_NORMAL .
+        '' .          FC_WEIGHT_NORMAL .
         'thin'.       FC_WEIGHT_THIN.
         'extralight'. FC_WEIGHT_EXTRALIGHT.
         'ultralight'. FC_WEIGHT_ULTRALIGHT.
@@ -161,13 +164,22 @@
         'ultrablack'. FC_WEIGHT_ULTRABLACK.
     }.
     StXStyle2FCSlantMap := Dictionary withKeysAndValues:{
-    	''.         FC_SLANT_ROMAN .
+        nil .       FC_SLANT_ROMAN .
+        ''.         FC_SLANT_ROMAN .
         'roman'.    FC_SLANT_ROMAN.
         'italic'.   FC_SLANT_ITALIC.
         'oblique'.  FC_SLANT_OBLIQUE.
     }.
 
     "Created: / 17-02-2016 / 10:49:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 29-02-2016 / 07:45:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!FcConstants class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
 ! !
 
 
--- a/FontDescription.st	Sun Feb 28 14:47:05 2016 +0000
+++ b/FontDescription.st	Mon Feb 29 07:18:01 2016 +0000
@@ -958,20 +958,34 @@
 sameDeviceFontAs:aFont
     aFont species == self species ifFalse:[^ false].
 
-    (family = aFont family) ifFalse:[ ^ false ].
-    (face = aFont face) ifFalse:[ ^ false ].
-    ((style = aFont style) 
-      or:[ (style = 'italic' and:[aFont style = 'oblique'])
-      or:[ style = 'oblique' and:[aFont style = 'italic']]]) ifFalse:[ ^ false ].
+    ^ self sameFamily: aFont family 
+                 face: aFont face
+                style: aFont style 
+                 size: aFont size 
+                 unit: aFont sizeUnit 
+            pixelSize: aFont pixelSize
+             encoding: aFont encoding
+
+    "Modified: / 29-02-2016 / 08:30:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
 
-    (encoding isNil or:[encoding = aFont encoding]) ifFalse:[ ^ false ].
-    (sizeUnit ? #pt) = aFont sizeUnit ifFalse:[ ^ false ].
+sameFamily: otherFamily face: otherFace style: otherStyle size: otherSize unit: otherSizeUnit pixelSize: otherPixelSize encoding: otherEncoding
+    (family = otherFamily) ifFalse:[ ^ false ].
+    (face = otherFace) ifFalse:[ ^ false ].
+    ((style = otherStyle) 
+      or:[ (style = 'italic' and:[otherStyle = 'oblique'])
+      or:[ style = 'oblique' and:[otherStyle = 'italic']]]) ifFalse:[ ^ false ].
+
+    (encoding isNil or:[encoding = otherEncoding]) ifFalse:[ ^ false ].
+    (sizeUnit ? #pt) = otherSizeUnit ifFalse:[ ^ false ].
     (sizeUnit ? #pt) == #pt ifTrue:[
-        (size = aFont size) ifFalse:[ ^ false ].
+        (size = otherSize) ifFalse:[ ^ false ].
     ] ifFalse:[
-        (pixelSize = aFont pixelSize) ifFalse:[ ^ false ].
+        (pixelSize = otherPixelSize) ifFalse:[ ^ false ].
     ].
     ^ true
+
+    "Created: / 29-02-2016 / 08:28:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !FontDescription methodsFor:'converting'!
--- a/XftFontDescription.st	Sun Feb 28 14:47:05 2016 +0000
+++ b/XftFontDescription.st	Mon Feb 29 07:18:01 2016 +0000
@@ -156,37 +156,42 @@
     |proto|
 
     RecentlyUsedFonts notNil ifTrue:[
-	proto := RecentlyUsedFonts
-		detect:[:fn |
-		    fn family = familyString
-		    and:[ fn size = size and:[fn sizeUnit = sizeUnit
-		    and:[ fn face = faceString
-		    and:[ (fn style = styleString
-			  or:[ (fn style = 'oblique' and:[styleString = 'italic'])
-			  or:[ (fn style = 'italic' and:[styleString = 'oblique']) ]]) ]]]]]
-		ifNone:nil.
-	proto notNil ifTrue:[
-	    ^ proto
-	].
+        proto := RecentlyUsedFonts
+                detect:[:fn |
+                    fn sameFamily: familyString 
+                             face: faceString
+                            style: styleString 
+                             size: size 
+                             unit: sizeUnit 
+                        pixelSize: nil
+                         encoding: encoding]
+                ifNone:[ nil ].
+        proto notNil ifTrue:[
+            ^ proto
+        ].
     ].
 
     CachedFontList notNil ifTrue:[
-	proto := CachedFontList
-		detect:[:fn |
-		    fn family = familyString
-		    and:[ fn face = faceString
-		    and:[ (fn style = styleString
-			  or:[ (fn style = 'oblique' and:[styleString = 'italic'])
-			  or:[ (fn style = 'italic' and:[styleString = 'oblique']) ]]) ]]]
-		ifNone:nil.
-	proto notNil ifTrue:[
-	    ^ (proto shallowCopy)
-		setDevice: nil patternId: nil fontId: nil;
-		family:familyString face:faceString style:styleString size:size sizeUnit:sizeUnit encoding:encoding
-	].
+        proto := CachedFontList
+                detect:[:fn |
+                    fn sameFamily: familyString 
+                             face: faceString
+                            style: styleString 
+                             size: size 
+                             unit: sizeUnit 
+                        pixelSize: nil
+                         encoding: encoding]
+                ifNone:[ nil ].
+        proto notNil ifTrue:[
+            ^ (proto shallowCopy)
+                setDevice: nil patternId: nil fontId: nil;
+                family:familyString face:faceString style:styleString size:size sizeUnit:sizeUnit encoding:encoding
+        ].
     ].
     ^ super
-	family:familyString face:faceString style:styleString size:size sizeUnit:sizeUnit encoding:encoding
+        family:familyString face:faceString style:styleString size:size sizeUnit:sizeUnit encoding:encoding
+
+    "Modified: / 29-02-2016 / 08:34:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 for:aFontOrFontDescription
@@ -319,10 +324,6 @@
     ^ encoding ? 'iso10646-1'
 !
 
-face
-    ^ face ? ''
-!
-
 fullName
     ^ name ? (self userFriendlyName)
 !
@@ -353,10 +354,6 @@
     ^ size ? 0
 !
 
-style
-    ^ style ? ''
-!
-
 weight:aNumber
     "set the weight"
 
@@ -752,120 +749,93 @@
     "Create a new XftFont representing the closes font as
      myself on aDevice; if one already exists, return the one."
 
+    ^ self onDevice: aGraphicsDevice ifAbsent: nil
+
+    "Modified: / 14-04-1997 / 18:22:31 / cg"
+    "Modified: / 29-02-2016 / 07:08:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+onDevice:aGraphicsDevice ifAbsent: aBlock
+    "Create a new XftFont representing the closes font as
+     myself on aDevice; if one already exists, return the one."
+
     | myPatternId closestPatternId1 closestPatternId2 newFontId |
 
-    "if I am already assigned to that device ..."
-    (device == aGraphicsDevice) ifTrue:[^ self].
-
-    (aGraphicsDevice isNil and:[device notNil]) ifTrue:[
-	^ self
+    (device == aGraphicsDevice) ifTrue:[
+        "I am already assigned to that device ..."
+        ^ self
+    ].
+    aGraphicsDevice isNil ifTrue:[
+        ^ self
     ].
     aGraphicsDevice supportsXftFonts ifFalse:[
-	^ super onDevice:aGraphicsDevice
-    ].
-
-    (closestFont notNil and:[closestFont graphicsDevice == aGraphicsDevice]) ifTrue:[
-	^ closestFont onDevice: aGraphicsDevice.
+        ^ super onDevice:aGraphicsDevice ifAbsent:aBlock.
     ].
 
     RecentlyUsedFonts isNil ifTrue:[
-	RecentlyUsedFonts := OrderedCollection new:10.
+        RecentlyUsedFonts := OrderedCollection new:20.
     ].
 
     RecentlyUsedFonts keysAndValuesDo:[:index :aFont |
-	((aFont class == self class) and:[(self sameDeviceFontAs:aFont) and:[aFont getFontId notNil]]) ifTrue:[
-	    "/ Transcript showCR:'hit'.
-	    RecentlyUsedFonts removeIndex:index.
-	    RecentlyUsedFonts addFirst:aFont.
-	    ^ aFont
-	]
+        ((aFont class == self class) and:[(self sameDeviceFontAs:aFont)]) ifTrue:[
+            "/ Transcript showCR:'hit'.
+            RecentlyUsedFonts
+                removeIndex:index;
+                addFirst:aFont.
+            ^ aFont
+        ]
     ].
 
-    RecentlyUsedFonts size > 20 ifTrue:[
-	RecentlyUsedFonts removeLast.
+    RecentlyUsedFonts size >= 20 ifTrue:[
+        RecentlyUsedFonts removeLast.
     ].
 
     aGraphicsDevice deviceFonts do:[:aFont |
-	((aFont class == self class) and:[self sameDeviceFontAs:aFont]) ifTrue:[
-	    RecentlyUsedFonts addFirst:aFont.
-	    ^ aFont
-	].
-    ].
+        ((aFont class == self class) and:[self sameDeviceFontAs:aFont]) ifTrue:[
+            RecentlyUsedFonts addFirst:aFont.
+            ^ aFont
+        ].
+    ]. 
 
+    "/ Transcript show: 'XFT font not found in cache:'; showCR: self printString.
     [
-	Error handle:[:ex |
-	    ex suspendedContext fullPrintAll.
-	    ^ self asNonXftFont onDevice:aGraphicsDevice
-	] do:[
-	    myPatternId := FcPattern fromFontDescription: self.
-	].
-
-	newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: myPatternId.
-	newFontId notNil ifTrue:[
-	    "/ Good, this font exists!!
+        myPatternId := FcPattern fromFontDescription: self. 
+        newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: myPatternId.
+        newFontId notNil ifTrue:[
+            "/ Good, this font exists!!
             myPatternId := nil.
-	    fontId := newFontId.
-	    device := aGraphicsDevice.
-	    aGraphicsDevice registerFont:self.
-	    RecentlyUsedFonts addFirst:self.
-	    ^ self.
-	] ifFalse:[
-	    closestPatternId1 := self xftFontMatch: aGraphicsDevice displayId screen: aGraphicsDevice screen pattern: myPatternId.
-	    closestPatternId1 isNil ifTrue:[
-		self error: 'No font matches'.
-	    ].
-	    "
-	    closestPatternId at: 'family'
-	    closestPatternId at: 'size'
-	    "
-	    closestPatternId2 := closestPatternId1 copy.
-	    newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: closestPatternId1.
-	    "/ !!!!!!!! closestPatternId is no longer valid !!!!!!!!
-	    closestPatternId1 :=  nil.
-	    newFontId isNil ifTrue:[
-		self error: 'Pattern matched, but font could not be opened (should not happen)'.
-	    ].
-
-	    "/ Search for existing registered font. Note, that XftFont instances
-	    "/ are shared (and refcounted) so newFontId = aFont getFontId is enough
-	    "/ to check whether some other font instance represents the same font...
-	    aGraphicsDevice deviceFonts do:[:aFont |
-		((self class == aFont class) and:[newFontId = aFont getFontId]) ifTrue:[
-		    closestFont := aFont.
-		    ^ closestFont
-		].
-	    ].
-
-	    closestFont := self shallowCopy
-				setDevice: aGraphicsDevice patternId: closestPatternId2 fontId: newFontId;
-				yourself.
-	    aGraphicsDevice registerFont: closestFont.
-	    RecentlyUsedFonts addFirst:closestFont.
-	    ^ closestFont
-	].
+        ] ifFalse:[
+            closestPatternId1 := self xftFontMatch: aGraphicsDevice displayId screen: aGraphicsDevice screen pattern: myPatternId.
+            closestPatternId1 isNil ifTrue:[
+                self error: 'No font matches'.
+            ].
+            closestPatternId2 := closestPatternId1 copy.
+            newFontId := self xftFontOpenPattern: aGraphicsDevice displayId pattern: closestPatternId1.
+            "/ !!!!!!!! closestPatternId is no longer valid !!!!!!!!
+            closestPatternId1 :=  nil.
+            newFontId isNil ifTrue:[
+                ^ aBlock value
+            ].
+        ].
+        fontId := newFontId.
+        device := aGraphicsDevice.
+        aGraphicsDevice registerFont:self.
+        RecentlyUsedFonts addFirst:self.
+        myPatternId notNil ifTrue:[myPatternId release].
+        closestPatternId1 notNil ifTrue:[closestPatternId1 release].
+        closestPatternId2 notNil ifTrue:[closestPatternId2 release].
+        ^ self. 
     ] ensure:[
-	myPatternId notNil ifTrue:[myPatternId release].
-	closestPatternId1 notNil ifTrue:[closestPatternId1 release].
-	closestPatternId2 notNil ifTrue:[closestPatternId2 release].
+        myPatternId notNil ifTrue:[myPatternId release].
+        closestPatternId1 notNil ifTrue:[closestPatternId1 release].
+        closestPatternId2 notNil ifTrue:[closestPatternId2 release].
     ].
 
     "
      (XftFontDescription family:'monospace' size:16) onDevice:Screen current
     "
 
-    "Modified: / 14-04-1997 / 18:22:31 / cg"
-    "Modified: / 02-01-2014 / 23:43:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-!
-
-onDevice:aWorkstation ifAbsent:aBlock
-    "Create a new XftFont representing the same font as
-     myself on aWorkstation. This does NOT try to look for existing
-     or replacement fonts (i.e. can be used to get physical fonts)."
-
-    ^ self onDevice:aWorkstation
-
-    "Modified: / 02-01-2014 / 23:15:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified (comment): / 04-01-2014 / 02:06:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 29-02-2016 / 08:36:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !XftFontDescription methodsFor:'initialization'!
@@ -888,7 +858,7 @@
     ].
 
     "Created: / 21-12-2013 / 00:46:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 26-02-2016 / 16:41:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 29-02-2016 / 07:43:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 setName: aString