<div dir="ltr"><div><div><div><div><div><div><div><div><div><div><div><div><div>Currently, the scanner family is wrapping the composition/display on next line when line is too long.<br></div><div>With a single space, the feature is quite simple, a space is then conceptually equal to a cr (and a line feed if you are stuck to the typewriter).<br>
</div><div></div>So for example in rightFlush alignment:<br></div>- align character before space with right margin<br></div>- let character after space lay on next line<br></div>- do not materialize any spacing in text selection<br>
selecting before the space let the cursor at upper line, right margin.<br></div>selecting after the space let the cursor at lower line, left of next character.<br><br></div>But what if there are two spaces?<br>Should spacing be materialized before right margin or left of next line?<br>
</div>IMHO, when rightFlush, spacing should be materialized left of next line, by symmetry with leftFlush (in which case they are materialized right of current line).<br><br></div>And what about Centered? And Justified?<br>
</div><div><br></div>Currently CharacterBlockScanner and rightFlush alignment don&#39;t play well together.<br></div>Even leftFlush doesn&#39;t correctly update the cursor position (and I checked that this was already broken before I touched anything).<br>
<br></div>It&#39;s not really amazing, looking at the bunch of states that come onto the playfield:<br>- spaceCount for adjusting the padding in Justified case<br></div>- spaceX for determining the (left) position of last space (or other breakable char)<br>
</div><div>- lastIndex the index of next character to be processed in the text<br>- runStopIndex the last index in the text from current position (?) before a change of run (emphasis)<br></div><div>- destX the (left) position for next character to go<br>
- kern &amp; pendingKernX for adjusting spacing of next character (if in same font)<br></div><div>plus all the ones specific for CharacterBlockScanner:<br></div>- lastCharacter the last character that was processed<br><div>
- lastCharacterExtent  its extent<br>- lastSpaceOrTabExtent the extent of last spce or tab (why?)<br></div><div>- specialWidth if it wasn&#39;t a character but an embedded morph<br><br></div><div>And the number of conditions scattered in the stop conditions:<br>
<br>    ((characterIndex ~= nil<br>        and: [characterIndex &gt; text size])<br>            or: [(line last = text size)<br>                and: [(destY + line lineHeight) &lt; characterPoint y]])<br><br>    characterIndex == nil ifFalse: [<br>
        characterIndex &gt; text size ifTrue: [<br><br>    characterPoint x &lt;= (destX + (lastCharacterExtent x // 2))<br>        ifTrue:    [<br><br>    lastIndex &gt;= line last <br>        ifTrue:    [<br><br>    (((characterIndex ~~ nil and:<br>
        [runStopIndex &lt; characterIndex and: [runStopIndex &lt; text size]])<br>            or:    [characterIndex == nil and: [lastIndex &lt; line last]]) or: [<br>                ((lastIndex &lt; line last)<br>                and: [((text at: lastIndex) leadingChar ~= (text at: lastIndex+1) leadingChar)<br>
                    and: [lastIndex ~= characterIndex]])])<br>        ifTrue:    [<br><br>    ((lastCharacter = Space and: [alignment = Justified])<br>        or: [lastCharacter = Tab and: [lastSpaceOrTabExtent notNil]])<br>
        ifTrue: [<br><br>    runStopIndex = text size<br>        ifTrue:    [<br><br>    (destX + lastSpaceOrTabExtent x)  &gt;= characterPoint x<br>        ifTrue: [<br><br>    (alignment = Justified and: [self leadingTab not])<br>
        ifTrue:        &quot;imbedded tabs in justified text are weird&quot;<br>            [<br><br>    currentX &gt;= characterPoint x<br>        ifTrue: <br>            [<br><br></div><div>Plus the ones before and after scanning<br>
<br>    (text isEmpty or: [(characterPoint y &lt; destY or: [characterPoint x &lt; destX])<br>                or: [characterIndex notNil and: [characterIndex &lt; line first]]])<br>        ifTrue:    [<br><br>    characterIndex<br>
        ifNil: [<br>            (stopCondition ~~ #cr and: [ lastIndex = line last<br>                and: [ aPoint x &gt; ((characterPoint x) + (lastCharacterExtent x / 2)) ]])<br>                    ifTrue: [<br><br></div>
<div>Of course, a MVC Paragraph does not behave exactly the same.<br><br></div><div>I cannot really reverse engineer the state machine... It&#39;s not our best production.<br></div><div>I can conjecture that:<br>- characterIndex ~~ nil tests are probably related to the fact that moving cursor position with mouse or with arrow keys does not always result in consistent behavior (the cursor disappear in one case, remain visible in the other)<br>
</div><div>- testing once for (destX + lastSpaceOrTabExtent x) and the other for (destX + (lastCharacterExtent x // 2)) sounds weird<br><br></div><div>If you have any advice, reminiscence of bug report, useful comments to explain each and every logic, or anything related in this area, that might be helpful.<br>
<br></div><div>Nicolas<br></div><div><br></div></div>