Text Morph Embedding Broken

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Text Morph Embedding Broken

Sean P. DeNigris
Administrator
http://bugs.squeak.org/view.php?id=7806

Squeak4.5 latest update: #13352

Text withAll: 'foo') , (Text string: '*' attribute: (TextAnchor new anchoredMorph: MenuIcons confirmIcon)) , (Text withAll: 'bar').
text asMorph openInHand.

The Morph contents are 'foo*bar' i.e. no icon
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Nicolas Cellier
Ah yes, that's true.
Try with Character value: 1 instead of *:

text := (Text withAll: 'foo') , (Text string: (Character value: 1) asString attribute: (TextAnchor new
anchoredMorph: MenuIcons confirmIcon)) , (Text withAll: 'bar').
text asMorph openInHand


2014/1/8 Sean P. DeNigris <[hidden email]>
http://bugs.squeak.org/view.php?id=7806

Squeak4.5 latest update: #13352

Text withAll: 'foo') , (Text string: '*' attribute: (TextAnchor new
anchoredMorph: MenuIcons confirmIcon)) , (Text withAll: 'bar').
text asMorph openInHand.

The Morph contents are 'foo*bar' i.e. no icon



-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Text-Morph-Embedding-Broken-tp4735055.html
Sent from the Squeak - Dev mailing list archive at Nabble.com.




Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Sean P. DeNigris
Administrator
Nicolas Cellier wrote
Ah yes, that's true.
Try with Character value: 1 instead of *:
Yes, that works. So is it a bug or not?

Another thing… There is noise around the embedded form. It seems that BitBltDisplayScanner>>#displayEmbeddedForm: should be changed to:
        aForm
                displayOn: bitBlt destForm
                at: destX @ (lineY + line baseline - aForm height)
                clippingBox: bitBlt clipRect
                rule: Form blend
                fillColor: Color white
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Nicolas Cellier



2014/1/8 Sean P. DeNigris <[hidden email]>
Nicolas Cellier wrote
> Ah yes, that's true.
> Try with Character value: 1 instead of *:

Yes, that works. So is it a bug or not?


I don't know.
See the comment of Morphic-nice.695 which explains why this change was made.
The old code (lr 2006) was buggy and wrong: it did cause glitches.

For example, just insert a space between foo and the icon after opening the morph and see how it hurts.
And note how differently weird it behaved when you replaced * with Character value: 1...

Embedded morphs/forms created interactively will be over (Character value: 1) and work OK.
For embedded morphs/forms created programmaticaly as you did, we have to decide something...

Another thing… There is noise around the embedded form. It seems that
BitBltDisplayScanner>>#displayEmbeddedForm: should be changed to:
        aForm
                displayOn: bitBlt destForm
                at: destX @ (lineY + line baseline - aForm height)
                clippingBox: bitBlt clipRect
                rule: Form blend
                fillColor: Color white


Yes I saw that too.
If we change it, it should use BitBltDisplayScanner backgroundColor inst. var. (transparent) rather than white in any case.

But I'd like to understand first.
What is strange is that old code in DisplayScanner>>placeEmbeddedObject: did just
        anchoredMorph
            displayOn: bitBlt destForm
            at: destX - anchoredMorph width @ destY
            clippingBox: bitBlt clipRect
Exactly as the new code do in BitBltDisplayScanner>>displayEmbeddedForm:

But this was probably happening in a different order - as soon as setFont (mutated graphics context in action).
I instrumented, and it seems that the new version is using combinationRule 37 (rgbMul) at time of Form display...
This is one rule used by StrikeFont subpixel rendering:
(SystemNavigation default browseAllCallsOn: 37) -> rgbMul -> installStrikeFont:foregroundColor:backgroundColor:.

It might be those lines in new DisplayScanner>>displayLine:offset:leftInRun:
        stopConditionsMustBeReset
            ifTrue:[self setStopConditions].

Lazyness + stateful mutations might lead to modified side effects...
 

-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Text-Morph-Embedding-Broken-tp4735055p4735059.html
Sent from the Squeak - Dev mailing list archive at Nabble.com.




Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Sean P. DeNigris
Administrator
Nicolas Cellier wrote
If we change it, it should use BitBltDisplayScanner backgroundColor inst.
var. (transparent) rather than white in any case.
In Pharo, changing to "… fillColor: backgroundColor" makes the embedded form invisible
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Nicolas Cellier

2014/1/8 Sean P. DeNigris <[hidden email]>
Nicolas Cellier wrote
> If we change it, it should use BitBltDisplayScanner backgroundColor inst.
> var. (transparent) rather than white in any case.

In Pharo, changing to "… fillColor: backgroundColor" makes the embedded form
invisible


Yep, you were right, I learned BitBlt in st80 v2 and Smalltalk V, but it was in B&W and too long ago...
I should recycle and revise the colorfull halftone rules ;)
 


-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Text-Morph-Embedding-Broken-tp4735055p4735066.html
Sent from the Squeak - Dev mailing list archive at Nabble.com.




Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Sean P. DeNigris
Administrator
In reply to this post by Nicolas Cellier
Nicolas Cellier wrote
For embedded morphs/forms created programmaticaly as you did, we have to
decide something...
Just reifying and documenting may be enough. For Pharo, I'm proposing (1) an update to the TextAnchor class comment and (2):
Morph>>#asText

        | anchor embedMorphSignal |
        anchor := TextAnchor new anchoredMorph: self.
        embedMorphSignal := (Character value: 1) asString. "required by the scanner"
        ^ Text string: embedMorphSignal attribute: anchor.

b.t.w. is "required by the scanner" accurate
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Nicolas Cellier

