[squeak-dev] The Trunk: Graphics-nice.237.mcz

commits at source.squeak.org commits at source.squeak.org
Sun Sep 29 14:28:10 UTC 2013


Nicolas Cellier uploaded a new version of Graphics to project The Trunk:
http://source.squeak.org/trunk/Graphics-nice.237.mcz

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

Name: Graphics-nice.237
Author: nice
Time: 29 September 2013, 4:26:28.942 pm
UUID: f73a5da8-0cca-42c7-a0b3-08472216f2cf
Ancestors: Graphics-nice.236

Copy the multi-lingual methods from MultiCharacterScanner hierarchy that were missing in CharacterScanner hierarchy.
Note that this does not include the precomposed unicode Combining which deserves a rewrite.
Also note that non-space breakable chars are handled a bit differently in CompositionScanner in order to make the minimal change that could work.
Start using the CharacterScanner hierarchy instead of the Multi one.

=============== Diff against Graphics-nice.236 ===============

Item was added:
+ ----- Method: CharacterBlockScanner>>theFirstCharCrossedX (in category 'private') -----
+ theFirstCharCrossedX
+ 	"Note: it is hard to explain why, but this is required to keep selection of leftmost char possible."
+ 	^false!

Item was added:
+ ----- Method: CharacterScanner>>isBreakableAt:in:in: (in category 'scanner methods') -----
+ isBreakableAt: index in: sourceString in: encodingClass
+ "check with the encoding whether the character at index is a breakable character- only the JISX0208 & JapaneseEnvironment will ever return true, so only the scanJapaneseCharacters... method calls this"
+ 	^ encodingClass isBreakableAt: index in: sourceString.
+ !

Item was removed:
- ----- Method: CharacterScanner>>isBreakableAtIndex: (in category 'scanner methods') -----
- isBreakableAtIndex: index
- "appears t obe unused - cf MultiCharacterScanner>isBreakableAt:in:in"
- 	^ (EncodedCharSet at: ((text at: index) leadingChar + 1)) isBreakableAt: index in: text.
- !

Item was added:
+ ----- Method: CharacterScanner>>registerBreakableIndex (in category 'multilingual scanning') -----
+ registerBreakableIndex
+ 
+ 	"Record left x and character index of the line-wrappable point. 
+ 	The default implementation here does nothing."
+ 
+ 	^ false.
+ !

Item was changed:
  ----- Method: CharacterScanner>>scanJapaneseCharactersFrom:to:in:rightX:stopConditions:kern: (in category 'scanner methods') -----
  scanJapaneseCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta
  
  	| ascii encoding nextDestX startEncoding |
  	lastIndex := startIndex.
  	lastIndex > stopIndex ifTrue: [lastIndex := stopIndex. ^ stops endOfRun].
  	startEncoding := (sourceString at: startIndex) leadingChar.
  	[lastIndex <= stopIndex] whileTrue: [
  		encoding := (sourceString at: lastIndex) leadingChar.
  		encoding ~= startEncoding ifTrue: [lastIndex := lastIndex - 1. ^ stops endOfRun].
  		ascii := (sourceString at: lastIndex) charCode.
  		(encoding = 0 and: [ascii < 256 and:[(stops at: ascii + 1) notNil]]) 
  			ifTrue: [^ stops at: ascii + 1].
+ 		(self isBreakableAt: lastIndex in: sourceString in: (EncodedCharSet charsetAt: encoding)) ifTrue: [
+ 			self registerBreakableIndex.
+ 		].
  		nextDestX := destX + (font widthOf: (sourceString at: lastIndex)).
+ 		nextDestX > rightX ifTrue: [self theFirstCharCrossedX ifFalse: [^ stops crossedX]].
- 		nextDestX > rightX ifTrue: [^ stops crossedX].
  		destX := nextDestX + kernDelta.
- 		"destX printString displayAt: 0@(lastIndex*20)."
  		lastIndex := lastIndex + 1.
  	].
  	lastIndex := stopIndex.
  	^ stops endOfRun!

Item was changed:
  ----- Method: CharacterScanner>>scanMultiCharactersFrom:to:in:rightX:stopConditions:kern: (in category 'scanning') -----
  scanMultiCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta
  
+ 	| ascii encoding nextDestX startEncoding floatDestX widthAndKernedWidth nextChar atEndOfRun |
- 	| ascii encoding nextDestX startEncoding |
  	lastIndex := startIndex.
  	lastIndex > stopIndex ifTrue: [lastIndex := stopIndex. ^ stops endOfRun].
  	startEncoding := (sourceString at: startIndex) leadingChar.
