Neil’s Place

December 10, 2009

Template Logging

Filed under: Uncategorized — enndeakin @ 5:03 pm

I’ve been going over some of the patches I’ve had sitting around for a while. One of the oldest was adding some error checking and logging to XUL templates.

See bug 321169 to try this out.

October 24, 2009

Command Updating Performance

Filed under: Uncategorized — enndeakin @ 2:13 pm

This week, I’ve been investigating how to improve command handling in XUL, both in terms of manner their used and particularly, performance. Command handling is what deals with performing actions in response to menu or keypresses. There are several types of commands. The first are those like cut and paste that typically appear on menus, where the bulk of the handling deals with ensuring that the menus, toolbar buttons and actions are enabled and disabled at the right time. The second are input field cursor and selection commands (such as move to next word, page down, etc). Mozilla cheats a bit and doesn’t check if they should be enabled as they don’t normally have UI that shows this. The third are complex edit commands such as bold, font changes and so forth. These are similar to the first set really. As an aside, it would be quite nice to be handle all of these in a similar fashion.

For whatever reason, most of the handling is done in C++ with a small amount of code done in script. In many cases, though the script is unnecessary. For example, a typical cut command looks like the following:

<command id=”cmd_cut” oncommand=”goDoCommand(‘cmd_cut’)”/>

This is quite pointless as the act of ‘do’ing the command should just be the default behaviour.

Updating command state is another issue and one which can be quite slow. In fact, a workaround was added just to improve performance due to this. Updating command state refers to the process of updating the UI when the focus or selection changes to reflect which commands are now enabled. For example, a cut operation is only valid when there is text selected.

Here’s an overview of how the update process breaks down in time used:

Fire commandupdate event at updaters: 17%
Retrieve the topmost window: 14%
Retrieve the command dispatcher: 8%
Retrieve the right controller: 33%
Checking if the command is enabled: 15%
Set disabled attribute on command elements: 13%

I was expecting the latter two steps to be the bulk of the time used, but this wasn’t the case. This was a good sign since the other steps are easier to optimize away. One particular issue is that, except for the first step, the remaining steps occur again and again for every command that needs to be updated, which includes additional time due to calling into Javascript and back several times.

Instead, by optimizing to perform the repeated steps only once, as well as not calling into Javascript unnecessarily we can reduce the amount of time taken up. Most of the time, the script just calls back to update each command in the same way every time much like goDoCommand is called in the earlier example, so this is also a bit silly.

I created a simple performance test which updates the typical eight edit-related commands one thousand times. With current code, the test took over 625 milliseconds to complete (which means about half a millisecond each). This isn’t much individually, but might be noticeable if lots of commands were being updated.

I created a simple implementation of the changes described above, still a work in progress, and have reduced this to about 60 milliseconds to update one thousand times. This is a speedup of over 10 times.

I have also been experimenting with caching the list of commands and their disabled state, rather than setting a disabled attribute on the command elements. This can improve the time to 40 milliseconds. One advantage to this is is that it could mean that the command element isn’t needed for many commands — if we cache the disabled state internally, in many cases we don’t really need the command element any more.

In many cases, the UI for commands such as undo isn’t actually visible until the Edit menu is opened. Using some smart caching, we can make the work of updating these commands only occur when the menu is opened. This already happens to some degree, but much additional and extraneous work is done upfront rather than later.

Next, I’m going to investigate some of the other types of commands and further see how a smart command caching mechanism might work.

October 5, 2009

Visible Focus Rings

Filed under: Uncategorized — enndeakin @ 3:59 pm

Platforms differ in the way that they show which element is focused. So does Firefox, which differs in a number of ways from platform conventions.

The typical way is to draw either a glow or dotted outline around a button or input field that accepts keyboard entry. However, this behaviour can sometimes cause unwanted visible display or bad interactions when the keyboard is not being used. For instance, when clicking a link on a page, the behaviour is to draw a visible dotted outline around the link, then load the next page. This is useful to know that the link has been clicked, but causes an unnecessary outline that can disrupt the appearance, especially if the link is an image or part of an image map.

One significant advantage of showing the link however, is that when going back to a page, one can immediately see where the keyboard focus is, and for non-keyboard use, indicates clearly which link was clicked, a useful indicator when visiting a series of links in succession.

Another behaviour is that, especially on Mac, various elements don’t switch the focus when clicking on them. For instance, clicking a checkbox in a dialog box or selecting from a dropdown list doesn’t change which element is focused. In this image, the first dropdown has a visible focus indicator (a blue glow around it), but clicking the later dropdown has not changed this.

