[squeak-dev] What is the task of NullEncoder?

H. Hirzel hannes.hirzel at gmail.com
Mon Oct 2 12:10:41 UTC 2017

Hello Marcel, Nicolas, Tobias and Dave

Thank you Marcel W. for the illustrations and pointing out that the
NullEncoder (figures now included [5]) implements a pipe/and filter

The video about app architectures [6] in which you describe different
architecture styles is helpful. In particular you point out that the
choice of a pipe/filter architecture has advantages in terms of memory

Tobias, you ask
[the fact that some canvas subclasses do not use the 'target' object]
>  That’s only technically true, and really an oversight.  All canvases write their output somewhere, be it a bitmap, native display surface or other ‘DisplayMedium'.  A canvas is a filter for converting morphs to this target ‘DisplayMedium’.
> And having filter-canvases would be really cool :-)

You mean like ColorMappingCanvas, AlphaBlendingCanvas, and ShadowDrawingCanvas?
(Which, by your account, should not have an own myCanvas but rather
reuse target…)?

My answer is that I do not see any benefit of using 'target' in these classes.

But Marcel Weiher gave as well an example of a more elaborate
NullEncoder/FlattenEncoder/Canvas hierarchy to be used in a
pipe/filter architecture style. [7]

So let's try to add more output classes to see how we can benefit from
this architecture style.

Marcel Weiher noted in 1999 [8]
[10 Sept 1999,MPW]
The current MorphicPostscript support includes both EPS and multi-page
Postscript generation.

BookMorphs generate multi-page files, all other Morphs generate an EPS
ready for inclusion, though currently without a bitmap preview.

Postscript generation is split between a high-level class that maps
Morphic drawing commands to Postscript imaging model commands and a
low level class for generating actual Postscript code for the
commands, in order to facilitate drop-in replacements for SPDF, SVG or
comparable formats.

I also think this is a good base for supporting other device
independent graphic models and even direct device independent drawing.

So the best thing to see how the mechanism / architecture works is
actually to try out to add a few more "output encoders"

For example to render
1. a bookmorph (or just a series of morphs serving as 'slides') as a sequence
    of web pages or a series of slides in a presentation program,
2. a morph a SVG code
3. morphs as JSON descriptions to be used by a web services.
4. a sequence of morphs as a presentation for LibreOffice Impress export
    (LO Impress offers a 'flat XML format')
5. Powerpoint slides (zip archive generation needed)

I attach a demo / start of a MorphicHTMLCanvas  implementation
(Monticello mcz file).
The description of the implementation steps are under [9].

The demo does not actually run but brings up the context where it
shows that it is useful to have  access to a  'target' object  -- a
HTML/CSS encoder - from within the morph hierarchy.

    MorphicHTMLCanvas0Test new test01

The screen shot shows the method call hierarchy.

The demo does not show yet at which abstraction level in terms of
"drawing commands"

    aMorph fullDrawHTMLOn: self.

should operate. A more elaborate version of MorphicHTMLCanvas and a
JSON example added will follow.

Kind regards

[5] NullEncoder http://wiki.squeak.org/squeak/5052

     NullEncoder implements a filter

     Object subclass: #NullEncoder
	    instanceVariableNames: 'target filterSelector'
	    classVariableNames: ''
	    poolDictionaries: ''
	    category: 'Morphic-Support'

[6] UIKonf 2017 – Day 1 – Marcel Weiher – High Performance App Architecture

     pipe/filter architecture at

     minute 12:00, but 0:00..12:00 is useful to get the context
    - traditional call/return  'architecture' style

[7] Marcel Weiher  --

[8] Squeak Postscript support http://wiki.squeak.org/squeak/753

[9] Implementation steps to create a HTML/CSS canvas for rendering
morphs as a web code.

"1.   create a canvas for rendering Morphs as HTML"

      Canvas subclass: #MorphicHTMLCanvas0
	instanceVariableNames: 'morphLevel'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Add-Ons-HTML0'	

"2.  create a test class for it"

      TestCase subclass: #MorphicHTMLCanvas0Test
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Add-Ons-HTML0'

"3. Add an encoder to be used by  MorphicHTMLCanvas0 for generating HTML/CSS"

      PrintableEncoder subclass: #HTMLCSSEncoder0
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Add-Ons-HTML0'
"4a. Attach the  HTMLCSSEncoder0 to the MorphicHTMLCanvas0"
    MorphicHTMLCanvas0 class

	^HTMLCSSEncoder0 stream	