+ 	floatDestX := destX.
+ 	widthAndKernedWidth := Array new: 2.
+ 	atEndOfRun := false.
  	[lastIndex <= stopIndex] whileTrue: [
  		encoding := (sourceString at: lastIndex) leadingChar.
  		encoding ~= startEncoding ifTrue: [lastIndex := lastIndex - 1. ^ stops endOfRun].
  		ascii := (sourceString at: lastIndex) charCode.
+ 		(ascii < 256 and: [(stops at: ascii + 1) ~~ nil]) ifTrue: [^ stops at: ascii + 1].
+ 		nextChar := (lastIndex + 1 <= stopIndex) 
+ 			ifTrue:[sourceString at: lastIndex + 1]
+ 			ifFalse:[
+ 				atEndOfRun := true.
+ 				"if there is a next char in sourceString, then get the kern 
+ 				and store it in pendingKernX"
+ 				lastIndex + 1 <= sourceString size
+ 					ifTrue:[sourceString at: lastIndex + 1]
+ 					ifFalse:[	nil]].
+ 		font 
+ 			widthAndKernedWidthOfLeft: (sourceString at: lastIndex) 
+ 			right: nextChar
+ 			into: widthAndKernedWidth.
+ 		nextDestX := floatDestX + (widthAndKernedWidth at: 1).
+ 		nextDestX > rightX ifTrue: [self theFirstCharCrossedX ifFalse: [^stops crossedX]].
+ 		floatDestX := floatDestX + kernDelta + (widthAndKernedWidth at: 2).
+ 		atEndOfRun 
+ 			ifTrue:[
+ 				pendingKernX := (widthAndKernedWidth at: 2) - (widthAndKernedWidth at: 1).
+ 				floatDestX := floatDestX - pendingKernX].
+ 		destX := floatDestX .
- 		(encoding = 0 and: [ascii < 256 and:[(stops at: ascii + 1) notNil]]) 
- 			ifTrue: [^ stops at: ascii + 1].
- 		nextDestX := destX + (font widthOf: (sourceString at: lastIndex)).
- 		nextDestX > rightX ifTrue: [^ stops crossedX].
- 		destX := nextDestX + kernDelta.
- 		"destX printString displayAt: 0@(lastIndex*20)."
  		lastIndex := lastIndex + 1.
  	].
  	lastIndex := stopIndex.
  	^ stops endOfRun!

Item was added:
+ ----- Method: CharacterScanner>>theFirstCharCrossedX (in category 'private') -----
+ theFirstCharCrossedX
+ 	"Tell whether the left most char crossed the right margin boundary"
+ 	^destX = leftMargin!

Item was changed:
  CharacterScanner subclass: #CompositionScanner
+ 	instanceVariableNames: 'spaceX spaceIndex lineHeight baseline lineHeightAtSpace baselineAtSpace lastBreakIsNotASpace'
- 	instanceVariableNames: 'spaceX spaceIndex lineHeight baseline lineHeightAtSpace baselineAtSpace'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Graphics-Text'!
  
  !CompositionScanner commentStamp: '<historical>' prior: 0!
  CompositionScanners are used to measure text and determine where line breaks and space padding should occur.!

Item was changed:
  ----- Method: CompositionScanner>>columnBreak (in category 'stop conditions') -----
  columnBreak
  
  	"Answer true. Set up values for the text line interval currently being 
  	composed."
  
  	pendingKernX := 0.
  	line stop: lastIndex.
  	spaceX := destX.
+ 	lastBreakIsNotASpace := false.
  	line paddingWidth: rightMargin - spaceX.
  	^true!

Item was changed:
  ----- Method: CompositionScanner>>composeFrom:inRectangle:firstLine:leftSide:rightSide: (in category 'scanning') -----
  composeFrom: startIndex inRectangle: lineRectangle
  	firstLine: firstLine leftSide: leftSide rightSide: rightSide
  	"Answer an instance of TextLineInterval that represents the next line in the paragraph."
  	| runLength stopCondition |
  	"Set up margins"
  	leftMargin := lineRectangle left.
  	leftSide ifTrue: [leftMargin := leftMargin +
  						(firstLine ifTrue: [textStyle firstIndent]
  								ifFalse: [textStyle restIndent])].
  	destX := spaceX := leftMargin.
  	rightMargin := lineRectangle right.
  	rightSide ifTrue: [rightMargin := rightMargin - textStyle rightIndent].
  	lastIndex := startIndex.	"scanning sets last index"
  	destY := lineRectangle top.
  	lineHeight := baseline := 0.  "Will be increased by setFont"
  	line := (TextLine start: lastIndex stop: 0 internalSpaces: 0 paddingWidth: 0)
  				rectangle: lineRectangle.
  	self setStopConditions.	"also sets font"
  	runLength := text runLengthFor: startIndex.
  	runStopIndex := (lastIndex := startIndex) + (runLength - 1).
  	spaceCount := 0.