On Windows, what used to be the norm is to show dotted outlines around focused elements, and show underlines under letters of the labels of controls or menus to indicate a key which can be used to focus or activate it. In today’s versions of Windows, though, that behaviour isn’t used, although it can be enabled through a system setting. Instead, these indicators are only visible once the user presses a key. For instance, pressing Alt shows the menu label indicators, as well as shows a visible focus ring around the element that accepts keyboard input. Tabbing to an element does similar.

The goal of bug 418521 is to improve the situations described above in Mozilla to be more compatible with how the system behaves. Followup bugs will address additional issues with specific controls. More specifically, this means:

On Windows, don’t show indicators at all until the user uses the keyboard to access an element. But, respect the system setting if the user wants them visible at all times.

On Mac, don’t focus elements when clicking on them, except for lists and text input fields.

On Linux, always show indicators. This is the current behaviour so Linux users won’t notice changes from this bug.

One change of note on all platforms is that links will no longer show the dotted focus outline when they are clicked, whether they are image links or otherwise. However, the dotted outline will be made visible when navigating back to the page, or when switching tabs back to that page. This solves the issue of not adding visible noise to the page in normal usage, but doesn’t prevent the user from seeing which link was clicked when going back to that page again.

For this change to be effective, a new css pseudoclass is proposed, to accompany the existing :focus pseudoclass.

The :focus pseudoclass will continue to work as it does now. If will match any element which is focused. However, the new pseudoclass :-moz-focusring will only match when the element is focused and the focus indicator should be shown. So if you are creating a theme for instance, the :-moz-focusring pseudoclass should be used to show focus indicators as this deals with all of the platform specific details. For example:


button:-moz-focusring {
  outline: 1px dotted black;
}

For details of the changes see comment 57 in the bug.

September 8, 2009

How to Fix Focus Related Problems in Tests

Filed under: Uncategorized — enndeakin @ 10:27 pm

One common problem with the existing tests is that they make a number of assumptions about a window being focused. For instance, tests tend to assume that once the load event fires, everything is ready to go. This is incorrect. In fact, the window may not even be visible yet. Because of this, some tests tend to fail randomly, especially on Linux.

The focusing of a window can occur before or after the load event, depending on circumstances and platform specific variations. For instance, an incrementally loaded page can be focused long before the page has finished loading, whereas a new XUL window can be focused afterwards, since the entire XUL file needs to be parsed and laid out before the window size is known.

Even the performance tests aren’t immune to this. If they operate based on the load event, they test only the time it takes to load, not the time to focus a window or page.

A number of things rely on a window being focused in order to work. For instance, tests that synthesize key presses or open popups. These are kinds of things that will fail when the window isn’t focused.

One common, yet not actually correct solution is to call window.focus(). This function is typically used to raise (bring a window to the front) and focus the window. However, it should not be assumed that the window.focus() method will do so before it returns. (Technically, on Linux the window manager isn’t required to honour this request at all). For this reason, it is best to wait for a focus event on the window before proceeding.

This can be a bit of hassle, so a few days ago I added a new function to do this for you, called waitForFocus. It’s very easy to use, and does lots of magical incantations for you. Just add something like the following at the end of the test’s script:

SimpleTest.waitForFocus(callback, window)

Set callback to a callback function to be called when the specified window has been loaded and focused, typically this will be the function that executes the actual tests. (The window argument is optional, if it happens to be ‘window’) If the window is not focused, an attempt is made to focus it. Don’t worry if the window has already loaded or is already focused, the function will take care of checking that for you. All you need to do is add the line above and everything will work out. No need to listen to any load or focus events. At least that’s the intent. The tests that now use this function haven’t failed due to focus issues yet.

Currently, waitForFocus also logs some debugging output. I’d expect this to be removed at some point — for now it’s being used to look for problems that might occur in the near future.

This method should be used for tests that:

  • synthesize key presses
  • tests that open popups
  • tests that open a new window
  • tests that close a window
  • tests that rely on focus rings to be drawn
  • tests that rely on focus or blur events to occur

Know any tests that could have problems? Why not fix them?

September 1, 2009

Resizing Text Boxes

Filed under: Mozilla — enndeakin @ 7:42 pm

In bug 167951, I am implementing text areas which can be resized, which will look something like the following:

The notch in the corner will allow the box to be resized smaller and larger. This will be available for all HTML <textarea> elements as well as XUL multiline textbox elements. However, for XUL elements, a resizable attribute set to either true or false may be used to enable or disable this feature. The default is false as it is likely that multiline textboxes in dialog boxes won’t have room to be resized anyway.