"4b. Add creation method"
    MorphicHTMLCanvas0 class

    morphAsHTML: aMorph
    | htmlCanvas |
    htmlCanvas := self new.
    htmlCanvas reset.
    htmlCanvas fullDrawMorph: aMorph .
  ^htmlCanvas contents.

"4c. Add main method for rendering morphs as HTML"


    fullDraw: aMorph
	  aMorph fullDrawHTMLOn: self.

"5. within the Morph hierarchy implement messages to 'draw' morphs as HTML"
    fullDrawHTMLOn: aStream
      "do not do anything yet"

"6. Morph"

    fullDrawHTMLOn: aCanvas

    self halt.

    "Here I can access

    aCanvas target

    and directly generate HTML and CSS code"

"7a.   set up test environment "

     self assert: (MorphicHTMLCanvas0 morphAsHTML: self createTestMorph)  notNil

"7b. an example morph for testing"

	"MorphicHTMLCanvas0Test new createTestMorph openInWorld"
	| slide |
	slide := RectangleMorph new extent: 800 @ 600;
				 position: 10 @ 50;
				 color: Color blue.
	slide addMorph: (RectangleMorph new extent: 100 @ 100;
			 position: 20 @ 60;
			 color: Color yellow).
	^ slide

On 10/2/17, Marcel Weiher <marcel.weiher at gmail.com> wrote:
>> On Sep 30, 2017, at 7:34 , Tobias Pape <Das.Linux at gmx.de
>> <mailto:Das.Linux at gmx.de>> wrote:
>> No, thats Marcel Weiher. He did a quite a lot Squeak/Postscript Stuff.
>> I CC'ed him.
>> Marcel, can you comment on the Encoder Hierarchie?
>> (Full thread here)
> Hi Tobias et al,
> thanks for tagging me.  :-)
> The “Encoder” classes are a Squeak version of an “object oriented pipes and
> filters” system I implemented in Objective-C in the late 90s:
> https://github.com/mpw/MPWFoundation/tree/master/Streams.subproj
> <https://github.com/mpw/MPWFoundation/tree/master/Streams.subproj>
> Why?  Well, because the Postscript generation code was based on my
> Objective-C Postscript processing code
> (http://www.metaobject.com/Technology/#EGOS
> <http://www.metaobject.com/Technology/#EGOS>), which is heavily based on
> these filters.
> I have found the filters to be incredibly useful over the last 20 years,
> partly because they compose so well:  just like Unix pipes and filters, they
> are symmetric so that their input protocol ( #writeObject: ) is the same as
> their output protocol ( #writeObject:).  The filterSelector is there to
> allow filter-specific processing using double dispatch, but once the
> processing is done the result is once again normalized to a #writeObject:
> You can therefore combine these filters any way you want.
> Another feature is that they are, like Unix filters, fundamentally
> incremental, so multiple processing steps are interleaved and both input and
> output can stream directly to/from disk/network.  When doing pre-press in
> the early 90ies (file sizes >> memory sizes) this was a useful feature, and
> it is still helpful today, see for example the first part of my UIKonf
> talk:
> 	https://www.youtube.com/watch?v=kHG_zw75SjE
> <https://www.youtube.com/watch?v=kHG_zw75SjE>
> More recently, the fact that filters are dataflow-oriented and therefore
> don’t care much about the control flow has made them useful in implementing
> asynchronous processing pipelines  Think “FRP” just simpler, more readable
> and faster.  The Microsoft To-Do network stack is implemented using this.
> With all the references to Unix P/F, it is probably no surprise that this
> also subsumes Unix I/O, just with the advantage of an OO hierarchy of
> shareable behavior.  Oh, and also the interesting feature of subsuming both
> filters and (output) streams, so ‘stdout’ in Objective-Smalltalk is one of
> these, a ByteStream that knows how to serialize objects and output them to
> some target that expects bytes.  And in ‘stsh’ it’s a slight variant of
> MPWByteStream that is more helpful to a human interacting.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Demo_how_to_render_morphs_as_HTML_2017-10-02.png
Type: image/png
Size: 57381 bytes
Desc: not available
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20171002/85aca901/attachment-0001.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Add-Ons-HTML0-hjh.1.mcz
Type: application/octet-stream
Size: 3093 bytes
Desc: not available
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20171002/85aca901/attachment-0001.obj>

More information about the Squeak-dev mailing list