+ 	lastBreakIsNotASpace := false.
  	self handleIndentation.
  	leftMargin := destX.
  	line leftMargin: leftMargin.
  
  	[stopCondition := self scanCharactersFrom: lastIndex to: runStopIndex
  		in: text string rightX: rightMargin stopConditions: stopConditions
  		kern: kern.
  	"See setStopConditions for stopping conditions for composing."
  	self perform: stopCondition] whileFalse.
  
  	^ line
  		lineHeight: lineHeight + textStyle leading
  		baseline: baseline + textStyle leading!

Item was changed:
  ----- Method: CompositionScanner>>composeLine:fromCharacterIndex:inParagraph: (in category 'scanning') -----
  composeLine: lineIndex fromCharacterIndex: startIndex inParagraph: aParagraph 
  	"Answer an instance of TextLineInterval that represents the next line in the paragraph."
  	| runLength stopCondition |
  	destX := spaceX := leftMargin := aParagraph leftMarginForCompositionForLine: lineIndex.
  	destY := 0.
  	rightMargin := aParagraph rightMarginForComposition.
  	leftMargin >= rightMargin ifTrue: [self error: 'No room between margins to compose'].
  	lastIndex := startIndex.	"scanning sets last index"
  	lineHeight := textStyle lineGrid.  "may be increased by setFont:..."
  	baseline := textStyle baseline.
  	self setStopConditions.	"also sets font"
  	self handleIndentation.
  	runLength := text runLengthFor: startIndex.
  	runStopIndex := (lastIndex := startIndex) + (runLength - 1).
  	line := TextLineInterval
  		start: lastIndex
  		stop: 0
  		internalSpaces: 0
  		paddingWidth: 0.
  	spaceCount := 0.
+ 	lastBreakIsNotASpace := false.
  	
  	[stopCondition := self scanCharactersFrom: lastIndex to: runStopIndex
  		in: text string rightX: rightMargin stopConditions: stopConditions
  		kern: kern.
  	"See setStopConditions for stopping conditions for composing."
  	self perform: stopCondition] whileFalse.
  
  	^line
  		lineHeight: lineHeight + textStyle leading
  		baseline: baseline + textStyle leading!

Item was changed:
  ----- Method: CompositionScanner>>cr (in category 'stop conditions') -----
  cr
  	"Answer true. Set up values for the text line interval currently being 
  	composed."
  
  	pendingKernX := 0.
  	(lastIndex < text size and: [(text at: lastIndex) = CR and: [(text at: lastIndex+1) = Character lf]]) ifTrue: [lastIndex := lastIndex + 1].
  	line stop: lastIndex.
  	spaceX := destX.
+ 	lastBreakIsNotASpace := false.
  	line paddingWidth: rightMargin - spaceX.
  	^true!

Item was changed:
  ----- Method: CompositionScanner>>crossedX (in category 'stop conditions') -----
  crossedX
  	"There is a word that has fallen across the right edge of the composition 
  	rectangle. This signals the need for wrapping which is done to the last 
+ 	space that was encountered, as recorded by the space stop condition,
+ 	or any other breakable character if the language permits so."
- 	space that was encountered, as recorded by the space stop condition."
  
  	pendingKernX := 0.
+ 	
+ 	lastBreakIsNotASpace ifTrue:
+ 		["In some languages break is possible on non space."
+ 		line stop: spaceIndex.
+ 		lineHeight := lineHeightAtSpace.
+ 		baseline := baselineAtSpace.
+ 		spaceCount := spaceCount - 1.
+ 		spaceIndex := spaceIndex - 1.
+ 		line paddingWidth: rightMargin.
+ 		line internalSpaces: spaceCount.
+ 		^true].
+ 	 
  	spaceCount >= 1 ifTrue:
  		["The common case. First back off to the space at which we wrap."
  		line stop: spaceIndex.
  		lineHeight := lineHeightAtSpace.
  		baseline := baselineAtSpace.
  		spaceCount := spaceCount - 1.
  		spaceIndex := spaceIndex - 1.
  
  		"Check to see if any spaces preceding the one at which we wrap.
  			Double space after punctuation, most likely."
  		[(spaceCount > 1 and: [(text at: spaceIndex) = Space])]
  			whileTrue:
  				[spaceCount := spaceCount - 1.
  				"Account for backing over a run which might
  					change width of space."
  				font := text fontAt: spaceIndex withStyle: textStyle.
  				spaceIndex := spaceIndex - 1.
  				spaceX := spaceX - (font widthOf: Space)].
  		line paddingWidth: rightMargin - spaceX.
  		line internalSpaces: spaceCount]
  	ifFalse:
  		["Neither internal nor trailing spaces -- almost never happens."
  		lastIndex := lastIndex - 1.
  		[destX <= rightMargin or: [ lastIndex = 0 ]]
  			whileFalse:
  				[destX := destX - (font widthOf: (text at: lastIndex)).
  				lastIndex := lastIndex - 1].
  		spaceX := destX.
  		line paddingWidth: rightMargin - destX.
  		line stop: (lastIndex max: line first)].
  	^true!