Adding support for this feature involved adding a number of other XUL features. The first, in bug 510335, adds support to the <stack> element for right and bottom attributes, in addition to supporting left as top as it does currently. This allows alignment of the children of a stack to any of the four sides by specifying a margin. For instance, this example positions a button 10 pixels from the right edge and 5 pixels from the bottom edge.

<stack width="100" height="100">
  <button label="Hello" right="10" bottom="5"/>
</stack>

You can also specify all four positions, and they then just act like margins from the stack’s edge.

The second feature is extending the <resizer> element in bug 511180 to allow resizing any element. Currently, the <resizer> is always used to resize the window. You can see this kind of resizing notch in use in Firefox in the lower right corner of a window below the scrollbar.

But, by adding an element attribute, you can specify the id of a specific element to resize. Most common, you would use the special value ‘_parent’ which means to resize the parent element. The following pattern might be common:

<stack>
  <button label="Resizable"/>
  <resizer dir="bottomend" right="0" bottom="0" element="_parent"/>
</stack>

All of these features are works in progress, so note that the specifics may change.

August 27, 2009

Mouse Capturing

Filed under: Mozilla — enndeakin @ 11:49 pm

I have been working on adding a mouse capturing API, mostly compatible with the IE API. This means that when the mouse button is pressed on an element, you can trap the mouse movement and redirect the movement events to this element instead. This mechanism appears in Mozilla in a number of places already, although there is currently no public way of doing this. For example, try clicking on a scrollbar thumb and dragging it. Notice how when the pointer is moved away from the scrollbar, it continues to move or traps all mouse movement such that other parts of the UI do not respond. When the mouse is released, everything reverts back to normal again. This is used in few other places as well, for example the draggable splitters between columns in a tree view, the splitters between frames and when drag-selecting.

In bug 503943, I am implementing this feature for both XUL applications and web pages.

Using the feature is quite easy:

onmousedown="this.setCapture(false)"

Within a mousedown event handler, just call the setCapture method. This enables capturing on the element until it is either stopped by calling the releaseCapture method, by releasing the mouse button, or if a drag begins. To prevent odd or possibly nasty things from happening, setCapture will only work while processing a mousedown event.

The argument to setCapture specifies whether children of the capturing element will receive mouse events or not. If false, then they do. If true, then only the capturing element receives them. In the former case, you could set capturing on a containing box, yet still handle the mouse as normal inside it.

There are three small incompatibilities with the IE implementation. First, IE allows setCapture to be called at any time and not just when a mouse button is pressed down. This isn’t recommended and usually causes the mouse to go into a funky state where it doesn’t seem to work properly. Naturally, it’s also very easy to abuse this. So Mozilla won’t allow this and instead only allows capturing during a mouse down.

The second difference is that the argument is optional in both IE and Mozilla, but defaults to false in Mozilla, but true in IE. (We’d have to implement some idl changes to change this). It isn’t too much of a burden since you can always supply the argument if this is a problem.

The third difference is that IE has a different event model so compatibility can be affected and can impact what elements seem to receive events.

However, these differences should be minor for normal usage.

July 30, 2009

Removing chromedir for right-to-left UI

Filed under: Mozilla — enndeakin @ 9:20 am

I just checked in a patch which eliminates uses of the chromedir attribute in Firefox. This was previously a way in which right-to-left user interfaces were handled. Essentially, various elements and parts of the UI had a chromedir attribute set which retrieved either the value ‘ltr’ or ‘rtl’ from a localized DTD file. Stylesheets could then be modified based on the value. Since it was effectively a global state, it wasn’t very flexible, and required the use of hundreds of extra attributes. This was a very ineffective way to handle this.

Instead, I have replaced this with a pseudoclass:

:-moz-locale-dir(ltr) { ... }
:-moz-locale-dir(rtl) { ... }

The former matches when the user interface is using a locale displayed left-to-right, and the latter matches when the user interface is in a locale displayed right-to-left.

Locales which are right-to-left are controlled by a preference of the form ‘intl.uidirection.<locale>’, where <locale> is a language code such as ‘en’ or ‘ar-QA’. The value of the preference should be either ‘ltr’ or ‘rtl’.

This means that someone can transform their user interface into a right-to-left mode simply by changing the preference. The user interface will  redisplay immediately without having to restart. For instance, I might set ‘intl.uidirection.en’ to ‘rtl’. This means that the ForceRTL extension is no longer needed for this purpose.

