Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 1 addition & 85 deletions README
Original file line number Diff line number Diff line change
@@ -1,85 +1 @@
/***************************************************************************

HTMLview.mcc - HTMLview MUI Custom Class
Copyright (C) 1997-2000 Allan Odgaard
Copyright (C) 2023-2026 Dimitris Panokostas <midwan@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

Project home: https://github.com/midwan/htmlview

***************************************************************************/

With full permission of the previous author (Allan Odgaard) HTMLview.mcc
12.6+ is released as free software under the GNU Lesser General Public
License. Please read COPYING for the full terms.


BUILDING
--------

The class and its reference test programs cross-compile from macOS/Linux
using the Docker toolchain images published by sacredbanana:

# AmigaOS 3 (m68k)
docker run --rm -v "$(pwd):/work" -w /work/mcc \
sacredbanana/amiga-compiler:m68k-amigaos sh -c "make -f makefile OS=os3"

# AmigaOS 4 (ppc)
docker run --rm -v "$(pwd):/work" -w /work/mcc \
sacredbanana/amiga-compiler:ppc-amigaos sh -c "make -f makefile OS=os4"

# MorphOS (ppc)
docker run --rm -v "$(pwd):/work" -w /work/mcc \
sacredbanana/amiga-compiler:ppc-morphos sh -c "make -f makefile OS=mos"

Build products land under mcc/bin_<os>/:

HTMLview.mcc -- the MUI custom class binary
libhtmlview_nethook.a -- reusable image/content load hook library
SimpleTest, LibLoad_Test -- reference programs exercising the class


LINKING THE NET HOOK
--------------------

Host applications that want the built-in HTTP / HTTPS load hook link
libhtmlview_nethook.a and call HTMLviewNet_InitHook(&hook) at startup --
see mcc/net_hook/htmlview_nethook.h for the full API. The hook opens
bsdsocket / AmiSSL lazily from the decoder task, so the host does not
need to OpenLibrary any networking library itself.

Optional runtime knobs (all hook-local, no MUI tags required):

HTMLviewNet_SetCABundle(path) -- override AmiSSL CA trust store
HTMLviewNet_SetVerifyMode(mode) -- AUTO / NONE / PEER
HTMLviewNet_SetCacheDir(path) -- enable on-disk response cache
HTMLviewNet_SetCacheTTL(seconds) -- fallback TTL for unhinted responses


BEHAVIOUR NOTES
---------------

* MUIA_HTMLview_Scrollbars is now a no-op: OM_NEW always returns the
bare HTMLview gadget. Callers that want scrollbars wrap the gadget
externally with MUIC_Scrollgroup -- SimpleTest.c shows the pattern.
The legacy auto-wrap path was incompatible with class-introspecting
hosts (e.g. RapaGUI) and the change makes the gadget cooperate with
them. Apps that built directly against ScrollGroupClass are
unaffected; the class is still registered.


CONTRIBUTING
------------

Issues and pull requests are welcome on GitHub. The roadmap for ongoing
work lives in IMPROVEMENTS.md at the repo root; each phase there is
scoped to be independently mergeable.
This file has been superseded by README.md.
122 changes: 122 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# HTMLview.mcc

An HTML rendering MUI custom class for AmigaOS, MorphOS, and AROS.

Originally written by Allan Odgaard in the late 1990s, now actively maintained
and modernised. HTMLview renders HTML 4 inside any MUI application — email
clients, documentation viewers, help browsers, and more.

**Current version:** 13.7 · **License:** LGPL 2.1+ · **Repo:**
<https://github.com/midwan/htmlview>


## Runtime requirements

| Dependency | Required | Notes |
|---|---|---|
| MUI 3.8+ (`muimaster.library` ≥ 19) | **Yes** | Core UI framework |
| BetterString.mcc | No | Used by the preferences editor for enhanced text input. Falls back to standard MUI `String` gadgets when absent. |
| HotkeyString.mcc | No | Used by the preferences editor for the page-scroll key binding. Falls back to a standard MUI `String` gadget when absent. |
| TextEditor.mcc | No | Required for HTML `<textarea>` form elements. If absent, textarea fields are silently skipped. |

All three optional MCCs ship with standard MUI distributions. The class will
not crash if any of them are missing — every external custom class is tried at
runtime with a built-in fallback.


## Building

Cross-compile from Linux/macOS/Windows using the Docker toolchain images:

```bash
# AmigaOS 3 (m68k)
docker run --rm -v "$(pwd):/work" -w /work/mcc \
sacredbanana/amiga-compiler:m68k-amigaos sh -c "make -f makefile OS=os3"

# AmigaOS 4 (ppc)
docker run --rm -v "$(pwd):/work" -w /work/mcc \
sacredbanana/amiga-compiler:ppc-amigaos sh -c "make -f makefile OS=os4"

# MorphOS (ppc)
docker run --rm -v "$(pwd):/work" -w /work/mcc \
sacredbanana/amiga-compiler:ppc-morphos sh -c "make -f makefile OS=mos"
```