Item was added:
+ ----- Method: CompositionScanner>>registerBreakableIndex (in category 'multilingual scanning') -----
+ registerBreakableIndex
+ 	"Record left x and character index of the line-wrappable point. 
+ 	Used for wrap-around in eastern Asian languages."
+ 
+ 	spaceX := destX.
+ 	lineHeightAtSpace := lineHeight.
+ 	baselineAtSpace := baseline.
+ 	spaceIndex := lastIndex.
+ 	lastBreakIsNotASpace := true.!

Item was changed:
  ----- Method: CompositionScanner>>space (in category 'stop conditions') -----
  space
+ 	"Record left x and character index of the space character just encountered. 
- 	"Record left x and character index of the space character just encounted. 
  	Used for wrap-around. Answer whether the character has crossed the 
  	right edge of the composition rectangle of the paragraph."
  
  	pendingKernX := 0.
  	spaceX := destX.
  	destX := spaceX + spaceWidth.
  	spaceIndex := lastIndex.
  	lineHeightAtSpace := lineHeight.
  	baselineAtSpace := baseline.
  	lastIndex := lastIndex + 1.
  	spaceCount := spaceCount + 1.
+ 	lastBreakIsNotASpace := false.
  	destX > rightMargin ifTrue: 	[^self crossedX].
  	^false
  !