2014/1/8 Sean P. DeNigris <[hidden email]>
Nicolas Cellier wrote
> For embedded morphs/forms created programmaticaly as you did, we have to
> decide something...

Just reifying and documenting may be enough. For Pharo, I'm proposing (1) an
update to the TextAnchor class comment and (2):
Morph>>#asText

        | anchor embedMorphSignal |
        anchor := TextAnchor new anchoredMorph: self.
        embedMorphSignal := (Character value: 1) asString. "required by the
scanner"
        ^ Text string: embedMorphSignal attribute: anchor.

b.t.w. is "required by the scanner" accurate

Yep, exactly, that's how the scanner loop works.
If you want it, here are a few things I can tell about the scanner and some recent evolutions:

The scanner processes run after run (a run is a chunk of text with homogeneous emphasis, like, bold italic, ...).
In each run, the font is set according to current emphasis.
Inside a run, the scanner then compose/displays string chunks separated by well know special character (space if justified alignment, tab, cr/lf and (Character value: 1)).
A special action associated to the special character is then processed, and this composiiton/display loop continues until end of run.
Those special characters and associated actions are stored in stopConditions which map special character code ->special action (nil if none).
Note that currently (heritage of ASCII) the special character code are limited from 0 to 255. There currently cannot be any special wide character.
Two more code are used for two special conditions
- the composition crossed the X boundary (the right margin in latin - we don't yet support arabic or hebrew right to left).
- the endOfRun was reached
In fact, the two external loops (runs and chunks) are (or can be) fused, thanks to the #endOfRun actions linked to these EndOfRun special code.

The character by character scanning for stop conditions is performed inside an internal loop which is very simple and can be generated as a primitive.
This provides great speed up for composing/displaying on slow devices, but is unfortunately restricted to StrikeFonts and char codes < 256 currently...
This primitive access/mutates some of the scanner states, and thus requires a specific inst. var. layout which was broken quite some times ago (search mantis or this mailing list for reference).
It must also have two reserved slots for crossedX and endOfRun conditions which I previously broke (in order to correct a bug: endOfRun was hikacking A-macron char code, perventing its display).
Note that some people (including me) thought that having an indirection stopConditions at: EndOfRun put:#endOfRun was an unecessarily over-engineered feature.
This was not the original goal : the original goal was to have a primitive, and indeed the VM cannot easily perform a squeak method, thus the indirection.
Also the VM cannot easily access Symbols by name - unless we reserve additional SpecialObjects (oh no!) - thus the two reserved slots.
We restored all these conditions recently with Tim, enabling the primitive to run again in both Squeak and Pharo.
Tim added the double dispatch things to properly handle other kind of fonts or WideString by non primitive code.
This should enable using Squeak/Pharo on Pi or other slow devices with smoother user experience (if restricting to latin1 StrikeFont).

The old TextAnchor code did not play well this logic. It was a hack added a posteriori, which tried to perform special actions outside the composition/display loop (during setting of the font).
Unfortunately, this violates some implicit invariants, because some states are either not yet correctly set, or set twice (like advancing the X position).
These are the glitches that you can see when inserting a white space in 'foo *bar'.
An unused control Character (value: 1) had been assigned previously for embedded morph/form before this hack, (late 90s ? early 2000s ?), but maybe the hack was older after all (use Bob Arning site for exploring old Squeak changes if you are curious)...

If we really insist on transforming any character code as an anchor, we can as well try to rewrite the logic to handle TextAnchor specially (as an isolated run ?), but:
1. this is quite involved: I greatly reduced the number of mutated states (inst-var) in my recent reviews, but there are still a bit too many
2. this is constrained by the fact that the internal loop must remain simple in order to be generated.
3. if you change the internal loop logic, then you must allocate a new primitive # (or you break the property that the interpreter VM supports old images - we wish to keep it)
4. we miss (non regression) tests - I started some unpublished attempts, but given that there are many logics in those composition/display, it's really hard to write good tests. Moreover, I'm not sure that using MethodWrappers on such kind of low level methods in order to measure coverage is an easy thing ;).

Another strategy in Pharo is to let things as they are now, and wait for a better (but you must tell versus which criterion) or at least revisited Text model...

Last thing, the FreeTypePlugin primitives currently can only compose and display character by character... This is a pity because it's a huge slow down !
So if you start Pharo 3.0 on a Pi, please revert to a strike font like dejaVu sans.
Maybe that's something we could address with moderate effort, if there is good will and interest.
But what are the mid-term Pharo plans about Text composition/redering? Will some new 3rd party libraries be used?

Nicolas



-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Text-Morph-Embedding-Broken-tp4735055p4735207.html
Sent from the Squeak - Dev mailing list archive at Nabble.com.




Reply | Threaded
Open this post in threaded view
|

Re: Text Morph Embedding Broken

Nicolas Cellier
In reply to this post by Sean P. DeNigris
2014/1/8 Sean P. DeNigris <[hidden email]>
Nicolas Cellier wrote
> Ah yes, that's true.
> Try with Character value: 1 instead of *:

Yes, that works. So is it a bug or not?

Another thing… There is noise around the embedded form. It seems that
BitBltDisplayScanner>>#displayEmbeddedForm: should be changed to:
        aForm
                displayOn: bitBlt destForm
                at: destX @ (lineY + line baseline - aForm height)
                clippingBox: bitBlt clipRect
                rule: Form blend
                fillColor: Color white



OK, I understood my mistake...
There were two different implementations in DisplayScanner and MultiDisplayScanner, and I picked the wrong one... Gah !
You have the right snippet. Thanks!
 
Nicolas


-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/Text-Morph-Embedding-Broken-tp4735055p4735059.html
Sent from the Squeak - Dev mailing list archive at Nabble.com.