[ENH] Displaying undefined glyphs

Andreas Raab andreas.raab at gmx.de
Sun Apr 10 10:42:05 UTC 2005


Folks -

It has annoyed me for a long time that MultiCharacters are often only 
displayed as question marks which makes it very simple to confuse them 
with a real question mark. The attached changes fix this so that e.g., 
"Character value: 500" is printed as \u1F4. The attached images 
illustrate the difference. How the undefined character is displayed can 
be changed in Character>>asUndefinedGlyph (so if you prefer to prefer 
<Character value: 500> instead you are free to do this ;-)

Cheers,
   - Andreas
-------------- next part --------------
'From Squeak3.8gamma of ''24 November 2004'' [latest update: #6643] on 10 April 2005 at 3:34:54 am'!
"Change Set:		DisplayUndefined
Date:			10 April 2005
Author:			Andreas Raab

Change the display of undefined characters from a question mark to a \uXYZ format. E.g., instead of

	Character value: 500 -> $?
	Character value: 500 -> $\u1F4
"!


!AbstractFont methodsFor: 'measuring' stamp: 'ar 4/10/2005 03:14'!
widthOf: aCharacter 
	"Answer the width of the argument as a character in the receiver."
	^self widthOf: aCharacter ifAbsent:[self widthOfString: aCharacter asUndefinedGlyph].! !

!AbstractFont methodsFor: 'measuring' stamp: 'ar 4/10/2005 03:02'!
widthOf: aCharacter ifAbsent: aBlock
	"Return the width of the given character if defined in the font. 
	If absent evaluate aBlock."
	^self subclassResponsibility! !


!Character methodsFor: 'printing' stamp: 'ar 4/10/2005 03:00'!
asUndefinedGlyph
	^'\u', (value printStringBase: 16)! !


!FixedFaceFont methodsFor: 'measuring' stamp: 'ar 4/10/2005 03:03'!
widthOf: aCharacter ifAbsent: aBlock
	"Characters are always defined in a fixed face font"
	^ baseFont widthOf: substitutionCharacter! !


!StrikeFont methodsFor: 'accessing' stamp: 'ar 4/10/2005 03:04'!
widthOf: aCharacter ifAbsent: aBlock
	"Characters are always defined in a fixed face font"
	| code |
	code := aCharacter class == Character
				ifTrue: [aCharacter asciiValue]
				ifFalse: [aCharacter charCode].
	((code < minAscii or: [maxAscii < code]) or: [(xTable at: code + 1) < 0])
		ifTrue: [^aBlock value].
	^(xTable at: code + 2) - (xTable at: code + 1)! !

!StrikeFont methodsFor: 'displaying' stamp: 'ar 4/10/2005 03:20'!
displayMultiString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY

	| destPoint leftX rightX glyphInfo char destY str |
	destPoint _ aPoint.
	charIndex _ startIndex.
	glyphInfo _ Array new: 5.
	[charIndex <= stopIndex] whileTrue: [
		char _ aString at: charIndex.
		(self hasGlyphOf: char) not ifTrue: [
			str := char asUndefinedGlyph.
			destPoint := self displayString: str on: aBitBlt from: 1 to: str size at: destPoint kern: kernDelta baselineY: baselineY.
			charIndex _ charIndex + 1.
		] ifFalse: [
			self glyphInfoOf: char into: glyphInfo.
			leftX _ glyphInfo second.
			rightX _ glyphInfo third.
			(glyphInfo fifth ~= aBitBlt lastFont) ifTrue: [
				glyphInfo fifth installOn: aBitBlt.
			].
			aBitBlt sourceForm: glyphInfo first.
			destY _ baselineY - glyphInfo fourth. 
			aBitBlt destX: destPoint x.
			aBitBlt destY: destY.
			aBitBlt sourceOrigin: leftX @ 0.
			aBitBlt width: rightX - leftX.
			aBitBlt height: self height.
			aBitBlt copyBits.
			destPoint _ destPoint + (rightX - leftX + kernDelta @ 0).
			charIndex _ charIndex + 1.
		].
	].
	^destPoint.