Item was changed:
  ----- Method: DisplayScanner>>displayLine:offset:leftInRun: (in category 'scanning') -----
  displayLine: textLine offset: offset leftInRun: leftInRun
  	"The call on the primitive (scanCharactersFrom:to:in:rightX:) will be interrupted according to an array of stop conditions passed to the scanner at which time the code to handle the stop condition is run and the call on the primitive continued until a stop condition returns true (which means the line has terminated).  leftInRun is the # of characters left to scan in the current run; when 0, it is time to call setStopConditions."
  	| stopCondition nowLeftInRun startIndex string lastPos |
  	line := textLine.
  	morphicOffset := offset.
  	lineY := line top + offset y.
  	lineHeight := line lineHeight.
  	rightMargin := line rightMargin + offset x.
  	lastIndex := line first.
  	leftInRun <= 0 ifTrue: [self setStopConditions].
  	leftMargin := (line leftMarginForAlignment: alignment) + offset x.
  	destX := runX := leftMargin.
  	fillBlt == nil ifFalse:
  		["Not right"
  		fillBlt destX: line left destY: lineY
  			width: line width left height: lineHeight; copyBits].
  	lastIndex := line first.
  	leftInRun <= 0
  		ifTrue: [nowLeftInRun := text runLengthFor: lastIndex]
  		ifFalse: [nowLeftInRun := leftInRun].
  	destY := lineY + line baseline - font ascent.
  	runStopIndex := lastIndex + (nowLeftInRun - 1) min: line last.
  	spaceCount := 0.
  	string := text string.
  	[
  		"remember where this portion of the line starts"
  		startIndex := lastIndex.
  		lastPos := destX at destY.
  		
  		"find the end of this portion of the line"
  		stopCondition := self scanCharactersFrom: lastIndex to: runStopIndex
  						in: string rightX: rightMargin stopConditions: stopConditions
  						kern: kern.
  
  		"display that portion of the line"
  		lastIndex >= startIndex ifTrue:[
  			font displayString: string on: bitBlt 
  				from: startIndex 
  	"XXXX: The following is an interesting bug. All stopConditions exept #endOfRun
  		have lastIndex past the last character displayed. #endOfRun sets it *on* the character.
  		If we display up until lastIndex then we will also display invisible characters like
  		CR and tab. This problem should be fixed in the scanner (i.e., position lastIndex
  		consistently) but I don't want to deal with the fallout right now so we keep the
  		fix minimally invasive."
  				to: (stopCondition == #endOfRun ifTrue:[lastIndex] ifFalse:[lastIndex-1]) 
  				at: lastPos kern: kern].
  
  		"handle the stop condition"
  		"see setStopConditions for stopping conditions for displaying."
+ 		self perform: stopCondition
- 		(self perform: stopCondition)
- 			or: [lastIndex > runStopIndex].
  	] whileFalse.
  	^ runStopIndex - lastIndex   "Number of characters remaining in the current run"!

Item was added:
+ ----- Method: DisplayScanner>>isBreakableAt:in:in: (in category 'multilingual scanning') -----
+ isBreakableAt: index in: sourceString in: encodingClass
+ 
+ 	^ false.
+ !

Item was changed:
  ----- Method: TextComposer>>composeLinesFrom:to:delta:into:priorLines:atY:textStyle:text:container:wantsColumnBreaks: (in category 'as yet unclassified') -----
  composeLinesFrom: argStart to: argStop delta: argDelta into: argLinesCollection priorLines: argPriorLines atY: argStartY textStyle: argTextStyle text: argText container: argContainer wantsColumnBreaks: argWantsColumnBreaks
  
  	wantsColumnBreaks := argWantsColumnBreaks.
  	lines := argLinesCollection.
  	theTextStyle := argTextStyle.
  	theText := argText.
  	theContainer := argContainer.
  	deltaCharIndex := argDelta.
  	currCharIndex := startCharIndex := argStart.
  	stopCharIndex := argStop.
  	prevLines := argPriorLines.
  	currentY := argStartY.
  	maxRightX := theContainer left.
  	possibleSlide := stopCharIndex < theText size and: [theContainer isMemberOf: Rectangle].
  	nowSliding := false.
  	prevIndex := 1.
  	"choose an appropriate scanner - should go away soon, when they can be unified"
+ 	scanner := CompositionScanner new.
- 	scanner := (theText string isOctetString 
- 						ifTrue:[CompositionScanner new] 
- 						ifFalse:[MultiCompositionScanner new]).
  	scanner text: theText textStyle: theTextStyle.
  	scanner wantsColumnBreaks: wantsColumnBreaks.
  	defaultLineHeight := scanner computeDefaultLineHeight.
  	isFirstLine := true.
  	self composeAllLines.
  	isFirstLine ifTrue: ["No space in container or empty text"
  		self 
  			addNullLineWithIndex: startCharIndex
  			andRectangle: (theContainer topLeft extent: 0 at defaultLineHeight)
  	] ifFalse: [
  		self fixupLastLineIfCR
  	].
  	^{lines asArray. maxRightX}
  
  !

Item was changed:
  ----- Method: TextComposer>>multiComposeLinesFrom:to:delta:into:priorLines:atY:textStyle:text:container:wantsColumnBreaks: (in category 'as yet unclassified') -----
  multiComposeLinesFrom: argStart to: argStop delta: argDelta into: argLinesCollection priorLines: argPriorLines atY: argStartY textStyle: argTextStyle text: argText container: argContainer wantsColumnBreaks: argWantsColumnBreaks
  
  "temporarily add this here to support move to drop MultiTextComposer"
  "now redundant and ready to remove later"
  	wantsColumnBreaks := argWantsColumnBreaks.
  	lines := argLinesCollection.
  	theTextStyle := argTextStyle.
  	theText := argText.
  	theContainer := argContainer.
  	deltaCharIndex := argDelta.
  	currCharIndex := startCharIndex := argStart.
  	stopCharIndex := argStop.
  	prevLines := argPriorLines.
  	currentY := argStartY.
  	maxRightX := theContainer left.
  	possibleSlide := stopCharIndex < theText size and: [theContainer isMemberOf: Rectangle].
  	nowSliding := false.
  	prevIndex := 1.
+ 	scanner := CompositionScanner new text: theText textStyle: theTextStyle.
- 	scanner := MultiCompositionScanner new text: theText textStyle: theTextStyle.
  	scanner wantsColumnBreaks: wantsColumnBreaks.
  	defaultLineHeight := scanner computeDefaultLineHeight.
  	isFirstLine := true.
  	self composeAllLines.
  	isFirstLine ifTrue: ["No space in container or empty text"
+ 		self
- 		self 
  			addNullLineWithIndex: startCharIndex
  			andRectangle: (theContainer topLeft extent: 0 at defaultLineHeight)
  	] ifFalse: [
  		self fixupLastLineIfCR
  	].
  	^{lines asArray. maxRightX}
  
  !



More information about the Squeak-dev mailing list