Mozilla

Feature Articles

Sort by:

View:

  1. DOM selectors API in Firefox 3.5

    The Selectors API recommendation, published by the W3C, is a relatively new effort that gives JavaScript developers the ability to find DOM elements on a page using CSS selectors. This single API takes the complicated process of traversing and selecting elements from the DOM and unifies it under a simple unified interface.

    Out of all the recent work to come out of the standards process this is one of the better-supported efforts across all browsers: Usable today in Internet Explorer 8, Chrome, and Safari and arriving in Firefox 3.5 and Opera 10.

    Using querySelectorAll

    The Selectors API provides two methods on all DOM documents, elements, and fragments: querySelector and querySelectorAll. The methods work virtually identically, they both accept a CSS selector and return the resulting DOM elements (the exception being that querySelector only returns the first element).

    For example, given the following HTML snippet:

    <div id="id" class="class">
        <p>First paragraph.</p>
        <p>Second paragraph.</p>
    </div>

    We would be able to use querySelectorAll to make the background of all the paragraphs, inside the div with the ID of ‘id’, red.

    var p = document.querySelectorAll("#id p");
    for ( var i = 0; i < p.length; i++ ) {
        p[i].style.backgroundColor = "red";
    }

    Or we could find the first child paragraph of a div that has a class of ‘class’ and give it a class name of ‘first’.

    document.querySelector("div.class > p:first-child")
        .className = "first";

    Normally these types of traversals would be very tedious in long-form JavaScript/DOM code, taking up multiple lines and queries each.

    While the actual use of the Selectors API methods is relatively simple (each taking a single argument) the challenging part comes in when choosing which CSS selectors to use. The Selectors API taps in to the native CSS selectors provided by the browser, for use in styling elements with CSS. For most browsers (Firefox, Safari, Chrome, and Opera) this means that you have access to the full gamut of CSS 3 selectors. Internet Explorer 8 provides a more-limited subset that encompasses CSS 2 selectors (which are still terribly useful).

    The biggest hurdle, for most new users to the Selectors API, is determining which CSS selectors are appropriate for selecting the elements that you desire – especially since most developers who write cross-browser code only have significant experience with a limited subset of fully-working CSS 1 selectors.

    While the CSS 2 and CSS 3 selector specifications can serve as a good start for learning more about what’s available to you there also exist a number of useful guides for learning more:

    Implementations in the Wild

    The most compelling use case of the Selectors API is not its direct use by web developers, but its use by 3rd-party libraries that already provide DOM CSS selector functionality. The trickiest problem towards adopting the use of the Selectors API, today, is that it isn’t available in all browsers that users develop for (this includes IE 6, IE 7 and Firefox 3). Thus, until those browsers are no longer used, we must use some intermediary utility to recreate the full DOM CSS selector experience.

    Thankfully, a number of libraries already exist that provide an API compatible with the Selectors API (in fact, much of the inspiration for the Selectors API comes from the existence of these libraries in the first place). Additionally, many of these implementations already use the Selectors API behind the scenes. This means that you can use using DOM CSS selectors in all browsers that you support AND get the benefit of faster performance from the native Selectors API implementation, with no work to you.

    Some existing implementations that gracefully use the new Selectors API are:

    It’s important to emphasize the large leap in performance that you’ll gain from using this new API (in comparison to the traditional mix of DOM and JavaScript that you must employ). You can really see the difference when you look at the improvement that occurred when JavaScript libraries began to implement the new Selectors API.

    When some tests were run previously the results were as follows:

    You can see the dramatic increase in performance that occurred once the libraries began using the native Selectors API implementations – it’s quite likely that this performance increase will happen in your applications, as well.

    Test Suite

    To coincide with the definition of the Selectors API specification a Selectors API test suite was created by John Resig of Mozilla. This test suite can be used as a way to determine the quality of the respective Selectors API implementations in the major browsers.

    The current results for the browsers that support the API are:

    • Firefox 3.5: 99.3%
    • Safari 4: 99.3%
    • Chrome 2: 99.3%
    • Opera 10b1: 97.5%
    • Internet Explorer 8: 47.4%

    Internet Explorer 8, as mentioned before, is missing most CSS 3 selectors – thus failing most of the associated tests.

    As it stands, the Selectors API should serve as a simple, and fast, way of selecting DOM elements on a page. It’s already benefiting those who use JavaScript libraries that provide similar functionality so feel free to dig in today and give the API a try.

  2. shadow boxing with -moz-box-shadow

    Another fun CSS3 feature that’s been implemented in Firefox 3.5 is box shadows. This feature allows the casting of a drop “shadow” from the frame of almost any arbitrary element.

    As the CSS3 box shadow property is still a work in progress, however, it’s been implemented as -moz-box-shadow in Firefox. This is how Mozilla tests experimental properties in CSS, with property names prefaced with “-moz-“. When the specification is finalized, the property will be named “box-shadow.”

    How it works

    Applying a box shadow to an element is straightforward. The CSS3 standard allows as its value:

    none | <shadow> [ <shadow> ]*

    where <shadow> is:

    <shadow> = inset? && [ <length>{2,4} && <color>? ]

    The first two lengths are the horizontal and vertical offset of the shadow, respectively. The third length is the blur radius (compare that to the blur radius in in the text-shadow property). Finally the fourth length is the spread radius, allowing the shadow to grow (positive values) or shrink (negative values) compared to the size of the parent element.

    The inset keyword is pretty well explained by the standard itself:

    if present, [it] changes the drop shadow from an outer shadow (one that shadows the box onto the canvas, as if it were lifted above the canvas) to an inner shadow (one that shadows the canvas onto the box, as if the box were cut out of the canvas and shifted behind it).

    But talk is cheap, let’s look at some examples.

    To draw a simple shadow, just define an offset and a color, and off you go:

     -moz-box-shadow: 1px 1px 10px #00f;

     

    simple box shadow

    (Each of the examples in this article are live examples first, followed by a screen shot from Firefox 3.5 on OSX).

    Similarly, you can draw an in-set shadow with the aforementioned keyword.

    -moz-box-shadow: inset 1px 1px 10px #888;

     

    inset box shadow

    With the help of a spread radius, you can define smaller (or bigger) shadows than the element it is applied to:

    -moz-box-shadow: 0px 20px 10px -10px #888;

     

    box shadow with spread radius

    If you want, you can also define multiple shadows by defining several shadows, separated by commas (courtesy of Markus Stange):

    -moz-box-shadow: 0 0 20px black, 20px 15px 30px yellow, -20px 15px 30px lime, -20px -15px 30px blue, 20px -15px 30px red;

     

    multiple box shadows

    The different shadows blend into each other very smoothly, and as you may have noticed, the order in which they are defined does make a difference. As box-shadow is a CSS3 feature, Firefox 3.5 adheres to the CSS3 painting order. That means, the first specified shadow shows up on top, so keep that in mind when designing multiple shadows.

    As a final example, I want to show you the combination of -moz-box-shadow with an RGBA color definition. RGBA is the same as RGB, but it adds an alpha-channel transparency to change the opacity of the color. Let’s make a black, un-blurred box shadow with an opacity of 50 percent, on a yellow background:

    -moz-box-shadow: inset 5px 5px 0 rgba(0, 0, 0, .5);

     

    box shadow with RGBA

    As you can see, the yellow background is visible though the half-transparent shadow without further ado. This feature becomes particularly interesting when background images are involved, as you’ll be able to see them shining through the box shadow.

    Cross-Browser Compatibility

    As a newer, work-in-progress CSS3 property, box-shadow has not yet been widely adopted by browser makers.

    • Firefox 3.5 supports the feature as -moz-box-shadow, as well as multiple shadows, the inset keyword and a spread radius.
    • Safari/WebKit has gone down a similar route as Firefox by implementing the feature as -webkit-box-shadow. Multiple shadows are supported since version 4.0, while neither inset shadows nor the spread radius feature are supported yet in WebKit.
    • Finally, Opera and Microsoft Internet Explorer have not yet implemented the box shadow property, though in MSIE you may want to check out their proprietary DropShadow filter.

    To achieve the biggest possible coverage, it is advisable to define all three, the -moz, -webkit, and standard CSS3 syntax in parallel. Applicable browsers will then pick and adhere to the ones they support. For example:

     -moz-box-shadow: 1px 1px 10px #00f;
     -webkit-box-shadow: 1px 1px 10px #00f;
     box-shadow: 1px 1px 10px #00f;

    The good news is that the box-shadow property degrades gracefully on unsupported browsers. For example, all the examples above will look like plain and boring boxes with no shadow in MSIE.

    Conclusions

    The CSS3 box-shadow property is not yet as widely available in browsers (and therefore, to users) as, for example, the text-shadow property, but with the limited box shadow support of WebKit as well as the full support provided by Firefox 3.5 (as far as the current status of the feature draft is concerned), more and more users will be able to see some level of CSS box shadows.

    As a web developer, you can therefore use the feature, confident that you are giving users with modern browsers an improved experience while not turning away users with older browsers.

    Further resources
    Documentation

    Examples

  3. beautiful fonts with @font-face

    This article is also available in Bulgarian.

    While Firefox 3.0 improved typographic rendering by introducing support for kerning, ligatures, and multiple weights along with support for rendering complex scripts, authors are still limited to using commonly available fonts in their designs. Firefox 3.5 removes this restriction by introducing support for the CSS @font-face rule, a way of linking to TrueType and OpenType fonts just as code and images are linked to today. Safari has supported this type of font linking since version 3.1, and Opera has announced that they plan to support it in Opera 10.

    Using @font-face for font linking is relatively straightforward. Within a stylesheet, each @font-face rule defines a family name to be used, the font resource to be loaded, and the style characteristics of a given face such as whether it’s bold or italic. Firefox 3.5 only downloads the fonts as needed, so a stylesheet can list a whole set of fonts of which only a select few will actually be used.

    /* Graublau Sans Web (www.fonts.info) */
     
    @font-face {
      font-family: Graublau Sans Web;
      src: url(GraublauWeb.otf) format("opentype");
    }
     
    body {
      font-family: Graublau Sans Web, Lucida Grande, sans-serif;
    }

    Browsers that support @font-face will render text using Graublau Sans Web while older browsers will render text using either Lucida Grande or the default sans-serif face. Example here:



    Digging A Little Deeper

    Most font families today consist of only four faces: regular, bold, italic and bold italic. To define each of these faces the font-weight and font-style descriptors are used. These define the style of the face; there’s no concept of a cascade or inheritance that applies here. Without an explicit definition each of these defaults to a value of ‘normal':

    /* Gentium by SIL International   */
    /* http://scripts.sil.org/gentium */
     
    @font-face {
      font-family: Gentium;
      src: url(Gentium.ttf);
      /* font-weight, font-style ==> default to normal */
    }
     
    @font-face {
      font-family: Gentium;
      src: url(GentiumItalic.ttf);
      font-style: italic;
    }
     
    body { font-family: Gentium, Times New Roman, serif; }

    The sample text below when rendered with this font family:



    A feature that’s easy to overlook is that @font-face allows the creation of families with more than just regular and bold faces — up to nine weights can be defined for a single family. This is true even on Windows, where underlying platform limitations usually restrict font families to just regular and bold weights. Fonts such as those of the Japanese open source M+ Fonts project have as many as seven weights. A selection of these are used in the sample below:



    In some situations, authors may prefer to use fonts available locally and only download fonts when those faces aren’t available. This is possible with the use of local() in the definition of the src descriptor of an @font-face rule. The browser will iterate over the list of fonts in the src descriptor until it successfully loads one.

    /* MgOpen Moderna                      */
    /* http://www.zvr.gr/typo/mgopen/index */
     
    @font-face {
      font-family: MyHelvetica;
      src: local("Helvetica Neue"),
           local("HelveticaNeue"),
           url(MgOpenModernaRegular.ttf);
    }
     
    @font-face {
      font-family: MyHelvetica;
      src: local("Helvetica Neue Bold"),
           local("HelveticaNeue-Bold"),
           url(MgOpenModernaBold.ttf);
      font-weight: bold;
    }
     
    body { font-family: MyHelvetica, sans-serif; }

    The screenshot below shows from top to bottom the results on Mac OS X, Windows and Linux for a simple testcase that uses the font family defined above:



    The Helvetica Neue font family is available on most Mac OS X systems but generally on neither Windows nor Linux machines. When the example here is rendered on Mac OS X, the local Helvetica Neue faces are used and no font is downloaded. Under Windows and Linux the attempt to load a local font fails and a substitute font — MgOpen Moderna — is downloaded and used instead. MgOpen Moderna is designed to be a substitute for Helvetica, so it renders similarly to Helvetica Neue. This way, an author can guarantee text appearance but avoid a font download when it’s unnecessary.

    The name used to refer to a specific font face is the full name for an individual font. Generally it’s the family name plus the style name (e.g. “Helvetica Bold”). Under Mac OS X, the name is listed in the information panel for a given face. Select a single face and choose ‘Show Font Info’ from the Preview menu in FontBook:

    Similar tools exist under Linux. On Windows, use the font properties extension, a free download from Microsoft to view these names. With the extension installed, the properties panel shows information about an individual font. The full name is referred to as the “Font Name” on the Name tab:

    Safari only supports PostScript name lookup under Mac OS X, so under Mac OS X Postscript names are also supported. For OpenType PS fonts (often labeled with an .otf extension) the full name is the same as the PostScript name under Windows. So for these fonts, authors are advised to include both the full name and the PostScript name for cross-platform interoperability.

    Supporting Many Languages

    Many languages suffer from a lack of commonly available fonts. For minority languages and ancient scripts, the options often dwindle to just a handful. The use of @font-face allows authors using these languages to ameliorate this by including fonts with their pages.

    @font-face {
      font-family: Scheherazade;
      src: url(fonts/ScheherazadeRegAAT.ttf) format("truetype-aat"),
           url(fonts/ScheherazadeRegOT.ttf) format("opentype");
    }
     
    body { font-family: Scheherazade, serif; }

    Languages such as Arabic require text shaping, where the display of a given character is affected by the characters surrounding it. Different platforms support different rendering technologies to enable text shaping; under Mac OS X, AAT fonts are required while under Windows and Linux OpenType fonts are required. Without a font in a format required for a given platform, text shaping will not be rendered correctly.



    Under Mac OS X, the AAT version of the font is downloaded. On Windows and Linux, where rendering with AAT fonts is not supported, the download of the AAT font is skipped and the OpenType font is used instead. Hence, the text is rendered correctly on all platforms.

    Cross-Site Font Usage

    By default, Firefox 3.5 only allows fonts to be loaded for pages served from the same site. This prevents sites from freely using fonts found on other sites. For sites that explicitly want to allow cross-site font sharing, an online font library for example, Firefox 3.5 supports the use of access control headers to control this behavior. By adding an additional header to the HTTP headers sent with font files, sites can enable cross-site usage.

    # example Apache .htaccess file to add access control header
     
    <filesMatch ".(ttf|otf)$">
    <ifModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
    </ifModule>
    </filesMatch>

    With this HTTP header enabled, any page can access the fonts on this site, not just pages from the same site.

    Font Licensing Issues

    When using a font for a website, it’s important to always confirm that the font license permits use on a website. If the license agreement is filled with opaque legalese, err on the side of caution and check with the font vendor before using a font on a site. If the license permits its use, it’s a good idea to add a comment near the @font-face rules that points to the license, for future reference.

    “I found a free font, can I use it on my site?”

    Maybe, maybe not. Some free fonts are distributed as teaser products to encourage a purchase and don’t allow for redistribution or posting on a web server. Check the license, even for free fonts.

    “I just want to use [insert favorite font name here] on my site. Is that possible?”

    Right now, probably not. The use of font linking on the web is still in its infancy. Most fonts that ship with proprietary OS’s today have licenses that limit their use to standard desktop applications, so uploading these fonts to a web server is almost certainly not permitted. Piracy has plagued the font industry in the past, so most font vendors are wary of allowing their fonts to be used except in relatively limited contexts. Many font vendors are focused on the needs of publishing and printing industries, and the relative complexity of their license agreements often reflects this. In the future, some font designers may conclude that the sales of fonts as web fonts will outweigh any potential loss in sales due to piracy, others may not. Their license agreements will reflect this choice and should be respected.

    The stock photography market is often described as a $2 billion market but the web font market is still close to a $0 market, it can only go up!

    Font Linking In Internet Explorer

    Font linking has been possible with Internet Explorer but only for linking to fonts in the proprietary EOT font format. The only way to create EOT fonts is to use the Microsoft WEFT tool, available only on Windows. Only TrueType and OpenType TT fonts can be converted to EOT format, OpenType PS (.otf) fonts cannot be used.

    Internet Explorer only recognizes the font-family and src descriptors within @font-face rules, so each family can only contain a single face. It doesn’t understand format() hints and will ignore any @font-face rule containing these hints. This behavior can be used enable font linking cross platform:

    /* Font definition for Internet Explorer */
    /*         (*must* be first)             */
    @font-face {
      font-family: Gentium;
      src: url(Gentium.eot) /* can't use format() */;
    }
     
    /* Font definition for other browsers */
    @font-face {
      font-family: Gentium;
      src: url(Gentium.ttf) format("opentype");
    }

    Future Work

    For Firefox 3.5, the font-stretch and unicode-range descriptors are not supported. Fonts defined in SVG documents are also not supported yet. These are under consideration for inclusion in future releases. As always, patches are welcome!

    Further Resources

    Translations

    Documentation

    Examples

    Font Resources

    Font Politics

  4. stylish text with text-shadow

    This post is from Frederic Wenzel, who works on Mozilla’s Web Development team.

    The text-shadow CSS property does what the name implies: It lets you create a slightly blurred, slightly moved copy of text, which ends up looking somewhat like a real-world shadow.

    The text-shadow property was first introduced in CSS2, but as it was improperly defined at the time, its support was dropped again in CSS2.1. The feature was re-introduced with CSS3 and has now made it into Firefox 3.5.

    How it Works

    According to the CSS3 specification, the text-shadow property can have the following values:

    none | [<shadow>, ] * <shadow>,

    <shadow> is defined as:

    [ <color>? <length> <length> <length>? | <length> <length> <length>? <color>? ],

    where the first two lengths represent the horizontal and vertical offset and the third an optional blur radius. The best way to describe it is with examples.

    We can make a simple shadow like this, for example:

    text-shadow: 2px 2px 3px #000;
    A simple shadow

    (All of the examples are a live example first, then a picture of the working feature — so you can compare your browser’s behavior with the one of Firefox 3.5 on OSX)

    If you are a fan of hard edges, you can just refrain from using a blur radius altogether:

    text-shadow: 2px 2px 0 #888;
    I don’t like blurs

    Glowing text, and multiple shadows

    But due to the flexibility of the feature, the fun does not stop here. By varying the text offset, blur radius, and of course the color, you can achieve various effects, a mysterious glow for example:

     text-shadow: 1px 1px 5px #fff;
    Glowing text

    or a simple, fuzzy blur:

    text-shadow: 0px 0px 5px #000;
    Blurry text

    Finally, you can add ”more than one shadow”, allowing you to create pretty “hot” effects (courtesy of http://www.css3.info/preview/text-shadow/ css3.info):

    text-shadow: 0 0 4px white, 0 -5px 4px #FFFF33, 2px -10px 6px #FFDD33, -2px -15px 11px #FF8800, 2px -25px 18px #FF2200
    Multiple shadows are hot

    The number of text-shadows you can apply at the same time in Firefox 3.5 is — in theory — unlimited, though you may want to stick with a reasonable amount. Like all CSS properties, you can modify text-shadow on the fly using JavaScript:

    Animated shadows with JavaScript

    Performance, Accessibility and Cross-Browser Compatibility

    The times of using pictures (or even worse, Flash) for text shadows on the web are numbered for two reasons:

    First, there are significant advantages to using text instead of pictures. Not using pictures saves on bandwidth and HTTP connection overhead. Accessibility, both for people who use screen readers and search engines, is greatly improved. And page zoom will work better because the text can be scaled instead of using pixel interpolation to scale up an image.

    Second this feature is largely cross-browser compatible:

    • Opera supports text-shadow since version 9.5. According to the Mozilla Developer Center, Opera 9.x supports up to 6 shadows on the same element.
    • Safari has had the feature since version 1.1 (and other WebKit-based browsers along with it).
    • Internet Explorer does not support the text-shadow property, but the feature degrades gracefully to regular text. In addition, if you want to emulate some of the text-shadow functionality in MSIE, you can use Microsoft’s proprietary ”Shadow” and ”DropShadow” filters.
    • Similarly to MSIE, when other, older browsers do not support the feature (including Firefox 3 and older), they will just show the regular text without any shadows.

    A caveat worth mentioning is the ”drawing order”: While Opera 9.x adheres to the CSS2 painting order (i.e., the first specified shadow is drawn at the bottom), Firefox 3.5 adheres to the CSS3 painting order (the first specified shadow is on top). Keep this in mind when drawing multiple shadows.

    Conclusions

    text-shadow is a subtle but powerful CSS feature that is — now that it is supported by Firefox 3.5 — likely to be widely adopted across the web in the foreseeable future. Due to its graceful degradation in older browsers, it can safely be used by developers and will, over time, be seen by more and more users.

    Finally, some words of wisdom: Like any eye candy, use it like salt in a soup — with moderation, not by the bucket. If the web developers of the world overdo it, text-shadow may die a short, yet painful death. It would be sad if we make users flinch at the sight of text shadows like typography geeks at the sight of “Papyrus”, and thus needed to bury the feature deeply in our treasure chest.

    That being said: Go try it out!

    Further resources

    Documentation

    Examples

  5. geolocation in Firefox 3.5

    This post is from Doug Turner, one of the engineers who is behind the Geolocation support in Firefox 3.5.

    Location is all around us. As of this writing, I am in a coffee shop in Toronto, Canada. If I type google into the url bar, it takes me to www.google.ca, the Canadian version of Google, based on my IP address. And when I want to find the closest movie theater to where I am located, I typically just type in my postal code. That information is often stored with the site so that it’s easier to find the movie theater next time. In these two situations, having the web application automatically figure out where I am is much more convenient. In fact, I have no idea what the postal code is for Toronto. I know how to find it, but that is a lot of work to simply tell a web application where I am.

    Firefox 3.5 includes a simple JavaScript API that allows you to quickly geo-enable your web application. It allows users to optionally share their location with websites without having to type in a postal code. What follows is a general overview of how to use geolocation in Firefox 3.5, how it works, and examines some of the precautions you should take when using geolocation.

    The Basics

    Getting the user’s location is very easy:

    function showPosition(position) {
        alert(position.coords.latitude + “ “ +
        position.coords.longitude);
    }
     
    navigator.geolocation.getCurrentPosition(showPosition);

    The call to getCurrentPosition gets the users current location and puts it into an alert dialog. Location is expressed in terms of longitude and latitude. Yes, it’s that simple.

    When you ask for that information the user will see a notification bar like this:

    Their options are to allow or not, and to remember or not.

    Handling Errors

    It is important to handle two error cases in your code:

    First, the user can deny or not respond to the request for location information. The API allows you to set an optional error callback. If the user explicitly cancels the request your error callback will be called with an error code. In the case where the user doesn’t respond, no callback will be fired. To handle that case you should include a timeout parameter to the getCurrentPosition call and you will get an error callback when the timer expires.

    navigator.geolocation.getCurrentPosition(successCallback,
                                             errorCallback,
                                             {timeout:30000});

    With this code your errorCallback function will be called if the user cancels. It will also be called if 30 seconds pass and the user hasn’t responded.

    Second, the accuracy of the user’s location can vary quite a bit over time. This might happen for a few reasons:

    • Different methods for determining a person’s location have different levels of accuracy.
    • The user might choose not to share his or her exact location with you.
    • Many GPS devices have limited accuracy depending on the view of the sky. Over time if your view of the sky gets worse, so can the accuracy.
    • Many GPS devices can take several minutes to go from a very rough location to a very specific location, even with a good view of the sky.

    These cases can and will happen, and supporting changes in accuracy is important to provide a good user experience.

    If you want to monitor the location as it changes, you can use the watchPosition callback API:

    navigator.geolocation.watchPosition(showPosition);

    showPosition will be called every time there is a position change.

    Note that you can also watch for changes in position by calling getCurrentPosition on a regular basis. But for power savings and performance reasons we suggest that you use watchPosition when you can. Callback APIs generally save power and are only called when required. This will make the browser more responsive, especially on mobile devices.

    For more information, please take a look at the API draft specification which has other examples which may be useful.

    Under the Hood

    There are a few common ways to get location information. The most common are local WiFi networks, IP address information, and attached GPS devices. In Firefox 3.5 we use local WiFi networks and IP address information to try and guess your location.

    There are a few companies that drive cars around listening for WiFi access points spots and recording the access point’s signal strength at a specific point on the planet. They then throw all of this collected data into a big database. Then they have algorithms that allow you to ask the question “If I see these access points, where am I?”. This is Firefox 3.5’s primary way of figuring out your location.

    But not everyone has a WiFi card. And not every place has been scanned for WiFi. In that case Firefox will use your local IP address to try to figure out your location using a reverse database lookup that roughly maps your IP address to a location. IP derived locations often have much lower accuracy than a WiFi derived location. As an example, here in Toronto, a location from WiFi is accurate to within 150 meters. The same location using just an IP address is about 25 km.

    Privacy

    Protecting a user’s privacy is very important to Mozilla – it’s part of our core mission. Within the realm of data that people collect online, location can be particularly sensitive. In fact, the EU considers location information personally identifiable information (PII) and must be handled accordingly (Directive 95/46/EC). We believe that users should have strict control over when their data is shared with web sites. This is why Firefox asks before sharing location information with a web site, allows users to easily “forget” all of the places that the user has shared their location with, and surfaces sharing settings in Page Info.

    Firefox does what it can to protect our users’ privacy but in addition the W3C Geolocation working group has proposed these privacy considerations for web site developers and operators:

    • Recipients must only request location information when necessary.
    • Recipients must only use the location information for the task for which it was provided to them.
    • Recipients must dispose of location information once that task is completed, unless expressly permitted to retain it by the user.
    • Recipients must also take measures to protect this information against unauthorized access.
    • If location information is stored, users should be allowed to update and delete this information.
    • The recipient of location information must not retransmit the location information without the user’s consent. Care should be taken when retransmitting and use of HTTPS is encouraged.
    • Recipients must clearly and conspicuously disclose the fact that they are collecting location data, the purpose for the collection, how long the data is retained, how the data is secured, how the data is shared if it is shared, how users may access, update and delete the data, and any other choices that users have with respect to the data. This disclosure must include an explanation of any exceptions to the guidelines listed above.

    Obviously these are voluntary suggestions, but we hope that it forms a basis for good web site behavior that users will help enforce.

    Caveats

    We have implemented the first public draft of the Geolocation specification from the W3C . Some minor things may change, but we will encourage the working group to maintain backwards compatibly.

    The only issue that we know about that may effect you is the possible renaming of enableHighAccuracy to another name such as useLowPower. Firefox 3.5 includes the enableHighAccuracy call for compatibility reasons, although it doesn’t do anything at the moment. If the call is renamed, we are very likely to include both versions for compatibility reasons.

    Conclusion

    Firefox 3.5 represents the first step in support for Geolocation and a large number of other standards that are starting to make their way out of the various working groups. We know that people will love this feature for mapping applications, photo sites and sites like twitter and facebook. What is most interesting to us is knowing that people will find new uses for this that we haven’t even thought of. The web is changing and location information plays a huge role in that. And we’re happy to be a part of it.

  6. pushing pixels with canvas

    This post was written by Paul Rouget, who is a member of the Mozilla Evangelism team. Paul lives in Paris, France and is well known for some of his amazing work with open video on the web among other things.

    Canvas, at its most simple level, is an easy way to draw bitmap data into an HTML page. It has methods that allow you to draw rectangles, arcs, curves and other simple primitives. However, for some types of effects and drawing you need direct access to the pixels.

    In Firefox 3.5 we’ve added a new method to the canvas element – createImageData. The createImageData call is a convenience method to create a blank set of pixels for manipulation that can eventually be copied back onto a canvas.

    Since we’re talking about a single call we thought that it might be worth it to go through all of the calls that let you read, manipulate and update the pixels directly in a canvas and put createImageData in its full context.

    Retrieving Pixel Data

    You can’t directly manipulate pixels in a canvas. In order to make changes to the data in a canvas you first need to copy the data out, make changes, and copy the changed data back to the target canvas.

    The getImageData call lets you copy a rectangle of pixels out of a canvas. A call to get all of the pixel data out of a canvas looks like this:

    var canvas = document.getElementById('myCanvasElt');
    var ctx = canvas.getContext('2d');
    var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);

    The canvasData object contains the pixel data. It has the following members:

    canvasData {
        width: unsigned long, // the width of the canvas
        height: unsigned long, // the height of the canvas
        data: CanvasPixelArray // the values of the pixels
    }

    The data is a flat array of values that has one value for each component in a pixel, organized left to right, top to bottom, with each pixel represented as four values in RGBA order.

    For example, in a 2×2 canvas, there would be 4 pixels represented with 16 values that look like this:

    0,0  0,1  1,0  1,1
    RGBA RGBA RGBA RGBA
    

    So you can calculate the length of that array with the following formula: width * height * 4.

    In a larger canvas if you wanted to know the value of a blue in a pixel at x = 10, y = 20 you would use the following code:

    var x = 10;
    var y = 10;
    var blue = canvasData.data[(y * width + x) * 4 + 2];
    

    Note that each RGB pixel has a value of 0..255 with the alpha bit being 0..255 with 0 being completely transparent and 255 fully opaque.

    Create a new set of pixels

    If you want to create a new matrix from scratch, just use the createImageData call which needs two arguments: the height and the width of the matrix.

    Note that the createImageData call does not copy pixels out of the existing canvas, it produces a blank matrix of pixels with the values set to transparent black (255,255,255,0).

    Here’s an example you want to create a set of pixels that fits the canvas size:

    var canvas = document.getElementById('myCanvasElt');
    var ctx = canvas.getContext('2d');
    var canvasData = ctx.createImageData(canvas.width, canvas.height);

    Note that this is the method that you should use to create pixel data. Previous versions of Firefox allowed you to create a canvasData object out of a simple JavaScript object and use it in later calls to update the canvas data. This call was added to maintain compatibility with WebKit which under the hood uses a specialized object instead of a generic JavaScript object.

    Update the pixels

    Once you have the canvasData object you can update the pixel values through the array. Here’s one example of how to walk through the array reading and updating the values.

    for (var x = 0; x < canvasData.width; x++)  {
        for (var y = 0; y < canvasData.height; y++)  {
     
            // Index of the pixel in the array
            var idx = (x + y * width) * 4;
     
            // If you want to know the values of the pixel
            var r = canvasData.data[idx + 0];
            var g = canvasData.data[idx + 1];
            var b = canvasData.data[idx + 2];
            var a = canvasData.data[idx + 3];
     
            //[...] do what you want with these values
     
            // If you want to update the values of the pixel
            canvasData.data[idx + 0] = ...; // Red channel
            canvasData.data[idx + 1] = ...; // Green channel
            canvasData.data[idx + 2] = ...; // Blue channel
            canvasData.data[idx + 3] = ...; // Alpha channel
        }
    }

    Update the canvas

    Now that you’ve got a set of pixels updated you can use the simple putImageData call. This call takes the canvasData object and the x,y location where you would like to draw the rectangle of pixel data into the canvas:

    var canvas = document.getElementById('myCanvasElt');
    var ctx = canvas.getContext('2d');
    var canvasData = ctx.putImageData(canvasData, 0, 0);

    Full example for getImageData

    Here is code that transforms a color image to a grey scale version of the image. You can also see a live version of this demo on Paul’s site.

    var canvas = document.getElementById('myCanvasElt');
    var ctx = canvas.getContext('2d');
    var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    for (var x = 0; x < canvasData.width; x++) {
        for (var y = 0; y < canvasData.height; y++) {
            // Index of the pixel in the array
            var idx = (x + y * canvas.width) * 4;
     
            // The RGB values
            var r = canvasData.data[idx + 0];
            var g = canvasData.data[idx + 1];
            var b = canvasData.data[idx + 2];
     
            // Update the values of the pixel;
            var gray = (r + g + b) / 3;
            canvasData.data[idx + 0] = gray;
            canvasData.data[idx + 1] = gray;
            canvasData.data[idx + 2] = gray;
        }
    }
    ctx.putImageData(canvasData, 0, 0);

    Full example for createImageData

    This bit of code will draw a fractal into a canvas. Once again, you can see a live demo of this code on Paul’s site.

    var canvas = document.getElementById('myCanvasElt');
    var ctx = canvas.getContext('2d');
    var canvasData = ctx.createImageData(canvas.width, canvas.height);
     
    // Mandelbrot
    function computeColor(x, y) {
        x = 2.5 * (x/canvas.width - 0.5);
        y = 2 * (y/canvas.height - 0.5);
        var x0 = x;
        var y0 = y;
     
        var iteration = 0;
        var max_iteration = 100;
     
        while (x * x + y * y <= 4 && iteration < max_iteration ) {
            var xtemp = x*x - y*y + x0;
            y = 2*x*y + y0;
            x = xtemp;
            iteration++;
        }
     
        return Math.round(255 * iteration / max_iteration);
    }
     
    for (var x = 0; x < canvasData.width; x++) {
        for (var y = 0; y < canvasData.height; y++) {
            var color = computeColor(x, y);
     
            // Index of the pixel in the array
            var idx = (x + y * canvas.width) * 4;
     
            // Update the values of the pixel;
            canvasData.data[idx + 0] = color;
            canvasData.data[idx + 1] = color;
            canvasData.data[idx + 2] = color;
            canvasData.data[idx + 3] = 255;
        }
    }
     
    ctx.putImageData(canvasData, 0, 0);

    More Documentation

    If you want to know more about Canvas, we strongly encourage you to browse the MDC documentation that we have for canvas:

    We hope that this was useful for everyone and puts the single call in its full context.