Site-Specific Preferences: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(update schedule with latest developments)
Line 101: Line 101:
== Repository ==
== Repository ==


The code for the feature currently lives in an extension.  The service portion of the code should land in the Mozilla repository.  The consolidated user interface for viewing and setting preferences should either land in the Mozilla repository or a Mozdev project repository depending on whether it ends up as a core component or remains as an extension.
The code for the feature currently lives in the extension.  The service, controller, and text zoom handler should land in the Mozilla CVS repository.  The sidebar and other handlers should either land in the Mozilla repository or a Mozdev project repository depending on whether it ends up as a core component or remains as an extension.


= Design & Implementation =
= Design & Implementation =

Revision as of 00:59, 3 May 2007

Status

Content Preferences, a prototype extension implementing some of the proposed functionality, has been developed and is being distributed on AMO. The prototype implements the persistent datastore, service, controller, sidebar, and handlers plus sidebar widgets for the text zoom, page style, and character encoding settings.

Two functional requirements have been added to the Firefox 3 product requirements document: a framework for site-specific preferences comprising the datastore, service, and controller (bug 378547) and persistent text zoom (bug 378549).

A meeting to review the API, extensibility, and security of the feature is scheduled for Thursday, May 3 at 11:00AM PDT (6:00PM UTC) at 1-800-707-2533, pin 369, conf 224 (intl: 1-650-215-1282, ext 91, conf 224).

Overview

Motivation

The primary purpose of this feature is to enable users to set and to persist preferences for certain core browser and content settings (f.e. text zoom, page style, and character encoding) that affect web page appearance and behavior for specific sites rather than merely for specific tabs or for the browsing session, since users often prefer certain values for these settings for specific sites and would like those preferences to persist across sessions and tabs.

Use Cases

Text Zoom

Every day, Joe visits a web site whose text size is too small for him to read it easily. After going to the site, Joe uses the View > Text Size > Increase command to increase the browser's text zoom value until the text is a reasonable size.

Joe has to do this each time he goes to the site, and when he leaves the site, he has to use the View > Text Size > Decrease command to return the text zoom to its normal value for the other sites he browses.

If the text zoom setting was site-specific, Joe would only have to change it once for the site whose size is too small, and he would never have to reset the setting to its normal value after leaving the site.

Note: John Lilly and Dan Veditz have described personal use cases which aren't satisfied by a site-specific text zoom.

John sometimes increases the text zoom for the browser in order to browse the web (including potentially multiple sites) while sitting farther away from his monitor. Afterwards, he decreases the text zoom back to its normal value.

