Contribution - An XHTML+CSS 2.1 control based on Flying Saucer

Ever wanted to display XHTML content in JME? Well, now you can! The following is a TonegodGUI renderer for Flying Saucer, a pure java XML/XHTML+CSS 2.1 engine.

The core class is the TGXHTMLRenderer. This is a TonegodGUI “Element” and so is treated the same as all other controls. Some key features …

  • Styles XML/XHTML content.
  • Fairly complete CSS 2.1 compliance.
  • ALMOST no AWT involved (apart from image loading and scaling).
  • Based on ScrollPanel, AnimText and the core Flying Saucer library.
  • Intercept links.
  • Intercept form submissions.
  • Abstracted “User Agent”. Loaded stuff from the net, the classpath, whereever.
  • Use as either a traditional browser type panel with a background, or remove the background and overlay XHTML on your scene.

It is not …

  • Able to render any old web page, it needs to be fully compliant XHTML, so you really need to be in control of the content you display.
  • Complete and bug free, yet. I’ll detail what’s missing below.

I based this on Tonegod for a few reasons. Firstly of course TonegodGUI provides all the required form controls. It also has “Content Paging” which takes care of keeping non-visible elements out of the scene (BIG help on large documents). It also has AnimText which amongst other things should make some cool stuff possible later.

Here is a quick video showing all the demo pages Flying Saucer comes with (here is a link to the Swing version of this, you can use it for comparing the possible level of support).

[video]http://youtu.be/Mz0OVLvmh3o[/video]

The test app shown in the Video (also use this for now to get the libraries if you want to try it out yourself) …

Linux Demo App,
MacOSX Demo App,
Windows Demo App

So what doesn’t work properly? Probably the biggest thing is ‘targeted repaints’. This is repainting of only the elements that have changed. I haven’t yet worked out how best to do this, but it’s usable without on relatively small documents. The Hamlet example was removed from the demo because it is pretty large. Another symptom of this missing feature is css positioning doesn’t work correctly with elements that are supposed to stay at fixed positions as the page is scrolled.

Also some drawing primitives are only partially implemented. For example filled circles (and ovals) and filled paths. This defiency is visible in the borders test page. I am open to suggestions how best to paint shapes such as filled circles and paths without using BufferedImage and AWT drawing. I found some code on the forum for a custom circle mesh that is a line, I presume this needs to be expanded upon to get filled meshes.

Note this required some hacks to the Tonegod source, and the demo app here is using that hacked version. It won’t work with standard Tonegod GUI currently. I had the following issues, please feel free to ask for more details on any of them. Some I can supply patches for.

  1. Content paging - awesome, but can there be a way to manually call it, or maybe call it when content is added. When adding content, until you scroll, you can end up with lots of stuff in the scene.
  2. Needed a Element.setColorMap(Image) method. Image objects are passed around, but Element only takes string paths.
  3. Clipping needs fixing on AnimText. Also TextElement has a clipping layer added by default, I have to remove this or fonts that descend beyond baseline get chopped. This may be the vertical alignment issue below.
  4. Need option to turn off anim text tag parsing. I don’t really need any of the tags (except maybe as a fallback when no style specific fonts are available).
  5. Rounding in ScrollPanel (was causing 1 pixel out problems for borders) and blurring of text.
  6. ComboBox and SelectList both caused lots of headaches. It’s hard to set font / font size of items in a combo box, or in a selectlist. Also have to get at menuItemHeight via and set it via reflection so highlighting works. The also both act very stangely when resizing. I REALLY look forward to these getting some attention :slight_smile:
  7. No way of ‘disabling’ combobox items or list items. (for optiongroups, also indenting). Presumably currently this won’t be possibly without some controls.
  8. There are some issues will scroll panel sizing. It’s possible for content to start moving down when it shouldn’t. I also find that calling reshape() always messes up.
  9. Some vertical alignment issues with AnimText. The font in use and the font size seems to have an impact on alignment. I intend to produce a test app to show these issues.

There is a little more work to do before I can make the source available, but feel free to have a play with the demo apps. If you want to try to include it in your own app now, the example source should help. Just add all the libraries included in the above downloads.

RR

9 Likes

That’s pretty

Thanks!

PS Multicoloured vomit is a compliment, right?

@rockfire
I believe it is… because I just did it too =)

This is awesome. I’ll have time tomorrow to put this and the split panel control into the library. I’ve been sorting out a bug I found with android input after the app loses focus. I found it… I squashed it… I’m exhausted from the hair pulling >.<

I may be able to do this tonight. Are there any issues that would stop this from compiling on Android or iOS that you are aware of? I’ll test it a buncheses… but in case you are aware of what I should be looking for.

Ok… maybe a support plugin for this one? We’ll see what works. Too cool to not have readily available somehow.

@rockfire
Also… we can address each of the issues stated, I’ve just been trying to get through the existing list I have in the order received.

@t0neg0d said: @rockfire I believe it is... because I just did it too =)

This is awesome. I’ll have time tomorrow to put this and the split panel control into the library. I’ve been sorting out a bug I found with android input after the app loses focus. I found it… I squashed it… I’m exhausted from the hair pulling >.<

I may be able to do this tonight. Are there any issues that would stop this from compiling on Android or iOS that you are aware of? I’ll test it a buncheses… but in case you are aware of what I should be looking for.

Ok… maybe a support plugin for this one? We’ll see what works. Too cool to not have readily available somehow.

Hehe. That would be cool. I’m actually away for a week as from tomorrow, so will try to get you as much as you need tongiht.

