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!
--- 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