Build products land under `mcc/bin_<os>/`:

| File | Description |
|---|---|
| `HTMLview.mcc` | The MUI custom class |
| `HTMLview.mcp` | Preferences editor (MUI preferences panel) |
| `libhtmlview_nethook.a` | Reusable image/content load hook library |
| `SimpleTest`, `LibLoad_Test` | Reference programs exercising the class |

CI builds all three platforms on every push and attaches binaries to releases.


## Net hook library

Host applications that want HTTP/HTTPS image loading link
`libhtmlview_nethook.a` and call `HTMLviewNet_InitHook(&hook)` at startup —
see `mcc/net_hook/htmlview_nethook.h` for the full API. The hook opens
bsdsocket/AmiSSL lazily from the decoder task, so the host never needs to
open a networking library itself.

Runtime knobs (all hook-local, no MUI tags required):

```c
HTMLviewNet_SetCABundle(path) // override AmiSSL CA trust store
HTMLviewNet_SetVerifyMode(mode) // AUTO / NONE / PEER
HTMLviewNet_SetCacheDir(path) // enable on-disk response cache
HTMLviewNet_SetCacheTTL(seconds) // fallback TTL for unhinted responses
```


## What's new since v12

Maintenance picked up at v12.6 (the last SourceForge release). Highlights
through v13.7:

- **Robustness** — runtime fallback for missing external MCCs (BetterString,
HotkeyString); NULL-safety in HTML form gadgets; no system crashes when
optional classes are absent.
- **HTTPS** — TLS via AmiSSL with certificate verification and http→https
redirect following.
- **Net hook library** — the ~600-line image load hook extracted into a
reusable static library (`libhtmlview_nethook.a`) with TLS verify, disk
cache, and diagnostics logging.
- **MUI 4 compatibility** — backfill handler guards that were causing
rendering corruption on MUI 4+ (Zune, MUI 5) fixed.
- **Scrollbars reworked** — `MUIA_HTMLview_Scrollbars` is now a no-op. The
class always returns the bare HTMLview gadget. Wrap externally with
`MUIC_Scrollgroup` for scrollbars (`SimpleTest.c` shows the pattern). This
fixes compatibility with class-introspecting hosts like RapaGUI.
- **Multi-platform CI** — automated builds for AmigaOS 3, AmigaOS 4, and
MorphOS on every push, with GitHub Release publishing.
- **Crash fixes** — half-constructed OM_DISPOSE path that rebooted MUI 4+
machines, sprintf→snprintf overflow, and various null-pointer paths.


## Behaviour notes

- **Text outside `<body>` is not shown.** HTML 4 does not require the tag,
but the current parser gates on it. Tracked in IMPROVEMENTS.md Phase 7.
- **Entities without trailing `;` are ignored.** `&amp` vs `&amp;`. Also
tracked in Phase 7.
- **No CSS support.** Inline `style=` attributes are silently dropped. CSS
subset support is planned (Phase 5).
- **Built-in image decoders:** GIF, JPEG, PNG only. Other formats require a
matching datatype (Phase 6 will add `picture.datatype` fallback).


## Contributing

Issues and pull requests are welcome on GitHub. The roadmap lives in
`IMPROVEMENTS.md`; each phase is scoped to be independently mergeable.


## Credits

Originally by Allan Odgaard. Maintained since 2023 by Dimitris Panokostas
with contributions from Alfonso Ranieri, Ilkka Lehtoranta, Jens Langner,
Thore Boeckelmann, and Dwight Meese. See `AUTHORS` for the full list.
2 changes: 1 addition & 1 deletion mcc/classes/InputClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ VOID InputClass::AppendGadget (struct AppendGadgetMessage &amsg)
break;
*/
case Input_Button:
obj = SimpleButton(Value);
obj = SimpleButton(Value ? Value : (STRPTR)"");
break;