I’m not sure about android. IIRC Android doesn’t have BufferedImage right? That currently comes into play if an image needs reszing, so it will fail there (just avoid content that needs it I guess). I think the long term solution there would be to add ImagePainter plugin as a dependency. I’m not super familiar with that plugin, maybe it can draw some of the primitives too as bitmaps instead.

Other than that everything else is standard stuff.

The only API breakage would be Element.setColorMap(Image img). So you’ll need this method …

[java]

public void setColorMap(Image colorMap) {
	Texture color = null;
	if (screen.getUseTextureAtlas() &amp;&amp; !useLocalTexture) {
		if (this.getElementTexture() != null)	color = getElementTexture();
		else									color = screen.getAtlasTexture();
	} else {
		color = new Texture2D(colorMap);
		color.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
		color.setMagFilter(Texture.MagFilter.Nearest);
		color.setWrap(Texture.WrapMode.Clamp);
	}
	
	this.defaultTex = color;
	
	if (!screen.getUseTextureAtlas() || useLocalTexture) {
		float imgWidth = color.getImage().getWidth();
		float imgHeight = color.getImage().getHeight();
		float pixelWidth = 1f/imgWidth;
		float pixelHeight = 1f/imgHeight;

		this.model = new ElementQuadGrid(this.dimensions, borders, imgWidth, imgHeight, pixelWidth, pixelHeight, 0, 0, imgWidth, imgHeight);

		geom.setMesh(model);
	} else {
		throw new UnsupportedOperationException();
	}
	
	mat.setTexture("ColorMap", color);
	mat.setColor("Color", ColorRGBA.White);
}

[/java]

All the other tweaks I mentioned just show as alignment issues or would just be nice to have.

Give us an hour or so and I can get the source together for you too. Will post download link here.

Here is the source, its just two SDK projects with the private directories removed.

I should probably explain how fonts are handled. Supplied in the library are twelve fonts (of size 20). 4 variants of 3 main families.

Monospace

Monospace
MonospaceBold
MonospaceItalic
MonospaceBoldItalic

Sans

Sans
SansBold
SansItalic
SansBoldItalic

Serif

Serif
SerifBold
SerifItalic
SerifBoldItalic

Also in the library is a font mapping file. This maps some common logical font names to the actual bitmap fonts used. If you want to use more fonts, you’d make the .fnt files and add some mappings to the fontmap.properties resource (I need to make this ‘pluggable’ somehow, allowing override of the defaults and addition of new fonts without messing with this file).

[java]
default*=!sans

Monospaced

monospace=tonegod/gui/xhtml/styles/def/monospace20.fnt
monospaceBold=tonegod/gui/xhtml/styles/def/monospaceBold20.fnt
monospaceItalic=tonegod/gui/xhtml/styles/def/monospaceItalic20.fnt
monospaceBoldItalic=tonegod/gui/xhtml/styles/def/monospaceBoldItalic20.fnt
monospaced*=!monospace
couriernew*=!monospace

Sans

sans=tonegod/gui/xhtml/styles/def/sans20.fnt
sansBold=tonegod/gui/xhtml/styles/def/sansBold20.fnt
sansItalic=tonegod/gui/xhtml/styles/def/sansItalic20.fnt
sansBoldItalic=tonegod/gui/xhtml/styles/def/sansBoldItalic20.fnt
arial*=!sans
tahoma*=!sans
verdana*=!sans
sansSerif*=!sans

Serif

serif=tonegod/gui/xhtml/styles/def/serif20.fnt
serifBold=tonegod/gui/xhtml/styles/def/serifBold20.fnt
serifBoldItalic=tonegod/gui/xhtml/styles/def/serifBoldItalic20.fnt
serifItalic=tonegod/gui/xhtml/styles/def/serifItalic20.fnt
serifBoldItalic=tonegod/gui/xhtml/styles/def/serifBoldItalic20.fnt
times*=!serif
timesnewroman*=!serif
[/java]

The font names (the keys in this properties file) are normalised before use. Spaces, ‘-’ and ‘_’ are stripped and the whole thing is lower cased, so “Times New Roman” becomes “timesnewroman”. “Sans-Serif” becomes “sansserif”.

There are also a couple of special patterns used there. Using a ‘!’ in the value points one font name to another. Using a ‘*’ on the end of the key expands that key to 4 separate mappings, one for each type.

@rockfire said: Hehe. That would be cool. I'm actually away for a week as from tomorrow, so will try to get you as much as you need tongiht.

I’m not sure about android. IIRC Android doesn’t have BufferedImage right? That currently comes into play if an image needs reszing, so it will fail there (just avoid content that needs it I guess). I think the long term solution there would be to add ImagePainter plugin as a dependency. I’m not super familiar with that plugin, maybe it can draw some of the primitives too as bitmaps instead.

Other than that everything else is standard stuff.

I’m perfectly ok with limitations that need to be enforced… as long as will still compile for android is all I would be concerned about… some usable functionality that enhances the library is a heck of a lot better than none that enhances nothing :wink:

There are a couple options for BufferedImage support, depending on the need.

  1. custom Interface and switch the backing to Bitmap for android.
  2. ImagePainter, however this requires a dependency
  3. ImageRaster and write what is needed for bare bones… this can be expanded at some future time.

3 would be my preference only because it is part of JME core.

Wow, that is just outstanding.
Very good.
You guys really amaze me with the work you do.
Well done.

@ndebruyn said: Wow, that is just outstanding. Very good. You guys really amaze me with the work you do. Well done.

Total side note. I was playing your game last night =) It sure is a lot of fun! 247 is the best I can do so far.

Excellent
=D