Also, for those of you who may be unaware, long-time Mozillian Gervase Markham passed away, surrounded by his family. He was ever a professional to the end. I didn't know him as well as some, but I'll always remember him, not least of which for his unwavering faith in the face of adversity and leaving us far too soon. Go with God.
TenFourFox Feature Parity Release 9 beta 1 is now available (downloads, hashes, release notes). There are several new features and many bug fixes in this version. FPR9 is also the first TenFourFox release to pull from the new extended support release, Firefox 60ESR, and we have updated the extended validation certificate roots and our certs'n'pins import script to pull from that source instead of the shortly-to-be-decommissioned 52ESR. All relevant security and stability patches on 60ESR so far have also been backported.
On the bug fix side, there is a crash fix for media tracks from Raphael, updates to the ATSUI font blacklist (mostly for certain Japanese fonts) that can now block incompatible fonts through the CSS Font Loading API as well, updated timezone data for the ICU internationalization library, ICU security fixes, fixes for button sensing in events which should get around some weird glitchy things where the mouse buttons get ignored, and a dumb old bug with WiFi scanning. I also added a layout fix for button subelements that keep getting split apart, fixing problems on sites like Twitch and GoDaddy.
There are also a number of performance related changes. First, the idle observer minimal interval has been increased to be a better fit for our old machines, since doing this every second (potentially) robs CPU time and possibly instruction cache space away from user interaction. Do note, however, that while this reduces work being run while you use the browser the work is only delayed and not eliminated, meaning improvements in responsiveness and animation will be at the cost of memory being occasionally held longer and taking longer to release, and possibly longer GC pauses (though less often), so advise if you don't think the tradeoff is worth it (this is adjustable, though it's hardcoded within TenFourFox and is not a pref). This release also has some tuning to Cocoa events handling to slightly reduce scroll wheel latency and reduce some overhead with custom events, and additional code in JavaScript to make it more nimble about cancelling and recompiling since most of our systems are uniprocessor.
The other big change is to array handling. I backported a number of changes that landed in Firefox 55 which increase the performance of certain array operations such as splices and shifts by anywhere from 35 to 80 times. This does not translate into as dramatic a boost as you might think because in small numbers these types of operations were already reasonably swift, nor are they typically executed in large numbers or in tight loops back to back, but for those sites that do, they will run quite a bit quicker.
Of the new features, CSS column properties are now unprefixed and tested, which will help improve site compatibility. Unfortunately one big new feature that I planned for FPR9 won't make this release: deferred idle callbacks. The requestIdleCallback DOM API was enabled in Firefox in Fx55 and allows browsers to schedule work in the idle time between animation frames. Rarely do any of our old systems have such idle time available, and the 50ms or less usually granted (and actually checked for by the W3C test suite) isn't much time to do much work anyway. However, we can also infer from the timeout that is (optionally) passed that the website is able to tolerate the work being deferred up to that long, so deferred idle callbacks deferred the work up to that long. For example, on YouTube this would delay comments and other pieces of the UI so that the CPU could concentrate more on decoding and blitting frames. My initial thought was to try to run the callback when the system was not under load, but it turned out to be simpler and more reliable to just run it at the maximum timeout interval (or after a default interval if one was not specified). Unfortunately, after a lot of idle callbacks had run test builds started suffering random stalls even after the callbacks had completed, indicating something wasn't getting cleaned up, so it is pref'ed off in this version while I try to figure out what I did wrong. You can play with it by turning tenfourfox.dom.requestIdleCallback.enabled to true, but you'll have to restart the browser if you change that setting, so remember that any assessment you make about performance should keep in mind whether the browser is "fresh" or not. This is something I want to get working but it's not a major issue right now because most of the sites that depend on it (including YouTube) have polyfills.
However, the other big new feature I wanted in FPR9 did land: native HTML5 time and date input controls. On my list of future features likely to be used by sites, these scored very high because for those sites that don't need custom clock/calendar UIs this can eliminate them having to load and maintain one of their own just to select intervals. Date and time input controls were not implemented in Firefox until Fx60, and the implementation Firefox uses is a cross-platform one with a fair bit of JavaScript and other support code for vagaries in date handling and localization. I really didn't want to backport all of that because it would be slower and bloatier and especially because we already have all of this special handling built into Mac OS X itself through NSDate. So I took a tip from the Android version and, in a like manner to the colour picker and file picker, which use native Cocoa widgets, implemented date and time pickers using the built-in NSDatePicker widget. This, in turn, handles all the calendar and date manipulations so we don't have to, displays the calendar and time and date using the user's own locale, and does it all at native speed to boot. Genius!
For simplicity I chose to implement this as a modal window rather than the drop-down Firefox 60 uses, which solved a lot of synchronization issues even though it's not as slick. Ordinarily you'd implement a simple modal window in Cocoa with an NSAlert, and if you want to add something to the alert box, you do so by creating an NSView with the widgets you want to splice in and inserting it as an accessory view.
There's just one problem: NSAlert didn't implement setAccessoryView: until 10.5, so you can't do that in Tiger. Or can you?
When looking for undocumented functionality in Cocoa, the best tools are either class-dump (3.1.2 works with Tiger), or my personal favourite GUI tool, MagicHat. Let's see what MagicHat comes up with for NSAlert:
// Framework: AppKit // Header: NSAlert.h // Documentation: Unknown @interface NSAlert : NSObject { int _alertStyle; float _buttonPadding; float _buttonSpacing; float _buttonSpacingMaxX; float _buttonSpacingY; NSArray* _buttons; NSSize _defaultPanelSize; id _delegate; SEL _didDismissSelector; SEL _didEndSelector; NSWindow* _docWindow; id _first; id _helpAnchor; id _helpButton; id _imageView; NSTextField* _informationField; id _messageField; float _messagePadding; NSSize _minButtonSize; id _modalDelegate; NSPanel* _panel; id _second; char _showsHelp; id _third; NSImage* _unbadgedImage; char _useNSLayout; [?] reserved; id reserved1; id reserved2; }+ (id) alertWithError: (id) parameter1;
+ (id) alertWithMessageText: (id) parameter1 defaultButton: (id) parameter2 alternateButton: (id) parameter3 otherButton: (id) parameter4 informativeTextWithFormat: (id) parameter5;
+ (void) stopAllTimersForSpeaking;
- (char) _dontWarnAgain;
- (void) _setDontWarnMessage: (id) parameter1;
- (char) _showsDontWarnAgain;
- (id) addButtonWithTitle: (id) parameter1;
- (int) alertStyle;
- (void) beginSheetModalForWindow: (id) parameter1 modalDelegate: (id) parameter2 didEndSelector: (SEL) parameter3 contextInfo: (void*) parameter4;
- (id) buildAlertStyle: (int) parameter1 title: (id) parameter2 formattedMsg: (id) parameter3 first: (id) parameter4 second: (id) parameter5 third: (id) parameter6 oldStyle: (char) parameter7;
- (id) buildAlertStyle: (int) parameter1 title: (id) parameter2 message: (id) parameter3 first: (id) parameter4 second: (id) parameter5 third: (id) parameter6 oldStyle: (char) parameter7 args: (char*) parameter8;
- (id) buttonPressed: (id) parameter1;
- (id) buttons;
- (void) dealloc;
- (id) delegate;
- (void) didEndAlert: (id) parameter1 returnCode: (int) parameter2 contextInfo: (void*) parameter3;
- (void) didEndSheet: (id) parameter1 returnCode: (int) parameter2 contextInfo: (void*) parameter3;
- (void) finalize;
- (id) helpAnchor;
- (id) icon;
- (id) informativeText;
- (id) init;
- (id) messageText;
- (float) messageWidthForMessage: (id) parameter1;
- (void) placeButtons: (int) parameter1 firstWidth: (float) parameter2 secondWidth: (float) parameter3 thirdWidth: (float) parameter4;
- (void) prepare;
- (char) rememberChoice;
- (int) runModal;
- (int) runModalSheetForWindow: (id) parameter1;
- (void) setAlertStyle: (int) parameter1;
- (void) setDelegate: (id) parameter1;
- (void) setHelpAnchor: (id) parameter1;
- (void) setIcon: (id) parameter1;
- (void) setInformativeText: (id) parameter1;
- (id) setMessage: (id) parameter1;
- (void) setMessageText: (id) parameter1;
- (void) setRemberChoiceMessage: (id) parameter1;
- (void) setShowsHelp: (char) parameter1;
- (id) setTitle: (id) parameter1 andMessage: (id) parameter2;
- (char) showsHelp;
- (void) startSpeaking: (id) parameter1;
- (void) startTimerForSpeaking;
- (void) stopTimerForSpeaking;
- (id) window;
- (void) windowDidBecomeKey: (id) parameter1;
@end
Most of these are documented. Unfortunately there is no obvious analogue to setAccessoryView:, so there's no easy way that way. However, there is an interesting selector called buildAlertStyle:. This is not documented, but the name suggests that it gets called at some point to construct the NSAlert, presumably out of a generic NSWindow. Unfortunately because it's undocumented it's not at all clear what those parameters actually do.
I ruminated over this for a couple of days until by dumb luck I ran across an old library called NSAlertCheckbox. This library, though fragmentary and appearing to hail from around the days of Jaguar 10.2, does exactly what the name implies: it adds a checkbox control to an NSAlert. Well, said I, if it can add an NSButton, it can add a NSDatePicker. I cleaned up and expanded the library and wrote a little model (modal?) application to test my theory. It looked like this:
(Here is the source code for this example. You can compile it with Xcode 2.5 and the Mac OS X 10.4 SDK. Note in this and the below examples, because the model is being run from the command line and not within a regular NSApplication, it cannot intercept keystrokes. Just roll with this for the explanations below.)
The way the library works is by hooking those mysterious functions, which do indeed get called during window construction. Happily it turns out we don't need to know anything about what those opaque parameters are; we can modify the window without them (and just pass them along) by iterating through the components within the NSWindow that makes up the NSAlert. Once the code finds the second text field (the explanatory text, here articulately represented by the deep and meaningful words "Blah blah"), it then inserts a subview after that containing the date picker, et voilá.
This is not enough, however. While we can easily select the date and emit it (using NSDateFormatter), we can't type it, so selecting years and arbitrary months can sometimes require a lot of mousing around. Indeed, if you go to System Preferences to set the date and time, you have the choice of either using a stepper to manually enter a date or selecting one off the calendar. We can support that here too ... by adding another NSDatePicker!
(Source code for this example.)
The trick here was to keep them in sync so that you could type a date and have the calendar widget reflect it. By using a delegate on each date picker's cell, we can make modifications in one picker be synchronized to the other.
That suffices for dates. How about times? Straightforward enough: we just change the style to make the twin NSDatePickers into a clock and time stepper instead, and alter our template to NSDateFormatter to emit the time (in hours and minutes, and optionally seconds). Since the HTML spec also requires that we allow sites to specify minimums and maximums, let's implement that here too:
(Source code for this example.)
Because of the time interval constraint we implemented, when you run it you can only pick a time between 7:30am and 5:45pm; the pickers won't let you select anything else. Exactly what we want.
Before you upgrade to the beta, open either the MDN time or date picker pages and click in one of the demonstration input fields. In FPR8, this is just a text box, and you just enter text. (Same for Safari.) In FPR9, however, when you click or select that field the appropriate picker will pop open and the field will be autofilled for you in the proper format. If you press delete in the field, the date or time will be cleared. If you click Cancel, no change will occur. All of the standard constraints are supported, along with defaults (if no default is specified, the current time and/or date is used). Easy. As a safety measure, though, I implemented a basic filter to prevent NSDateFormatter from being exposed directly to web content since who knows what crap is lurking in there; it's only used as a secondary validator once the web-provided date is known to be in a non-pathological format.
Still to be implemented are month (easily done by just returning the month, not the full date), local date and time (needing a quadruple date picker) and week (harder, but possible). With the exception of local date'n'time, however, these are much less likely to be common and I'll defer those to later versions of the browser.
FPR9 will come out officially parallel to Firefox 62 and 60.2 on September 4, but I wanted a nice long beta test period since there is a lot of stuff in this release and to provide a sufficient timeframe for additional betas if required, so you're getting what I've got now. Bang on it and post your impressions in the comments.