[squeak-dev] The Trunk: Graphics-mt.498.mcz

commits at source.squeak.org commits at source.squeak.org
Mon Mar 14 14:46:12 UTC 2022

Marcel Taeumel uploaded a new version of Graphics to project The Trunk:

==================== Summary ====================

Name: Graphics-mt.498
Author: mt
Time: 14 March 2022, 3:46:04.661786 pm
UUID: 83e89fe1-0c23-5345-b0f9-a17ee4008714
Ancestors: Graphics-mt.497

Adds "text composition" protocol to TextStyle to be able to derive a pixel-based composition rectangle using the style's default font and
	(a) number of characters per line
	(b) factor of the font's type size
See commentary in methods for more information.

=============== Diff against Graphics-mt.497 ===============

Item was changed:
  Object subclass: #TextStyle
+ 	instanceVariableNames: 'fontArray alignment firstIndent restIndent rightIndent tabsArray marginTabsArray defaultFontIndex lineSpacing normalizedCharacterWidth'
- 	instanceVariableNames: 'fontArray alignment firstIndent restIndent rightIndent tabsArray marginTabsArray defaultFontIndex lineSpacing'
  	classVariableNames: 'NumSpacesPerTab'
  	poolDictionaries: 'TextConstants'
  	category: 'Graphics-Text'!
  !TextStyle commentStamp: 'mt 2/21/2022 10:55' prior: 0!
  A text style comprises the formatting information for composing and displaying a unit (usually a paragraph) of text. It provides a #defaultFont to use, but text attributes can change that per character (see CompositionScanner and DisplayScanner). It also has a default #alignment that attributes can override. Those defaults make it possible to compose and display (unformatted) strings in paragraphs without having to style them first as texts (i.e., string+attributes).
  NOTE THAT for each use you *must* make a copy of a font's master text style (e.g., "TextStyle default copy") or create a fresh one with at least a single font (see TextStyle class >> #fontArray: and AbstractFont >> #asNewTextStyle). That specific instance is typically altered in the process of editing: change default font size, change default alignment, ... and you wouldn't want to change that properties for other applications by accident.
  A text style also drives the interpretation of Character tab. Both tabsArray and marginTabsArray are initialized for the #defaultFont(Index:). When you change a style's default font size, those "tab positions" will be recomputed for fast access during composition. See the preference #numSpacesPerTab(:).
  While each text style looks like it could handle an arbitrary array of fonts, it is *best practice* to only store fonts of the same font family. A font's master style thus collects all known point sizes at a single place (i.e. "TextStyle named: aFamilyName"). Copies will share that array. The attribute TextFontChange makes it possible to switch to any index in that array, but this is not portable and hence discouraged. TextFontReference adds an explicit reference to font, which is also not good. (February 2022: We plan to add TextFont(Point)Size and TextFontFamily as a portable way to change the font per character.).
  There are some legacy information, which should no longer be used:
  	- #baseline: ... used to prescribe baseline info but is now completely derived from #defaultFont
  	- #lineGrid: ... same as #baseLine:
  	- #leading(:) ... is replaced by #lineSpacing(:) and denotes the extra spacing relative to the respective line's height in the composition
  The #lineSpacing is noticeable in a paragraph's text selection. Line spacing < 0.0 will appear as overlaps between (translucent) selection rectangles. Lince spacing > 0.0 will appear as gaps between selection rectangles.
  Here are some example styles to explore:
  	- TextStyle default
  	- TextStyle defaultFixes!

Item was added:
+ ----- Method: TextStyle>>compositionWidthFor: (in category 'text composition') -----
+ compositionWidthFor: aNumber
+ 	"Answer the width of the composition rectangle in pixels using the receiver's #defaultFont.
+ 		- Positive numbers are used as number of characters per line
+ 		- Negative numbers are used as factor of #typoTypeSize
+ 		- Zero will try to approximate 66 characters per line
+ 	See commentaries in both #compositionWidthForTypeFactor and #compositionWidthForNumChars."
+ 	aNumber = 0 ifTrue: [^ self compositionWidthForNumChars].
+ 	^ aNumber > 0
+ 		ifTrue: [self compositionWidthForNumChars: aNumber]
+ 		ifFalse: [self compositionWidthForTypeFactor: aNumber negated]!

Item was added:
+ ----- Method: TextStyle>>compositionWidthForNumChars (in category 'text composition') -----
+ compositionWidthForNumChars
+ 	"Constant is based on the book
+ 		The Elements of Typographic Style (version 3.0)
+ 		by Robert Bringhurst
+ 	Excerpts from Section 2.1.2 Choose a comfortable measure, page 26:
+ 		[...] Anything from 45 to 75 characters is widely regarded as a satisfactory length of a line for a single-column page set in a serifed text face in a text size. The 66-character line (counting both letters and spaces) is widely regarded as ideal. For multiple-column work, a better average is 40 to 50 characters. [...]
+ 	Note that these numbers consider continuous text in English."
+ 	^ self compositionWidthForNumChars: 66!

