Skip to content

Commit 8cc083e

Browse files
authored
Merge pull request #16419 from Rinzwind/freetypecache-shrinkto
Change #shrinkTo: on FreeTypeCache to selectively remove entries rather than all of them
2 parents c451a72 + 7d1b3b6 commit 8cc083e

File tree

4 files changed

+113
-61
lines changed

4 files changed

+113
-61
lines changed

src/FreeType-Tests/FreeTypeCacheTest.class.st

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,17 +230,18 @@ FreeTypeCacheTest >> testMaximumSizeRespectedOnIfAbsentPut [
230230
ifAbsentPut: [font1XGlyph].
231231
self validateSizes: cache.
232232
self validateCollections: cache.
233+
self assert: (cache instVarNamed: #used) equals: (cache sizeOf: font1XGlyph).
233234
cache
234235
atFont: font1
235236
charCode: $Y asInteger
236237
type: FreeTypeCacheGlyph
237238
scale: 1
238239
ifAbsentPut: [font1XGlyph].
239-
self assert: (cache instVarNamed: #used) equals: 0. "cache has been cleared on reaching max size"
240+
self assert: (cache instVarNamed: #used) equals: (cache sizeOf: font1XGlyph). "cache has been shrunk on reaching max size"
240241
self validateSizes: cache.
241242
self validateCollections: cache.
242243
self should: [ cache atFont: font1 charCode: $X asInteger type: FreeTypeCacheGlyph scale: 1 ] raise: Error.
243-
self should: [ cache atFont: font1 charCode: $Y asInteger type: FreeTypeCacheGlyph scale: 1 ] raise: Error
244+
self assert: (cache atFont: font1 charCode: $Y asInteger type: FreeTypeCacheGlyph scale: 1) identicalTo: font1XGlyph.
244245
]
245246

246247
{ #category : 'tests' }
@@ -255,17 +256,18 @@ FreeTypeCacheTest >> testMaximumSizeRespectedOnPut [
255256
put: font1XGlyph.
256257
self validateSizes: cache.
257258
self validateCollections: cache.
259+
self assert: (cache instVarNamed: #used) equals: (cache sizeOf: font1XGlyph).
258260
cache
259261
atFont: font1
260262
charCode: $Y asInteger
261263
type: FreeTypeCacheGlyph
262264
scale: 1
263265
put: font1XGlyph.
264-
self assert: (cache instVarNamed: #used) equals: 0. "cache has been cleared on reaching max size"
266+
self assert: (cache instVarNamed: #used) equals: (cache sizeOf: font1XGlyph). "cache has been shrunk on reaching max size"
265267
self validateSizes: cache.
266268
self validateCollections: cache.
267269
self should: [ cache atFont: font1 charCode: $X asInteger type: FreeTypeCacheGlyph scale: 1 ] raise: Error.
268-
self should: [ cache atFont: font1 charCode: $Y asInteger type: FreeTypeCacheGlyph scale: 1 ] raise: Error
270+
self assert: (cache atFont: font1 charCode: $Y asInteger type: FreeTypeCacheGlyph scale: 1) identicalTo: font1XGlyph.
269271
]
270272

271273
{ #category : 'tests' }
@@ -544,7 +546,7 @@ FreeTypeCacheTest >> testSetMaximumSizeShrink [
544546
| m |
545547
m := fullCache instVarNamed: #maximumSize.
546548
fullCache maximumSize: m // 2. "shrink"
547-
self assert: (fullCache instVarNamed: #used) equals: 0. "cache is cleared when used > maximumSize"
549+
self assert: (fullCache instVarNamed: #used) equals: 5 * (fullCache sizeOf: font1YGlyph). "cache is shrunk when used > maximumSize"
548550
self validateSizes: fullCache.
549551
self validateCollections: fullCache
550552
]
@@ -576,8 +578,14 @@ FreeTypeCacheTest >> validateCollections: aFreeTypeCache [
576578
fifo := aFreeTypeCache instVarNamed: #fifo.
577579
lastLink := fifo instVarNamed: #lastLink.
578580
fontTableEntries := Set new.
579-
fontTable keysAndValuesDo: [ :k1 :v1 | v1 keysAndValuesDo: [ :k2 :v2 | v2 keysAndValuesDo: [ :k3 :v3 | v3 keysAndValuesDo: [ :k4 :v4 |
580-
fontTableEntries add: v4 ] ] ] ].
581+
fontTable keysAndValuesDo: [ :k1 :v1 |
582+
self denyEmpty: v1.
583+
v1 keysAndValuesDo: [ :k2 :v2 |
584+
self denyEmpty: v2.
585+
v2 keysAndValuesDo: [ :k3 :v3 |
586+
self denyEmpty: v3.
587+
v3 keysAndValuesDo: [ :k4 :v4 |
588+
fontTableEntries add: v4 ] ] ] ].
581589
self assert: fifo size equals: fontTableEntries size.
582590
self assert: fifo asSet equals: fontTableEntries.
583591
self assert: (lastLink isNil or: [ lastLink nextLink isNil ])

src/FreeType/FreeTypeCache.class.st

Lines changed: 92 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Class {
55
#name : 'FreeTypeCache',
66
#superclass : 'Object',
77
#instVars : [
8+
'mutex',
89
'maximumSize',
910
'used',
1011
'fontTable',
@@ -96,7 +97,7 @@ FreeTypeCache >> atFont: aFreeTypeFont charCode: charCodeInteger type: typeFlag
9697

9798
| charCodeTable typeTable scaleTable entry v vSize |
9899

99-
aFreeTypeFont mutex criticalReleasingOnError: [
100+
mutex criticalReleasingOnError: [
100101
charCodeTable := fontTable at: aFreeTypeFont ifAbsentPut:[self dictionaryClass new: 60].
101102
typeTable := charCodeTable at: charCodeInteger ifAbsentPut:[self dictionaryClass new: 10].
102103
scaleTable := typeTable at: typeFlag ifAbsentPut:[self dictionaryClass new: 1].
@@ -105,10 +106,16 @@ FreeTypeCache >> atFont: aFreeTypeFont charCode: charCodeInteger type: typeFlag
105106
ifNotNil:[
106107
fifo moveDown: entry.
107108
^entry object].
108-
v := aBlock value.
109+
v := aBlock on: Error do: [ :error |
110+
self removeIfEmptyScaleTable: scaleTable type: typeFlag typeTable: typeTable
111+
charCode: charCodeInteger charCodeTable: charCodeTable font: aFreeTypeFont.
112+
error pass].
109113
vSize := self sizeOf: v.
110114
(maximumSize isNotNil and:[vSize > maximumSize])
111-
ifTrue:[^v].
115+
ifTrue:[
116+
self removeIfEmptyScaleTable: scaleTable type: typeFlag typeTable: typeTable
117+
charCode: charCodeInteger charCodeTable: charCodeTable font: aFreeTypeFont.
118+
^v].
112119
used := used + vSize.
113120
entry := (self fifoEntryClass new
114121
font: aFreeTypeFont;
@@ -128,7 +135,7 @@ FreeTypeCache >> atFont: aFreeTypeFont charCode: charCodeInteger type: typeFlag
128135

129136
| charCodeTable typeTable scaleTable anObjectSize oldEntry oldEntrySize entry |
130137

131-
aFreeTypeFont mutex criticalReleasingOnError: [
138+
mutex criticalReleasingOnError: [
132139
anObjectSize := self sizeOf: anObject.
133140
(maximumSize isNotNil and:[anObjectSize > maximumSize])
134141
ifTrue:[^anObject].
@@ -156,6 +163,14 @@ FreeTypeCache >> atFont: aFreeTypeFont charCode: charCodeInteger type: typeFlag
156163
^ anObject ]
157164
]
158165

166+
{ #category : 'private - sizing' }
167+
FreeTypeCache >> basicRemoveAll [
168+
169+
fontTable := self dictionaryClass new: self fontTableInitialMinimumCapacity.
170+
fifo := self fifoClass new.
171+
used := 0
172+
]
173+
159174
{ #category : 'public' }
160175
FreeTypeCache >> cacheSize [
161176

@@ -186,12 +201,19 @@ FreeTypeCache >> fifoEntryClass [
186201
^ FreeTypeCacheEntry
187202
]
188203

204+
{ #category : 'private - sizing' }
205+
FreeTypeCache >> fontTableInitialMinimumCapacity [
206+
207+
^ 100
208+
]
209+
189210
{ #category : 'initialization' }
190211
FreeTypeCache >> initialize [
191212

192213
super initialize.
214+
mutex := Semaphore forMutualExclusion.
193215
maximumSize := self class defaultMaximumSize.
194-
fontTable := self dictionaryClass new: 100.
216+
fontTable := self dictionaryClass new: self fontTableInitialMinimumCapacity.
195217
used := 0.
196218
fifo := self fifoClass new
197219
]
@@ -205,68 +227,97 @@ FreeTypeCache >> maximumSize [
205227
{ #category : 'public' }
206228
FreeTypeCache >> maximumSize: anIntegerOrNil [
207229

208-
maximumSize := anIntegerOrNil.
209-
maximumSize ifNotNil:[
210-
used > maximumSize
211-
ifTrue:["shrink"
212-
self shrinkTo: maximumSize]]
230+
mutex criticalReleasingOnError:[
231+
maximumSize := anIntegerOrNil.
232+
maximumSize ifNotNil:[
233+
used > maximumSize
234+
ifTrue:["shrink"
235+
self shrinkTo: maximumSize]]]
213236
]
214237

215238
{ #category : 'add-remove' }
216239
FreeTypeCache >> removeAll [
217240

218-
fontTable := self dictionaryClass new: 100.
219-
fifo := self fifoClass new.
220-
used := 0
241+
mutex criticalReleasingOnError: [
242+
self basicRemoveAll ]
221243
]
222244

223245
{ #category : 'add-remove' }
224246
FreeTypeCache >> removeAllForFont: aFreeTypeFont [
225247

226-
| toRemove |
227-
(fontTable includesKey: aFreeTypeFont) ifFalse: [ ^ self ].
228-
toRemove := IdentitySet new.
229-
fifo do: [ :entry |
230-
entry font = aFreeTypeFont ifTrue: [ toRemove add: entry ] ].
231-
toRemove do: [ :entry |
232-
| d |
233-
fifo remove: entry.
234-
d := ((fontTable at: entry font) at: entry charCode) at: entry type.
235-
d removeKey: entry scale.
236-
used := used - (self sizeOf: entry object) ]
248+
mutex criticalReleasingOnError: [
249+
| toRemove |
250+
(fontTable includesKey: aFreeTypeFont) ifFalse: [ ^ self ].
251+
toRemove := IdentitySet new.
252+
fifo do: [ :entry |
253+
entry font = aFreeTypeFont ifTrue: [ toRemove add: entry ] ].
254+
toRemove do: [ :entry | self removeEntry: entry ] ]
237255
]
238256

239257
{ #category : 'add-remove' }
240258
FreeTypeCache >> removeAllForType: typeFlag [
241259

242-
| toRemove |
243-
toRemove := IdentitySet new.
244-
fifo do: [ :entry |
245-
entry type = typeFlag ifTrue: [ toRemove add: entry ] ].
246-
toRemove do: [ :entry |
247-
| d |
248-
fifo remove: entry.
249-
d := ((fontTable at: entry font) at: entry charCode) at: entry type.
250-
d removeKey: entry scale.
251-
used := used - (self sizeOf: entry object) ]
260+
mutex criticalReleasingOnError: [
261+
| toRemove |
262+
toRemove := IdentitySet new.
263+
fifo do: [ :entry |
264+
entry type = typeFlag ifTrue: [ toRemove add: entry ] ].
265+
toRemove do: [ :entry | self removeEntry: entry ] ]
266+
]
267+
268+
{ #category : 'private - sizing' }
269+
FreeTypeCache >> removeEntry: entry [
270+
271+
fifo remove: entry.
272+
self removeFont: entry font charCode: entry charCode type: entry type scale: entry scale.
273+
used := used - (self sizeOf: entry object)
274+
]
275+
276+
{ #category : 'private - sizing' }
277+
FreeTypeCache >> removeFont: font charCode: charCode type: type scale: scale [
278+
279+
| charCodeTable typeTable scaleTable |
280+
281+
charCodeTable := fontTable at: font.
282+
typeTable := charCodeTable at: charCode.
283+
scaleTable := typeTable at: type.
284+
285+
scaleTable removeKey: scale.
286+
self removeIfEmptyScaleTable: scaleTable type: type typeTable: typeTable
287+
charCode: charCode charCodeTable: charCodeTable font: font
288+
]
289+
290+
{ #category : 'private - sizing' }
291+
FreeTypeCache >> removeIfEmptyScaleTable: scaleTable type: type typeTable: typeTable charCode: charCode charCodeTable: charCodeTable font: font [
292+
293+
scaleTable ifNotEmpty: [ ^ self ].
294+
typeTable removeKey: type.
295+
typeTable ifNotEmpty: [ ^ self ].
296+
charCodeTable removeKey: charCode.
297+
charCodeTable ifNotEmpty: [ ^ self ].
298+
fontTable removeKey: font.
299+
(fontTable capacity // 2 > self fontTableInitialMinimumCapacity
300+
and: [ fontTable capacity // 4 > fontTable size ]) ifFalse: [ ^ self ].
301+
fontTable compact
252302
]
253303

254304
{ #category : 'reporting' }
255305
FreeTypeCache >> reportCacheState [
256306
"Answer a description of the current state of the cache"
257307

258-
| usedPercent |
259-
usedPercent := maximumSize
260-
ifNil: [0]
261-
ifNotNil: [(used * 100 / maximumSize) asFloat rounded].
262-
^ usedPercent asString,'% Full (maximumSize: ', maximumSize asString, ' , used: ', used asString,')'
308+
^ mutex criticalReleasingOnError: [
309+
| usedPercent |
310+
usedPercent := maximumSize
311+
ifNil: [0]
312+
ifNotNil: [(used * 100 / maximumSize) asFloat rounded].
313+
usedPercent asString,'% Full (maximumSize: ', maximumSize asString, ' , used: ', used asString,')' ]
263314
]
264315

265316
{ #category : 'private - sizing' }
266317
FreeTypeCache >> shrinkTo: newSize [
267-
"if the used size is greater than newSize, then remove all the receiver's entries"
318+
"while the used size is greater than newSize, remove the receiver's first entry"
268319

269-
used > newSize ifTrue:[self removeAll]
320+
[ used > newSize ] whileTrue: [ self removeEntry: fifo firstLink ]
270321
]
271322

272323
{ #category : 'private - accessing' }

src/FreeType/FreeTypeCacheLinkedList.class.st

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ FreeTypeCacheLinkedList >> moveDown: aLink [
7272
e4 := e3 nextLink.
7373
e1 := e2 previousLink.
7474
"swap e2 & e3"
75-
e1 ifNotNil: [e1 nextLink: e2].
76-
e2 nextLink: e3.
77-
e3 nextLink: e4.
78-
e4 ifNotNil: [e4 previousLink: e3].
79-
e3 previousLink: e2.
80-
e2 previousLink: e1
75+
e1 ifNotNil: [e1 nextLink: e3] ifNil: [firstLink := e3].
76+
e2 nextLink: e4.
77+
e3 nextLink: e2.
78+
e4 ifNotNil: [e4 previousLink: e2] ifNil: [lastLink := e2].
79+
e3 previousLink: e1.
80+
e2 previousLink: e3
8181
]
8282

8383
{ #category : 'removing' }

src/FreeType/FreeTypeFont.class.st

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ Class {
1515
'cachedDescent',
1616
'subPixelPositioned',
1717
'symbolFont',
18-
'mutex',
1918
'characterWidthCache'
2019
],
2120
#pools : [
@@ -663,12 +662,6 @@ FreeTypeFont >> mode41GlyphOf: aCharacter colorValue: aColorValue mono: monoBool
663662
scale: scale ]
664663
]
665664

666-
{ #category : 'accessing' }
667-
FreeTypeFont >> mutex [
668-
669-
^ mutex ifNil: [ mutex := Semaphore forMutualExclusion ]
670-
]
671-
672665
{ #category : 'measuring' }
673666
FreeTypeFont >> pixelSize [
674667
^pixelSize ifNil:[pixelSize := super pixelSize rounded]

0 commit comments

Comments
 (0)