'From Squeakland.396-Nihongo7.29 of 14 March 2005 [latest update: #54] on 16 March 2005 at 7:15:31 pm'! "Change Set: TextComposerFix Date: 16 March 2005 Author: Yoshiki Ohshima Even if the width of text morph is so short, at least one character should go to a line. Otherwise so many bad things can happen. The early attempt was quite faulty but I believe this is much better fix."! Object subclass: #MultiCharacterScanner instanceVariableNames: 'destX lastIndex xTable destY stopConditions text textStyle alignment leftMargin rightMargin font line runStopIndex spaceCount spaceWidth emphasisCode kern indentationLevel wantsColumnBreaks presentation presentationLine numOfComposition baselineY firstDestX ' classVariableNames: 'DefaultStopConditions NilCondition PaddedSpaceCondition SpaceCondition ' poolDictionaries: 'TextConstants' category: 'Multilingual-Scanning'! MultiCharacterScanner subclass: #MultiCompositionScanner instanceVariableNames: 'spaceX lineHeight baseline breakableIndex lineHeightAtBreak baselineAtBreak breakAtSpace lastWidth' classVariableNames: '' poolDictionaries: '' category: 'Multilingual-Scanning'! !MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:03'! scanJapaneseCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta | ascii encoding f nextDestX maxAscii startEncoding | lastIndex _ startIndex. lastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun]. startEncoding _ (sourceString at: startIndex) leadingChar. font ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1]. ((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [ [f _ font fontArray at: startEncoding + 1] on: Exception do: [:ex | f _ font fontArray at: 1]. f ifNil: [ f _ font fontArray at: 1]. maxAscii _ f maxAscii. "xTable _ f xTable. maxAscii _ xTable size - 2." spaceWidth _ f widthOf: Space. ] ifFalse: [ (font isMemberOf: HostFont) ifTrue: [ f _ font. maxAscii _ f maxAscii. spaceWidth _ f widthOf: Space. ] ifFalse: [ maxAscii _ font maxAscii. ]. ]. [lastIndex <= stopIndex] whileTrue: [ "self halt." encoding _ (sourceString at: lastIndex) leadingChar. encoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun]. ascii _ (sourceString at: lastIndex) charCode. ascii > maxAscii ifTrue: [ascii _ maxAscii]. (encoding = 0 and: [(stopConditions at: ascii + 1) ~~ nil]) 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: [firstDestX ~= destX ifTrue: [^ stops at: CrossedX]]. destX _ nextDestX + kernDelta. lastIndex _ lastIndex + 1. ]. lastIndex _ stopIndex. ^ stops at: EndOfRun! ! !MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:09'! scanMultiCharactersCombiningFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta | charCode encoding f maxAscii startEncoding combining combined combiningIndex c | lastIndex _ startIndex. lastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun]. startEncoding _ (sourceString at: startIndex) leadingChar. font ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1]. ((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [ [f _ font fontArray at: startEncoding + 1] on: Exception do: [:ex | f _ font fontArray at: 1]. f ifNil: [ f _ font fontArray at: 1]. maxAscii _ f maxAscii. spaceWidth _ font widthOf: Space. ] ifFalse: [ maxAscii _ font maxAscii. spaceWidth _ font widthOf: Space. ]. combining _ nil. [lastIndex <= stopIndex] whileTrue: [ charCode _ (sourceString at: lastIndex) charCode. c _ (sourceString at: lastIndex). combining ifNil: [ combining _ CombinedChar new. combining add: c. combiningIndex _ lastIndex. lastIndex _ lastIndex + 1. ] ifNotNil: [ (combining add: c) ifFalse: [ self addCharToPresentation: (combined _ combining combined). combining _ CombinedChar new. combining add: c. charCode _ combined charCode. encoding _ combined leadingChar. encoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. (encoding = 0 and: [(stopConditions at: charCode + 1) ~~ nil]) ifTrue: [ ^ stops at: charCode + 1 ] ifFalse: [ ^ stops at: EndOfRun ]. ]. charCode > maxAscii ifTrue: [charCode _ maxAscii]. "" (encoding = 0 and: [(stopConditions at: charCode + 1) ~~ nil]) ifTrue: [ combining ifNotNil: [ self addCharToPresentation: (combining combined). ]. ^ stops at: charCode + 1 ]. (self isBreakableAt: lastIndex in: sourceString in: Latin1Environment) ifTrue: [ self registerBreakableIndex. ]. destX > rightX ifTrue: [ destX ~= firstDestX ifTrue: [ lastIndex _ combiningIndex. self removeLastCharFromPresentation. ^ stops at: CrossedX]]. combiningIndex _ lastIndex. lastIndex _ lastIndex + 1. ] ifTrue: [ lastIndex _ lastIndex + 1. numOfComposition _ numOfComposition + 1. ]. ]. ]. lastIndex _ stopIndex. combining ifNotNil: [ combined _ combining combined. self addCharToPresentation: combined. "assuming that there is always enough space for at least one character". destX _ destX + (self widthOf: combined inFont: font). ]. ^ stops at: EndOfRun! ! !MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:08'! scanMultiCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta | ascii encoding f nextDestX maxAscii startEncoding | lastIndex _ startIndex. lastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun]. startEncoding _ (sourceString at: startIndex) leadingChar. font ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1]. ((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [ [f _ font fontArray at: startEncoding + 1] on: Exception do: [:ex | f _ font fontArray at: 1]. f ifNil: [ f _ font fontArray at: 1]. maxAscii _ f maxAscii. spaceWidth _ f widthOf: Space. ] ifFalse: [ maxAscii _ font maxAscii. ]. [lastIndex <= stopIndex] whileTrue: [ encoding _ (sourceString at: lastIndex) leadingChar. encoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun]. ascii _ (sourceString at: lastIndex) charCode. ascii > maxAscii ifTrue: [ascii _ maxAscii]. (encoding = 0 and: [ascii < stopConditions size and: [(stopConditions at: ascii + 1) ~~ nil]]) ifTrue: [^ stops at: ascii + 1]. (self isBreakableAt: lastIndex in: sourceString in: Latin1Environment) ifTrue: [ self registerBreakableIndex. ]. nextDestX _ destX + (font widthOf: (sourceString at: lastIndex)). nextDestX > rightX ifTrue: [destX ~= firstDestX ifTrue: [^ stops at: CrossedX]]. destX _ nextDestX + kernDelta. lastIndex _ lastIndex + 1. ]. lastIndex _ stopIndex. ^ stops at: EndOfRun! ! !MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:08'! scanMultiCharactersR2LFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta "Note that 'rightX' really means 'endX' in R2L context. Ie. rightX is usually smaller than destX." | ascii encoding f nextDestX maxAscii startEncoding | lastIndex _ startIndex. lastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun]. startEncoding _ (sourceString at: startIndex) leadingChar. font ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1]. ((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [ [f _ font fontArray at: startEncoding + 1] on: Exception do: [:ex | f _ font fontArray at: 1]. f ifNil: [ f _ font fontArray at: 1]. maxAscii _ f maxAscii. spaceWidth _ f widthOf: Space. ] ifFalse: [ maxAscii _ font maxAscii. ]. [lastIndex <= stopIndex] whileTrue: [ encoding _ (sourceString at: lastIndex) leadingChar. encoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun]. ascii _ (sourceString at: lastIndex) charCode. ascii > maxAscii ifTrue: [ascii _ maxAscii]. (encoding = 0 and: [(stopConditions at: ascii + 1) ~~ nil]) ifTrue: [^ stops at: ascii + 1]. (self isBreakableAt: lastIndex in: sourceString in: Latin1Environment) ifTrue: [ self registerBreakableIndex. ]. nextDestX _ destX - (font widthOf: (sourceString at: lastIndex)). nextDestX < rightX ifTrue: [^ stops at: CrossedX]. destX _ nextDestX - kernDelta. lastIndex _ lastIndex + 1. ]. lastIndex _ stopIndex. ^ stops at: EndOfRun! ! !MultiCompositionScanner methodsFor: 'scanning' stamp: 'yo 3/16/2005 19:00'! composeFrom: startIndex inRectangle: lineRectangle firstLine: firstLine leftSide: leftSide rightSide: rightSide "Answer an instance of TextLineInterval that represents the next line in the paragraph." | runLength done stopCondition | "Set up margins" leftMargin _ lineRectangle left. leftSide ifTrue: [leftMargin _ leftMargin + (firstLine ifTrue: [textStyle firstIndent] ifFalse: [textStyle restIndent])]. destX _ spaceX _ leftMargin. firstDestX _ destX. 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" self setStopConditions. "also sets font" runLength _ text runLengthFor: startIndex. runStopIndex _ (lastIndex _ startIndex) + (runLength - 1). line _ (TextLine start: lastIndex stop: 0 internalSpaces: 0 paddingWidth: 0) rectangle: lineRectangle. presentationLine _ (TextLine start: lastIndex stop: 0 internalSpaces: 0 paddingWidth: 0) rectangle: lineRectangle. numOfComposition _ 0. spaceCount _ 0. self handleIndentation. leftMargin _ destX. line leftMargin: leftMargin. presentationLine leftMargin: leftMargin. presentation _ TextStream on: (Text fromString: (MultiString new: text size)). done _ false. [done] whileFalse: [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) ifTrue: [presentationLine lineHeight: lineHeight + textStyle leading baseline: baseline + textStyle leading. ^ line lineHeight: lineHeight + textStyle leading baseline: baseline + textStyle leading]]! ! !TextComposer methodsFor: 'as yet unclassified' stamp: 'dgd 2/22/2003 13:31'! composeOneLine | rectangles | rectangles := theContainer rectanglesAt: currentY height: defaultLineHeight. rectangles notEmpty ifTrue: [(self composeAllRectangles: rectangles) ifNil: [^nil]] ifFalse: [currentY := currentY + defaultLineHeight]. self checkIfReadyToSlide! ! !TextMorph methodsFor: 'geometry' stamp: 'di 7/20/2001 22:51'! minimumExtent | minExt | textStyle ifNil: [^ 9@16]. borderWidth ifNil: [^ 9@16]. minExt _ (9@(textStyle lineGrid+2)) + (borderWidth*2). margins ifNil: [^ minExt]. ^ ((0@0 extent: minExt) expandBy: margins) extent! ! Object subclass: #MultiCharacterScanner instanceVariableNames: 'destX lastIndex xTable destY stopConditions text textStyle alignment leftMargin rightMargin font line runStopIndex spaceCount spaceWidth emphasisCode kern indentationLevel wantsColumnBreaks presentation presentationLine numOfComposition baselineY firstDestX' classVariableNames: 'DefaultStopConditions NilCondition PaddedSpaceCondition SpaceCondition' poolDictionaries: 'TextConstants' category: 'Multilingual-Scanning'!