Item was added:
+ ----- Method: TextStyle>>compositionWidthForNumChars: (in category 'text composition') -----
+ compositionWidthForNumChars: numChars
+ 	"Answer the width of the composition rectangle in pixels for numChars
+ using the receiver's #defaultFont.
+ 	You can compare this with other ways to prescribe a 'sheet of paper' for
+ arbitrary content as follows:
+ 	| sample style font |
+ 	sample := 'the quick brown fox jumps over the lazy dog'.
+ 	style := TextStyle default.
+ 	font := style defaultFont.
+ 	((1 to: sample size) collect: [:i | {
+ 		font widthOfString: (sample first: i).
+ 		style compositionWidthForNumChars: i.
+ 		(font widthOf: $x) * i.
+ 		(font widthOf: $m) * i }]) explore
+ 	As you can see, using $x or $m will typically overshoot the values of
+ #widthOfString: and #compositionWidthForNumChars:.
+ 	"
+ 	^ (self normalizedCharacterWidth * numChars) truncated!

Item was added:
+ ----- Method: TextStyle>>compositionWidthForTypeFactor (in category 'text composition') -----
+ compositionWidthForTypeFactor
+ 	"Constant is based on the book
+ 		The Elements of Typographic Style (version 3.0)
+ 		by Robert Bringhurst
+ 	Excerpt from Section 2.1.2 Choose a comfortable measure, page 27:
+ 		[...] On a conventional book page, the measure, or length of line, is usually around 30 times the size of the type, but lines as little as 20 or as much as 40 times the type size fall within the expectable range. [...]
+ 	Note that these numbers consider continuous text in English."
+ 	^ self compositionWidthForTypeFactor: 30!

Item was added:
+ ----- Method: TextStyle>>compositionWidthForTypeFactor: (in category 'text composition') -----
+ compositionWidthForTypeFactor: typeFactor
+ 	"Answers a default composition width for the given typeFactor."
+ 	^ (self typoTypeSize * typeFactor) truncated!

Item was changed:
  ----- Method: TextStyle>>defaultFontIndex: (in category 'accessing - default font') -----
  defaultFontIndex: anIndex
  	defaultFontIndex := anIndex.
+ 	self initializeTabsArray.
+ 	self initializeNormalizedCharacterWIdth.!
- 	self initializeTabsArray.!

Item was removed:
- ----- Method: TextStyle>>flushFonts (in category 'fonts and font indexes') -----
- flushFonts
- 	"Clean out the fonts, an aid when snapshotting claims too many are 
- 	holding onto Display."
- 	(self confirm: 
- 'flushFonts is very dangerous.
- Are you foolish or clever enough to proceed?')
- 		ifTrue: [1 to: fontArray size do: [:index | fontArray at: index put: nil]]
- 		ifFalse: [Transcript cr; show: 'flushFonts cancelled']
- 	"TextStyle default flushFonts"!

Item was added:
+ ----- Method: TextStyle>>initializeNormalizedCharacterWIdth (in category 'initialize-release') -----
+ initializeNormalizedCharacterWIdth
+ 	normalizedCharacterWidth := nil.!

Item was added:
+ ----- Method: TextStyle>>normalizedCharacterWidth (in category 'text composition') -----
+ normalizedCharacterWidth
+ 	"Answer the normalized character width to compute a pixel-based box for text composition that follows what you specify via #compositionWidthForNumChars:. Cached for performance.
+ 	Alphabet-divide constant is based on the book (table on page 29):
+ 		The Elements of Typographic Style (version 3.0)
+ 		by Robert Bringhurst"
+ 	^ normalizedCharacterWidth ifNil: [
+ 		normalizedCharacterWidth := self defaultFont hasFixedWidth
+ 			ifTrue: [ self defaultFont widthOf: $M "often ~= #typoTypeSize!!"]
+ 			ifFalse: [ self typoAlphabetLength asFloat * 0.036 ]]!

Item was added:
+ ----- Method: TextStyle>>typoAlphabetLength (in category 'text composition') -----
+ typoAlphabetLength
+ 	"
+ 	TextStyle default typoAlphabetLength.
+ 	TextStyle defaultFixed typoAlphabetLength.
+ 	"	
+ 	| font |
+ 	font := self defaultFont.
+ 	^ ($a to: $z) inject: 0 into: [:sum :char | sum + (font widthOf: char)]!

Item was added:
+ ----- Method: TextStyle>>typoTypeSize (in category 'text composition') -----
+ typoTypeSize
+ 	"
+ 	TextStyle default typoTypeSize.
+ 	TextStyle defaultFixed typoTypeSize.	
+ 	"
+ 	^ self defaultFont height!

More information about the Squeak-dev mailing list