! !


!StrikeFontSet methodsFor: 'accessing' stamp: 'ar 4/10/2005 03:09'!
widthOf: aCharacter ifAbsent: aBlock
	"Answer the width of the argument as a character in the receiver."
	"1: optimizing"
	| encoding f |
	aCharacter class == Character
		ifTrue: [^ (fontArray at: 1) widthOf: aCharacter].
	"2: other case"
	encoding := aCharacter leadingChar + 1.
	f := ((((aCharacter isMemberOf: Character) not
							and: [encoding > 1])
						and: [encoding <= fontArray size])
					and: [(fontArray at: encoding) notNil])
				ifTrue: [fontArray at: encoding]
				ifFalse: [^aBlock value].
	^ f widthOf: aCharacter ifAbsent: aBlock! !

!StrikeFontSet methodsFor: 'displaying' stamp: 'ar 4/10/2005 03:27'!
displayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY

	| destPoint leftX rightX glyphInfo g destY ch str |
	destPoint _ aPoint.
	glyphInfo _ Array new: 5.
	startIndex to: stopIndex do: [:charIndex |
		ch _ aString at: charIndex.
		(self hasGlyphOf: ch) ifTrue:[
			self glyphInfoOf: ch into: glyphInfo.
			g _ glyphInfo first.
			leftX _ glyphInfo second.
			rightX _ glyphInfo third.
			(glyphInfo fifth ~= aBitBlt lastFont) ifTrue: [
				glyphInfo fifth installOn: aBitBlt.
			].
			aBitBlt sourceForm: g.
			destY _ baselineY - glyphInfo fourth. 
			aBitBlt destX: destPoint x.
			aBitBlt destY: destY.
			aBitBlt sourceOrigin: leftX @ 0.
			aBitBlt width: rightX - leftX.
			aBitBlt height: self height.
			aBitBlt copyBits.
			destPoint _ destPoint + (rightX - leftX + kernDelta @ 0).
		] ifFalse:[
			str _ ch asUndefinedGlyph.
			destPoint _ self displayString: str on: aBitBlt from: 1 to: str size at: destPoint kern: kernDelta baselineY: baselineY.
		].
	].
	^ destPoint.

! !

!StrikeFontSet methodsFor: 'private' stamp: 'ar 4/10/2005 03:26'!
hasGlyphOf: aCharacter

	| index f code leftX |
	index _ aCharacter leadingChar + 1.
	fontArray size < index ifTrue: [^false].
	(f _ fontArray at: index) ifNil: [^false].

	code _ aCharacter charCode.
	((code between: f minAscii and: f maxAscii) not) ifTrue: [^false].
	leftX _ f xTable at: code + 1.
	leftX < 0 ifTrue: [^ false].
	^true! !


!TTCFont methodsFor: 'friend' stamp: 'ar 4/10/2005 03:28'!
displayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY

	| destPoint form glyphInfo destY ch str |
	destPoint _ aPoint.
	glyphInfo _ Array new: 5.
	startIndex to: stopIndex do: [:charIndex |
		ch _ aString at: charIndex.
		(self hasGlyphOf: ch) ifTrue:[
			self glyphInfoOf: ch into: glyphInfo.
			form _ glyphInfo first.
			(glyphInfo fifth ~= aBitBlt lastFont) ifTrue: [
				glyphInfo fifth installOn: aBitBlt.
			].
			destY _ baselineY - glyphInfo fourth. 
			aBitBlt sourceForm: form.
			aBitBlt destX: destPoint x.
			aBitBlt destY: destY.
			aBitBlt sourceOrigin: (glyphInfo second) @ 0.
			aBitBlt width: glyphInfo third - glyphInfo second.
			aBitBlt height: form height.
			aBitBlt copyBits.
			destPoint _ destPoint + ((glyphInfo third - glyphInfo second) + kernDelta @ 0).
		] ifFalse:[
			str _ ch asUndefinedGlyph.
			destPoint _ self displayString: str on: aBitBlt from: 1 to: str size at: destPoint kern: kernDelta baselineY: baselineY.
		].
	].
	^ destPoint.