Those creating localizations in left-to-right languages, or localizations in right-to-left localizations of Arabic, Farsi or Herbew need do nothing special. The preferences are set accordingly already (even in browsers using other locales). Extra style rules in intl.css for Firefox are no longer needed as these are already handled automatically

Also, the direction can be different for each window. For instance an Ararbic browser user can install an English-only extension and have a window with English-only UI displayed left-to-right. Naturally, this is only window specific, so wouldn’t apply to overlaid UI.

An author can override the UI direction for a window by setting the localedir attribute on a <window> or <dialog>, and other toplevel elements.

July 3, 2009

What’s Next for Focus

Filed under: Mozilla — enndeakin @ 3:52 pm

Now that the focus work has been completed, I’ve been looking at some follow up focus work to finish up. There have been a number of regressions and crashes found but they were all fixed very easily. I think the new focus code is much easier to work with, enough such that each regression was easily fixed in under an hour or so of work, except for one which took a few hours. That’s much better than the two weeks it took before to investigate a bug, try to fix it and then fail at it.

There’s still some issues surrounding plugins on Linux but Karl knows quite a bit about how focus should work on GTK so I’m confident we’re going to have something working there.

There’s a push to get bug 418521 fixed which affects which elements should be focused on mouse clicks and when they should draw focus rings. The idea here is that focus rings shouldn’t be drawn in some cases. In others, such as Mac, elements shouldn’t even be focused when clicking them.

The -moz-user-focus property is currently used in XUL to identify if an element may be focused or not. This doesn’t belong as a style property. The logical choice is to use an attribute instead. That can be used, but I’m currently leaning towards a feature added to XBL which lets one set default focusability behaviour for an element. This would possibly be combined with some ideas I have about how to combine accessibility with XBL. I’ll revisit this when the XBL2 implementation is further along. This may also help with some issues where certain elements have special-cased focus behaviour, for instance, those that need to retarget focus when clicked, or when an accesskey is pressed.

There’s still some modules which are caching focus, accessibility and I think the IME code might be but haven’t investigated it too closely. Focus shouldn’t be cached anywhere but the focus system.

Also, I want to get rid of nsFocusController.cpp, which doesn’t do much focus related anymore. I tried to do that before the focus work was completed but ended up needing to create a chain of other patches to fix various other issues. I need to go back and finish that up.

I think my goal for the next little while is to just finish up all the patches and partially completed work I have had sitting around for a while. I’ll write more about those things later.

April 23, 2009

Focus How To

Filed under: Mozilla — enndeakin @ 10:42 pm

In the new land of focus, there is a single focus manager service which handles focus. It keeps track of the topmost top-level window (called the active window), and the child frame window where the focus currently is located. For instance, if something within a particular tab is focused, then the active window is the chrome browser window containing it and the child frame window is the DOM ‘window’ loaded within the tab. If the address field is focused however, the child frame window is the chrome window itself. In this latter case, both the active window and the child frame window have the same value.

The window itself (nsGlobalWindow.cpp in the Mozilla source) stores the currently focused element within the window. This is stored for every window, whether a toplevel chrome window, a child window or a frame. You can retrieve this element from script using a document’s activeElement property. If that element is within the current child frame that the focus manager points to, then that element will be the one where key events will be dispatched to, it will generally have a focus ring around it, and so forth. Only one such element in the entire application will be in such a state at a time. It’s important to note that the current focused element is still maintained whether the window is actually focused or not. That way, when a window or tab is brought back to the front, the same element that used to be focused still will be.

There are four ways in which an element can be focused:

  1. The user clicks the element with the mouse.
  2. The user presses the tab key.
  3. The user presses the access key associated with the element, if any.
  4. The element’s focus() method is called.

The latter method is the way you would focus an element with a script. Whatever means is used, all calls are routed through a single function within the focus manager. This ensures that focus behaviour remains consistent whatever method is used.

The old way of doing focus had a myriad of methods, all undocumented and confusing. Here is a guide to what the new way will be in the future:

  • To retrieve the focused element, use the ‘activeElement’ property of the document. This will be set if the window is focused or not.
  • To modify the focused element, call the focus() method. This will make this element focused in its window or tab, but will not bring the window or tab to the front.
  • To switch to another window, call the window’s focus() method.
  • To clear the focus from an element, call its blur() method, or just focus something else.
  • From extensions and chrome code, in all other cases, call the focus manager. This service is available using the contract id ‘@mozilla.org/focus-manager;1′ and the nsIFocusManager interface.

All other methods are deprecated or have been removed and should not be used. Specifically, this means the command dispatcher, docshells or any of the other shells, the event state manager, the focus controller, and well as some internal content node methods.

Blog at WordPress.com.