case Input_Submit:
Expand Down
117 changes: 86 additions & 31 deletions mcp/CreatePrefsGroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,23 @@ Object *
ostring(APTR key,APTR help)
{
#ifdef USEBETTERSTRING
return BetterStringObject,
#else
return StringObject,
Object *obj;

obj = BetterStringObject,
_HELP(help),
MUIA_ControlChar, GetKeyChar(key,TRUE),
MUIA_CycleChain, TRUE,
StringFrame,
//MUIA_Textinput_AdvanceOnCR, TRUE,
End;

if(obj)
return obj;
#endif

return StringObject,
_HELP(help),
MUIA_ControlChar, GetKeyChar(key,TRUE),
MUIA_ControlChar, GetKeyChar(key,TRUE),
MUIA_CycleChain, TRUE,
StringFrame,
//MUIA_Textinput_AdvanceOnCR, TRUE,
Expand Down Expand Up @@ -163,6 +174,7 @@ Object *CreatePrefsGroup(Object *parent,struct InstData_MCP *data)

Object **objs = data->Objects;
Object *group, *sample;
Object *keySetting;
#ifdef USEHOTKEY
Object *snoop;
#endif
Expand All @@ -177,6 +189,64 @@ Object *CreatePrefsGroup(Object *parent,struct InstData_MCP *data)
Dither[1] = GetStr(MSG_Images_Dither_None);
Dither[2] = NULL;

/* Pre-create the key-setting object: try HotkeyString.mcc first,
* fall back to a plain String gadget if the class is not installed. */
#ifdef USEHOTKEY
snoop = NULL;
{
Object *keyObj = HotkeyStringObject,
StringFrame,
MUIA_ControlChar, GetKeyChar(MSG_PageScroll_Key_Key,TRUE),
MUIA_CycleChain, TRUE,
MUIA_HotkeyString_Snoop, FALSE,
End;

if(keyObj)
{
Object *snoopBtn = obutton(MSG_Hotkey_Snoop,0,0);
if(snoopBtn)
{
keySetting = HGroup,
MUIA_Group_HorizSpacing,1,
Child, keyObj,
Child, snoopBtn,
End;

if(keySetting)
{
objs[PageScrollKey] = keyObj;
snoop = snoopBtn;
}
else
{
MUI_DisposeObject(snoopBtn);
MUI_DisposeObject(keyObj);
}
}
else
{
MUI_DisposeObject(keyObj);
}
}
}
if(!snoop)
{
objs[PageScrollKey] = StringObject,
MUIA_ControlChar, GetKeyChar(MSG_PageScroll_Key_Key,TRUE),
MUIA_CycleChain, TRUE,
StringFrame,
End;
keySetting = objs[PageScrollKey];
}
#else
objs[PageScrollKey] = StringObject,
MUIA_ControlChar, GetKeyChar(MSG_PageScroll_Key_Key,TRUE),
MUIA_CycleChain, TRUE,
StringFrame,
End;
keySetting = objs[PageScrollKey];
#endif

group = RegisterObject,
MUIA_CycleChain, TRUE,
MUIA_Register_Titles, PageTitles,
Expand Down Expand Up @@ -367,25 +437,7 @@ Object *CreatePrefsGroup(Object *parent,struct InstData_MCP *data)
End,

Child, olabel2(MSG_PageScroll_Key,MSG_PageScroll_Key_Key),
#ifdef USEHOTKEY
Child, HGroup,
MUIA_Group_HorizSpacing,1,
Child, objs[PageScrollKey] = HotkeyStringObject,
StringFrame,
MUIA_ControlChar, GetKeyChar(MSG_PageScroll_Key_Key,TRUE),
MUIA_CycleChain, TRUE,
MUIA_HotkeyString_Snoop, FALSE,
End,
Child, snoop = obutton(MSG_Hotkey_Snoop,0,0),
End,
#else
Child, objs[PageScrollKey] = KeyadjustObject,
MUIA_ControlChar, GetKeyChar(MSG_PageScroll_Key_Key,TRUE),
MUIA_CycleChain, TRUE,
MUIA_Keyadjust_AllowMouseEvents, FALSE,
MUIA_Keyadjust_AllowMultipleKeys, FALSE,
End,
#endif
Child, keySetting,

Child, olabel2(MSG_PageScroll_Move,MSG_PageScroll_Move_Key),
Child, objs[PageScrollMove] = SliderObject,
Expand Down Expand Up @@ -424,14 +476,17 @@ Object *CreatePrefsGroup(Object *parent,struct InstData_MCP *data)
End;

#ifdef USEHOTKEY
SetAttrs(snoop,
MUIA_Weight, 0,
MUIA_CycleChain, TRUE,
MUIA_InputMode, MUIV_InputMode_Toggle,
TAG_DONE);

DoMethod(snoop, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, (ULONG)objs[PageScrollKey], 3, MUIM_Set, MUIA_HotkeyString_Snoop, MUIV_TriggerValue);
DoMethod(snoop, MUIM_Notify, MUIA_Selected, TRUE, MUIV_Notify_Window, 3, MUIM_Set, MUIA_Window_ActiveObject, (ULONG)objs[PageScrollKey]);
if(snoop)
{
SetAttrs(snoop,
MUIA_Weight, 0,
MUIA_CycleChain, TRUE,
MUIA_InputMode, MUIV_InputMode_Toggle,
TAG_DONE);

DoMethod(snoop, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, (ULONG)objs[PageScrollKey], 3, MUIM_Set, MUIA_HotkeyString_Snoop, MUIV_TriggerValue);
DoMethod(snoop, MUIM_Notify, MUIA_Selected, TRUE, MUIV_Notify_Window, 3, MUIM_Set, MUIA_Window_ActiveObject, (ULONG)objs[PageScrollKey]);
}
#endif

DoMethod(sample,MUIM_Notify,MUIA_Pressed,FALSE,MUIV_Notify_Application,4,
Expand Down