! !

!TTCFont methodsFor: 'public' stamp: 'ar 4/10/2005 03:11'!
widthOf: aCharacter ifAbsent: aBlock

	"This method cannot use #formOf: because formOf: discriminates the color and causes unnecessary bitmap creation."

	| f assoc |
	aCharacter charCode > 255 ifTrue: [^aBlock value].
	assoc _ self cache at: (aCharacter charCode + 1).
	assoc ifNotNil: [
		^ assoc value width
	].

	f _ self computeForm: aCharacter.
	self at: aCharacter charCode put: f.
	^ f width.
! !


!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'ar 4/10/2005 03:13'!
widthOf: aCharacter ifAbsent: aBlock
	"ar 4/10/2005: This is odd - it looks like this assumes that all MultiTTCFonts define glyphs for all characters (which is rather unlikely...)"
	"This method cannot use #formOf: because formOf: discriminates the color and causes unnecessary bitmap creation."

	| newForm |
	self hasCached: aCharacter ifTrue: [:form :index |
		self access: aCharacter at: index.
		^ form width.
	].

	newForm _ self computeForm: aCharacter.
	self at: aCharacter put: newForm.
	^ newForm width.

! !


!TTCFontSet methodsFor: 'as yet unclassified' stamp: 'ar 4/10/2005 03:30'!
displayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY

	| destPoint font form encoding glyphInfo char charCode destY str |
	destPoint _ aPoint.
	glyphInfo _ Array new: 5.
	startIndex to: stopIndex do: [:charIndex |
		char _ aString at: charIndex.
		encoding _ char leadingChar + 1.
		charCode _ char charCode.
		font _ fontArray at: encoding.
		((charCode between: font minAscii and: font maxAscii) not) 
			ifTrue: [charCode _ nil].
		charCode ifNil:[
			str _ char asUndefinedGlyph.
			destPoint _ self displayString: str on: aBitBlt from: 1 to: str size at: destPoint kern: kernDelta baselineY: baselineY.
		] ifNotNil:[
			self glyphInfoOf: char into: glyphInfo.
			form _ glyphInfo first.
			(glyphInfo fifth ~= aBitBlt lastFont) ifTrue: [
				glyphInfo fifth installOn: aBitBlt.
			].
			destY _ baselineY - glyphInfo fourth. 
			aBitBlt sourceForm: form.
			aBitBlt destX: destPoint x.
			aBitBlt destY: destY.
			aBitBlt sourceOrigin: 0 @ 0.
			aBitBlt width: form width.
			aBitBlt height: form height.
			aBitBlt copyBits.
			destPoint _ destPoint + (form width + kernDelta @ 0).
		].
	].
	^ destPoint.
! !

!TTCFontSet methodsFor: 'as yet unclassified' stamp: 'ar 4/10/2005 03:14'!
widthOf: aCharacter ifAbsent: aBlock

	| encoding |
	encoding _ aCharacter leadingChar.
	^ (fontArray at: encoding + 1) widthOf: aCharacter ifAbsent: aBlock! !

TTCFontSet removeSelector: #widthOf:!
MultiTTCFont removeSelector: #widthOf:!
TTCFont removeSelector: #widthOf:!
StrikeFontSet removeSelector: #widthOf:!
StrikeFont removeSelector: #widthOf:!
FixedFaceFont removeSelector: #widthOf:!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: UndefinedCharsOLD.gif
Type: image/gif
Size: 2924 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20050410/4e3a9736/UndefinedCharsOLD.gif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: UndefinedCharsNEW.gif
Type: image/gif
Size: 5563 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20050410/4e3a9736/UndefinedCharsNEW.gif


More information about the Squeak-dev mailing list