Dan changes the text zoom each time he switches between two displays (I think his laptop's built-in display and an external monitor).

Although site-specific text zoom doesn't work well in these cases, tab-specific text zoom, which is what we currently have, probably doesn't work well either, because it makes them set (and later reset) the text zoom setting for every tab.

Character Encoding

-> Verify that the character encoding functionality currently in Firefox is accurately described in this section.

Jane lives in a country whose primary language uses a non-Western encoding. She frequently visits web sites whose character encoding is specified incorrectly (or not at all) by the server or page and is not correctly auto-detected by Firefox.

Every time she visits such a site, she has to set the correct encoding for it using the View > Character Encoding menu, but because Firefox only stores the character encoding for pages that she bookmarks, and then only for the specific bookmarked page (not for all pages on that site), Jane finds that she repeatedly has to set the encoding.

If the character encoding setting was site-specific (instead of or in addition to the bookmark-based page-specific mechanism), then Jane would no longer have to set the character encoding each time she visited a site for which it was set incorrectly. Instead, she could set it once and have Firefox reapply that encoding each subsequent time she visited the site.

Requirements

Note: these are suggested requirements for Firefox 3. Those of them that become actual requirements for the release will get added to the Firefox3/Product Requirements Document.

Service

  • P1 FR a service that stores and permits chrome code to get, set, remove, and observe changes to preferences for arbitrary settings on a site-specific basis
  • P1 FR support for defining sites by host name
  • P1 FR support for defining sites by ETLD + 1
  • P3 FR a hidden preference that allows users to switch between definitions of a site
  • P3 FR ability for extensions to define and register additional site definitions

Controller

  • P2 FR a controller for each browser window that simplifies the process of listening for location changes and retrieving preferences for specific sites by defining an API that pref handlers can use for the purpose

Sidebar

  • P? FR a sidebar or other UI area that displays and allows users to set and unset the consolidated group of site-specific preferences
  • P? FR support for setting the default value for each site-specific setting

Text Zoom Setting

  • P1 FR the value of the text zoom setting, which is set by commands in the View > Text Zoom menu or via the scrollwheel, is automatically recorded and restored on a site-specific basis
  • P1 FR a mechanism for changing the default value of the setting

Page Style Setting

  • P3 FR the value of the page style setting, which is set by commands in the View > Page Style menu, is automatically recorded and restored on a site-specific basis
  • P3 FR a mechanism for setting the default value of the setting to either "page default" or "no style"

Character Encoding Setting

  • P2 FR the value of the character encoding setting, which is set by commands in the View > Character Encoding menu, is automatically recorded and restored on a site-specific basis

Other Settings?

(are there other settings important and common enough to add to the core?)

Schedule

  • 2006 December 12: Content Preferences (cpref) extension, version 0.1 (announcement) - first prototype implementation, with support for site-specific text zoom
  • December 13: cpref, version 0.1.1 - minor bug fix release
  • 2007 January 26: cpref, version 0.1.2 - minor bug fix release
  • February 13: cpref, version 0.2 (announcement) - second prototype implementation, with API updates and support for scrollwheel-based text zoom changes
  • February 14: API/architecture discussion started - blog post mda.firefox article
  • March XX: API/security review
  • March XX April 24: cpref version 0.3 - third prototype implementation, with page style and character encoding handlers, undo buttons, and datastore/API updates
  • May 1: cpref version 0.3.1 - minor bug fix release
  • May 3: API, extensibility, security review
  • March/April May: land service on trunk
  • April May: cpref version 0.4 - fourth prototype implementation?
  • April/May: land additional elements of feature (controller, handlers for core prefs, sidebar or other UI) on trunk
  • May: release stable implementation of elements not destined for the core as extensions

Also see history of extension on AMO.

Repository

The code for the feature currently lives in the extension. The service, controller, and text zoom handler should land in the Mozilla CVS repository. The sidebar and other handlers should either land in the Mozilla repository or a Mozdev project repository depending on whether it ends up as a core component or remains as an extension.

Design & Implementation

Support for site-specific prefs in Firefox 3 comprises:

  1. a persistent datastore for saving prefs across sessions;
  2. an application-wide service for getting and setting prefs;
  3. a controller for each browser window that observes pref-related events and notifies handlers about them;
  4. a handler for the text zoom setting that applies preferences for that setting to the browser and saves changes to that setting as preferences.

Persistent Datastore

The persistent datastore is a SQLite database that lives in the profile directory. It gets created automatically if it doesn't exist when the service gets instantiated. It records its schema version in the user_version pragma so that its schema can be updated if modified in the future.

The schema, as declared by a JavaScript data structure in the service's code, is as follows:

 _dbSchema: {
   groupers:   "id           INTEGER PRIMARY KEY, \
                name         TEXT NOT NULL",

   groups:     "id           INTEGER PRIMARY KEY, \
                name         TEXT NOT NULL, \
                grouperID    INTEGER NOT NULL REFERENCES groupers(id)",

   settings:   "id           INTEGER PRIMARY KEY, \
                name         TEXT NOT NULL",

   prefs:      "id           INTEGER PRIMARY KEY, \
                groupID      INTEGER REFERENCES groups(id), \
                settingID    INTEGER NOT NULL REFERENCES settings(id), \
                value        BLOB"
 },

Some notes:

  1. The schema (and the code) generally uses the word "setting" to mean "a runtime configuration option that affects the behavior of the application" and the word "pref" or "preference" to mean "a user-defined value for a setting".
  2. The schema uses arbitrary integers to identify all records, even though all tables have other unique columns (or combinations thereof), primarily because in my experience this approach makes future schema changes easier. Integer IDs may also provide minor space savings and performance improvements.
  3. The schema tracks groupers (components that categorize URIs by site or via some other mechanism) as a way of namespacing groups created by different groupers. An earlier version of the schema didn't do this, and I'm having second thoughts about it, thinking that we should make groupers be responsible for namespacing their groups in cases where collisions are possible.
  4. Pref values are stored in a BLOB because it's the only column type that does no type conversion, so it provides maximum round-trip integrity of data from consumers through the service to the datastore and back.
  5. prefs.groupID is nullable to enable the service to store global preferences (prefs that apply to all groups, a.k.a. the whole web). We could make consumers store global prefs using the existing nsIPrefService, but that'd add significant complexity to consumers, which would have to support two separate and non-compatible interfaces, as nsIPrefService doesn't use nsIVariant. Supporting global prefs in the site-specific pref service, on the other hand, is straightforward and adds relatively little complexity.

Service

The service is implemented as a JavaScript XPCOM component with contract ID "@mozilla.org/content-pref/service;1" that implements the nsIContentPrefService interface.

Core Methods

The service's core API comprises the following four methods:

 nsIVariant getPref(in nsIURI uri, in AString name);
 void setPref(in nsIURI uri, in AString name, in nsIVariant value);
 boolean hasPref(in nsIURI uri, in AString name);
 void removePref(in nsIURI uri, in AString name);

All four methods take as input a URI belonging to the site in question and a name for the preference. The service is responsible for extracting the name of the site from the URI.

Question: should we make the consumer responsible for extracting site names from URIs so consumers can set preferences for non-standard groupings?

The name of the preference is an arbitrary string. Preference namespacing is the responsibility of the consumer, as it is with the application-wide preferences accessed via nsIPrefBranch.

The setPref method also takes as input an nsIVariant representing the value of the preference, while the getPref method returns such an nsIVariant. Consumers can set the value of a preference to null (nsIVariant::VTYPE_EMPTY), and the service distinguishes between preferences set to null and those that have not been set by representing the latter as the undefined value (nsIVariant::VTYPE_VOID).

Consumers can pass null as the value of the uri parameter to access a global preference (one which does not belong to any specific group), which they can use when a site-specific pref is not available.

Getting All Prefs

The getPrefs method allows consumers to retrieve all preferences for a given site:

 nsIPropertyBag getPrefs(in nsIURI uri);

The method returns an instance of "@mozilla.org/hash-property-bag;1", which implements both the nsIPropertyBag and the nsIPropertyBag2 interfaces. Bag keys are preference names, while bag values are preference values.

Observers

The service also implements methods for adding and removing observers:

 void addObserver(in AString name, in nsIObserver observer, in boolean holdWeak);
 void removeObserver(in AString name, in nsIObserver observer);

When a pref changes, the service notifies observers via the "content-pref-changed" topic. The notification is similar to one nsIPrefBranch2 sends with the "nsPref:changed" topic, but it has two key differences:

  • nsIContentPrefService takes only an exact preference name (nsIPrefBranch2 permits a consumer to watch an entire preference branch by passing in a branch prefix like "foo.bar.")
  • nsIContentPrefService passes the new value of the pref in notification's subject parameter, which is an nsIPropertyBag containing the following properties:
    • group: the site (or other grouping) to which the preference belongs;
    • name: the name of the preference;
    • oldValue: the old value of the preference;
    • newValue: the new value of the preference.

Question: should the service support preference branches?

Question: should the service pass a custom component with a custom interface (like the LiveTitleNotificationSubject component with the nsILiveTitleNotificationSubject interface) instead of a property bag?

Question: is there any use for the notification's data parameter?

Groupers

Groupers are components that categorize URIs into groups (f.e. by site). They implement a simple interface, nsIContentURIGrouper:

   readonly attribute AString name;
   AString group(in nsIURI uri);

The name attribute is an arbitrary identifier for the grouper that the service uses to associate a preference in the database with the grouper responsible for determining its group. The group method returns the name of the group to which a given URI belongs.

Question: should we just use the contract ID as the arbitrary identifier for the grouper, and how do we retrieve that from an instance of the component?

The default grouper categorizes URIs by effective TLD + one additional hostname segment (i.e. example.com or bbc.co.uk).

Question: should the default grouper categorize URIs by entire hostname?

The service distinguishes between groups with the same name that have been categorized by different groupers to avoid collisions between groups that have the same name but are semantically different.

Question: should we make groupers responsible for namespacing group names to avoid these collisions the same way we make pref consumers responsible for namespacing pref names?

The service implements an attribute representing the grouper it uses to extract a site from a URI:

 attribute nsIContentURIGrouper grouper;

The attribute is read/write so that extensions can change the way URIs get grouped.

Question: would it make more sense for this to be read-only and for the service to use the grouper specified by an application-wide preference?

Controller

The controller API is implemented as a ContentPrefController JavaScript object in the chrome window context of browser windows.

Question: is "controller" conceptually an accurate description of this component?

It implements the following API for pref handlers to register themselves for notification of changes to preferences for the page currently being displayed in the browser:

 void addObserver(in AString name, in nsIObserver observer);
 void removeObserver(in AString name, in nsIObserver observer);

Question: should the controller let observers tell it to hold weak references to them?

The controller registers itself as a web progress listener and DOMContentLoaded event listener for the tab browser widget and then notifies its observers when the widget's location changes (nsIWebProgressListener::onLocationChange) or a DOMContentLoaded event fires for a browser in the widget.

For location changes, the controller notifies observers with the "content-pref-location-changed" topic, the URI of the new location as the subject, and the value of the site-specific preference for the new location (if any) as the data.

For DOMContentLoaded events, the controller notifies observers with the "content-pref-dom-content-loaded" topic, the document object whose content was loaded as the subject, and the value of the site-specific preference for the document (if any) as the data.

Question: are these the right topic names for these notifications?

Text Zoom Handler

The text zoom handler is a TextZoomHandler JavaScript object in the chrome window context of browser windows. It registers itself with the controller as a "text.zoom" preference handler and takes over responsibility for handling the View > Text Size commands (both menu items and keyboard shortcuts for them) as well as scrollwheel events that are configured to signify text zoom changes.

When the user changes the text zoom for the current page via any mechanism, the handler applies the change to the text zoom setting and then sets the site-specific "text.zoom" preference for the page to the new value of the setting.

Question: should we provide a mechanism for setting a global text zoom preference?

Question: if we provide a mechanism for setting a global text zoom preference, should that preference be applied in addition a site-specific preference or instead of one? For example, if the global preference is 120% and the site-specific preference for a given site is 130%, should we set the text zoom for the site to 130% or 156% (100 * 1.3 * 1.2)?

When the user browses to a different page (i.e. the location of the tab browser widget changes) the handler applies the site-specific preference, if any, handed to it by the controller. Otherwise, it applies the global preference, if we provide a mechanism for setting this preference. Otherwise it applies the default value 100%.

Cross-Cutting Concerns

API Changes

This feature changes no existing APIs, but it does add several APIs. First, it adds a application-wide "service" API for getting and setting site-specific preferences. Second, it adds a window-specific "controller" API for registering as a pref handler and observing pref-related events. Third, it adds a "sidebar" API for adding controls to a sidebar presenting a consolidated view of preferences for the current site.

Extensibility

Extensibility of this feature is a top priority, since numerous and popular extensions provide users with ways to alter browser settings affecting site appearance and behavior, and the ability to set preferences for those settings on a site-specific basis is a common function of (or feature request for) those extensions.

Examples of extensions that permit site-specific control over browser settings include Flashblock and NoSquint. An experimental version of the HashColouredTabs+ extension supports site-specific functionality via the version 0.2 of the Content Preferences prototype extension.

This feature should be extensible in the following ways:

  1. it should be possible for extensions to get and set site-specific preferences via the same APIs that core code uses;
  2. it should be possible for extensions to overlay themselves onto the site preferences sidebar so that their controls for setting preferences are visible alongside (or perhaps below) core controls and are as usable as the core controls;
  3. extensions should be able to register themselves as pref handlers in the same way that core code registers themselves as pref handlers and receive the same notifications that core code receives.

Should it be possible for extensions to override core pref handlers so that they can implement enhanced/modified functionality to that provided by the core handlers?

Should it be possible for extensions to provide additional ways of defining sites so that users who want a different way of looking at sites can get it and to promote innovation in site definition? F.e. one could say that all Mozilla domains (mozilla.org, mozilla.com) are a single site because they all relate to the Mozilla project, or one could define a site as every domain that uses an SSL certificate issued to the same organization, or every site that uses a certain stylesheet (for browser settings like text zoom and page style that affect style), or perhaps finer-grained controls that define different paths on a certain host as separate sites.

Customization

This feature adds customization controls to a sidebar, which has potential impact on many preferences and customization controls, particularly the Preferences > Content pane and items in the View menu like Text Zoom, Page Style, and Character Encoding.

The potential impact includes:

  • items in the View menu might start to affect browser settings on a site-specific basis rather than a tab- or page-specific basis;
  • the Content pane might provide an option for viewing and editing preferences for sites;
  • other site-specific lists in the Preferences dialog like the list of cookies and extension whitelists might be combined with UI for viewing preferences for sites generally;
  • items in the View menu and Content prefpane might be removed or modified in favor of UI in the consolidated preference view.

Performance

There are two notable potential consequences for a performance regression from this functionality.

First, as the user goes from site to site, the controller will get preferences for each site from the service, which queries the datastore for them. There is some cost to doing this, but it's not yet clear what that is. A test for this would be to populate a database with some site-specific preferences and then measure the amount of time it takes for the controller to retrieve a set of preferences for a site.

Second, because settings may be changed on a site-specific basis, switching from one site to another may now prompt costly changes to browser settings.

The effect of this is mitigated by the fact that such changes will only take place when the user has explicitly set preferences for a site, so users who don't use the feature won't be affected, and users who do use the feature probably are willing to experience the regression in exchange for the functionality provided.

But we should keep an eye on that latter assertion, since users may assume that site-specific preferences (at least those built into the core product) do not cause performance regressions and thus not understand why certain sites load more slowly than others. At a minimum, we must make it obvious and easy to undo a site-specific preference. And if settings built into the core product turn out to be costly, we should reconsider making them site-specific or provide additional feedback to the user about the cost (f.e. by providing progress or some other indication that the preference was applied) to inform the user about the cost so she can make an informed decision whether or not to accept it.

Reliability/Stability

In general, this feature should not impact reliability or stability, although it could expose or amplify the effect of bugs in core browser functionality (f.e. the code that adjusts text zoom) to the extent that it increases the frequency by which that functionality is invoked.

Security

The service and the controller are only available to chrome code, so they should have no security impact.

Site-specific preferences can be loosely grouped into "browser" and content categories. Browser prefs are those that affect the browser object (browser, docShell, presShell, etc.) embedded into each tab in Firefox, f.e. the text zoom preference. Content prefs are those that affect the document object for a given web page which is loaded into a browser object, f.e. the page style preference.

Existing prefs of either type should have no additional security impact, although they could expose security holes in core browser functionality to the extent that they increase the frequency by which that functionality is invoked.

New content prefs could have additional security impact, although no such prefs are being proposed yet.

To the extent that this functionality makes it easier to write extensions that add content prefs, however, it may cause the number of such extensions, and thus the danger of security holes in them, to increase.

Privacy

In general, site-specific preferences are not expected to be particularly high value or personal, but they can provide some information about users should be considered private. Preferences are stored persistently in a file in the user's profile, so they are subject to the same security measures we use to protect other personal data in the profile directory. Preference data is transiently stored in the memory of chrome objects to which content does not have access and in chrome controls to which content does not have access.

Global Audience

Since this feature introduces new UI, care should be taken to ensure that it remains accessible in the same way that the current non-site-specific UI is accessible.

L10n requirements apply as they do to other chrome.

Web Compatibility

Users might find that some of their preferences are incompatible with web sites, so it should be easy to remove a preference that results in an incompatibility.

To the extent this feature and its popularity causes web sites to become less insistent on appearing and behaving in a particular way, this feature should have a positive impact on web compatibility.

Other

Discussion & Implications

Caveats / What We've Tried Before

References