Merge mozilla-central into services-central
authorGregory Szorc <gps@mozilla.com>
Tue, 18 Sep 2012 11:37:04 -0700
changeset 111085 3df5819108f95eaa2424e8f6f547fad0d35e35f2
parent 111084 1a7e69990b601e2660ba7e62a771087448c055e4 (current diff)
parent 107444 e4757379b99a45135be2606b20bc14c6695f0495 (diff)
child 111086 ec93b64f28bbe937076e5e91abdc169c6e6060e1
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone18.0a1
Merge mozilla-central into services-central
b2g/components/CameraContent.js
dom/bluetooth/BluetoothNullServiceFactory.cpp
dom/bluetooth/BluetoothPairingEvent.cpp
dom/bluetooth/BluetoothPairingEvent.h
dom/bluetooth/gonk/BluetoothGonkServiceFactory.cpp
dom/bluetooth/linux/BluetoothDBusServiceFactory.cpp
dom/bluetooth/nsIDOMBluetoothAuthorizeEvent.idl
dom/bluetooth/nsIDOMBluetoothPairingEvent.idl
dom/tests/mochitest/localstorage/test_removeOwnersAPI.html
dom/tests/mochitest/localstorage/test_removeOwnersAPISessionOnly.html
dom/tests/unit/test_domstorage_aboutpages.js
editor/idl/nsIEditorObserver.idl
js/src/jsatom.tbl
js/src/jskeyword.tbl
mobile/android/locales/en-US/chrome/aboutHome.dtd
netwerk/base/public/nsIProxyAutoConfig.idl
netwerk/base/src/nsProxyAutoConfig.js
netwerk/base/src/nsProxyAutoConfig.manifest
netwerk/protocol/device/nsB2GProtocolHandler.cpp
netwerk/protocol/device/nsB2GProtocolHandler.h
services/sync/modules/resource.js
services/sync/tests/unit/test_resource_async.js
toolkit/components/places/tests/unit/test_preventive_maintenance_console.js
toolkit/mozapps/extensions/test/unit/data/test_bug356370.rdf
toolkit/mozapps/extensions/test/unit/data/test_bug356370_1.rdf
toolkit/mozapps/extensions/test/unit/data/test_bug356370_2.rdf
toolkit/mozapps/extensions/test/unit/data/test_bug356370_4.rdf
toolkit/mozapps/extensions/test/unit/data/test_bug421396/chrome.manifest
toolkit/mozapps/extensions/test/unit/data/test_bug421396/install.rdf
toolkit/mozapps/extensions/test/unit/data/test_bug463819.rdf
toolkit/mozapps/extensions/test/unit/data/test_bug463819.xml
toolkit/mozapps/extensions/test/unit/head_extensionmanager.js
toolkit/mozapps/extensions/test/unit/tail_extensionmanager.js
toolkit/mozapps/extensions/test/unit/test_bug356370.js
toolkit/mozapps/extensions/test/unit/test_bug421396.js
toolkit/mozapps/extensions/test/unit/test_bug463819.js
new file mode 100644
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,1071 @@
+This is an (incomplete) list of people who have contributed to the
+codebase which lives in this repository. If you make a contribution
+here, you may add your name and, optionally, email address in the
+appropriate place.
+
+For a full list of the people who are credited with making a
+contribution to Mozilla, see http://www.mozilla.org/credits/ .
+
+<1010mozilla@Ostermiller.com>
+Aaron Boodman <aa@google.com>
+Aaron Kaluszka <ask@swva.net>
+Aaron Leventhal <aaronleventhal@moonset.net>
+Aaron Nowack <anowack@mimiru.net>
+Aaron Reed <aaronr@us.ibm.com>
+Aaron Spangler <aaron@spangler.ods.org>
+Aaron Train <aaron.train@gmail.com>
+Achim Hasenmueller <achimha@innotek.de>
+ActiveState Tool Corp.
+Adam Barth <hk9565@gmail.com>
+Adam Christian <adam.christian@gmail.com>
+Adam Hauner
+Adam Lock <adamlock@netscape.com>
+Adam L. Peller
+Adam Souzis <adam@souzis.com>
+Aditya Rao <adicoolrao@gmail.com>
+Adobe Systems Incorporated
+Adrian Havill <havill@redhat.com>
+Adrian Herscu <bmf1972@icqmail.com>
+Adrian Johnson <ajohnson@redneon.com>
+Adrian Kalla <akalla@aviary.pl>
+Adrian Klein <dragosan@dragosan.net>
+a-higuti
+Aiko
+Akhil Arora <akhil.arora@sun.com>
+Akkana Peck <akkana@netscape.com>
+Alden D'Souza <aldenfloyd@gmail.com>
+Alec Flett <alecf@flett.org>
+Aleksey Chernoraenko <archer@meta-comm.com>
+Aleksey Nogin <ayn2@cornell.edu>
+Aleks Totic <a@totic.org>
+Alexander Law <1@1o.ru>
+Alexander Surkov <surkov.alexander@gmail.com>
+Alexey Chernyak <alexeyc@bigfoot.com>
+Alex Fritze <alex@croczilla.com>
+Alex Miller <amiller@mozilla.com>
+Alex Musil
+Alex Pakhotin <alexp@mozilla.com>
+Alex Russell
+Alex Vincent <ajvincent@gmail.com>
+Alfred Kayser <alfredkayser@nl.ibm.com>
+Alfred Peng <alfred.peng@sun.com>
+Ali Juma <ajuma@mozilla.com>
+Allan Beaufour <allan@beaufour.dk>
+Allen Eubank <adeubank@gmail.com>
+Allison Naaktgeboren <ally@mozilla.com>
+Alon Zakai <azakai@mozilla.com>
+Amir Szekely <kichik@gmail.com>
+Anant Narayanan <anant@kix.in>
+An-Cheng Huang <pach@cs.cmu.edu>
+Anders Hammarquist
+Andras Timar
+Andrea Canciani <ranma42@gmail.com>
+Andreas Gal <gal@uci.edu>
+Andreas M. Schneider <clarence@clarence.de>
+Andreas Otte <andreas.otte@debitel.net>
+Andrei Saprykin
+Andrei Volkov <av@netscape.com>
+Andrew Drake <drakedevel@gmail.com>
+Andrew Halberstadt <halbersa@gmail.com>
+Andrew Huntwork <ash@huntwork.net>
+Andrew Schultz <ajschult@verizon.net>
+Andrew Shilliday <andrewshilliday@gmail.com>
+Andrew Shultz
+Andrew Smith
+Andrew Sutherland <asutherland@asutherland.org>
+Andrew Thompson
+Andrew Zabolotny
+Andrzej Skalski <askalski@mozilla.com>
+Annie Sullivan <annie.sullivan@gmail.com>
+Anoop Saldanha <poonaatsoc@gmail.com>
+antonglv
+Antti Järvelin <antti.i.jarvelin@gmail.com>
+Arkady Blyakher <rkadyb@mit.edu>
+Armen Zambrano Gasparnian <armenzg@mozilla.com>
+Arno Renevier
+Arpad Borsos <arpad.borsos@googlemail.com>
+Arron Mogge <paper@animecity.nu>
+Arthur Wiebe <artooro@gmail.com>
+Asaf Romano <mozilla.mano@sent.com>
+Asko Tontti <atontti@cc.hut.fi>
+Atul Apte <aapte135@gmail.com>
+Atul Varma <atul@mozilla.com>
+Axel Hecht <axel@pike.org>
+Aza Raskin <aza@mozilla.com>
+Bart <dev@bartbizon.com>
+Bas Schouten <bschouten@mozilla.com>
+Bastiaan Jacques <b.jacques@planet.nl>
+<bedney@technicalpursuit.com>
+Behdad Esfahbod <behdad@behdad.org>
+Behnam Esfahbod <behnam@zwnj.org>
+Ben Basson <contact@cusser.net>
+Ben Bucksch <mozilla@bucksch.org>
+Ben Combee <bcombee@mozilla.com>
+Bencsath Boldizsar
+Benedict Hsieh <bhsieh@mozilla.com>
+Ben Goodger <ben@bengoodger.com>
+Ben Hearsum <bhearsum@mozilla.com>
+Ben Hsieh <ben.hsieh@gmail.com>
+Benjamin Frisch <bfrisch@gmail.com>
+Benjamin Otte <otte@gnome.org>
+Benjamin Smedberg <benjamin@smedbergs.us>
+Benjamin Stover <bstover@mozilla.com>
+Ben Newman <bnewman@mozilla.com>
+Benoit Girard <b56girard@gmail.com>
+Benoit Jacob <bjacob@mozilla.com>
+Ben Turner <bent.mozilla@gmail.com>
+Bertrand Le Roy
+bex@xaotec.com
+Biju
+Bill Haneman (bill.haneman@sun.com)
+Bill Law <law@netscape.com>
+Bill Worley
+Biro Arpad
+Bjarne Geir Herland <bjarne@runitsoft.com>
+Björn Jacke <bjoern.jacke@gmx.de>
+Blair McBride <bmcbride@mozilla.com>
+Blake Kaplan <mrbkap@gmail.com>
+Blake Ross <blake@blakeross.com>
+Blue Static
+Bobby Holley <bobbyholley@gmail.com>
+Bob Clary <bob@bclary.com>
+bobj@netscape.com
+Bob Lord <lord@netscape.com>
+Bob Miller <kbob@oblix.com>
+Bob Moss <bmoss@mozilla.com>
+Bob Relyea <rrelyea@redhat.com>
+Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>
+bogomip
+Bolian Yin <bolian.yin@sun.com>
+Boris Zbarsky <bzbarsky@mit.edu>
+Brad Lassey <brad@lassey.us>
+Bradley Baetz <bbaetz@acm.org>
+Brad Taylor <brad@getcoded.net>
+Bram Moolenaar
+Brandon Pung <brandonpung@gmail.com>
+Brandon Sterne <bsterne@mozilla.com>
+Brant Gurganus <brantgurganus2001@cherokeescouting.org>
+Braun <ebraun@o2.pl>
+Brendan Eich <brendan@mozilla.org>
+Brett Wilson <brettw@gmail.com>
+Brian Birtles <birtles@gmail.com>
+Brian Bober <netdemonz@yahoo.com>
+Brian Crowder <crowderbt@gmail.com>
+briang@tonic.com
+Brian Hackett <bhackett@mozilla.com>
+Brian Lu <brian.lu@sun.com>
+Brian Nesse <bnesse@netscape.com>
+Brian Nicholson <bnicholson@mozilla.com>
+Brian O'Keefe <bokeefe@alum.wpi.edu>
+Brian R. Bondy <netzen@gmail.com>
+Brian Ryner <bryner@brianryner.com>
+Brian Smith <bsmith@mozilla.com>
+Brian Stell <bstell@ix.netcom.com>
+Brijesh Patel <brijesh3105@gmail.com>
+Brodie Thiesfield <brofield@jellycan.com>
+Bruce Hoult
+Bruno Haible <bruno@clisp.org>
+Bryant Chen
+Calum Robinson <calumr@mac.com>
+CanadianGuy
+Canonical Ltd
+Caolan McNamara <cmc@openoffice.org>
+Carl D. Worth <cworth@cworth.org>
+Carlo Alberto Ferraris <cafxx@strayorange.com>
+Carsten Book
+Catalin Patulea
+Cavin Song <cavin@netscape.com>
+Cedric Vivier <cedricv@neonux.com>
+Celso Aguiar <celsoaguiar@hotmail.com>
+Chak Nanga <chak@netscape.com>
+Chao-ying Fu <fu@mips.com>
+Charles Manske <cmanske@netscape.com>
+Charles Verdon
+Chase Phillips <chase@mozilla.org>
+Chase Tingley <tingley@sundell.net>
+Chenxia Liu <liuche@mozilla.com>
+Chip Clark <chipc@netscape.com>
+Chookij Vanatham <Chookij.Vanatham@Eng.Sun.COM>
+Chris AtLee <catlee@mozilla.com>
+Chris Beard <cbeard@mozilla.com>
+Chris Coulson <chris.coulson@canonical.com>
+Chris Double <chris.double@double.co.nz>
+Chris Evans
+Chris Halls
+Chris Jones <jones.chris.g@gmail.com>
+Chris Leary <cdleary@mozilla.com>
+Chris Lord <chrislord.net@gmail.com>
+Chris McAfee <mcafee@netscape.com>
+Chris Pearce <chris@pearce.org.nz>
+Chris Saari <saari@netscape.com>
+Chris Seawood <cls@seawood.org>
+Christian Biesinger <cbiesinger@gmail.com>
+Christian Bodart <chris@bodar.com>
+Christian Schneider <c.schneider@scram.de>
+christine@netscape.com
+Christopher A. Aillon <christopher@aillon.com>
+Christopher Blizzard <blizzard@mozilla.org>
+Christopher Davis <chrisd@torproject.org>
+Christopher Nebergall <cneberg@sandia.gov>
+Christopher Thomas <cst@yecc.com>
+Chris Torek <torek@bsdi.com>
+Chris Waterson <waterson@netscape.com>
+Chris Wilson <chris@chris-wilson.co.uk>
+<chwu@nortelnetworks.com>
+Claudio Ciccani <klan@users.sf.net>
+Clayton Williams <claytonw@mit.edu>
+Clint Talbert <cmtalbert@gmail.com>
+Colin Barrett <cbarrett@mozilla.com>
+Colin Blake <colin@theblakes.com>
+<coliver@mminternet.com>
+Collabora Ltd
+Collin Jackson <mozilla@collinjackson.com>
+conor@the325project.org
+Conrad Carlen <conrad@ingress.com>
+Constantine A. Murenin <cnst+moz#bugmail.mojo.ru>
+Craig Topper <craig.topper@gmail.com>
+crock@veilnetworks.com
+Crocodile Clips Ltd
+Cryptography Research
+CSIRO
+Curtis Bartley <cbartley@mozilla.com>
+Cyrus Omar
+Cyrus Patel <cyp@fb14.uni-mainz.de>
+Dafydd Jones
+Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
+Daniel Aquino <mr.danielaquino@gmail.com>
+Daniel Bratell <bratell@lysator.liu.se>
+Daniel Brooks <db48x@db48x.net>
+Daniel Glazman <daniel.glazman@disruptive-innovations.com>
+Daniel Holbert <dholbert@mozilla.com>
+Daniel Kouril <kouril@ics.muni.cz>
+Daniel Kraft <d@domob.eu>
+Daniel Krieg
+Daniel Veditz <dveditz@cruzio.com>
+Daniel Witte <dwitte@stanford.edu>
+Dan Matejka <danm@netscape.com>
+Dan Mills <thunder@mozilla.com>
+Dan Mosedale <dmose@mozilla.org>
+Dan Rosen <dr@netscape.com>
+Dan Witte <dwitte@mozilla.com>
+Dão Gottwald <dao@design-noir.de>
+Darin Fisher <darin@meer.net>
+darren.deridder@icarusproject.com
+Dave Camp <dcamp@mozilla.com>
+Dave Herman <dherman@mozilla.com>
+davel@mozilla.com
+Dave Mandelin <dmandelin@mozilla.com>
+Dave Reed
+Dave Townsend <dtownsend@oxymoronical.com>
+David Anderson <danderson@mozilla.com>
+David Baron <dbaron@dbaron.org>
+David Bienvenu <bienvenu@nventure.com>
+David Bradley <bradley@netscape.com>
+David Burns <dburns@mozilla.com>
+David Courtin <dcourtin@systemplus.fr>
+David Dahl <ddahl@mozilla.com>
+David Dick <ddick@cpan.org>
+David Drinan <ddrinan@netscape.com>
+David Einstein <Deinst@world.std.com>
+Davide Prina
+David Finch
+David Gardiner <david.gardiner@unisa.edu.au>
+David Greenspan
+David Haas <haasd@cae.wisc.edu>
+David Hamp-Gonsalves
+David Humphrey <david.humphrey@senecac.on.ca>
+David Hyatt <hyatt@mozilla.org>
+David James
+David J. Fiddes <D.J.Fiddes@hw.ac.uk>
+David Andersson <liorean@gmail.com>
+<davidm@netscape.com>
+David P. Caldwell <inonit@inonit.com>
+David Rajchenbach-Teller <dteller@mozilla.com>
+David Savage
+David S. Miller <davem@redhat.com>
+David Woodhouse <dwmw2@infradead.org>
+David Zbarsky <dzbarsky@gmail.com>
+Dean Tessman <dean_tessman@hotmail.com>
+<deneen@alum.bucknell.edu>
+Denis Antrushin <adu@sparc.spb.su>
+Denis Issoupov <denis@macadamian.com>
+Dennis Handly
+Derrick Rice <derrick.rice@gmail.com>
+<desale@netscape.com>
+diablohn
+Diane Trout <diane@ghic.org>
+Dietrich Ayala <dietrich@mozilla.com>
+Digital Creations 2, Inc
+Disruptive Innovations
+<djoham@criadvantage.com>
+Don Bragg <dbragg@netscape.com>
+Don Brown
+Don Cone <dcone@netscape.com>
+Doodle <doodle@scenergy.dfmk.hu>
+Doron Rosenberg <doronr@naboonline.com>
+Dorus Peelen
+Douglas Stebila <douglas@stebila.ca>
+Doug Sherk <dsherk@mozilla.com>
+Doug Turner <dougt@dougt.org>
+Doug Wright
+<drbrain-bugzilla@segment7.net>
+Drew Willcoxon <adw@mozilla.com>
+<drimbk@yahoo.com>
+Dr Stephen Henson <stephen.henson@gemplus.com>
+<d-russo@ti.com>
+Dr Vipul Gupta <vipul.gupta@sun.com>
+Dvornik Laszlo
+Ed Burns <edburns@acm.org>
+Edward Lee <edilee@mozilla.com>
+Egor Starkov <starkov.egor@gmail.com>
+Ehsan Akhgari <ehsan.akhgari@gmail.com>
+Eitan Isaacson <eitan@monotonous.org>
+Eli Friedman <sharparrow1@yahoo.com>
+Elika J. Etemad <fantasai@inkedblade.net>
+Emanuele Costa <emanuele.costa@gmail.com>
+emk <VYV03354@nifty.ne.jp>
+Emmanuel Pacaud <emmanuel.pacaud@free.fr>
+<epstein@tellme.com>
+Ere Maijala <emaijala@kolumbus.fi>
+Eric Anholt <eric@anholt.net>
+Eric Butler <zantifon@gmail.com>
+Eric Hedekar <afterthebeep@gmail.com>
+Eric J. Burley <ericb@neoplanet.com>
+Eric Promislow
+Eric Vaughan <evaughan@netscape.com>
+Erik Fabert <jerfa@yahoo.com>
+Erik van der Poel
+Erik Vold <erikvvold@gmail.com>
+Ervin Yan <ervin.yan@sun.com>
+Erwan Loisant <eloisant@gmail.com>
+Esben Mose Hansen <esben@oek.dk>
+Ethan Hugg
+Eugeniy Meshcheryakov <eugen@debian.org>
+Evan Yan <evan.yan@sun.com>
+Fabrice Desré <fabrice.desre@gmail.com>
+Federico Mena-Quintero <federico@novell.com>
+Felipe Gomes <felipc@gmail.com>
+Felix Fung <felix.the.cheshire.cat@gmail.com>
+<felix.meschberger@day.com>
+Feng Qian
+Fernando Herrera <fherrera@onirica.com>
+Fernando Jimenez <ferjmoreno@gmail.com>
+Flock Inc.
+Florian Boesch <pyalot@gmail.com>
+Florian Hänel <heeen@gmx.de>
+Florian Queze <florian@queze.net>
+Florian Scholz <elchi3@elchi3.de>
+<flying@dom.natm.ru>
+France Telecom Research and Development
+Franck
+Frank Tang <ftang@netscape.com>
+Frank Yan <fyan@mozilla.com>
+Franky Braem
+<franky@pacificconnections.com>
+Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+Frederic Plourde <frederic.plourde@polymtl.ca>
+Frederic Wang <fred.wang@free.fr>
+Fredrik Holmqvist <thesuckiestemail@yahoo.se>
+Fredrik Larsson <nossralf@gmail.com>
+Fritz Schneider <fritz@google.com>
+<fur@netscape.com>
+Gagan Saksena <gagan@netscape.com>
+Ming Gao <gaoming@cn.ibm.com>
+Garrett Arch Blythe
+Garrett Smith
+Garth Smedley <garths@oeone.com>
+Gary Kwong
+Gavin Sharp <gavin@gavinsharp.com>
+Gefferth Andras
+Geoff Lankow <geoff@darktrojan.net>
+George Kangas
+<george@vanous.com>
+George Wright <george@mozilla.com>
+Georgi Guninski <guninski@guninski.com>
+Georg Maaß <georg@bioshop.de>
+Gervase Markham <gerv@gerv.net>
+Gian-Carlo Pascutto <gpascutto@mozilla.com>
+Gianluca Turconi
+Gianugo Rabellino <gianugo@apache.org>
+Gijs Kruitbosch <gijskruitbosch@gmail.com>
+Ginn Chen <ginn.chen@sun.com>
+Giorgio Maone <g.maone@informaction.com>
+Girish Sharma <scrapmachines@gmail.com>
+Girts
+Giscard Girard
+Giuseppe Modugno
+Glen Nakamura <glen@imodulo.com>
+Glenn Randers-Pehrson <glennrp@gmail.com>
+Goldman Eleonora
+Google Inc.
+Gordon Sheridan <gordon@netscape.com>
+Graeme McCutcheon <graememcc_firefox@graeme-online.co.uk>
+Graydon Hoare <graydon@mozilla.com>
+Gregory Szorc <gps@mozilla.com>
+Grig Gheorghiu <grig@gheorghiu.net>
+Guillermo Robla Vicario <groblavicario@gmail.com>
+Guoxin Fan <gfan@sta.samsung.com>
+Gus Verdun <gustavoverdun@aol.com>
+<gwatmuff@geographicweb.com.au>
+Haamed Gheibi <gheibi@metanetworking.com>
+Håkan Waara <hwaara@gmail.com>
+Halacsy Peter
+<hannes@helma.at>
+Hanno Boeck <hanno@hboeck.de>
+Hans-Andreas Engel
+Harri Pitkanen
+Harshal Pradhan <keeda@hotpop.com>
+Heather Arthur <fayearthur@gmail.com>
+Heikki Toivonen <heikki@netscape.com>
+Hein Roehrig
+Henrik Gemal <mozilla@gemal.dk>
+Henrik Skupin <hskupin@gmail.com>
+Henri Sivonen <hsivonen@iki.fi>
+Henry Cejtin
+Henry Sobotka <sobotka@axess.com>
+Heriot-Watt University
+Hermann Schwab <hhschwab@gmail.com>
+Hermecz Vajk
+Hernan Rodriguez Colmeiro <colmeiro@gmail.com>.
+Hewlett-Packard Company
+Hiroshi Shimoda <piro@p.club.ne.jp>
+Hoa Nguyen <hoa.nguyen@intel.com>
+Honza Bambas <honzab@firemni.cz>
+Howard Chu <hyc@symas.com>
+Hubbie Shaw
+Hubert Figuière <hub@mozilla.com>
+Ian Gilman <ian@iangilman.com>
+Ian Hickson <ian@hixie.ch>
+Ian McGreer <mcgreer@netscape.com>
+Ian Melven <imelven@mozilla.com>
+Ian Oeschger
+IBM Corporation
+i-DNS.net International
+<igor3@apochta.com>
+Igor Bazarny <igor.bazarny@gmail.com>
+Igor Bukanov <igor@mir2.org>
+igor@fastmail.fm
+igor@icesoft.no
+Igor Tandetnik
+Ilya Konstantinov <mozilla-code@future.shiny.co.il>
+Intel Corporation
+Jaakko Kiviluoto <jaakko.kiviluoto@digia.com>
+Jacek Piskozub <piskozub@iopan.gda.pl>
+Jacob Bramley <Jacob.Bramely@arm.com>
+Jae-Seong Lee-Russo <lusian@gmail.com>
+James Boston <mozilla@jamesboston.ca>
+James Bunton <jamesbunton@fastmail.fm>
+James Justin Harrell
+James L. Nance
+James Ross <silver@warwickcompsoc.co.uk>
+James Willcox <jwillcox@mozilla.com>
+Jamie Zawinski <jwz@jwz.org>
+Jan Bambas <honzab@firemni.cz>
+Jan Darmochwal
+Jan de Mooij <jandemooij@gmail.com>
+Jan Horak <jhorak@redhat.com>
+Jan-Klaas Kollhof
+Jan Odvarko <odvarko@gmail.com>
+Jan Varga <Jan.Varga@gmail.com>
+Jan Wrobel <wrobel@blues.ath.cx>
+Jared Wein <jwein@mozilla.com>
+Jason Barnabe <jason_barnabe@fastmail.fm>
+Jason Duell <jduell.mcbugs@gmail.com>
+Jason Eager <jce2@po.cwru.edu>
+Jason Sachs <jmsachs@gmail.com>
+Jason Kersey <kerz@netscape.com>
+Jason Orendorff <jorendorff@mozilla.com>
+Jason Voll <jvoll@mozilla.com>
+Javier Delgadillo <javi@netscape.com>
+Javier Pedemonte <pedemont@us.ibm.com>
+Jay Patel <jay@mozilla.org>
+Jean-Francois Ducarroz <ducarroz@netscaape.com>
+Jean-Jacques Enser <jj@netscape.com>
+Jeff Gilbert <jgilbert@mozilla.com>
+Jeff Hammel <jhammel@mozilla.com>
+Jeff Muizelaar <jmuizelaar@mozilla.com>
+Jeff Thompson
+Jeff Walden <jwalden+bmo@mit.edu>
+Jens Bannmann <jens.b@web.de>
+Jens Hatlak <jh@junetz.de>
+Jeremias Bosch <jeremias.bosch@gmail.com>
+Jeremy D. Lea <reg@openpave.org>
+Jeroen Dobbelaere <jeroen.dobbelaere@acunia.com>
+<Jerry.Kirk@Nexwarecorp.com>
+Jesper Kristensen <mail@jesperkristensen.dk>
+Jesse Ruderman <jruderman@gmail.com>
+Jessica Blanco <jblanco@us.ibm.com>
+<jhs@lysator.liu.se>
+<ji_bo@yahoo.com>
+Jignesh Kakadiya <jigneshhk1992@gmail.com>
+Jim Blandy <jimb@mozilla.com>
+Jim Chen <jchen@mozilla.com>
+Jim Grandy
+Jim Ley <jim@jibbering.com>
+Jim Mathies <jmathies@mozilla.com>
+Jim Nance <jim_nance@yahoo.com>
+<jim-patterson@ncf.ca>
+Jim Roskind <jar@netscape.com>
+<jlaprise@delanotech.com>
+Joachim Kuebart
+Joaquin Cuenca Abela
+Joe Drew <joe@drew.ca>
+Joe Hewitt <hewitt@netscape.com>
+Joe Hughes <joe@retrovirus.com>
+Joel Maher <joel.maher@gmail.com>
+joerg.schaible@gmx.de
+Joe Walker <jwalker@mozilla.com>
+Joey Armstrong <joey@mozilla.com>
+Joey Minta <jminta@gmail.com>
+Johan Charlez <johan.charlez@gmail.com>
+Johann Petrak <johann@ai.univie.ac.at>
+Johnathan Nightingale <johnath@mozilla.com>
+John Bandhauer <jband@netscape.com>
+John B. Keiser
+John C. Griggs <johng@corel.com>
+John Daggett <jdaggett@mozilla.com>
+John Fairhurst <john_fairhurst@iname.com>
+John Ford <jhford@mozilla.com>
+John Gardiner Myers <jgmyers@speakeasy.net>
+John Gaunt <jgaunt@netscape.com>
+John Hanely
+John Morkel <jmorkel@gmail.com>
+John Morrison <jrgmorrison@aol.com>
+Johnny Stenback <jst@mozilla.com>
+John Resig <jresig@mozilla.com>
+John Schneider
+John Sun <john.sun@sun.com>
+John Taylor <jtaylor@netscape.com>
+John Zhang <jzhang@aptana.com>
+Jonas Jonsson <mozilla.nospam@fatbrain.org>
+Jonas Sicking <jonas@sicking.cc>
+Jonathan Granrose <granrose@netscape.com>
+Jonathan Griffin <jgriffin@mozilla.com>
+Jonathan Hage <hage.jonathan@gmail.com>
+Jonathan Kew <jfkthame@gmail.com>
+Jonathan Protzenko <jonathan.protzenko@gmail.com>
+Jonathan Watt <jwatt@jwatt.org>
+Jonathan Wilson <jonwil@tpgi.com.au>
+Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>
+Jon Herron <leftturnsolutions@yahoo.com>
+Jono DiCarlo <jdicarlo@mozilla.com>
+Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+Jorge Villalobos <jorge@mozilla.com>
+Jory A. Pratt <geekypenguin@gmail.com>
+Josh Aas <josh@mozilla.com>
+Josh Lurz <jlurz24@gmail.com>
+Josh Matthews <josh@joshmatthews.net>
+Joshua M. <soapyhamhocks@gmail.com>
+Joshua Randall <jcrandall@alum.mit.edu>
+J. Paul Reed <preed@mozilla.com>
+Juan Lang
+Julian Seward <jseward@acm.org>
+Julian Viereck <jviereck@mozilla.com>
+Julien Lafon <julien.lafon@gmail.com>
+Julien Lecomte
+Jungshik Shin <jshin@mailaps.org>
+Justin Arthur <justinarthur@ieee.org>
+Justin Bradford <jab@atdot.org>
+Justin Dolske <dolske@mozilla.com>
+Justin Lebar <justin.lebar@gmail.com>
+Kai Engert <kaie@redhat.com>
+Kailas Patil <patilkr24@gmail.com>
+Kan-Ru Chen <kchen@mozilla.com>
+Karl Tomlinson <karlt+@karlt.net>
+Karsten Sperling <spiff@phreax.net>
+Kartikaya Gupta <kgupta@mozilla.com>
+Kaspar Brand <mozcontrib@velox.ch>
+Kathleen Brade <brade@pearlcrescent.com>
+Katsuhiko Momoi
+Keith Packard <keithp@keithp.com>
+Keith Rarick <kr@xph.us>
+Keith Schwarz <kschwarz@mozilla.com>
+Keith Visco <kvisco@ziplink.net>
+Ken Key <key+mozilla@ksquared.net>
+Kenneth Herron <kherron@fmailbox.com>
+Kenny Heaton <kennyheaton@gmail.com>
+Kevin Gerich <kevin@kmgerich.com>
+Kevin Hendricks <kevin.hendricks@sympatico.ca>
+Kevin McCluskey <kmcclusk@netscape.com>
+Kevin Puetz <puetzk@iastate.edu>
+<khanson@netscape.com>
+Kin Blas <kin@netscape.com>
+Kipp E.B. Hickman
+Kishore Arepalli <kishore.arepalli@gmail.com>
+<k.mike@gmx.net>
+Konstantin Mirny
+Korea Information Security Agency
+Kris Maglione <maglione.k@gmail.com>
+Kristian Høgsberg <krh@redhat.com>
+Kurt Lidl <lidl@pix.net>
+Kyle Huey <khuey@kylehuey.com>
+Kyle Machulis <kyle@nonpolynomial.com>
+Kyle Simpson <ksimpson@mozilla.com>
+Kyle Yuan <kyle.yuan@sun.com>
+Landry Breuil <landry@openbsd.org>
+Lan Qiang <jameslan@gmail.com>
+Larry Fitzpatrick <lef@opentext.com>
+Lars Erdmann
+Lars Knoll <knoll@kde.org>
+LastPass.com
+László Jánszky
+László Németh <nemethl@gyorsposta.hu>
+Laurent Jouanneau <laurent.jouanneau@disruptive-innovations.com>
+Lenka Fibikova <fibikova@exp-math.uni-essen.de>
+Leon Sha <leon.sha@oracle.com>
+Lev Serebryakov <lev@serebryakov.spb.ru>
+Le Zhang <r0bertz@gentoo.org>
+Liam Davis-Mead
+Lidong <lidong520@263.net>
+Lina Kemmel <lkemmel@il.ibm.com>
+Louie Zhao <louie.zhao@sun.com>
+Lubos Ures
+Lucas Rocha <lucasr@mozilla.com>
+Luke Wagner <lw@mozilla.com>
+<Lupin.wp@gmail.com>
+Maha Abou El Rous <mahar@eg.ibm.com>
+Makoto Kato <m_kato@ga2.so-net.ne.jp>
+Malcolm Rowe <malcolm-bmo@farside.org.uk>
+Malcolm Smith <malsmith@cs.rmit.edu.au>
+Malini Das <mdas@mozilla.com>
+Manish Singh <manish@flock.com>
+Marc Attinasi
+Marc Bevand <bevand_m@epita.fr>
+Marcin Lubonski
+Marc Mulcahy <marc.mulcahy@sun.com>
+Marco Bonardo <mak77@bonardo.net>
+Marco Castelluccio <mar.castelluccio@studenti.unina.it>
+Marco Fabbri
+Marco Pesenti Gritti <marco@gnome.org>
+Margaret Leibovic <margaret.leibovic@gmail.com>
+Marina Samuel <msamuel@mozilla.com>
+Mark Banner <bugzilla@standard8.plus.com>
+Mark Capella <markcapella@twcny.rr.com>
+Mark Cote <mcote@mozilla.com>
+Mark Finkle <mark.finkle@gmail.com>
+Mark Hammond <markh@activestate.com>
+Mark Mentovai <mark@moxienet.com>
+Mark Pilgrim <pilgrim@gmail.com>
+Mark Smith <mcs@pearlcrescent.com>
+Mark Steele <mwsteele@gmail.com>
+Markus G. Kuhn <mkuhn@acm.org>
+Markus Stange <mstange@themasta.com>
+Martijn Pieters <mj@digicool.com>
+Martijn Wargers <martijn.martijn@gmail.com>
+Martin Hassman <hassman@czilla.cz>
+Martin Honnen <martin.honnen@gmx.de>
+Martin McNickle <mmcnickle@gmail.com>
+Martin Schroeder <mschroeder@mozilla.x-home.org>
+Martin Stransky <stransky@redhat.com>
+Martin v. Loewis <martin@v.loewis.de>
+Martin Zvieger <martin.zvieger@sphinx.at>
+Masakazu Takahashi
+Masaki Katakai <katakai@japan.sun.com>
+Masatoshi Kimura <VYV03354@nifty.ne.jp>
+Masayuki Nakano <masayuki@d-toybox.com>
+Mathias Hasselmann <mathias.hasselmann@gmx.de>
+Mathieu Fenniak
+Mats Palmgren <matspal@gmail.com>
+Matt Brubeck <mbrubeck@mozilla.com>
+Matt Crocker <matt@songbirdnest.com>
+Matt Fisher <matt@netscape.com>
+Matthew Gregan <kinetik@flim.org>
+Matthew Noorenberghe <mnoorenberghe@mozilla.com>
+Matt Woodrow <mwoodrow@mozilla.com>
+Max Stepin <maxstepin@gmail.com>
+<mcmullen@netscape.com>
+Meena Vyas <meena.vyas@oracle.com>
+Mehdi Mulani <mmulani@mozilla.com>
+Merle Sterling <msterlin@us.ibm.com>
+<mff@research.att.com>
+Michael Ash <kal_el_1938@hotmail.com>
+Michael Daumling <daumling@adobe.com>
+Michael Emmel <mike.emmel@gmail.com>
+Michael Hanson <mhanson@mozilla.com>
+Michael J. Fromberger <sting@linguist.dartmouth.edu>
+Michael Johnston <special.michael@gmail.com>
+Michael Judge <mjudge@netscape.com>
+Michael Kohler <michaelkohler@live.com>
+Michael Kraft <morac99-firefox2@yahoo.com>
+Michael Lipp
+Michael Lowe <michael.lowe@bigfoot.com>
+Michael Martin
+michaelp
+Michael Ratcliffe <mratcliffe@mozilla.com>
+Michael Roovers
+Michael Ventnor <m.ventnor@gmail.com>
+Michael Wu <flamingice@sourmilk.net>
+Michael Yoshitaka Erlewine <mitcho@mitcho.com>
+Michal Novotny <michal.novotny@gmail.com>
+Michiel van Leeuwen <mvl@exedo.nl>
+Mihai Șucan <mihai.sucan@gmail.com>
+Miika Jarvinen <mjarvin@gmail.com>
+Mikeal Rogers <mikeal.rogers@gmail.com>
+Mike Beltzner <beltzner@mozilla.com>
+Mike Connor <mconnor@steelgryphon.com>
+Mike Hommey <mh@glandium.org>
+Mike Kaplinskiy <mike.kaplinskiy@gmail.com>
+Mike Kaply
+Mike Kowalski <mikejk@ameritech.net>
+Mike Kristoffersen <mikek@mikek.dk>
+Mike McCabe <mccabe@netscape.com>
+Mike Pinkerton <pinkerton@netscape.com>
+Mike Shaver <shaver@off.net>
+Milen Nankov
+Milind <sukhisoul@yahoo.com>
+Mitchell Field <mitch_1_2@live.com.au>
+Mitchell Stoltz <mstoltz@netscape.com>
+Mitesh Shah <mitesh@netscape.com>
+M Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+Mohammad R. Haghighat <mohammad.r.haghighat@intel.com>
+Mook <mook.moz@gmail.com>
+Morten Nilsen <morten@nilsen.com>
+Mounir Lamouri <mounir.lamouri@mozilla.com>
+moz_bug_r_a4
+Mozdev Group, Inc
+Mozilla Foundation
+Mozilla Japan
+<mozilla@pdavis.cx>
+Mrinal Kant <mrinal.kant@gmail.com>
+Ms2ger <ms2ger@gmail.com>
+Murali S R <murali.sr92@yahoo.com>
+Muzaffar Mahkamov <mmahkamov@eisst.com>
+Myk Melez <myk@mozilla.org>
+<myngs@hotmail.com>
+Nagendra Modadugu <ngm@google.com>
+Nagy Viktor
+Naoki Hotta <nhotta@netscape.com>
+Nao Toyamo
+Nate Nielsen <nielsen@memberwebs.com>
+Nattachai Ungsriwong <nattachai@gmail.com>
+Neil Deakin <enndeakin@gmail.com>
+Neil Rashbrook <neil@parkwaycc.co.uk>
+Nelson Bolyard <nelson@bolyard.me>
+Neo Liu <nian.liu@sun.com>
+Netscape Communications Corporation
+Nicholas Nethercote <nnethercote@mozilla.com>
+Nick Fitzgerald <nfitzgerald@mozilla.com>
+Nickolay Ponomarev <asqueella@gmail.com>
+Niels Provos <niels@google.com>
+Nikhil Marathe <nsm.nikhil@gmail.com>
+Nils Gura <nils.gura@sun.com>
+Nils Larsch <nla@trustcenter.de>
+Nils Maier <maierman@web.de>
+Ningjie Chen <chenn@email.uc.edu>
+Nino D'Aversa <ninodaversa@gmail.com>
+Nippon Telegraph and Telephone Corporation
+Nochum Sossonko <highmind63@gmail.com>
+Nokia Corporation
+Noll Janos
+Norris Boyd <nboyd@atg.com>
+Novell Corporation
+NVIDIA Corporation
+OEone Corporation
+<okin7@yahoo.fr>
+Oleg Romashin <romaxa@gmail.com>
+Oliver Hunt
+Olivier Cahagne
+Olivier Gerardin <ogerardin@vo.lu>
+Olli Pettay <Olli.Pettay@helsinki.fi>
+Ondrej Brablc <ondrej@allpeers.com>
+Oracle Corporation
+Oscar Fogelberg <osfo@home.se>
+Owen Taylor <otaylor@redhat.com>
+Øyvind Kolås <pippin@gimp.org>
+Pamela Greene <pamg.bugs@gmail.com>
+Panagiotis Astithas <past@mozilla.com>
+Paolo Amadini <http://www.amadzone.org/>
+Patipat Susumpow <kengggg@gmail.com>
+Patrick Beard <beard@netscape.com>
+Patrick Fey <bugzilla@nachtarbeiter.net>
+Patrick McManus <mcmanus@ducksong.com>
+Patrick Walton <pwalton@mozilla.com>
+Pattara Kiatisevi <ott@linux.thai.net>
+Paul Ashford <arougthopher@lizardland.net>
+Paul Biggar <pbiggar@mozilla.com>
+Paul Kocher
+Paul Kurczaba
+Paul O'Shannessy <paul@oshannessy.com>
+Paul Rouget <paul@mozilla.com>
+Paul Sandoz <paul.sandoz@sun.com>
+Pavel Cvrcek
+Pawel Chmielowski
+PenPal
+Pete Collins <petejc@collab.net>
+Peter Annema <disttsc@bart.nl>
+Peter Bajusz <hyp-x@inf.bme.hu>
+Peter Lubczynski <peterl@netscape.com>
+Peter Naulls
+Peter Parente <parente@cs.unc.edu>
+Peter Seliger
+Peter Van der Beken <peter@propagandism.org>
+Peter van der Woude
+Peter Weilbacher <mozilla@weilbacher.org>
+Pete Zha <pete.zha@sun.com>
+Petr Kostka <petr.kostka@st.com>
+Philipp Kewisch <mozilla@kewis.ch>
+Philipp Vogt <vogge@vlbg.dhs.org>
+Philipp von Weitershausen <philipp@weitershausen.de>
+Philip Taylor <philip.taylor@cl.cam.ac.uk>
+Phil Ringnalda
+Phil Schwartau <pschwartau@meer.net>
+Pierre Chanial <chanial@noos.fr>
+Pierre Phaneuf <pp@ludusdesign.com>
+Pierre Tardy <tardyp@gmail.com>
+POTI Inc
+Prabhat Hegde <prabhat.hegde@sun.com>
+Pranav Ravichandran <prp.1111@gmail.com>
+Prasad Sunkari <prasad@medhas.org>
+Priit Laes
+Proofpoint, Inc.
+Q42 <http://www.q42.nl>
+Radha Kulkarni <radha@netscape.com>
+Ramanathan Guha <guha@netscape.com>
+Ramiro Estrugo <ramiro@netscape.com>
+Randell Jesup
+Randolph Chung <tausq@debian.org>
+Rangan Sen <rangansen@netscape.com>
+Raúl Porcel <armin76@gentoo.org>
+Raymond Lee <raymond@appcoast.com>
+Red Hat, Inc
+Rene Engelhard
+Rene Pronk <r.pronk@its.tudelft.nl>
+Reto Laemmler
+<rhp@netscape.com>
+Ria Klaassen
+Richard C. Swift <swift@netscape.com>
+Richard L. Walsh <dragtext@e-vertise.com>
+Richard Newman <rnewman@mozilla.com>
+Richard Verhoeven <river@win.tue.nl>
+Richard Walsh
+Rich Dougherty
+Rich Salz
+Rich Walsh <dragtext@e-vertise.com>
+Rick Gessner <rickg@netscape.com>
+R.J. Keller <rlk@trfenv.com>
+Rob Arnold <tellrob@gmail.com>
+Rob Campbell <rcampbell@mozilla.com>
+Robert Accettura <robert@accettura.com>
+Robert Churchill <rjc@netscape.com>
+Robert Ginda <rginda@hacksrus.com>
+Robert Kaiser <kairo@kairo.at>
+Robert Longson <longsonr@gmail.com>
+Robert Miner <rminer@geomtech.com>
+Robert O'Callahan <robert@ocallahan.org>
+Roberto Estrada <roberto.estrada@yahoo.es>
+Robert Relyea <rrelyea@redhat.com>
+Robert Sayre <sayrer@gmail.com>
+Robert Sesek <rsesek@bluestatic.org>
+Robert Strong <robert.bugzilla@gmail.com>
+Robin Lu <robin.lu@sun.com>
+Rob McCool
+Rod Spears <rods@netscape.com>
+Roger B. Sidje <rbs@maths.uq.edu.au>
+<rogerl@netscape.com>
+<rokicki@instantis.com>
+Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
+Roman Ivanov <thingol@mail.ru>
+Ronny Perinke <ronny.perinke@gmx.de>
+Roozbeh Pournader <roozbeh@sharif.edu>
+Roy Frostig <rfrostig@mozilla.com>
+Roy Yokoyama <yokoyama@netscape.com>
+RSA Security, Inc
+Russell King <rmk@arm.linux.org.uk>
+Rusty Lynch <rusty.lynch@intel.com>
+Ryan Cassin <rcassin@supernova.org>
+Ryan Flint <rflint@dslr.net>
+Ryan Jones <sciguyryan@gmail.com>
+Ryan VanderMeulen <ryanvm@gmail.com>
+Ryoichi Furukawa <oliver@1000cp.com>
+sagdjb@softwareag.com
+Samir Gehani <sgehani@netscape.com>
+Sammy Ford
+Samphan Raruenrom
+Samuel Sieb <samuel@sieb.net>
+Sarlos Tamas
+scole@planetweb.com
+Scooter Morris <scootermorris@comcast.net>
+Scott Collins <scc@ScottCollins.net>
+Scott MacGregor <mscott@mozilla.org>
+Scott Putterman <putterman@netscape.com>
+Sean Cotter <cotter@netscape.com>
+Sean Dunn <seanedunn@yahoo.com>
+Sean Echevarria <sean@beatnik.com>
+Sean McMurray
+Sean Stangl <sstangl@mozilla.com>
+Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Sebastian Kromp <46b@gulli.com>
+Seno Aiko <Seno.Aiko@gmail.com>
+Serge Gautherie <sgautherie.bz@free.fr>
+Sergei Dolgov <sergei_d@fi.tartu.ee>
+Sergey Novikov <sergeyn@google.com>
+Seth Spitzer <sspitzer@mozilla.org>
+sfraser@netscape.com
+shadowpage
+Shailendra N Jain<shailen.n.jain@gmail.com>
+Shaohua Wen
+Shawn Gong <shawn@mozilla.com>
+Shawn Wilsher <me@shawnwilsher.com>
+Sheueling Chang Shantz <sheueling.chang@sun.com>,
+Shi-Jun He
+Shoji Matsumoto <shom@vinelinux.org>
+Shoshannah Forbes <xslf@xslf.com>
+shutdown@flashmail.com
+Shyjan Mahamud <mahamud@cs.cmu.edu>
+Shy Shalom <shooshX@gmail.com>
+Siarhei Siamashka <siarhei.siamashka@gmail.com>
+Siddharth Agarwal <sid.bugzilla@gmail.com>
+Sid Stamm <sid@mozilla.com>
+Silvia Zhao <silvia.zhao@sun.com>
+Silviu Trasca
+Simeon Morrison <smorrison@gte.com>
+Simmule Turner
+Simon Brouwer
+Simon Bünzli <zeniko@gmail.com>
+Simon Fraser <smfr@smfr.org>
+Simon Montagu <smontagu@smontagu.org>
+Simon Wilkinson <simon@sxw.org.uk>
+simonzack
+Sindre Dammann <sindrebugzilla@gmail.com>
+Sinker Li <thinker@codemud.net>
+Sion Fraser <sfraser@netscape.com>
+Siraj Razick <siraj.razick@collabora.co.uk>
+Sjoerd Visscher <sjoerd@w3future.com>
+Slavomir Katuscak <slavomir.katuscak@sun.com>
+smorrison@gte.com
+Soeren Munk Skroeder
+Sonja Mirtitsch
+Sonny Piers <sonny.piers@gmail.com>
+Søren Sandmann <sandmann@daimi.au.dk>
+Spyros Livathinos <livathinos.spyros@gmail.com>
+Sriram Ramasubramanian <sriram@mozilla.com>
+Srirang G Doddihal <brahmana@doddihal.com>
+Stanford University
+Stan Shebs <stanshebs@earthlink.net>
+Stefan Borggraefe
+Stefan Hundhammer <HuHa-zilla@gmx.de>
+Stefanik Gábor
+Stefan Sitter <ssitter@gmail.com>
+Steffen Imhof <steffen.imhof@gmail.com>
+Steffen Wilberg <steffen.wilberg@web.de>
+Stephen Blackheath <entangled.mooched.stephen@blacksapphire.com>
+Stephen Donner
+Stephen Fung <fungstep@hotmail.com>
+Stephen Horlander <shorlander@mozilla.com>
+Stephen Lamm <slamm@netscape.com>
+Steve Chapel <steven.chapel@sbcglobal.net>
+Steve Clark <buster@netscape.com>
+Steve Dagley <sdagley@netscape.com>
+Steve Fink <sfink@mozilla.org>
+Steve Lamm <slamm@netscape.com>
+Steve Meredith <smeredith@netscape.com>
+Steve Morse <morse@netscape.com>
+Steven Garrity <steven@silverorange.com>
+Steven Michaud <smichaud@pobox.com>
+Steve Roussey
+Steve Swanson <steve.swanson@mackichan.com>
+Stuart Morgan <stuart.morgan@alumni.case.edu>
+Stuart Parmenter <pavlov@pavlov.net>
+Sungjoon Steve Won <stevewon@gmail.com>
+Sun Microsystems, Inc.
+Suresh Duddi <dp@netscape.com>
+<svendtofte@svendtofte.com>
+Sylvain Pasche <sylvain.pasche@gmail.com>
+Takayuki Tei <taka@netscape.com>
+Takeshi Ichimaru <ayakawa.m@gmail.com>
+Takuro Ashie <ashie@clear-code.com>
+Tanner M. Young <mozilla@alyoung.com>
+Taras Glek <tglek@mozilla.com>
+Tatiana Meshkova <tanya.meshkova@gmail.com>
+Ted Mielczarek <ted@mielczarek.org>
+Tero Koskinen <tero.koskinen@iki.fi>
+Terrence Cole <terrence@mozilla.com>
+Terry Hayes <thayes@netscape.com>
+Teune van Steeg <t.vansteeg@gmail.com>
+The Hewlett-Packard Company
+The MITRE Corporation
+The Nokia Corporation
+Theppitak Karoonboonyanan <thep@linux.thai.net>
+The University of Queensland
+Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+Thomas Blatter <bebabo@swissonline.ch>
+Thomas de Grenier de Latour <tom.gl@free.fr>
+Thomas K. Dyas <tom.dyas@gmail.com>
+Tim Copperfield <timecop@network.email.ne.jp>
+timeless <timeless@mac.com>
+Tim Hill <tim@prismelite.com>
+Tim Miller <mille449@gmail.com>
+Timothy B. Terriberry <tterriberry@mozilla.com>
+Timothy Nikkel <tnikkel@gmail.com>
+Timothy Wall <twalljava@dev.java.net>
+Timothy Watt <riceman+moz@mail.rit.edu>
+Tim Rowley <tor@cs.brown.edu>
+Tim Taubert <tim.taubert@gmx.de>
+Tom Brinkman <reportbase@gmail.com>
+Tom Germeau <tom.germeau@epigoon.com>
+Tomi Leppikangas <tomi.leppikangas@oulu.fi>
+Tom Kneeland <tomk@mitre.org>
+Tom Pixley <joki@netscape.com>
+Tom Schuster <evilpies@gmail.com>
+Tom St Denis, tomstdenis@iahu.ca
+Tom Tromey
+Tony Chang <tony@ponderer.org>
+Tor Lillqvist
+Travis Bogard <travis@netscape.com>
+Trent Mick <TrentM@ActiveState.com>
+Trevor Fairey <tnfairey@gmail.com>
+Trevor Saunders <trev.saunders@gmail.com>
+Troy Farrell <troy@entheossoft.com>
+Tuukka Tolvanen <tt@lament.cjb.net>
+T. Zachary Laine <whatwasthataddress@gmail.com>
+Ulrich Drepper <drepper@redhat.com>
+University of Southern California
+Uri Bernstein <uriber@gmail.com>
+Varga Daniel
+Vee Satayamas <vsatayamas@gmail.com>
+Victor Porof <vporof@mozilla.com>
+Vidur Apparao <vidur@netscape.com>
+Vilya Harvey <vilya@nag.co.uk>
+Vincent Béron <vberon@hermes.usherb.ca>
+Vipul Gupta <vipul.gupta@sun.com>
+Viswanath Ramachandran <vishy@netscape.com>
+Vivien Nicolas <21@vingtetun.org>
+Vladan Djeric <vdjeric@mozilla.com>
+Vladimir Vukicevic <vladimir@pobox.com>
+Vlad Sukhoy <vladimir.sukhoy@gmail.com>
+WADA <m-wada@japan.com>
+Waldemar Horwat <waldemar@acm.org>
+Walter Meinl <wuno@lsvw.de>
+Warren Harris <warren@netscape.com>
+Wellington Fernando de Macedo <wfernandom2004@gmail.com>
+Werner Sharp
+Wesley Garland
+Wesley Johnston <wjohnston@mozilla.com>
+Will Guaraldi <will.guaraldi@pculture.org>
+William A. Law <law@netscape.com>
+William B. Ackerman
+William Chen <wchen@mozilla.com>
+William Cook <william.cook@crocodile-clips.com>
+William Jon McCann <william.jon.mccann@gmail.com>
+William Lachance <wlachance@mozilla.com>
+William Price <bugzilla@mob.rice.edu>
+William R. Price <wrprice@alumni.rice.edu>
+<william.tan@i-dns.net>
+Wladimir Palant <trev@gtchat.de>
+Wolfgang Rosenauer <wr@rosenauer.org>
+<wtam@bigfoot.com>
+Wyllys Ingersoll <wyllys.ingersoll@sun.com>
+<x00000000@freenet.de>
+Yueheng Xu <yueheng.xu@intel.com>
+Yuh-Ruey Chen
+Yury <async.processingjs@yahoo.com>
+Yury Delendik
+Zachary Weinberg <zweinberg@mozilla.com>
+Zach Linder <zakness@gmail.com>
+Zach Lipton <zach@zachlipton.com>
+Zack Rusin <zack@kde.org>
+<zack-weg@gmx.de>
+Zack Weinberg <zweinberg@mozilla.com>
+Zbigniew Braniecki <gandalf@e-gandalf.net>
+<zen-parse@gmx.net>
+Zero-Knowledge Systems, Inc
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -992,35 +992,37 @@ nsAccessibilityService::GetOrCreateAcces
 
     newAcc = new HyperTextAccessibleWrap(content, docAcc);
     if (docAcc->BindToDocument(newAcc, aria::GetRoleMap(aNode)))
       return newAcc;
     return nullptr;
   }
 
   nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aNode);
+
+  // If the element is focusable or global ARIA attribute is applied to it or
+  // it is referenced by ARIA relationship then treat role="presentation" on
+  // the element as the role is not there.
   if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::presentation)) {
-    // Ignore presentation role if element is focusable (focus event shouldn't
-    // be ever lost and should be sensible).
-    if (content->IsFocusable())
-      roleMapEntry = nullptr;
-    else
+    if (!content->IsFocusable() && !HasUniversalAriaProperty(content) &&
+        !HasRelatedContent(content))
       return nullptr;
+
+    roleMapEntry = nullptr;
   }
 
   if (weakFrame.IsAlive() && !newAcc && isHTML) {  // HTML accessibles
-    bool tryTagNameOrFrame = true;
-
     nsIAtom *frameType = weakFrame.GetFrame()->GetType();
 
     bool partOfHTMLTable =
       frameType == nsGkAtoms::tableCaptionFrame ||
       frameType == nsGkAtoms::tableCellFrame ||
       frameType == nsGkAtoms::tableRowGroupFrame ||
       frameType == nsGkAtoms::tableRowFrame;
+    bool legalPartOfHTMLTable = partOfHTMLTable;
 
     if (partOfHTMLTable) {
       // Table-related frames don't get table-related roles
       // unless they are inside a table, but they may still get generic
       // accessibles
       nsIContent *tableContent = content;
       while ((tableContent = tableContent->GetParent()) != nullptr) {
         nsIFrame *tableFrame = tableContent->GetPrimaryFrame();
@@ -1052,60 +1054,60 @@ nsAccessibilityService::GetOrCreateAcces
             // Table-related descendants of presentation table are also
             // presentation if they aren't focusable and have not explicit ARIA
             // role (don't create accessibles for them unless they need to fire
             // focus events).
             return nullptr;
           }
 
           // otherwise create ARIA based accessible.
-          tryTagNameOrFrame = false;
+          legalPartOfHTMLTable = false;
           break;
         }
 
         if (tableContent->Tag() == nsGkAtoms::table) {
           // Stop before we are fooled by any additional table ancestors
           // This table cell frameis part of a separate ancestor table.
-          tryTagNameOrFrame = false;
+          legalPartOfHTMLTable = false;
           break;
         }
       }
 
       if (!tableContent)
-        tryTagNameOrFrame = false;
+        legalPartOfHTMLTable = false;
     }
 
     if (roleMapEntry) {
-      // Create ARIA grid/treegrid accessibles if node is not of a child or
-      // valid child of HTML table and is not a HTML table.
-      if ((!partOfHTMLTable || !tryTagNameOrFrame) &&
+      // Create ARIA grid/treegrid accessibles if node is not a child or legal
+      // child of HTML table and is not a HTML table.
+      if ((!partOfHTMLTable || !legalPartOfHTMLTable) &&
           frameType != nsGkAtoms::tableOuterFrame) {
 
         if (roleMapEntry->role == roles::TABLE ||
             roleMapEntry->role == roles::TREE_TABLE) {
           newAcc = new ARIAGridAccessibleWrap(content, docAcc);
 
         } else if (roleMapEntry->role == roles::GRID_CELL ||
             roleMapEntry->role == roles::ROWHEADER ||
             roleMapEntry->role == roles::COLUMNHEADER) {
           newAcc = new ARIAGridCellAccessibleWrap(content, docAcc);
         }
       }
     }
 
-    if (!newAcc && tryTagNameOrFrame) {
+    if (!newAcc) {
       // Prefer to use markup (mostly tag name, perhaps attributes) to
       // decide if and what kind of accessible to create.
       // The method creates accessibles for table related content too therefore
       // we do not call it if accessibles for table related content are
       // prevented above.
       newAcc = CreateHTMLAccessibleByMarkup(weakFrame.GetFrame(), content,
-                                            docAcc);
+                                            docAcc, legalPartOfHTMLTable);
 
-      if (!newAcc) {
+      if (!newAcc && (!partOfHTMLTable || legalPartOfHTMLTable)) {
         // Do not create accessible object subtrees for non-rendered table
         // captions. This could not be done in
         // nsTableCaptionFrame::GetAccessible() because the descendants of
         // the table caption would still be created. By setting
         // *aIsSubtreeHidden = true we ensure that no descendant accessibles
         // are created.
         nsIFrame* f = weakFrame.GetFrame();
         if (!f) {
@@ -1548,18 +1550,30 @@ nsAccessibilityService::CreateAccessible
 
   NS_IF_ADDREF(accessible);
   return accessible;
 }
 
 already_AddRefed<Accessible>
 nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
                                                      nsIContent* aContent,
-                                                     DocAccessible* aDoc)
+                                                     DocAccessible* aDoc,
+                                                     bool aIsLegalPartOfHTMLTable)
 {
+  if (aIsLegalPartOfHTMLTable) {
+    if (nsCoreUtils::IsHTMLTableHeader(aContent)) {
+      Accessible* accessible =
+        new HTMLTableHeaderCellAccessibleWrap(aContent, aDoc);
+      NS_IF_ADDREF(accessible);
+      return accessible;
+    }
+
+    return nullptr;
+  }
+
   // This method assumes we're in an HTML namespace.
   nsIAtom* tag = aContent->Tag();
   if (tag == nsGkAtoms::figcaption) {
     Accessible* accessible = new HTMLFigcaptionAccessible(aContent, aDoc);
     NS_IF_ADDREF(accessible);
     return accessible;
   }
 
@@ -1630,22 +1644,16 @@ nsAccessibilityService::CreateHTMLAccess
       tag == nsGkAtoms::h5 ||
       tag == nsGkAtoms::h6 ||
       tag == nsGkAtoms::q) {
     Accessible* accessible = new HyperTextAccessibleWrap(aContent, aDoc);
     NS_IF_ADDREF(accessible);
     return accessible;
   }
 
-  if (nsCoreUtils::IsHTMLTableHeader(aContent)) {
-    Accessible* accessible = new HTMLTableHeaderCellAccessibleWrap(aContent, aDoc);
-    NS_IF_ADDREF(accessible);
-    return accessible;
-  }
-
   if (tag == nsGkAtoms::output) {
     Accessible* accessible = new HTMLOutputAccessible(aContent, aDoc);
     NS_IF_ADDREF(accessible);
     return accessible;
   }
 
   if (tag == nsGkAtoms::progress) {
     Accessible* accessible =
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -224,17 +224,18 @@ private:
   already_AddRefed<Accessible>
     CreateAccessibleByType(nsIContent* aContent, DocAccessible* aDoc);
 
   /**
    * Create accessible for HTML node by tag name.
    */
   already_AddRefed<Accessible>
     CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, nsIContent* aContent,
-                                 DocAccessible* aDoc);
+                                 DocAccessible* aDoc,
+                                 bool aIsLegalPartOfHTMLTable);
 
   /**
    * Create accessible if parent is a deck frame.
    */
   already_AddRefed<Accessible>
     CreateAccessibleForDeckChild(nsIFrame* aFrame, nsIContent* aContent,
                                  DocAccessible* aDoc);
 
--- a/accessible/src/base/nsEventShell.cpp
+++ b/accessible/src/base/nsEventShell.cpp
@@ -13,34 +13,34 @@
 
 void
 nsEventShell::FireEvent(AccEvent* aEvent)
 {
   if (!aEvent)
     return;
 
   Accessible* accessible = aEvent->GetAccessible();
-  NS_ENSURE_TRUE(accessible,);
+  NS_ENSURE_TRUE_VOID(accessible);
 
   nsINode* node = aEvent->GetNode();
   if (node) {
     sEventTargetNode = node;
     sEventFromUserInput = aEvent->IsFromUserInput();
   }
 
   accessible->HandleAccEvent(aEvent);
 
   sEventTargetNode = nullptr;
 }
 
 void
 nsEventShell::FireEvent(uint32_t aEventType, Accessible* aAccessible,
                         EIsFromUserInput aIsFromUserInput)
 {
-  NS_ENSURE_TRUE(aAccessible,);
+  NS_ENSURE_TRUE_VOID(aAccessible);
 
   nsRefPtr<AccEvent> event = new AccEvent(aEventType, aAccessible,
                                           aIsFromUserInput);
 
   FireEvent(event);
 }
 
 void 
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -38,16 +38,17 @@
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsPIDOMWindow.h"
 
 #include "nsIDocument.h"
 #include "nsIContent.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 
+#include "nsDeckFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIPresShell.h"
 #include "nsIStringBundle.h"
 #include "nsPresContext.h"
 #include "nsIFrame.h"
 #include "nsIView.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIScrollableFrame.h"
@@ -601,58 +602,72 @@ Accessible::TranslateString(const nsStri
   nsresult rv = stringBundle->GetStringFromName(aKey.get(), getter_Copies(xsValue));
   if (NS_SUCCEEDED(rv))
     aStringOut.Assign(xsValue);
 }
 
 uint64_t
 Accessible::VisibilityState()
 {
-  uint64_t vstates = states::INVISIBLE | states::OFFSCREEN;
-
   nsIFrame* frame = GetFrame();
   if (!frame)
-    return vstates;
-
-  nsIPresShell* shell(mDoc->PresShell());
-  if (!shell)
-    return vstates;
-
-  // We need to know if at least a kMinPixels around the object is visible,
-  // otherwise it will be marked states::OFFSCREEN.
-  const uint16_t kMinPixels  = 12;
-  const nsSize frameSize = frame->GetSize();
-  const nsRectVisibility rectVisibility =
-    shell->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
-                             nsPresContext::CSSPixelsToAppUnits(kMinPixels));
-
-  if (rectVisibility == nsRectVisibility_kVisible)
-    vstates &= ~states::OFFSCREEN;
+    return states::INVISIBLE;
+
+  // Walk the parent frame chain to see if there's invisible parent or the frame
+  // is in background tab.
+  if (!frame->GetStyleVisibility()->IsVisible())
+    return states::INVISIBLE;
+
+  nsIFrame* curFrame = frame;
+  do {
+    nsIView* view = curFrame->GetView();
+    if (view && view->GetVisibility() == nsViewVisibility_kHide)
+      return states::INVISIBLE;
+
+    // Offscreen state for background tab content.
+    nsIFrame* parentFrame = curFrame->GetParent();
+    nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
+    if (deckFrame && deckFrame->GetSelectedBox() != curFrame)
+      return states::OFFSCREEN;
+
+    if (!parentFrame) {
+      parentFrame = nsLayoutUtils::GetCrossDocParentFrame(curFrame);
+      if (parentFrame && !parentFrame->GetStyleVisibility()->IsVisible())
+        return states::INVISIBLE;
+    }
+
+    curFrame = parentFrame;
+  } while (curFrame);
 
   // Zero area rects can occur in the first frame of a multi-frame text flow,
   // in which case the rendered text is not empty and the frame should not be
   // marked invisible.
   // XXX Can we just remove this check? Why do we need to mark empty
   // text invisible?
   if (frame->GetType() == nsGkAtoms::textFrame &&
       !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
       frame->GetRect().IsEmpty()) {
     nsAutoString renderedText;
     frame->GetRenderedText(&renderedText, nullptr, nullptr, 0, 1);
     if (renderedText.IsEmpty())
-      return vstates;
-
+      return states::INVISIBLE;
   }
 
-  // XXX Do we really need to cross from content to chrome ancestor?
-  if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY))
-    return vstates;
-
-  // Assume we are visible enough.
-  return vstates &= ~states::INVISIBLE;
+  // We need to know if at least a kMinPixels around the object is visible,
+  // otherwise it will be marked states::OFFSCREEN.
+  const uint16_t kMinPixels  = 12;
+  const nsSize frameSize = frame->GetSize();
+  const nsRectVisibility rectVisibility =
+    mDoc->PresShell()->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
+                                         nsPresContext::CSSPixelsToAppUnits(kMinPixels));
+
+  if (rectVisibility != nsRectVisibility_kVisible)
+    return states::OFFSCREEN;
+
+  return 0;
 }
 
 uint64_t
 Accessible::NativeState()
 {
   uint64_t state = 0;
 
   if (!IsInDocument())
@@ -2924,17 +2939,17 @@ Accessible::ContainerWidget() const
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible protected methods
 
 void
 Accessible::CacheChildren()
 {
   DocAccessible* doc = Document();
-  NS_ENSURE_TRUE(doc,);
+  NS_ENSURE_TRUE_VOID(doc);
 
   nsAccTreeWalker walker(doc, mContent, CanHaveAnonChildren());
 
   Accessible* child = nullptr;
   while ((child = walker.NextChild()) && AppendChild(child));
 }
 
 void
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1700,17 +1700,17 @@ HyperTextAccessible::GetSelectionDOMRang
   }
 
   if (!startNode)
     return;
 
   uint32_t childCount = startNode->GetChildCount();
   nsresult rv = domSel->
     GetRangesForIntervalArray(startNode, 0, startNode, childCount, true, aRanges);
-  NS_ENSURE_SUCCESS(rv,);
+  NS_ENSURE_SUCCESS_VOID(rv);
 
   // Remove collapsed ranges
   uint32_t numRanges = aRanges->Length();
   for (uint32_t idx = 0; idx < numRanges; idx ++) {
     if ((*aRanges)[idx]->Collapsed()) {
       aRanges->RemoveElementAt(idx);
       --numRanges;
       --idx;
--- a/accessible/src/html/HTMLFormControlAccessible.cpp
+++ b/accessible/src/html/HTMLFormControlAccessible.cpp
@@ -154,17 +154,17 @@ HTMLRadioButtonAccessible::GetPositionAn
   nsRefPtr<nsContentList> inputElms;
 
   nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent));
   dom::Element* formElm = formControlNode->GetFormElement();
   if (formElm)
     inputElms = NS_GetContentList(formElm, namespaceId, tagName);
   else
     inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName);
-  NS_ENSURE_TRUE(inputElms, );
+  NS_ENSURE_TRUE_VOID(inputElms);
 
   uint32_t inputCount = inputElms->Length(false);
 
   // Compute posinset and setsize.
   int32_t indexOf = 0;
   int32_t count = 0;
 
   for (uint32_t index = 0; index < inputCount; index++) {
--- a/accessible/src/xul/XULColorPickerAccessible.cpp
+++ b/accessible/src/xul/XULColorPickerAccessible.cpp
@@ -134,17 +134,17 @@ XULColorPickerAccessible::AreItemsOperab
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULColorPickerAccessible: protected Accessible
 
 void
 XULColorPickerAccessible::CacheChildren()
 {
-  NS_ENSURE_TRUE(mDoc,);
+  NS_ENSURE_TRUE_VOID(mDoc);
 
   nsAccTreeWalker walker(mDoc, mContent, true);
 
   Accessible* child = nullptr;
   while ((child = walker.NextChild())) {
     uint32_t role = child->Role();
 
     // Get an accessible for menupopup or panel elements.
--- a/accessible/src/xul/XULFormControlAccessible.cpp
+++ b/accessible/src/xul/XULFormControlAccessible.cpp
@@ -176,17 +176,17 @@ XULButtonAccessible::CacheChildren()
                                        nsGkAtoms::menu,
                                        eCaseMatters);
 
   bool isMenuButton = isMenu ?
     false :
     mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                           nsGkAtoms::menuButton, eCaseMatters);
 
-  NS_ENSURE_TRUE(mDoc,);
+  NS_ENSURE_TRUE_VOID(mDoc);
   if (!isMenu && !isMenuButton)
     return;
 
   Accessible* menupopup = nullptr;
   Accessible* button = nullptr;
 
   nsAccTreeWalker walker(mDoc, mContent, true);
 
@@ -818,17 +818,17 @@ XULTextFieldAccessible::GetEditor() cons
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTextFieldAccessible: Accessible protected
 
 void
 XULTextFieldAccessible::CacheChildren()
 {
-  NS_ENSURE_TRUE(mDoc,);
+  NS_ENSURE_TRUE_VOID(mDoc);
   // Create child accessibles for native anonymous content of underlying HTML
   // input element.
   nsCOMPtr<nsIContent> inputContent(GetInputField());
   if (!inputContent)
     return;
 
   nsAccTreeWalker walker(mDoc, inputContent, false);
 
--- a/accessible/tests/mochitest/states/test_visibility.html
+++ b/accessible/tests/mochitest/states/test_visibility.html
@@ -11,37 +11,66 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+  <script type="application/javascript"
+          src="../browser.js"></script>
 
   <script type="application/javascript">
-    function doTest()
+    function addTab(aURL)
     {
-      testStates("div", 0, 0, STATE_INVISIBLE);
-      testStates("div_off", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
-      testStates("div_abschild", 0, 0, STATE_INVISIBLE);
+      this.eventSeq = [
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
+      ];
+
+      this.invoke = function addTab_invoke()
+      {
+        tabBrowser().loadOneTab(aURL, null, "", null, false);
+      }
+
+      this.finalCheck = function addTab_finalCheck()
+      {
+        var tabDoc = tabDocumentAt(0);
+        var input = getAccessible(tabDoc.getElementById("input"));
+        testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+      }
 
-      // Confirm destruction of accessibles.
-      document.getElementById("div").style.visibility = "hidden";
-      document.getElementById("div_off").style.visibility="hidden";
-      document.getElementById("div_abschild").style.visibility="hidden";
-      document.body.clientWidth; // flush layout
-      testAccessibleTree("outer_div", {children:[]});
+      this.getID = function addTab_getID()
+      {
+        return "add tab: " + aURL;
+      }
+    }
+
+    var gInputDocURI = "data:text/html,<html><input id='input'></html>";
 
+    function doTests()
+    {
+      testStates("div", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
+      testStates("div_off", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+      testStates("div_abschild", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
 
-      SimpleTest.finish();
+      gQueue = new eventQueue();
+
+      // Accessibles in background tab should have offscreen state and no
+      // invisible state.
+      gQueue.push(new addTab("about:blank"));
+
+      gQueue.onFinish = function() { closeBrowserWindow(); }
+      gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
-    addA11yLoadEvent(doTest);
+    openBrowserWindow(doTests, gInputDocURI);
   </script>
 
 </head>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=591363"
--- a/accessible/tests/mochitest/tree/Makefile.in
+++ b/accessible/tests/mochitest/tree/Makefile.in
@@ -12,16 +12,17 @@ relativesrcdir  = accessible/tree
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_A11Y_FILES =\
 		dockids.html \
 	$(warning test_applicationacc.xul temporarily disabled, see bug 561508) \
 		test_aria_globals.html \
 		test_aria_imgmap.html \
 		test_aria_presentation.html \
+		test_brokencontext.html \
 		test_button.xul \
 		test_canvas.html \
 		test_combobox.xul \
 		test_cssoverflow.html \
 		test_dochierarchy.html \
 		test_dockids.html \
 		test_filectrl.html \
 		test_formctrl.html \
--- a/accessible/tests/mochitest/tree/test_aria_presentation.html
+++ b/accessible/tests/mochitest/tree/test_aria_presentation.html
@@ -49,16 +49,29 @@
             { CELL: [ //td
               { TEXT_LEAF: [ ] }
             ] }
           ] }
         ] }
       ] };
     testAccessibleTree("tblfocusable_cnt", tree);
 
+    // Has ARIA globals or referred by ARIA relationship.
+    tree =
+      { SECTION: [ // container
+        { LABEL: [ // label, has aria-owns
+          { TEXT_LEAF: [ ] }
+        ] },
+        { TEXT_LEAF: [ ] },
+        { LABEL: [ // label, referenced by aria-owns
+          { TEXT_LEAF: [ ] }
+        ] }
+      ] };
+    testAccessibleTree("airaglobalprop_cnt", tree);
+
     SimpleTest.finish();
   }
 
   SimpleTest.waitForExplicitFinish();
   addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -93,10 +106,15 @@
   <div id="tblfocusable_cnt">
     <table role="presentation" tabindex="0">
       <tr>
         <td>cell</td>
       </tr>
     </table>
   </div>
 
+  <div id="airaglobalprop_cnt">
+    <label role="presentation" aria-owns="ariaowned">has aria-owns</label>
+    <label role="presentation" id="ariaowned">referred by aria-owns</label>
+  </div>
+
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/tree/test_brokencontext.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Broken context hierarchy</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+
+  <script type="application/javascript">
+  function doTest()
+  {
+    ////////////////////////////////////////////////////////////////////////////
+    // HTML table elements outside table context.
+
+    ok(!isAccessible("tr_in_presentation_table"), "tr shouldn't be accessible");
+    ok(!isAccessible("th_in_presentation_table"), "th shouldn't be accessible");
+    ok(!isAccessible("td_in_presentation_table"), "td shouldn't be accessible");
+
+    var tree =
+      { PUSHBUTTON: [ // table
+        { NOTHING: [ // tbody
+          { NOTHING: [ // tr
+            { NOTHING: [ // th
+              { TEXT_LEAF: [ ] }
+            ] },
+            { NOTHING: [ // td
+              { TEXT_LEAF: [ ] }
+            ] }
+          ] },
+        ] },
+      ] };
+    testAccessibleTree("button_table", tree);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Styled as HTML table elements, accessible is created by tag name
+
+    tree =
+      { LINK: [ // a
+        { TEXT_LEAF: [ ] }
+      ] };
+    testAccessibleTree("a_as_td", tree);
+
+    tree =
+      { HEADING: [
+        { TEXT_LEAF: [ ] }
+      ] };
+    testAccessibleTree("h1_as_td", tree);
+    testAccessibleTree("h2_as_td", tree);
+    testAccessibleTree("h3_as_td", tree);
+    testAccessibleTree("h4_as_td", tree);
+    testAccessibleTree("h5_as_td", tree);
+    testAccessibleTree("h6_as_td", tree);
+
+    SimpleTest.finish();
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  addA11yLoadEvent(doTest);
+  </script>
+</head>
+
+<body>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=706849"
+     title="Create accessible by tag name as fallback if table descendant style is used out of table context">
+    Mozilla Bug 706849
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <!-- HTML table elements out of table -->
+  <table role="presentation">
+    <tr id="tr_in_presentation_table">
+      <th id="th_in_presentation_table">not a header</th>
+      <td id="td_in_presentation_table">not a cell</td>
+    </tr>
+  </table>
+
+  <table role="button" id="button_table">
+    <tr id="tr_in_button_table">
+      <th id="th_in_button_table">not a header</th>
+      <td id="td_in_button_table">not a cell</td>
+    </tr>
+  </table>
+
+  <!-- styled as HTML table elements -->
+  <a id="a_as_td" style="display:table-cell;" href="http://www.google.com">Google</a>
+  <h1 id="h1_as_td" style="display: table-cell;">h1</h1>
+  <h2 id="h2_as_td" style="display: table-cell;">h2</h2>
+  <h3 id="h3_as_td" style="display: table-cell;">h3</h3>
+  <h4 id="h4_as_td" style="display: table-cell;">h4</h4>
+  <h5 id="h5_as_td" style="display: table-cell;">h5</h5>
+  <h6 id="h6_as_td" style="display: table-cell;">h6</h6>
+</body>
+</html>
--- a/accessible/tests/mochitest/tree/test_table.html
+++ b/accessible/tests/mochitest/tree/test_table.html
@@ -134,16 +134,17 @@
         { TABLE: [
           { ROW: [
             { CELL: [
               { TEXT_LEAF: [ ] }
             ] }
           ] } ]
         };
       testAccessibleTree("table4", accTree);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -12,16 +12,18 @@ builtin(include, build/autoconf/pkg.m4)d
 builtin(include, build/autoconf/codeset.m4)dnl
 builtin(include, build/autoconf/altoptions.m4)dnl
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/mozcommonheader.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
 builtin(include, build/autoconf/gcc-pr49911.m4)dnl
+builtin(include, build/autoconf/gcc-pr39608.m4)dnl
+builtin(include, build/autoconf/llvm-pr8927.m4)dnl
 builtin(include, build/autoconf/frameptr.m4)dnl
 builtin(include, build/autoconf/compiler-opts.m4)dnl
 builtin(include, build/autoconf/expandlibs.m4)dnl
 builtin(include, build/autoconf/arch.m4)dnl
 builtin(include, build/autoconf/android.m4)dnl
 builtin(include, build/autoconf/zlib.m4)dnl
 builtin(include, build/autoconf/linux.m4)dnl
 
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -430,32 +430,40 @@ pref("media.volume.steps", 10);
 
 #ifdef ENABLE_MARIONETTE
 //Enable/disable marionette server, set listening port
 pref("marionette.defaultPrefs.enabled", true);
 pref("marionette.defaultPrefs.port", 2828);
 #endif
 
 #ifdef MOZ_UPDATER
+// Timeout before the update prompt automatically installs the update
+pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
+// Optional timeout the user can wait before getting another update prompt
+pref("b2g.update.apply-wait-timeout", 1800000); // milliseconds
+// Amount of time the updater waits for the process to exit cleanly before
+// forcefully exiting the process
+pref("b2g.update.self-destruct-timeout", 5000); // milliseconds
+
 pref("app.update.enabled", true);
-pref("app.update.auto", true);
-pref("app.update.silent", true);
+pref("app.update.auto", false);
+pref("app.update.silent", false);
 pref("app.update.mode", 0);
 pref("app.update.incompatible.mode", 0);
 pref("app.update.staging.enabled", true);
 pref("app.update.service.enabled", true);
 
 // The URL hosting the update manifest.
-pref("app.update.url", "http://update.boot2gecko.org/m2.5/updates.xml");
+pref("app.update.url", "http://update.boot2gecko.org/nightly/update.xml");
 // Interval at which update manifest is fetched.  In units of seconds.
-pref("app.update.interval", 3600); // 1 hour
+pref("app.update.interval", 86400); // 1 day
 // First interval to elapse before checking for update.  In units of
 // milliseconds.  Capped at 10 seconds.
-pref("app.update.timerFirstInterval", 30000);
-pref("app.update.timerMinimumDelay", 30); // seconds
+pref("app.update.timerFirstInterval", 3600000); // 1 hour
+pref("app.update.timerMinimumDelay", 3600); // 1 hour in seconds
 // Don't throttle background updates.
 pref("app.update.download.backgroundInterval", 0);
 
 // Enable update logging for now, to diagnose growing pains in the
 // field.
 pref("app.update.log", true);
 #endif
 
@@ -479,17 +487,17 @@ pref("dom.disable_window_print", true);
 pref("dom.disable_window_showModalDialog", true);
 
 // Enable new experimental html forms
 pref("dom.experimental_forms", true);
 
 // Turns on gralloc-based direct texturing for Gonk
 pref("gfx.gralloc.enabled", false);
 
-// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging 
+// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging
 pref("javascript.options.mem.log", true);
 
 // Increase mark slice time from 10ms to 30ms
 pref("javascript.options.mem.gc_incremental_slice_ms", 30);
 
 pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 120);
 pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 101);
 pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 40);
@@ -500,19 +508,19 @@ pref("javascript.options.mem.high_water_
 // Show/Hide scrollbars when active/inactive
 pref("ui.showHideScrollbars", 1);
 
 // Enable the ProcessPriorityManager, and give processes with no visible
 // documents a 1s grace period before they're eligible to be marked as
 // background.
 pref("dom.ipc.processPriorityManager.enabled", true);
 pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
-pref("hal.processPriorityManager.gonk.masterOomAdjust", 0);
-pref("hal.processPriorityManager.gonk.foregroundOomAdjust", 1);
-pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 6);
+pref("hal.processPriorityManager.gonk.masterOomScoreAdjust", 0);
+pref("hal.processPriorityManager.gonk.foregroundOomScoreAdjust", 67);
+pref("hal.processPriorityManager.gonk.backgroundOomScoreAdjust", 400);
 pref("hal.processPriorityManager.gonk.masterNice", -1);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
 
 #ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
 pref("dom.ipc.processPrelauch.enabled", true);
--- a/b2g/chrome/content/content.css
+++ b/b2g/chrome/content/content.css
@@ -180,17 +180,17 @@ select > button {
   padding: 0px !important;
   border-radius: 0;
   color: #414141;
 
   background-image: -moz-radial-gradient(bottom left, #bbbbbb 40%, #f5f5f5), url(arrow.svg) !important;
   background-color: transparent;
   background-position: -15px center, 4px center !important;
   background-repeat: no-repeat, no-repeat !important;
-  background-size: 100% 90%, normal normal;
+  background-size: 100% 90%, auto auto;
 
   -moz-binding: none !important;
   position: relative !important;
   font-size: inherit;
 }
 
 select[size]:focus,
 select[multiple]:focus,
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -101,8 +101,13 @@ SettingsListener.observe('devtools.debug
 
 SettingsListener.observe('debug.log-animations.enabled', false, function(value) {
   Services.prefs.setBoolPref('layers.offmainthreadcomposition.log-animations', value);
 });
 
 SettingsListener.observe('debug.dev-mode', false, function(value) {
   Services.prefs.setBoolPref('dom.mozApps.dev_mode', value);
 });
+
+// =================== Privacy ====================
+SettingsListener.observe('privacy.donottrackheader.enabled', false, function(value) {
+  Services.prefs.setBoolPref('privacy.donottrackheader.enabled', value);
+});
\ No newline at end of file
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -1,16 +1,11 @@
 # Scrollbars
 category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
 
-# CameraContent.js
-component {eff4231b-abce-4f7f-a40a-d646e8fde3ce} CameraContent.js
-contract @mozilla.org/b2g-camera-content;1 {eff4231b-abce-4f7f-a40a-d646e8fde3ce}
-category JavaScript-navigator-property mozCamera @mozilla.org/b2g-camera-content;1
-
 # AlertsService.js
 component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js
 contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9}
 
 # ContentPermissionPrompt.js
 component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js
 contract @mozilla.org/content-permission/prompt;1 {8c719f03-afe0-4aac-91ff-6c215895d467}
 
@@ -41,8 +36,12 @@ category app-startup ProcessGlobal servi
 
 # ContentHandler.js
 component {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} ContentHandler.js
 contract @mozilla.org/uriloader/content-handler;1?type=application/pdf {d18d0216-d50c-11e1-ba54-efb18d0ef0ac}
 
 # PaymentGlue.js
 component {8b83eabc-7929-47f4-8b48-4dea8d887e4b} PaymentGlue.js
 contract @mozilla.org/payment/ui-glue;1 {8b83eabc-7929-47f4-8b48-4dea8d887e4b}
+
+# YoutubeProtocolHandler.js
+component {c3f1b945-7e71-49c8-95c7-5ae9cc9e2bad} YoutubeProtocolHandler.js
+contract @mozilla.org/network/protocol;1?name=vnd.youtube {c3f1b945-7e71-49c8-95c7-5ae9cc9e2bad}
deleted file mode 100644
--- a/b2g/components/CameraContent.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-const kProtocolName = "b2g-camera:";
-
-let CameraContent = function() {
-  this.hasPrivileges = false;
-  this.mapping = [];
-}
- 
-CameraContent.prototype = {
-  getCameraURI: function(aOptions) {
-    if (!this.hasPrivileges)
-      return null;
-
-    let options = aOptions || { };
-    if (!options.camera)
-      options.camera = 0;
-    if (!options.width)
-      options.width = 320;
-    if (!options.height)
-      options.height = 240;
-
-    let uuid = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
-    uuid = uuid.substring(1, uuid.length - 2); // remove the brackets
-    this.mapping.push(uuid);
-    let uri = kProtocolName + "?camera=" + options.camera + 
-                              "&width=" + options.width +
-                              "&height=" + options.height +
-                              "&type=video/x-raw-yuv";
-    // XXX that's no e10s ready, but the camera inputstream itself is not...
-    Services.prefs.setCharPref("b2g.camera." + kProtocolName + "?" + uuid, uri);
-    return kProtocolName + "?" + uuid;
-  },
-  
-  observe: function(aSubject, aTopic, aData) {
-    if (aTopic == "inner-window-destroyed") {
-      let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
-      if (wId == this.innerWindowID) {
-        Services.obs.removeObserver(this, "inner-window-destroyed");
-        for (let aId in this.mapping)
-          Services.prefs.clearUserPref("b2g.camera." + kProtocolName + "?" + aId);
-        this.mapping = null;
-      }
-    }
-  },
-
-  init: function(aWindow) {
-    let principal = aWindow.document.nodePrincipal;
-    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
-
-    let perm = Services.perms.testExactPermissionFromPrincipal(principal, "content-camera");
-
-    //only pages with perm set and chrome pages can use the camera in content
-    this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
-
-    Services.obs.addObserver(this, "inner-window-destroyed", false);
-    let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-    this.innerWindowID = util.currentInnerWindowID;
-  },
- 
-  classID: Components.ID("{eff4231b-abce-4f7f-a40a-d646e8fde3ce}"),
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIB2GCameraContent, Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIObserver]),
-  
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{eff4231b-abce-4f7f-a40a-d646e8fde3ce}"),
-                                    contractID: "@mozilla.org/b2g-camera-content;1",
-                                    interfaces: [Ci.nsIB2GCameraContent],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "B2G Camera Content Helper"})
-}
- 
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([CameraContent]);
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -4,16 +4,17 @@
 
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 const Cc = Components.classes;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Webapps.jsm");
 
 function ContentPermissionPrompt() {}
 
 ContentPermissionPrompt.prototype = {
 
   handleExistingPermission: function handleExistingPermission(request) {
     let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
     if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
@@ -47,23 +48,39 @@ ContentPermissionPrompt.prototype = {
       if (evt.detail.type == "permission-allow") {
         request.allow();
         return;
       }
 
       request.cancel();
     });
 
+    let principal = request.principal;
+    let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
+
     let details = {
-      "type": "permission-prompt",
-      "permission": request.type,
-      "id": requestId,
-      "url": request.principal.URI.spec
+      type: "permission-prompt",
+      permission: request.type,
+      id: requestId,
+      origin: principal.origin,
+      isApp: isApp
     };
-    browser.shell.sendChromeEvent(details);
+
+    if (!isApp) {
+      browser.shell.sendChromeEvent(details);
+      return;
+    }
+
+    // When it's an app, get the manifest to add the l10n application name.
+    let app = DOMApplicationRegistry.getAppByLocalId(principal.appId);
+    DOMApplicationRegistry.getManifestFor(app.origin, function getManifest(aManifest) {
+      let helper = new DOMApplicationManifest(aManifest, app.origin);
+      details.appName = helper.name;
+      browser.shell.sendChromeEvent(details);
+    });
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
 };
 
 
--- a/b2g/components/Makefile.in
+++ b/b2g/components/Makefile.in
@@ -15,22 +15,22 @@ XPIDL_MODULE = B2GComponents
 XPIDLSRCS = \
         b2g.idl \
         $(NULL)
 
 EXTRA_PP_COMPONENTS = \
         ActivitiesGlue.js \
         AlertsService.js \
         B2GComponents.manifest \
-        CameraContent.js \
         ContentHandler.js \
         ContentPermissionPrompt.js \
         DirectoryProvider.js \
         MozKeyboard.js \
         ProcessGlobal.js \
         PaymentGlue.js \
+        YoutubeProtocolHandler.js \
         $(NULL)
 
 ifdef MOZ_UPDATER
 EXTRA_PP_COMPONENTS += UpdatePrompt.js
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -13,77 +13,246 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 const VERBOSE = 1;
 let log =
   VERBOSE ?
   function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
   function log_noop(msg) { };
 
+const APPLY_PROMPT_TIMEOUT =
+      Services.prefs.getIntPref("b2g.update.apply-prompt-timeout");
+const APPLY_WAIT_TIMEOUT =
+      Services.prefs.getIntPref("b2g.update.apply-wait-timeout");
+const SELF_DESTRUCT_TIMEOUT =
+      Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
+
+XPCOMUtils.defineLazyServiceGetter(Services, "aus",
+                                   "@mozilla.org/updates/update-service;1",
+                                   "nsIApplicationUpdateService");
+
 function UpdatePrompt() { }
 
 UpdatePrompt.prototype = {
   classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt,
+                                         Ci.nsIRequestObserver,
+                                         Ci.nsIProgressEventSink]),
 
+  _update: null,
+  _applyPromptTimer: null,
+  _applyWaitTimer: null,
   _selfDestructTimer: null,
 
   // nsIUpdatePrompt
 
   // FIXME/bug 737601: we should have users opt-in to downloading
   // updates when on a billed pipe.  Initially, opt-in for 3g, but
   // that doesn't cover all cases.
   checkForUpdates: function UP_checkForUpdates() { },
-  showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) { },
+
+  showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) {
+    if (!this.sendUpdateEvent("update-available", aUpdate,
+                             this.handleAvailableResult)) {
+
+      log("Unable to prompt for available update, forcing download");
+      this.downloadUpdate(aUpdate);
+    }
+  },
 
   showUpdateDownloaded: function UP_showUpdateDownloaded(aUpdate, aBackground) {
-    // FIXME/bug 737598: we should let the user request that the
-    // update be applied later, e.g. if they're in the middle of a
-    // phone call ;).
+    if (!this.sendUpdateEvent("update-downloaded", aUpdate,
+                             this.handleDownloadedResult)) {
+      log("Unable to prompt, forcing restart");
+      this.restartProcess();
+      return;
+    }
+
+    // Schedule a fallback timeout in case the UI is unable to respond or show
+    // a prompt for some reason
+    this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
+  },
+
+  showUpdateError: function UP_showUpdateError(aUpdate) {
+    if (aUpdate.state == "failed") {
+      log("Failed to download update, errorCode: " + aUpdate.errorCode);
+    }
+  },
+
+  showUpdateHistory: function UP_showUpdateHistory(aParent) { },
+  showUpdateInstalled: function UP_showUpdateInstalled() { },
+
+  sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate, aCallback) {
+    let detail = {
+      displayVersion: aUpdate.displayVersion,
+      detailsURL: aUpdate.detailsURL
+    };
+
+    let patch = aUpdate.selectedPatch;
+    if (!patch) {
+      // For now we just check the first patch to get size information if a
+      // patch hasn't been selected yet.
+      if (aUpdate.patchCount == 0) {
+        log("Warning: no patches available in update");
+        return false;
+      }
+      patch = aUpdate.getPatchAt(0);
+    }
+
+    detail.size = patch.size;
+    detail.updateType = patch.type;
+
+    this._update = aUpdate;
+    return this.sendChromeEvent(aType, detail, aCallback);
+  },
+
+  sendChromeEvent: function UP_sendChromeEvent(aType, aDetail, aCallback) {
+    let browser = Services.wm.getMostRecentWindow("navigator:browser");
+    if (!browser) {
+      log("Warning: Couldn't send update event " + aType +
+          ": no content browser");
+      return false;
+    }
+
+    let content = browser.getContentWindow();
+    if (!content) {
+      log("Warning: Couldn't send update event " + aType +
+          ": no content window");
+      return false;
+    }
 
+    let detail = aDetail || {};
+    detail.type = aType;
+
+    if (!aCallback) {
+      browser.shell.sendChromeEvent(detail);
+      return true;
+    }
+
+    let resultType = aType + "-result";
+    let handleContentEvent = (function(e) {
+      if (!e.detail) {
+        return;
+      }
+
+      let detail = e.detail;
+      if (detail.type == resultType) {
+        aCallback.call(this, detail);
+        content.removeEventListener("mozContentEvent", handleContentEvent);
+        this._update = null;
+      }
+    }).bind(this);
+
+    content.addEventListener("mozContentEvent", handleContentEvent);
+    browser.shell.sendChromeEvent(detail);
+    return true;
+  },
+
+  handleAvailableResult: function UP_handleAvailableResult(aDetail) {
+    // If the user doesn't choose "download", the updater will implicitly call
+    // showUpdateAvailable again after a certain period of time
+    switch (aDetail.result) {
+      case "download":
+        this.downloadUpdate(this._update);
+        break;
+    }
+  },
+
+  handleDownloadedResult: function UP_handleDownloadedResult(aDetail) {
+    if (this._applyPromptTimer) {
+      this._applyPromptTimer.cancel();
+      this._applyPromptTimer = null;
+    }
+
+    switch (aDetail.result) {
+      case "wait":
+        // Wait for a fixed period of time, allowing the user to temporarily
+        // postpone applying an update
+        this._applyWaitTimer = this.createTimer(APPLY_WAIT_TIMEOUT);
+        break;
+      case "restart":
+        this.restartProcess();
+        break;
+    }
+  },
+
+  downloadUpdate: function UP_downloadUpdate(aUpdate) {
+    Services.aus.downloadUpdate(aUpdate, true);
+    Services.aus.addDownloadListener(this);
+  },
+
+  restartProcess: function UP_restartProcess() {
     log("Update downloaded, restarting to apply it");
 
     // If not cleanly shut down within 5 seconds, this process will
     // explode.
-    this._setSelfDestructTimer(5000);
+    this._selfDestructTimer = this.createTimer(SELF_DESTRUCT_TIMEOUT);
 
-    let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
+    let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
+                       .getService(Ci.nsIAppStartup);
     // NB: on Gonk, we rely on the system process manager to restart
     // us.  Trying to restart here would conflict with the process
     // manager.  We should be using a runtime check to detect Gonk
     // instead of this gross ifdef, but the ifdef works for now.
     appStartup.quit(appStartup.eForceQuit
 #ifndef ANDROID
                     | appStartup.eRestart
 #endif
       );
   },
 
-  _setSelfDestructTimer: function UP__setSelfDestructTimer(timeoutMs) {
+  notify: function UP_notify(aTimer) {
+    if (aTimer == this._selfDestructTimer) {
+      this._selfDestructTimer = null;
+      this.selfDestruct();
+    } else if (aTimer == this._applyPromptTimer) {
+      log("Timed out waiting for result, restarting");
+      this._applyPromptTimer = null;
+      this.restartProcess();
+    } else if (aTimer == this._applyWaitTimer) {
+      this._applyWaitTimer = null;
+      this.showUpdatePrompt();
+    }
+  },
+
+  selfDestruct: function UP_selfDestruct() {
 #ifdef ANDROID
     Cu.import("resource://gre/modules/ctypes.jsm");
     let libc = ctypes.open("libc.so");
-    let _exit = libc.declare("_exit",  ctypes.default_abi,
+    let _exit = libc.declare("_exit", ctypes.default_abi,
                              ctypes.void_t, // [return]
                              ctypes.int);   // status
-    this.notify = function UP_notify(_) {
-      log("Self-destruct timer fired; didn't cleanly shut down.  BOOM");
-      _exit(0);
-    }
 
-    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    timer.initWithCallback(this, timeoutMs, timer.TYPE_ONE_SHOT);
-    this._selfDestructTimer = timer;
+    log("Self-destruct timer fired; didn't cleanly shut down.  BOOM");
+    _exit(0);
 #endif
   },
 
-  showUpdateInstalled: function UP_showUpdateInstalled() { },
+  createTimer: function UP_createTimer(aTimeoutMs) {
+    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    timer.initWithCallback(this, aTimeoutMs, timer.TYPE_ONE_SHOT);
+    return timer;
+  },
 
-  showUpdateError: function UP_showUpdateError(aUpdate) {
-    if (aUpdate.state == "failed") {
-      log("Failed to download update, errorCode: " + aUpdate.errorCode);
-    }
+  // nsIRequestObserver
+
+  onStartRequest: function UP_onStartRequest(aRequest, aContext) {
+    this.sendChromeEvent("update-downloading");
   },
 
-  showUpdateHistory: function UP_showUpdateHistory(aParent) { },
+  onStopRequest: function UP_onStopRequest(aRequest, aContext, aStatusCode) {
+    Services.aus.removeDownloadListener(this);
+  },
+
+  // nsIProgressEventSink
+
+  onProgress: function UP_onProgress(aRequest, aContext, aProgress,
+                                     aProgressMax) {
+    this.sendChromeEvent("update-progress", {
+      progress: aProgress,
+      total: aProgressMax
+    });
+  },
+
+  onStatus: function UP_onStatus(aRequest, aUpdate, aStatus, aStatusArg) { }
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdatePrompt]);
new file mode 100644
--- /dev/null
+++ b/b2g/components/YoutubeProtocolHandler.js
@@ -0,0 +1,117 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
+  return Cc["@mozilla.org/childprocessmessagemanager;1"]
+           .getService(Ci.nsIMessageSender);
+});
+
+// Splits parameters in a query string.
+function extractParameters(aQuery) {
+  let params = aQuery.split("&");
+  let res = {};
+  params.forEach(function(aParam) {
+    let obj = aParam.split("=");
+    res[obj[0]] = decodeURIComponent(obj[1]);
+  });
+  return res;
+}
+
+function YoutubeProtocolHandler() {
+}
+
+YoutubeProtocolHandler.prototype = {
+  classID: Components.ID("{c3f1b945-7e71-49c8-95c7-5ae9cc9e2bad}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),
+
+  scheme: "vnd.youtube",
+  defaultPort: -1,
+  protocolFlags: Ci.nsIProtocolHandler.URI_NORELATIVE |
+                 Ci.nsIProtocolHandler.URI_NOAUTH |
+                 Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
+
+  // Sample URL:
+  // vnd.youtube:iNuKL2Gy_QM?vndapp=youtube_mobile&vndclient=mv-google&vndel=watch&vnddnc=1
+  newURI: function yt_phNewURI(aSpec, aOriginCharset, aBaseURI) {
+    let uri = Cc["@mozilla.org/network/standard-url;1"]
+              .createInstance(Ci.nsIStandardURL);
+    let id = aSpec.substring(this.scheme.length + 1);
+    id = id.substring(0, id.indexOf('?'));
+    uri.init(Ci.nsIStandardURL.URLTYPE_STANDARD, -1, this.scheme + "://dummy_host/" + id, aOriginCharset,
+             aBaseURI);
+    return uri.QueryInterface(Ci.nsIURI);
+  },
+
+  newChannel: function yt_phNewChannel(aURI) {
+    // Get a list of streams for this video id.
+    let infoURI = "http://www.youtube.com/get_video_info?&video_id=" +
+                  aURI.path.substring(1);
+
+    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                .createInstance(Ci.nsIXMLHttpRequest);
+    xhr.open("GET", infoURI, true);
+    xhr.addEventListener("load", function() {
+      // Youtube sends the response as a double wrapped url answer:
+      // we first extract the url_encoded_fmt_stream_map parameter,
+      // and from each comma-separated entry in this value, we extract
+      // other parameters (url and type).
+      let key = "url_encoded_fmt_stream_map=";
+      let pos = xhr.responseText.indexOf(key);
+      if (pos == -1) {
+        return;
+      }
+      let streams = decodeURIComponent(xhr.responseText
+                                       .substring(pos + key.length)).split(",");
+      let uri;
+      let mimeType;
+
+      // Recognized mime types, ordered from the less usable to the most usable.
+      let recognizedTypes = ["video/webm"];
+#ifdef MOZ_WIDGET_GONK
+      recognizedTypes.push("video/mp4");
+#endif
+
+      let bestType = -1;
+
+      streams.forEach(function(aStream) {
+        let params = extractParameters(aStream);
+        let url = params["url"];
+        let type = params["type"] ? params["type"].split(";")[0] : null;
+
+        let index;
+        if (url && type && ((index = recognizedTypes.indexOf(type)) != -1) &&
+            index > bestType) {
+          uri = url;
+          mimeType = type;
+          bestType = index;
+        }
+      });
+
+      if (uri && mimeType) {
+        cpmm.sendAsyncMessage("content-handler", {
+          url: uri,
+          type: mimeType
+        });
+      }
+    });
+    xhr.send(null);
+
+    throw Components.results.NS_ERROR_ILLEGAL_VALUE;
+  },
+
+  allowPort: function yt_phAllowPort(aPort, aScheme) {
+    return false;
+  }
+};
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([YoutubeProtocolHandler]);
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1346451771000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1347572992000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -91,16 +91,20 @@
       <emItem  blockID="i19" id="{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}">
                         <versionRange  minVersion="1.1b1" maxVersion="1.1b1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i111" os="WINNT" id="{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}">
                         <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i136" id="Adobe@flash.com">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i38" id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
                         <versionRange  minVersion="0.1" maxVersion="3.3.0.*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                                 <versionRange  minVersion="3.3.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
@@ -443,44 +447,27 @@
                   <match name="filename" exp="npuplaypc\.dll" />                      <versionRange  minVersion="0" maxVersion="1.0.0.0" severity="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p123">
                   <match name="filename" exp="JavaPlugin2_NPAPI\.plugin" />                      <versionRange  minVersion="0" maxVersion="14.2.0" severity="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p129">
                   <match name="filename" exp="Silverlight\.plugin" />                      <versionRange  minVersion="0" maxVersion="5.0.99999" severity="1"></versionRange>
                   </pluginItem>
+      <pluginItem  blockID="p138">
+                  <match name="filename" exp="JavaAppletPlugin\.plugin" />                      <versionRange  minVersion="Java 7 Update 01" maxVersion="Java 7 Update 06" severity="0"></versionRange>
+                  </pluginItem>
     </pluginItems>
 
   <gfxItems>
     <gfxBlacklistEntry  blockID="g35">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
             <feature>DIRECT2D</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     <gfxBlacklistEntry  blockID="g36">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
             <feature>DIRECT3D_9_LAYERS</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     <gfxBlacklistEntry  blockID="g37">      <os>WINNT 5.1</os>      <vendor>0x10de</vendor>            <feature>DIRECT3D_9_LAYERS</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>7.0.0.0</driverVersion>      <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
-    <gfxBlacklistEntry  blockID="g81">      <os>WINNT 6.1</os>      <vendor>0x1002</vendor>              <devices>
-                      <device>0x9802</device>
-                      <device>0x9803</device>
-                      <device>0x9803</device>
-                      <device>0x9804</device>
-                      <device>0x9805</device>
-                      <device>0x9806</device>
-                      <device>0x9807</device>
-                  </devices>
-            <feature>DIRECT2D</feature>      <featureStatus>BLOCKED_DEVICE</featureStatus>      <driverVersion>1.0.0.0</driverVersion>      <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
-    <gfxBlacklistEntry  blockID="g95">      <os>WINNT 6.1</os>      <vendor>0x1002</vendor>              <devices>
-                      <device>0x9802</device>
-                      <device>0x9803</device>
-                      <device>0x9803</device>
-                      <device>0x9804</device>
-                      <device>0x9805</device>
-                      <device>0x9806</device>
-                      <device>0x9807</device>
-                  </devices>
-            <feature>DIRECT3D_9_LAYERS</feature>      <featureStatus>BLOCKED_DEVICE</featureStatus>      <driverVersion>1.0.0.0</driverVersion>      <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     </gfxItems>
 
 
 </blocklist>
\ No newline at end of file
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -189,17 +189,16 @@ pref("app.update.service.enabled", true)
 //  .. etc ..
 //
 pref("extensions.update.enabled", true);
 pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 pref("extensions.update.interval", 86400);  // Check for updates to Extensions and 
                                             // Themes every day
 // Non-symmetric (not shared by extensions) extension-specific [update] preferences
-pref("extensions.getMoreThemesURL", "https://addons.mozilla.org/%LOCALE%/firefox/getpersonas");
 pref("extensions.dss.enabled", false);          // Dynamic Skin Switching                                               
 pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
                                                 // restart.
 
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
 
 pref("xpinstall.whitelist.add", "addons.mozilla.org");
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -107,67 +107,74 @@ const SEARCH_ENGINES = {
 // The <a/> part of the snippet will be linked to the corresponding url.
 const DEFAULT_SNIPPETS_URLS = [
   "http://www.mozilla.com/firefox/features/?WT.mc_ID=default1"
 , "https://addons.mozilla.org/firefox/?src=snippet&WT.mc_ID=default2"
 ];
 
 const SNIPPETS_UPDATE_INTERVAL_MS = 86400000; // 1 Day.
 
-let gSearchEngine;
+let gObserver = new MutationObserver(function (mutations) {
+  for (let mutation of mutations) {
+    if (mutation.attributeName == "searchEngineURL") {
+      gObserver.disconnect();
+      setupSearchEngine();
+      loadSnippets();
+      return;
+    }
+  }
+});
 
-document.addEventListener("DOMContentLoaded", function init() {
-  setupSearchEngine();
-  loadSnippets();
+window.addEventListener("load", function () {
+  // Delay search engine setup, cause browser.js::BrowserOnAboutPageLoad runs
+  // later and may use asynchronous getters.
+  window.gObserver.observe(document.documentElement, { attributes: true });
+  fitToWidth();
 });
-window.addEventListener("load", fitToWidth);
 window.addEventListener("resize", fitToWidth);
 
 
 function onSearchSubmit(aEvent)
 {
   let searchTerms = document.getElementById("searchText").value;
-  if (gSearchEngine && searchTerms.length > 0) {
+  let searchURL = document.documentElement.getAttribute("searchEngineURL");
+  if (searchURL && searchTerms.length > 0) {
     const SEARCH_TOKENS = {
       "_searchTerms_": encodeURIComponent(searchTerms)
     }
-    let url = gSearchEngine.searchUrl;
     for (let key in SEARCH_TOKENS) {
-      url = url.replace(key, SEARCH_TOKENS[key]);
+      searchURL = searchURL.replace(key, SEARCH_TOKENS[key]);
     }
-    window.location.href = url;
+    window.location.href = searchURL;
   }
 
   aEvent.preventDefault();
 }
 
 
 function setupSearchEngine()
 {
-  gSearchEngine = JSON.parse(localStorage["search-engine"]);
-
-  if (!gSearchEngine)
+  let searchEngineName = document.documentElement.getAttribute("searchEngineName");
+  let searchEngineInfo = SEARCH_ENGINES[searchEngineName];
+  if (!searchEngineInfo) {
     return;
-
-  // Look for extended information, like logo and links.
-  let searchEngineInfo = SEARCH_ENGINES[gSearchEngine.name];
-  if (searchEngineInfo) {
-    for (let prop in searchEngineInfo)
-      gSearchEngine[prop] = searchEngineInfo[prop];
   }
 
   // Enqueue additional params if required by the engine definition.
-  if (gSearchEngine.params)
-    gSearchEngine.searchUrl += "&" + gSearchEngine.params;
+  if (searchEngineInfo.params) {
+    let searchEngineURL = document.documentElement.getAttribute("searchEngineURL");
+    searchEngineURL += "&" + searchEngineInfo.params;
+    document.documentElement.setAttribute("searchEngineURL", searchEngineURL);
+  }
 
   // Add search engine logo.
-  if (gSearchEngine.image) {
+  if (searchEngineInfo.image) {
     let logoElt = document.getElementById("searchEngineLogo");
-    logoElt.src = gSearchEngine.image;
-    logoElt.alt = gSearchEngine.name;
+    logoElt.src = searchEngineInfo.image;
+    logoElt.alt = searchEngineInfo.name;
   }
 
   // The "autofocus" attribute doesn't focus the form element
   // immediately when the element is first drawn, so the
   // attribute is also used for styling when the page first loads.
   let searchText = document.getElementById("searchText");
   searchText.addEventListener("blur", function searchText_onBlur() {
     searchText.removeEventListener("blur", searchText_onBlur);
@@ -175,17 +182,17 @@ function setupSearchEngine()
   });
 
 }
 
 function loadSnippets()
 {
   // Check last snippets update.
   let lastUpdate = localStorage["snippets-last-update"];
-  let updateURL = localStorage["snippets-update-url"];
+  let updateURL = document.documentElement.getAttribute("snippetsURL");
   if (updateURL && (!lastUpdate ||
                     Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS)) {
     // Try to update from network.
     let xhr = new XMLHttpRequest();
     try {
       xhr.open("GET", updateURL, true);
     } catch (ex) {
       showSnippets();
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -321,17 +321,17 @@ let SocialShareButton = {
       profileRow.hidden = true;
       this.updateButtonHiddenState();
       return;
     }
     // XXX - this shouldn't be done as part of updateProfileInfo, but instead
     // whenever we notice the provider has changed - but the concept of
     // "provider changed" will only exist once bug 774520 lands. 
     // get the recommend-prompt info.
-    let port = Social.provider._getWorkerPort();
+    let port = Social.provider.getWorkerPort();
     if (port) {
       port.onmessage = function(evt) {
         if (evt.data.topic == "social.user-recommend-prompt-response") {
           port.close();
           this.acceptRecommendInfo(evt.data.data);
           this.updateButtonHiddenState();
           this.updateShareState();
         }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -85,16 +85,19 @@ XPCOMUtils.defineLazyGetter(window, "gFi
 __defineSetter__("PluralForm", function (val) {
   delete this.PluralForm;
   return this.PluralForm = val;
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
                                   "resource://gre/modules/TelemetryStopwatch.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils",
+                                  "resource:///modules/AboutHomeUtils.jsm");
+
 #ifdef MOZ_SERVICES_SYNC
 XPCOMUtils.defineLazyGetter(this, "Weave", function() {
   let tmp = {};
   Cu.import("resource://services-sync/main.js", tmp);
   return tmp.Weave;
 });
 #endif
 
@@ -2490,20 +2493,29 @@ function PageProxyClickHandler(aEvent)
  *  to the DOM for unprivileged pages.
  */
 function BrowserOnAboutPageLoad(document) {
   if (/^about:home$/i.test(document.documentURI)) {
     // XXX bug 738646 - when Marketplace is launched, remove this statement and
     // the hidden attribute set on the apps button in aboutHome.xhtml
     if (getBoolPref("browser.aboutHome.apps", false))
       document.getElementById("apps").removeAttribute("hidden");
+
     let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
              getService(Components.interfaces.nsISessionStore);
     if (!ss.canRestoreLastSession)
       document.getElementById("launcher").removeAttribute("session");
+
+    // Inject search engine and snippets URL.
+    let docElt = document.documentElement;
+    docElt.setAttribute("snippetsURL", AboutHomeUtils.snippetsURL);
+    docElt.setAttribute("searchEngineName",
+                        AboutHomeUtils.defaultSearchEngine.name);
+    docElt.setAttribute("searchEngineURL",
+                        AboutHomeUtils.defaultSearchEngine.searchURL);
   }
 }
 
 /**
  * Handle command events bubbling up from error page content
  */
 let BrowserOnClick = {
   handleEvent: function BrowserOnClick_handleEvent(aEvent) {
@@ -5670,23 +5682,21 @@ var BrowserOffline = {
   }
 };
 
 var OfflineApps = {
   /////////////////////////////////////////////////////////////////////////////
   // OfflineApps Public Methods
   init: function ()
   {
-    Services.obs.addObserver(this, "dom-storage-warn-quota-exceeded", false);
     Services.obs.addObserver(this, "offline-cache-update-completed", false);
   },
 
   uninit: function ()
   {
-    Services.obs.removeObserver(this, "dom-storage-warn-quota-exceeded");
     Services.obs.removeObserver(this, "offline-cache-update-completed");
   },
 
   handleEvent: function(event) {
     if (event.type == "MozApplicationManifest") {
       this.offlineAppRequested(event.originalTarget.defaultView);
     }
   },
@@ -5795,20 +5805,16 @@ var OfflineApps = {
     for (let group of groups) {
       var uri = Services.io.newURI(group, null, null);
       if (uri.asciiHost == host) {
         var cache = cacheService.getActiveCache(group);
         usage += cache.usage;
       }
     }
 
-    var storageManager = Cc["@mozilla.org/dom/storagemanager;1"].
-                         getService(Ci.nsIDOMStorageManager);
-    usage += storageManager.getUsage(host);
-
     return usage;
   },
 
   _checkUsage: function(aURI) {
     // if the user has already allowed excessive usage, don't bother checking
     if (Services.perms.testExactPermission(aURI, "offline-app") !=
         Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN) {
       var usage = this._getOfflineAppUsage(aURI.asciiHost);
@@ -5918,29 +5924,17 @@ var OfflineApps = {
                         getService(Ci.nsIOfflineCacheUpdateService);
     updateService.scheduleUpdate(manifestURI, aDocument.documentURIObject, window);
   },
 
   /////////////////////////////////////////////////////////////////////////////
   // nsIObserver
   observe: function (aSubject, aTopic, aState)
   {
-    if (aTopic == "dom-storage-warn-quota-exceeded") {
-      if (aSubject) {
-        var uri = makeURI(aSubject.location.href);
-
-        if (OfflineApps._checkUsage(uri)) {
-          var browserWindow =
-            this._getBrowserWindowForContentWindow(aSubject);
-          var browser = this._getBrowserForContentWindow(browserWindow,
-                                                         aSubject);
-          OfflineApps._warnUsage(browser, uri);
-        }
-      }
-    } else if (aTopic == "offline-cache-update-completed") {
+    if (aTopic == "offline-cache-update-completed") {
       var cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
 
       var uri = cacheUpdate.manifestURI;
       if (OfflineApps._checkUsage(uri)) {
         var browser = this._getBrowserForCacheUpdate(cacheUpdate);
         if (browser) {
           OfflineApps._warnUsage(browser, cacheUpdate.manifestURI);
         }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -263,18 +263,22 @@
                 class="editSharePopupBottomButton"
                 label="&social.sharePopup.undo.label;"
                 accesskey="&social.sharePopup.undo.accesskey;"
                 command="Social:UnsharePage"/>
 #endif
       </hbox>
     </panel>
 
-    <panel id="social-notification-panel" class="social-panel"
-           type="arrow" hidden="true" noautofocus="true">
+    <panel id="social-notification-panel"
+           class="social-panel"
+           type="arrow"
+           hidden="true"
+           consumeoutsideclicks="true"
+           noautofocus="true">
       <box id="social-notification-box" flex="1"></box>
     </panel>
     <panel id="social-flyout-panel"
            class="social-panel"
            onpopupshown="SocialFlyout.onShown()"
            onpopuphidden="SocialFlyout.onHidden()"
            side="right"
            type="arrow"
--- a/browser/base/content/newtab/updater.js
+++ b/browser/base/content/newtab/updater.js
@@ -166,17 +166,17 @@ let gUpdater = {
       batch.push();
 
       // Create the new site and fade it in.
       let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]);
 
       // Set the site's initial opacity to zero.
       site.node.style.opacity = 0;
 
-      // Without the setTimeout() the node would just appear instead of fade in.
-      setTimeout(function () {
-        gTransformation.showSite(site, function () batch.pop());
-      }, 0);
+      // Flush all style changes for the dynamically inserted site to make
+      // the fade-in transition work.
+      window.getComputedStyle(site.node).opacity;
+      gTransformation.showSite(site, function () batch.pop());
     });
 
     batch.close();
   }
 };
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -815,17 +815,17 @@ nsContextMenu.prototype = {
     if (!name)
       name = "snapshot.jpg";
     var video = this.target;
     var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
     canvas.width = video.videoWidth;
     canvas.height = video.videoHeight;
     var ctxDraw = canvas.getContext("2d");
     ctxDraw.drawImage(video, 0, 0);
-    saveImageURL(canvas.toDataURL("image/jpeg", ""), name, "SaveImageTitle", true, false, document.documentURIObject);
+    saveImageURL(canvas.toDataURL("image/jpeg", ""), name, "SaveImageTitle", true, false, document.documentURIObject, this.target.ownerDocument);
   },
 
   fullScreenVideo: function () {
     let video = this.target;
     if (document.mozFullScreenEnabled)
       video.mozRequestFullScreen();
   },
 
@@ -1056,22 +1056,22 @@ nsContextMenu.prototype = {
   },
 
   // Save URL of the clicked upon image, video, or audio.
   saveMedia: function() {
     var doc =  this.target.ownerDocument;
     if (this.onCanvas) {
       // Bypass cache, since it's a data: URL.
       saveImageURL(this.target.toDataURL(), "canvas.png", "SaveImageTitle",
-                   true, false, doc.documentURIObject);
+                   true, false, doc.documentURIObject, doc);
     }
     else if (this.onImage) {
       urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
       saveImageURL(this.mediaURL, null, "SaveImageTitle", false,
-                   false, doc.documentURIObject);
+                   false, doc.documentURIObject, doc);
     }
     else if (this.onVideo || this.onAudio) {
       urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
       var dialogTitle = this.onVideo ? "SaveVideoTitle" : "SaveAudioTitle";
       this.saveHelper(this.mediaURL, null, dialogTitle, false, doc);
     }
   },
 
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -80,18 +80,18 @@ Sanitizer.prototype = {
         var cacheService = Cc["@mozilla.org/network/cache-service;1"].
                           getService(Ci.nsICacheService);
         try {
           // Cache doesn't consult timespan, nor does it have the
           // facility for timespan-based eviction.  Wipe it.
           cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
         } catch(er) {}
 
-        var imageCache = Cc["@mozilla.org/image/cache;1"].
-                         getService(Ci.imgICache);
+        var imageCache = Cc["@mozilla.org/image/tools;1"].
+                         getService(Ci.imgITools).getImgCacheForDocument(null);
         try {
           imageCache.clearCache(false); // true=chrome, false=content
         } catch(er) {}
       },
       
       get canClear()
       {
         return true;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -680,17 +680,20 @@
           <![CDATA[
             var browser = this.getBrowserForTab(aTab);
             browser.mIconURL = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
 
             if (aURI && this.mFaviconService) {
               if (!(aURI instanceof Ci.nsIURI))
                 aURI = makeURI(aURI);
               this.mFaviconService.setAndFetchFaviconForPage(browser.currentURI,
-                                                             aURI, false);
+                                                             aURI, false,
+                                                             gPrivateBrowsingUI.privateWindow ?
+                                                               this.mFaviconService.FAVICON_LOAD_PRIVATE :
+                                                               this.mFaviconService.FAVICON_LOAD_NON_PRIVATE);
             }
 
             if ((browser.mIconURL || "") != aTab.getAttribute("image")) {
               if (browser.mIconURL)
                 aTab.setAttribute("image", browser.mIconURL);
               else
                 aTab.removeAttribute("image");
               this._tabAttrModified(aTab);
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -10,74 +10,27 @@ registerCleanupFunction(function() {
   try {
     Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
   } catch (ex) {}
 });
 
 let gTests = [
 
 {
-  desc: "Check that rejecting cookies does not prevent page from working",
+  desc: "Check that clearing cookies does not clear storage",
   setup: function ()
   {
-    Services.prefs.setIntPref("network.cookies.cookieBehavior", 2);
-  },
-  run: function ()
-  {
-    let storage = getStorage();
-    isnot(storage.getItem("search-engine"), null);
-    try {
-      Services.prefs.clearUserPref("network.cookies.cookieBehavior");
-    } catch (ex) {}
-    executeSoon(runNextTest);
-  }
-},
-
-{
-  desc: "Check that asking for cookies does not prevent page from working",
-  setup: function ()
-  {
-    Services.prefs.setIntPref("network.cookie.lifetimePolicy", 1);
+    Cc["@mozilla.org/dom/storagemanager;1"]
+      .getService(Ci.nsIObserver)
+      .observe(null, "cookie-changed", "cleared");
   },
   run: function ()
   {
     let storage = getStorage();
-    isnot(storage.getItem("search-engine"), null);
-    try {
-      Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
-    } catch (ex) {}
-    executeSoon(runNextTest);
-  }
-},
-
-{
-  desc: "Check that clearing cookies does not prevent page from working",
-  setup: function ()
-  {
-    Components.classes["@mozilla.org/dom/storagemanager;1"].
-    getService(Components.interfaces.nsIObserver).
-    observe(null, "cookie-changed", "cleared");
-  },
-  run: function ()
-  {
-    let storage = getStorage();
-    isnot(storage.getItem("search-engine"), null);
-    executeSoon(runNextTest);
-  }
-},
-
-{
-  desc: "Check normal status is working",
-  setup: function ()
-  {
-  },
-  run: function ()
-  {
-    let storage = getStorage();
-    isnot(storage.getItem("search-engine"), null);
+    isnot(storage.getItem("snippets-last-update"), null);
     executeSoon(runNextTest);
   }
 },
 
 {
   desc: "Check default snippets are shown",
   setup: function ()
   {
@@ -115,24 +68,16 @@ let gTests = [
   }
 },
 ];
 
 function test()
 {
   waitForExplicitFinish();
 
-  // browser-chrome test harness inits browser specifying an hardcoded page
-  // and this causes nsIBrowserHandler.defaultArgs to not be evaluated since
-  // there is a predefined argument.
-  // About:home localStorage is populated with overridden homepage, that is
-  // setup in the defaultArgs getter.
-  // Thus to populate about:home we need to get defaultArgs manually.
-  Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs;
-
   // Ensure that by default we don't try to check for remote snippets since that
   // could be tricky due to network bustages or slowness.
   let storage = getStorage();
   storage.setItem("snippets-last-update", Date.now());
   storage.removeItem("snippets");
 
   executeSoon(runNextTest);
 }
@@ -143,20 +88,30 @@ function runNextTest()
     gBrowser.removeCurrentTab();
   }
 
   if (gTests.length) {
     let test = gTests.shift();
     info(test.desc);
     test.setup();
     let tab = gBrowser.selectedTab = gBrowser.addTab("about:home");
-    tab.linkedBrowser.addEventListener("load", function (event) {
-      tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
-      // Some part of the page is populated on load, so enqueue on it.
-      executeSoon(test.run);
+    tab.linkedBrowser.addEventListener("load", function load(event) {
+      tab.linkedBrowser.removeEventListener("load", load, true);
+
+      let observer = new MutationObserver(function (mutations) {
+        for (let mutation of mutations) {
+          if (mutation.attributeName == "searchEngineURL") {
+            observer.disconnect();
+            executeSoon(test.run);
+            return;
+          }
+        }
+      });
+      let docElt = tab.linkedBrowser.contentDocument.documentElement;
+      observer.observe(docElt, { attributes: true });
     }, true);
   }
   else {
     finish();
   }
 }
 
 function getStorage()
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -430,17 +430,17 @@ var gAllTests = [
       // Show details
       this.toggleDetails();
       this.checkDetails(true);
       this.cancelDialog();
     };
     wh.open();
   },
   function () {
-    // Test for offline apps data and cache deletion
+    // Test for offline cache deletion
 
     // Prepare stuff, we will work with www.example.com
     var URL = "http://www.example.com";
 
     var ios = Cc["@mozilla.org/network/io-service;1"]
               .getService(Ci.nsIIOService);
     var URI = ios.newURI(URL, null, null);
 
@@ -449,22 +449,16 @@ var gAllTests = [
     var principal = sm.getNoAppCodebasePrincipal(URI);
 
     // Give www.example.com privileges to store offline data
     var pm = Cc["@mozilla.org/permissionmanager;1"]
              .getService(Ci.nsIPermissionManager);
     pm.addFromPrincipal(principal, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
     pm.addFromPrincipal(principal, "offline-app", Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
-    // Store some user data to localStorage
-    var dsm = Cc["@mozilla.org/dom/storagemanager;1"]
-             .getService(Ci.nsIDOMStorageManager);
-    var localStorage = dsm.getLocalStorageForPrincipal(principal, URL);
-    localStorage.setItem("test", "value");
-
     // Store something to the offline cache
     const nsICache = Components.interfaces.nsICache;
     var cs = Components.classes["@mozilla.org/network/cache-service;1"]
              .getService(Components.interfaces.nsICacheService);
     var session = cs.createSession(URL + "/manifest", nsICache.STORE_OFFLINE, nsICache.STREAM_BASED);
 
     // Open the dialog
     let wh = new WindowHelper();
@@ -472,19 +466,17 @@ var gAllTests = [
       this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
       // Show details
       this.toggleDetails();
       // Clear only offlineApps
       this.uncheckAllCheckboxes();
       this.checkPrefCheckbox("offlineApps", true);
       this.acceptDialog();
 
-      // Check all has been deleted (data, cache)
-      is(localStorage.length, 0, "DOM storage cleared");
-
+      // Check if the cache has been deleted
       var size = -1;
       var visitor = {
         visitDevice: function (deviceID, deviceInfo)
         {
           if (deviceID == "offline")
             size = deviceInfo.totalSize;
 
           // Do not enumerate entries
--- a/browser/base/content/test/browser_social_chatwindow.js
+++ b/browser/base/content/test/browser_social_chatwindow.js
@@ -19,17 +19,17 @@ function test() {
       finishcb();
     });
   });
 }
 
 var tests = {
   testOpenCloseChat: function(next) {
     let chats = document.getElementById("pinnedchats");
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-sidebar-message":
           port.postMessage({topic: "test-chatbox-open"});
           break;
         case "got-chatbox-visibility":
@@ -38,16 +38,17 @@ var tests = {
             chats.selectedChat.toggle();
           } else if (e.data.result == "shown") {
             ok(true, "chatbox got shown");
             // close it now
             let iframe = chats.selectedChat.iframe;
             iframe.addEventListener("unload", function chatUnload() {
               iframe.removeEventListener("unload", chatUnload, true);
               ok(true, "got chatbox unload on close");
+              port.close();
               next();
             }, true);
             chats.selectedChat.close();
           }
           break;
         case "got-chatbox-message":
           ok(true, "got chatbox message");
           ok(e.data.result == "ok", "got chatbox windowRef result: "+e.data.result);
@@ -55,18 +56,19 @@ var tests = {
           break;
       }
     }
     port.postMessage({topic: "test-init", data: { id: 1 }});
   },
   testManyChats: function(next) {
     // open enough chats to overflow the window, then check
     // if the menupopup is visible
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
+    port.postMessage({topic: "test-init"});
     let width = document.documentElement.boxObject.width;
     let numToOpen = (width / 200) + 1;
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-chatbox-message":
           numToOpen--;
           if (numToOpen >= 0) {
@@ -76,39 +78,42 @@ var tests = {
           }
           // close our chats now
           let chats = document.getElementById("pinnedchats");
           ok(!chats.menupopup.parentNode.collapsed, "menu selection is visible");
           while (chats.selectedChat) {
             chats.selectedChat.close();
           }
           ok(!chats.selectedChat, "chats are all closed");
+          port.close();
           next();
           break;
       }
     }
     let num = numToOpen;
     while (num-- > 0) {
       port.postMessage({topic: "test-chatbox-open", data: { id: num }});
     }
   },
   testWorkerChatWindow: function(next) {
     const chatUrl = "https://example.com/browser/browser/base/content/test/social_chat.html";
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
+    port.postMessage({topic: "test-init"});
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-chatbox-message":
           ok(true, "got a chat window opened");
           let chats = document.getElementById("pinnedchats");
           while (chats.selectedChat) {
             chats.selectedChat.close();
           }
           ok(!chats.selectedChat, "chats are all closed");
+          port.close();
           ensureSocialUrlNotRemembered(chatUrl);
           next();
           break;
       }
     }
     port.postMessage({topic: "test-worker-chat", data: chatUrl});
   }
 }
--- a/browser/base/content/test/browser_social_flyout.js
+++ b/browser/base/content/test/browser_social_flyout.js
@@ -15,27 +15,28 @@ function test() {
   runSocialTestWithProvider(manifest, function (finishcb) {
     runSocialTests(tests, undefined, undefined, finishcb);
   });
 }
 
 var tests = {
   testOpenCloseFlyout: function(next) {
     let panel = document.getElementById("social-flyout-panel");
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-sidebar-message":
           port.postMessage({topic: "test-flyout-open"});
           break;
         case "got-flyout-visibility":
           if (e.data.result == "hidden") {
             ok(true, "flyout visibility is 'hidden'");
+            port.close();
             next();
           } else if (e.data.result == "shown") {
             ok(true, "flyout visibility is 'shown");
             panel.hidePopup();
           }
           break;
         case "got-flyout-message":
           ok(e.data.result == "ok", "got flyout message");
--- a/browser/base/content/test/browser_social_isVisible.js
+++ b/browser/base/content/test/browser_social_isVisible.js
@@ -14,49 +14,54 @@ function test() {
   };
   runSocialTestWithProvider(manifest, function (finishcb) {
     runSocialTests(tests, undefined, undefined, finishcb);
   });
 }
 
 var tests = {
   testSidebarMessage: function(next) {
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.postMessage({topic: "test-init"});
-    Social.provider.port.onmessage = function (e) {
+    port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-sidebar-message":
           // The sidebar message will always come first, since it loads by default
           ok(true, "got sidebar message");
+          port.close();
           next();
           break;
       }
     };
   },
   testIsVisible: function(next) {
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
+    port.postMessage({topic: "test-init"});
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-isVisible-response":
           is(e.data.result, true, "Sidebar should be visible by default");
           Social.toggleSidebar();
+          port.close();
           next();
       }
     };
     port.postMessage({topic: "test-isVisible"});
   },
   testIsNotVisible: function(next) {
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
+    port.postMessage({topic: "test-init"});
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-isVisible-response":
           is(e.data.result, false, "Sidebar should be hidden");
           Services.prefs.clearUserPref("social.sidebar.open");
+          port.close();
           next();
       }
     };
     port.postMessage({topic: "test-isVisible"});
   }
 }
--- a/browser/base/content/test/browser_social_mozSocial_API.js
+++ b/browser/base/content/test/browser_social_mozSocial_API.js
@@ -24,66 +24,54 @@ var tests = {
 
     function checkNext() {
       if (iconsReady && gotSidebarMessage)
         triggerIconPanel();
     }
 
     function triggerIconPanel() {
       let statusIcons = document.getElementById("social-status-iconbox");
-      ok(!statusIcons.firstChild.hidden, "status icon is visible");
-      // Click the button to trigger its contentPanel
-      let panel = document.getElementById("social-notification-panel");
-      EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
+      waitForCondition(function() statusIcons.firstChild && !statusIcons.firstChild.hidden,
+                       function() {
+        // Click the button to trigger its contentPanel
+        let panel = document.getElementById("social-notification-panel");
+        EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
+      }, "Status icon didn't become non-hidden");
     }
 
-    let port = Social.provider.port;
+    let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
+        case "test-init-done":
+          iconsReady = true;
+          checkNext();
+          break;
         case "got-panel-message":
           ok(true, "got panel message");
           // Check the panel isn't in our history.
           ensureSocialUrlNotRemembered(e.data.location);
           break;
         case "got-social-panel-visibility":
           if (e.data.result == "shown") {
             ok(true, "panel shown");
             let panel = document.getElementById("social-notification-panel");
             panel.hidePopup();
           } else if (e.data.result == "hidden") {
             ok(true, "panel hidden");
+            port.close();
             next();
           }
           break;
         case "got-sidebar-message":
           // The sidebar message will always come first, since it loads by default
           ok(true, "got sidebar message");
           gotSidebarMessage = true;
           // load a status panel
           port.postMessage({topic: "test-ambient-notification"});
           checkNext();
           break;
       }
     }
     port.postMessage({topic: "test-init"});
-
-    // Our worker sets up ambient notification at the same time as it responds to
-    // the workerAPI initialization. If it's already initialized, we can
-    // immediately check the icons, otherwise wait for initialization by
-    // observing the topic sent out by the social service.
-    if (Social.provider.workerAPI.initialized) {
-      iconsReady = true;
-      checkNext();
-    } else {
-      Services.obs.addObserver(function obs() {
-        Services.obs.removeObserver(obs, "social:ambient-notification-changed");
-        // Let the other observers (like the one that updates the UI) run before
-        // checking the icons.
-        executeSoon(function () {
-          iconsReady = true;
-          checkNext();
-        });
-      }, "social:ambient-notification-changed", false);
-    }
   }
 }
--- a/browser/base/content/test/browser_social_shareButton.js
+++ b/browser/base/content/test/browser_social_shareButton.js
@@ -35,17 +35,19 @@ function tabLoaded() {
     gFinishCB = finishcb;
     testInitial();
   });
 }
 
 function testInitial(finishcb) {
   ok(Social.provider, "Social provider is active");
   ok(Social.provider.enabled, "Social provider is enabled");
-  ok(Social.provider.port, "Social provider has a port to its FrameWorker");
+  let port = Social.provider.getWorkerPort();
+  ok(port, "Social provider has a port to its FrameWorker");
+  port.close();
 
   let {shareButton, sharePopup} = SocialShareButton;
   ok(shareButton, "share button exists");
   ok(sharePopup, "share popup exists");
 
   let okButton = document.getElementById("editSharePopupOkButton");
   let undoButton = document.getElementById("editSharePopupUndoButton");
   let shareStatusLabel = document.getElementById("share-button-status");
@@ -181,19 +183,82 @@ function checkNextInTabOrder(element, ne
 }
 
 function testCloseBySpace() {
   let sharePopup = SocialShareButton.sharePopup;
   is(document.activeElement.id, "editSharePopupOkButton", "testCloseBySpace, the ok button should be focused");
   sharePopup.addEventListener("popuphidden", function listener() {
     sharePopup.removeEventListener("popuphidden", listener);
     ok(true, "space closed the share popup");
-    executeSoon(testDisable);
+    executeSoon(testStillSharedIn2Tabs);
   });
   EventUtils.synthesizeKey("VK_SPACE", {});
 }
 
+function testStillSharedIn2Tabs() {
+  let toShare = "http://example.com";
+  let {shareButton} = SocialShareButton;
+  let initialTab = gBrowser.selectedTab;
+  if (shareButton.hasAttribute("shared")) {
+    SocialShareButton.unsharePage();
+  }
+  is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' for the initial tab");
+  let tab1 = gBrowser.selectedTab = gBrowser.addTab(toShare);
+  let tab1b = gBrowser.getBrowserForTab(tab1);
+
+  tab1b.addEventListener("load", function tabLoad(event) {
+    tab1b.removeEventListener("load", tabLoad, true);
+    let tab2 = gBrowser.selectedTab = gBrowser.addTab(toShare);
+    let tab2b = gBrowser.getBrowserForTab(tab2);
+    tab2b.addEventListener("load", function tabLoad(event) {
+      tab2b.removeEventListener("load", tabLoad, true);
+      // should start without either page being shared.
+      is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' before we've done anything");
+      EventUtils.synthesizeMouseAtCenter(shareButton, {});
+      is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
+      // and switching to the first tab (with the same URL) should still reflect shared.
+      gBrowser.selectedTab = tab1;
+      is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
+      // but switching back the initial one should reflect not shared.
+      gBrowser.selectedTab = initialTab;
+      is(shareButton.hasAttribute("shared"), false, "Initial tab should not reflect shared");
+
+      gBrowser.selectedTab = tab1;
+      SocialShareButton.unsharePage();
+      gBrowser.removeTab(tab1);
+      gBrowser.removeTab(tab2);
+      executeSoon(testStillSharedAfterReopen);
+    }, true);
+  }, true);
+}
+
+function testStillSharedAfterReopen() {
+  let toShare = "http://example.com";
+  let {shareButton} = SocialShareButton;
+
+  is(shareButton.hasAttribute("shared"), false, "Reopen: Share button should not have 'shared' for the initial tab");
+  let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
+  let tabb = gBrowser.getBrowserForTab(tab);
+  tabb.addEventListener("load", function tabLoad(event) {
+    tabb.removeEventListener("load", tabLoad, true);
+    SocialShareButton.sharePage();
+    is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
+    gBrowser.removeTab(tab);
+    // should be on the initial unshared tab now.
+    is(shareButton.hasAttribute("shared"), false, "Initial tab should be selected and be unshared.");
+    // now open the same URL - should be back to shared.
+    tab = gBrowser.selectedTab = gBrowser.addTab(toShare, {skipAnimation: true});
+    tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
+      tab.linkedBrowser.removeEventListener("load", tabLoad, true);
+      is(shareButton.hasAttribute("shared"), true, "New tab to previously shared URL should reflect shared");
+      SocialShareButton.unsharePage();
+      gBrowser.removeTab(tab);
+      executeSoon(testDisable);
+    }, true);
+  }, true);
+}
+
 function testDisable() {
   let shareButton = SocialShareButton.shareButton;
   Services.prefs.setBoolPref(prefName, false);
   is(shareButton.hidden, true, "Share button should be hidden when pref is disabled");
   gFinishCB();
 }
--- a/browser/base/content/test/social_worker.js
+++ b/browser/base/content/test/social_worker.js
@@ -6,16 +6,17 @@ let testPort, sidebarPort, apiPort;
 
 onconnect = function(e) {
   let port = e.ports[0];
   port.onmessage = function onMessage(event) {
     let topic = event.data.topic;
     switch (topic) {
       case "test-init":
         testPort = port;
+        port.postMessage({topic: "test-init-done"});
         break;
       case "sidebar-message":
         sidebarPort = port;
         if (testPort && event.data.result == "ok")
           testPort.postMessage({topic:"got-sidebar-message"});
         break;
       case "service-window-message":
         testPort.postMessage({topic:"got-service-window-message",
@@ -64,17 +65,16 @@ onconnect = function(e) {
         testPort.postMessage({topic:"got-flyout-visibility", result: event.data.result});
         break;
       case "test-worker-chat":
         apiPort.postMessage({topic: "social.request-chat", data: event.data.data });
         break;
       case "social.initialize":
         // This is the workerAPI port, respond and set up a notification icon.
         apiPort = port;
-        port.postMessage({topic: "social.initialize-response"});
         let profile = {
           portrait: "https://example.com/portrait.jpg",
           userName: "trickster",
           displayName: "Kuma Lisa",
           profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
         };
         port.postMessage({topic: "social.user-profile", data: profile});
         break;
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1610,27 +1610,41 @@
           // Use the popupid attribute to identify the notification type,
           // otherwise just rely on the panel id for common arrowpanels.
           let type = this._panel.firstChild.getAttribute("popupid") ||
                      this._panel.id;
           if (/^password-/.test(type))
             return "passwords";
           if (type == "editBookmarkPanel")
             return "bookmarks";
+          if (type == "addon-install-complete") {
+            if (!Services.prefs.prefHasUserValue("services.sync.username"))
+              return "addons";
+            if (!Services.prefs.getBoolPref("services.sync.engine.addons"))
+              return "addons-sync-disabled";
+          }
           return null;
         ]]></getter>
       </property>
       <property name="_notificationMessage">
         <getter><![CDATA[
           return gNavigatorBundle.getFormattedString(
             "syncPromoNotification." + this._notificationType + ".description",
             [this._brandBundle.GetStringFromName("syncBrandShortName")]
           );
         ]]></getter>
       </property>
+      <property name="_notificationLink">
+        <getter><![CDATA[
+          if (this._notificationType == "addons-sync-disabled") {
+            return "https://support.mozilla.org/kb/how-do-i-enable-add-sync";
+          }
+          return "https://services.mozilla.com/sync/";
+        ]]></getter>
+      </property>
       <method name="onCloseButtonCommand">
         <body><![CDATA[
           this._viewsLeft = 0;
           this.hidden = true;
         ]]></body>
       </method>
       <method name="onLinkClick">
         <body><![CDATA[
@@ -1651,30 +1665,31 @@
 
           // Only handle supported notification panels.
           if (!this._notificationType) {
             return;
           }
 
           let viewsLeft = this._viewsLeft;
           if (viewsLeft) {
-            if (Services.prefs.prefHasUserValue("services.sync.username")) {
+            if (Services.prefs.prefHasUserValue("services.sync.username") &&
+               this._notificationType != "addons-sync-disabled") {
               // If the user has already setup Sync, don't show the notification.
               this._viewsLeft = 0;
               // Be sure to hide the panel, in case it was visible and the user
               // decided to setup Sync after noticing it.
               viewsLeft = 0;
               // The panel is still hidden, just bail out.
               return;
             }
             else {
               this._viewsLeft = viewsLeft - 1;
             }
 
-            this._promolink.setAttribute("href", "https://services.mozilla.com/sync/");
+            this._promolink.setAttribute("href", this._notificationLink);
             this._promolink.value = gNavigatorBundle.getString("syncPromoNotification.learnMoreLinkText");
 
             this.hidden = false;
 
             // HACK: The description element doesn't wrap correctly in panels,
             // thus set a width on it, based on the available space, before
             // setting its textContent.  Then set its height as well, to
             // fix wrong height calculation on Linux (bug 659578).
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -1323,17 +1323,24 @@ FeedWriter.prototype = {
   function FW__setFaviconForWebReader(aReaderUrl, aMenuItem) {
     var readerURI = makeURI(aReaderUrl);
     if (!/^https?/.test(readerURI.scheme)) {
       // Don't try to get a favicon for non http(s) URIs.
       return;
     }
     var faviconURI = makeURI(readerURI.prePath + "/favicon.ico");
     var self = this;
+    var usePrivateBrowsing = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
+                                         .getInterface(Ci.nsIWebNavigation)
+                                         .QueryInterface(Ci.nsIDocShell)
+                                         .QueryInterface(Ci.nsILoadContext)
+                                         .usePrivateBrowsing;
     this._faviconService.setAndFetchFaviconForPage(readerURI, faviconURI, false,
+      usePrivateBrowsing ? this._faviconService.FAVICON_LOAD_PRIVATE
+                         : this._faviconService.FAVICON_LOAD_NON_PRIVATE,
       function (aURI, aDataLen, aData, aMimeType) {
         if (aDataLen > 0) {
           var dataURL = "data:" + aMimeType + ";base64," +
                         btoa(String.fromCharCode.apply(null, aData));
           self._contentSandbox.menuItem = aMenuItem;
           self._contentSandbox.dataURL = dataURL;
           var codeStr = "menuItem.setAttribute('image', dataURL);";
           Cu.evalInSandbox(codeStr, self._contentSandbox);
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -572,20 +572,16 @@ nsBrowserContentHandler.prototype = {
       // to have the overridePage's content vary depending on the version we're
       // upgrading from.
       let old_mstone = "unknown";
       try {
         old_mstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone");
       } catch (ex) {}
       let override = needHomepageOverride(prefb);
       if (override != OVERRIDE_NONE) {
-        // Setup the default search engine to about:home page.
-        AboutHomeUtils.loadDefaultSearchEngine();
-        AboutHomeUtils.loadSnippetsURL();
-
         switch (override) {
           case OVERRIDE_NEW_PROFILE:
             // New profile.
             overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url");
             break;
           case OVERRIDE_NEW_MSTONE:
             // Existing profile, new milestone build.
             copyPrefOverride();
@@ -598,23 +594,16 @@ nsBrowserContentHandler.prototype = {
             overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url");
             if (prefb.prefHasUserValue("app.update.postupdate"))
               overridePage = getPostUpdateOverridePage(overridePage);
 
             overridePage = overridePage.replace("%OLD_VERSION%", old_mstone);
             break;
         }
       }
-      else {
-        // No need to override homepage, but update snippets url if the pref has
-        // been manually changed.
-        if (Services.prefs.prefHasUserValue(AboutHomeUtils.SNIPPETS_URL_PREF)) {
-          AboutHomeUtils.loadSnippetsURL();
-        }
-      }
     } catch (ex) {}
 
     // formatURLPref might return "about:blank" if getting the pref fails
     if (overridePage == "about:blank")
       overridePage = "";
 
     var startPage = "";
     try {
@@ -830,46 +819,10 @@ nsDefaultCommandLineHandler.prototype = 
                  "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
                  gBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS);
     }
   },
 
   helpInfo : "",
 };
 
-let AboutHomeUtils = {
-  SNIPPETS_URL_PREF: "browser.aboutHomeSnippets.updateUrl",
-  get _storage() {
-    let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
-    let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
-                    getService(Components.interfaces.nsIScriptSecurityManager).
-                    getNoAppCodebasePrincipal(aboutHomeURI);
-    let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
-              getService(Components.interfaces.nsIDOMStorageManager);
-    return dsm.getLocalStorageForPrincipal(principal, "");
-  },
-
-  loadDefaultSearchEngine: function AHU_loadDefaultSearchEngine()
-  {
-    let defaultEngine = Services.search.originalDefaultEngine;
-    let submission = defaultEngine.getSubmission("_searchTerms_");
-    if (submission.postData)
-      throw new Error("Home page does not support POST search engines.");
-    let engine = {
-      name: defaultEngine.name
-    , searchUrl: submission.uri.spec
-    }
-    this._storage.setItem("search-engine", JSON.stringify(engine));
-  },
-
-  loadSnippetsURL: function AHU_loadSnippetsURL()
-  {
-    const STARTPAGE_VERSION = 3;
-    let updateURL = Services.prefs
-                            .getCharPref(this.SNIPPETS_URL_PREF)
-                            .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
-    updateURL = Services.urlFormatter.formatURL(updateURL);
-    this._storage.setItem("snippets-update-url", updateURL);
-  },
-};
-
 var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
 var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -311,20 +311,16 @@ var gAdvancedPane = {
     for (var i = 0; i < groups.length; i++) {
       var uri = ios.newURI(groups[i], null, null);
       if (uri.asciiHost == host) {
         var cache = cacheService.getActiveCache(groups[i]);
         usage += cache.usage;
       }
     }
 
-    var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
-                         getService(Components.interfaces.nsIDOMStorageManager);
-    usage += storageManager.getUsage(host);
-
     return usage;
   },
 
   /**
    * Updates the list of offline applications
    */
   updateOfflineApps: function ()
   {
@@ -402,22 +398,16 @@ var gAdvancedPane = {
     for (var i = 0; i < groups.length; i++) {
         var uri = ios.newURI(groups[i], null, null);
         if (uri.asciiHost == host) {
             var cache = cacheService.getActiveCache(groups[i]);
             cache.discard();
         }
     }
 
-    // send out an offline-app-removed signal.  The nsDOMStorage
-    // service will clear DOM storage for this host.
-    var obs = Components.classes["@mozilla.org/observer-service;1"]
-                        .getService(Components.interfaces.nsIObserverService);
-    obs.notifyObservers(null, "offline-app-removed", host);
-
     // remove the permission
     var pm = Components.classes["@mozilla.org/permissionmanager;1"]
                        .getService(Components.interfaces.nsIPermissionManager);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -303,20 +303,16 @@ var gAdvancedPane = {
     for (var i = 0; i < groups.length; i++) {
       var uri = ios.newURI(groups[i], null, null);
       if (uri.asciiHost == host) {
         var cache = cacheService.getActiveCache(groups[i]);
         usage += cache.usage;
       }
     }
 
-    var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
-                         getService(Components.interfaces.nsIDOMStorageManager);
-    usage += storageManager.getUsage(host);
-
     return usage;
   },
 
   /**
    * Updates the list of offline applications
    */
   updateOfflineApps: function ()
   {
@@ -394,22 +390,16 @@ var gAdvancedPane = {
     for (var i = 0; i < groups.length; i++) {
         var uri = ios.newURI(groups[i], null, null);
         if (uri.asciiHost == host) {
             var cache = cacheService.getActiveCache(groups[i]);
             cache.discard();
         }
     }
 
-    // send out an offline-app-removed signal.  The nsDOMStorage
-    // service will clear DOM storage for this host.
-    var obs = Components.classes["@mozilla.org/observer-service;1"]
-                        .getService(Components.interfaces.nsIObserverService);
-    obs.notifyObservers(null, "offline-app-removed", host);
-
     // remove the permission
     var pm = Components.classes["@mozilla.org/permissionmanager;1"]
                        .getService(Components.interfaces.nsIPermissionManager);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -646,18 +646,18 @@ PrivateBrowsingService.prototype = {
         cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
       } catch (ex) {
         Cu.reportError("Exception thrown while clearing the cache: " +
           ex.toString());
       }
     }
 
     // Image Cache
-    let (imageCache = Cc["@mozilla.org/image/cache;1"].
-                      getService(Ci.imgICache)) {
+    let (imageCache = Cc["@mozilla.org/image/tools;1"].
+                      getService(Ci.imgITools).getImgCacheForDocument(null)) {
       try {
         imageCache.clearCache(false); // true=chrome, false=content
       } catch (ex) {
         Cu.reportError("Exception thrown while clearing the image cache: " +
           ex.toString());
       }
     }
 
--- a/browser/components/sessionstore/test/browser_463205_sample.html
+++ b/browser/components/sessionstore/test/browser_463205_sample.html
@@ -1,25 +1,23 @@
 <!-- Testcase originally by <moz_bug_r_a4@yahoo.com> -->
 
 <!DOCTYPE html>
 <title>Test for bug 463205</title>
 
-<body>
+<body onload="onLoad()">
 <iframe src="data:text/html,<input%20id='original'>"></iframe>
 <iframe src="browser_463205_helper.html"></iframe>
 <iframe src="data:text/html,mark1"></iframe>
 
 <script type="application/javascript">
-  frames[2].addEventListener("DOMContentLoaded", function() {
-    frames[2].removeEventListener("DOMContentLoaded", arguments.callee, false);
-
+  function onLoad() {
     if (frames[2].document.location.href == "data:text/html,mark1") {
       frames[2].document.location = "data:text/html,mark2";
     }
     else {
       frames[1].document.location.hash = "#original";
       frames[0].document.location = "http://mochi.test:8888/browser/" +
         "browser/components/sessionstore/test/browser_463205_helper.html";
     }
-  }, false);
+  }
 </script>
 </body>
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -219,17 +219,17 @@ let PageThumbs = {
    * @param aCanvas The target canvas.
    * @return An array containing width, height and scale.
    */
   _determineCropSize: function PageThumbs_determineCropSize(aWindow, aCanvas) {
     let sw = aWindow.innerWidth;
     let sh = aWindow.innerHeight;
 
     let {width: thumbnailWidth, height: thumbnailHeight} = aCanvas;
-    let scale = Math.max(thumbnailWidth / sw, thumbnailHeight / sh);
+    let scale = Math.min(Math.max(thumbnailWidth / sw, thumbnailHeight / sh), 1);
     let scaledWidth = sw * scale;
     let scaledHeight = sh * scale;
 
     if (scaledHeight > thumbnailHeight)
       sh -= Math.floor(Math.abs(scaledHeight - thumbnailHeight) * scale);
 
     if (scaledWidth > thumbnailWidth)
       sw -= Math.floor(Math.abs(scaledWidth - thumbnailWidth) * scale);
--- a/browser/config/mozconfigs/win64/debug
+++ b/browser/config/mozconfigs/win64/debug
@@ -4,16 +4,20 @@ ac_add_options --host=x86_64-pc-mingw32
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 ENABLE_MARIONETTE=1
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
-mk_add_options MOZ_MAKE_FLAGS=-j1
+if test -n "${_PYMAKE}"; then
+  mk_add_options MOZ_MAKE_FLAGS=-j4
+else
+  mk_add_options MOZ_MAKE_FLAGS=-j1
+fi
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . $topsrcdir/build/win64/mozconfig.vs2010
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win64/nightly
+++ b/browser/config/mozconfigs/win64/nightly
@@ -13,16 +13,20 @@ ac_add_options --enable-profiling
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
-mk_add_options MOZ_MAKE_FLAGS=-j1
+if test -n "${_PYMAKE}"; then
+  mk_add_options MOZ_MAKE_FLAGS=-j4
+else
+  mk_add_options MOZ_MAKE_FLAGS=-j1
+fi
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . $topsrcdir/build/win64/mozconfig.vs2010
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/devtools/commandline/CmdAddon.jsm
+++ b/browser/devtools/commandline/CmdAddon.jsm
@@ -1,23 +1,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
-let EXPORTED_SYMBOLS = [ ];
+let EXPORTED_SYMBOLS = [ "Flags" ];
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 
+// We need to use an object in which to store any flags because a primitive
+// would remain undefined.
+let Flags = {
+  addonsLoaded: false
+};
+
 /**
  * 'addon' command.
  */
 gcli.addCommand({
   name: "addon",
   description: gcli.lookup("addonDesc")
 });
 
@@ -281,10 +287,11 @@ AddonManager.getAllAddons(function addon
       }
 
       let promise = context.createPromise();
       // List the installed add-ons, disable one when done listing.
       AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
       return promise;
     }
   });
+  Flags.addonsLoaded = true;
   Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
 });
--- a/browser/devtools/commandline/CmdScreenshot.jsm
+++ b/browser/devtools/commandline/CmdScreenshot.jsm
@@ -7,74 +7,107 @@ const { classes: Cc, interfaces: Ci, uti
 let EXPORTED_SYMBOLS = [ ];
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
                                   "resource:///modules/devtools/LayoutHelpers.jsm");
 
+// String used as an indication to generate default file name in the following
+// format: "Screen Shot yyyy-mm-dd at HH.MM.SS.png"
+const FILENAME_DEFAULT_VALUE = " ";
+
 /**
  * 'screenshot' command
  */
 gcli.addCommand({
   name: "screenshot",
   description: gcli.lookup("screenshotDesc"),
   manual: gcli.lookup("screenshotManual"),
-  returnType: "string",
+  returnType: "html",
   params: [
     {
       name: "filename",
       type: "string",
+      defaultValue: FILENAME_DEFAULT_VALUE,
       description: gcli.lookup("screenshotFilenameDesc"),
       manual: gcli.lookup("screenshotFilenameManual")
     },
     {
-      name: "delay",
-      type: { name: "number", min: 0 },
-      defaultValue: 0,
-      description: gcli.lookup("screenshotDelayDesc"),
-      manual: gcli.lookup("screenshotDelayManual")
-    },
-    {
-      name: "fullpage",
-      type: "boolean",
-      description: gcli.lookup("screenshotFullPageDesc"),
-      manual: gcli.lookup("screenshotFullPageManual")
-    },
-    {
-      name: "selector",
-      type: "node",
-      defaultValue: null,
-      description: gcli.lookup("inspectNodeDesc"),
-      manual: gcli.lookup("inspectNodeManual")
+      group: gcli.lookup("screenshotGroupOptions"),
+      params: [
+        {
+          name: "clipboard",
+          type: "boolean",
+          description: gcli.lookup("screenshotClipboardDesc"),
+          manual: gcli.lookup("screenshotClipboardManual")
+        },
+        {
+          name: "chrome",
+          type: "boolean",
+          description: gcli.lookup("screenshotChromeDesc"),
+          manual: gcli.lookup("screenshotChromeManual")
+        },
+        {
+          name: "delay",
+          type: { name: "number", min: 0 },
+          defaultValue: 0,
+          description: gcli.lookup("screenshotDelayDesc"),
+          manual: gcli.lookup("screenshotDelayManual")
+        },
+        {
+          name: "fullpage",
+          type: "boolean",
+          description: gcli.lookup("screenshotFullPageDesc"),
+          manual: gcli.lookup("screenshotFullPageManual")
+        },
+        {
+          name: "selector",
+          type: "node",
+          defaultValue: null,
+          description: gcli.lookup("inspectNodeDesc"),
+          manual: gcli.lookup("inspectNodeManual")
+        }
+      ]
     }
   ],
   exec: function Command_screenshot(args, context) {
-    var document = context.environment.contentDocument;
+    if (args.chrome && args.selector) {
+      // Node screenshot with chrome option does not work as inteded
+      // Refer https://bugzilla.mozilla.org/show_bug.cgi?id=659268#c7
+      // throwing for now.
+      throw new Error(gcli.lookup("screenshotSelectorChromeConflict"));
+    }
+    var document = args.chrome? context.environment.chromeDocument
+                              : context.environment.contentDocument;
     if (args.delay > 0) {
       var promise = context.createPromise();
       document.defaultView.setTimeout(function Command_screenshotDelay() {
-        let reply = this.grabScreen(document, args.filename);
+        let reply = this.grabScreen(document, args.filename, args.clipboard,
+                                    args.fullpage);
         promise.resolve(reply);
       }.bind(this), args.delay * 1000);
       return promise;
     }
     else {
-      return this.grabScreen(document, args.filename, args.fullpage, args.selector);
+      return this.grabScreen(document, args.filename, args.clipboard,
+                             args.fullpage, args.selector);
     }
   },
   grabScreen:
-  function Command_screenshotGrabScreen(document, filename, fullpage, node) {
+  function Command_screenshotGrabScreen(document, filename, clipboard,
+                                        fullpage, node) {
     let window = document.defaultView;
     let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
     let left = 0;
     let top = 0;
     let width;
     let height;
+    let div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
 
     if (!fullpage) {
       if (!node) {
         left = window.scrollX;
         top = window.scrollY;
         width = window.innerWidth;
         height = window.innerHeight;
       } else {
@@ -88,47 +121,113 @@ gcli.addCommand({
       width = window.innerWidth + window.scrollMaxX;
       height = window.innerHeight + window.scrollMaxY;
     }
     canvas.width = width;
     canvas.height = height;
 
     let ctx = canvas.getContext("2d");
     ctx.drawWindow(window, left, top, width, height, "#fff");
+    let data = canvas.toDataURL("image/png", "");
 
-    let data = canvas.toDataURL("image/png", "");
+    try {
+      if (clipboard) {
+        let io = Cc["@mozilla.org/network/io-service;1"]
+                   .getService(Ci.nsIIOService);
+        let channel = io.newChannel(data, null, null);
+        let input = channel.open();
+        let imgTools = Cc["@mozilla.org/image/tools;1"]
+                         .getService(Ci.imgITools);
+
+        let container = {};
+        imgTools.decodeImageData(input, channel.contentType, container);
+
+        let wrapped = Cc["@mozilla.org/supports-interface-pointer;1"]
+                        .createInstance(Ci.nsISupportsInterfacePointer);
+        wrapped.data = container.value;
+
+        let trans = Cc["@mozilla.org/widget/transferable;1"]
+                      .createInstance(Ci.nsITransferable);
+        if ("init" in trans) {
+          trans.init(null);
+        }
+        trans.addDataFlavor(channel.contentType);
+        trans.setTransferData(channel.contentType, wrapped, -1);
+
+        let clipid = Ci.nsIClipboard;
+        let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
+        clip.setData(trans, null, clipid.kGlobalClipboard);
+        div.textContent = gcli.lookup("screenshotCopied");
+        return div;
+      }
+    }
+    catch (ex) {
+      div.textContent = gcli.lookup("screenshotErrorCopying");
+      return div;
+    }
+
     let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
 
+    // Create a name for the file if not present
+    if (filename == FILENAME_DEFAULT_VALUE) {
+      let date = new Date();
+      let dateString = date.getFullYear() + "-" + (date.getMonth() + 1) +
+                       "-" + date.getDate();
+      dateString = dateString.split("-").map(function(part) {
+        if (part.length == 1) {
+          part = "0" + part;
+        }
+        return part;
+      }).join("-");
+      let timeString = date.toTimeString().replace(/:/g, ".").split(" ")[0];
+      filename = gcli.lookupFormat("screenshotGeneratedFilename",
+                                   [dateString, timeString]) + ".png";
+    }
     // Check there is a .png extension to filename
-    if (!filename.match(/.png$/i)) {
+    else if (!filename.match(/.png$/i)) {
       filename += ".png";
     }
 
     // If the filename is relative, tack it onto the download directory
     if (!filename.match(/[\\\/]/)) {
       let downloadMgr = Cc["@mozilla.org/download-manager;1"]
-        .getService(Ci.nsIDownloadManager);
+                          .getService(Ci.nsIDownloadManager);
       let tempfile = downloadMgr.userDownloadsDirectory;
       tempfile.append(filename);
       filename = tempfile.path;
     }
 
     try {
       file.initWithPath(filename);
     } catch (ex) {
-      return "Error saving to " + filename;
+      div.textContent = gcli.lookup("screenshotErrorSavingToFile") + " " + filename;
+      return div;
     }
 
     let ioService = Cc["@mozilla.org/network/io-service;1"]
-      .getService(Ci.nsIIOService);
+                      .getService(Ci.nsIIOService);
 
     let Persist = Ci.nsIWebBrowserPersist;
     let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
-      .createInstance(Persist);
+                    .createInstance(Persist);
     persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                            Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
 
     let source = ioService.newURI(data, "UTF8", null);
     persist.saveURI(source, null, null, null, null, file);
 
-    return "Saved to " + filename;
+    div.textContent = gcli.lookup("screenshotSavedToFile") + " " + filename;
+    div.addEventListener("click", function openFile() {
+      div.removeEventListener("click", openFile);
+      file.reveal();
+    });
+    div.style.cursor = "pointer";
+    let image = document.createElement("div");
+    let previewHeight = parseInt(256*height/width);
+    image.setAttribute("style",
+                       "width:256px; height:" + previewHeight + "px;" +
+                       "background-image: url('" + data + "');" +
+                       "background-size: 256px " + previewHeight + "px;" +
+                       "margin: 4px; display: block");
+    div.appendChild(image);
+    return div;
   }
-});
+});
\ No newline at end of file
--- a/browser/devtools/commandline/test/Makefile.in
+++ b/browser/devtools/commandline/test/Makefile.in
@@ -19,22 +19,24 @@ MOCHITEST_BROWSER_FILES = \
   browser_cmd_calllog_chrome.js \
   browser_cmd_commands.js \
   browser_cmd_cookie.js \
   browser_cmd_integrate.js \
   browser_cmd_jsb.js \
   browser_cmd_pagemod_export.js \
   browser_cmd_pref.js \
   browser_cmd_restart.js \
+  browser_cmd_screenshot.js \
   browser_cmd_settings.js \
   browser_gcli_web.js \
   head.js \
   helpers.js \
   $(NULL)
 
 MOCHITEST_BROWSER_FILES += \
   browser_dbg_cmd_break.html \
   browser_dbg_cmd.html \
+  browser_cmd_screenshot.html \
   browser_cmd_pagemod_export.html \
   browser_cmd_jsb_script.jsi \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/devtools/commandline/test/browser_cmd_addon.js
+++ b/browser/devtools/commandline/test/browser_cmd_addon.js
@@ -1,20 +1,24 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the addon commands works as they should
 
+let imported = {};
+Components.utils.import("resource:///modules/devtools/CmdAddon.jsm", imported);
+
 function test() {
   DeveloperToolbarTest.test("about:blank", [ GAT_test ]);
 }
 
 function GAT_test() {
   var GAT_ready = DeveloperToolbarTest.checkCalled(function() {
     Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
+    info("gcli_addon_commands_ready notification received, running tests");
 
     helpers.setInput('addon list dictionary');
     helpers.check({
       input:  'addon list dictionary',
       hints:                       '',
       markup: 'VVVVVVVVVVVVVVVVVVVVV',
       status: 'VALID'
     });
@@ -86,9 +90,19 @@ function GAT_test() {
         name: { value: 'Test Plug-in', status: 'VALID' },
       }
     });
 
     DeveloperToolbarTest.exec({ completed: false });
   });
 
   Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
+
+  if (imported.Flags.addonsLoaded) {
+    info("The getAllAddons command has already completed and we have missed ");
+    info("the notification. Let's send the gcli_addon_commands_ready ");
+    info("notification ourselves.");
+
+    Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
+  } else {
+    info("gcli_addon_commands_ready notification has not yet been received.");
+  }
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_cmd_screenshot.html
@@ -0,0 +1,6 @@
+<html>
+  <head></head>
+  <body>
+    <img id="testImage" ></img>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_cmd_screenshot.js
@@ -0,0 +1,148 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that screenshot command works properly
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
+                 "test/browser_cmd_screenshot.html";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+let tempScope = {};
+Cu.import("resource://gre/modules/FileUtils.jsm", tempScope);
+let FileUtils = tempScope.FileUtils;
+
+function test() {
+  DeveloperToolbarTest.test(TEST_URI, [ testInput, testCapture ]);
+}
+
+function testInput() {
+  helpers.setInput('screenshot');
+  helpers.check({
+    input:  'screenshot',
+    markup: 'VVVVVVVVVV',
+    status: 'VALID',
+    args: {
+    }
+  });
+
+  helpers.setInput('screenshot abc.png');
+  helpers.check({
+    input:  'screenshot abc.png',
+    markup: 'VVVVVVVVVVVVVVVVVV',
+    status: 'VALID',
+    args: {
+      filename: { value: "abc.png"},
+    }
+  });
+
+  helpers.setInput('screenshot --fullpage');
+  helpers.check({
+    input:  'screenshot --fullpage',
+    markup: 'VVVVVVVVVVVVVVVVVVVVV',
+    status: 'VALID',
+    args: {
+      fullpage: { value: true},
+    }
+  });
+
+  helpers.setInput('screenshot abc --delay 5');
+  helpers.check({
+    input:  'screenshot abc --delay 5',
+    markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+    status: 'VALID',
+    args: {
+      filename: { value: "abc"},
+      delay: { value: "5"},
+    }
+  });
+
+  helpers.setInput('screenshot --selector img#testImage');
+  helpers.check({
+    input:  'screenshot --selector img#testImage',
+    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+    status: 'VALID',
+    args: {
+      selector: { value: content.document.getElementById("testImage")},
+    }
+  });
+}
+
+function testCapture() {
+  function checkTemporaryFile() {
+    // Create a temporary file.
+    let gFile = FileUtils.getFile("TmpD", ["TestScreenshotFile.png"]);
+    if (gFile.exists()) {
+      gFile.remove(false);
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+
+  function clearClipboard() {
+    let clipid = Ci.nsIClipboard;
+    let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
+    clip.emptyClipboard(clipid.kGlobalClipboard);
+  }
+
+  function checkClipboard() {
+    try {
+      let clipid = Ci.nsIClipboard;
+      let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
+      let trans = Cc["@mozilla.org/widget/transferable;1"]
+                    .createInstance(Ci.nsITransferable);
+      if ("init" in trans) {
+        trans.init(null);
+      }
+      let io = Cc["@mozilla.org/network/io-service;1"]
+                 .getService(Ci.nsIIOService);
+      let contentType = io.newChannel("", null, null).contentType;
+      trans.addDataFlavor(contentType);
+      clip.getData(trans, clipid.kGlobalClipboard);
+      let str = new Object();
+      let strLength = new Object();
+      trans.getTransferData(contentType, str, strLength);
+      if (str && strLength > 0) {
+        clip.emptyClipboard(clipid.kGlobalClipboard);
+        return true;
+      }
+    }
+    catch (ex) {}
+    return false;
+  }
+
+  let path = FileUtils.getFile("TmpD", ["TestScreenshotFile.png"]).path;
+
+  DeveloperToolbarTest.exec({
+    typed: "screenshot " + path,
+    args: {
+      delay: 0,
+      filename: "" + path,
+      fullpage: false,
+      clipboard: false,
+      node: null,
+      chrome: false,
+    },
+    outputMatch: new RegExp("^Saved to "),
+  });
+
+  ok(checkTemporaryFile, "Screenshot got created");
+
+  clearClipboard();
+
+  DeveloperToolbarTest.exec({
+    typed: "screenshot --fullpage --clipboard",
+    args: {
+      delay: 0,
+      filename: " ",
+      fullpage: true,
+      clipboard: true,
+      node: null,
+      chrome: false,
+    },
+    outputMatch: new RegExp("^Copied to clipboard.$"),
+  });
+
+  ok(checkClipboard, "Screenshot got created and copied");
+}
+
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -41,18 +41,18 @@ DebuggerUI.prototype = {
   listenToTabs: function DUI_listenToTabs() {
     let win = this.chromeWindow;
     let tabs = win.gBrowser.tabContainer;
 
     let bound_refreshCommand = this.refreshCommand.bind(this);
     tabs.addEventListener("TabSelect", bound_refreshCommand, true);
 
     win.addEventListener("unload", function onClose(aEvent) {
+      win.removeEventListener("unload", onClose, false);
       tabs.removeEventListener("TabSelect", bound_refreshCommand, true);
-      win.removeEventListener("unload", onClose, false);
     }, false);
   },
 
   /**
    * Called by the DebuggerPane to update the Debugger toggle switches with the
    * debugger state.
    */
   refreshCommand: function DUI_refreshCommand() {
@@ -240,17 +240,17 @@ function DebuggerPane(aDebuggerUI, aTab)
 DebuggerPane.prototype = {
 
   /**
    * Initializes the debugger server.
    */
   _initServer: function DP__initServer() {
     if (!DebuggerServer.initialized) {
       // Always allow connections from nsIPipe transports.
-      DebuggerServer.init(function () { return true; });
+      DebuggerServer.init(function() true);
       DebuggerServer.addBrowserActors();
     }
   },
 
   /**
    * Creates and initializes the widgets containing the debugger UI.
    */
   _create: function DP__create() {
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -15,16 +15,17 @@ const SCRIPTS_URL_MAX_LENGTH = 64; // ch
 const SYNTAX_HIGHLIGHT_MAX_FILE_SIZE = 1048576; // 1 MB in bytes
 
 Cu.import("resource:///modules/source-editor.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import('resource://gre/modules/Services.jsm');
+Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 
 /**
  * Controls the debugger view by handling the source scripts, the current
  * thread state and thread stack frame cache.
  */
 let DebuggerController = {
 
   /**
@@ -46,16 +47,17 @@ let DebuggerController = {
   _startupDebugger: function DC__startupDebugger() {
     if (this._isInitialized) {
       return;
     }
     this._isInitialized = true;
     window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
 
     DebuggerView.cacheView();
+    DebuggerView.initializeKeys();
     DebuggerView.initializePanes();
     DebuggerView.initializeEditor(function() {
       DebuggerView.GlobalSearch.initialize();
       DebuggerView.Scripts.initialize();
       DebuggerView.StackFrames.initialize();
       DebuggerView.Breakpoints.initialize();
       DebuggerView.Properties.initialize();
       DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
@@ -242,33 +244,16 @@ let DebuggerController = {
           });
         });
 
       }.bind(this));
     }.bind(this));
   },
 
   /**
-   * Returns true if this is a remote debugger instance.
-   * @return boolean
-   */
-  get _isRemoteDebugger() {
-    return window._remoteFlag;
-  },
-
-  /**
-   * Returns true if this is a chrome debugger instance.
-   * @return boolean
-   */
-  get _isChromeDebugger() {
-    // Directly accessing window.parent.content may throw in some cases.
-    return !("content" in window.parent) && !this._isRemoteDebugger;
-  },
-
-  /**
    * Attempts to quit the current process if allowed.
    */
   _quitApp: function DC__quitApp() {
     let canceled = Cc["@mozilla.org/supports-PRBool;1"]
       .createInstance(Ci.nsISupportsPRBool);
 
     Services.obs.notifyObservers(canceled, "quit-application-requested", null);
 
@@ -291,16 +276,36 @@ let DebuggerController = {
   dispatchEvent: function DC_dispatchEvent(aType, aDetail) {
     let evt = document.createEvent("CustomEvent");
     evt.initCustomEvent(aType, true, false, aDetail);
     document.documentElement.dispatchEvent(evt);
   }
 };
 
 /**
+ * Returns true if this is a remote debugger instance.
+ * @return boolean
+ */
+XPCOMUtils.defineLazyGetter(DebuggerController, "_isRemoteDebugger", function() {
+  // We're inside a single top level XUL window, not an iframe container.
+  return !(window.frameElement instanceof XULElement) &&
+         !!window._remoteFlag;
+});
+
+/**
+ * Returns true if this is a chrome debugger instance.
+ * @return boolean
+ */
+XPCOMUtils.defineLazyGetter(DebuggerController, "_isChromeDebugger", function() {
+  // We're inside a single top level XUL window, but not a remote debugger.
+  return !(window.frameElement instanceof XULElement) &&
+         !window._remoteFlag;
+});
+
+/**
  * ThreadState keeps the UI up to date with the state of the
  * thread (paused/attached/etc.).
  */
 function ThreadState() {
   this._update = this._update.bind(this);
 }
 
 ThreadState.prototype = {
@@ -1267,16 +1272,17 @@ SourceScripts.prototype = {
       case "chrome":
       case "resource":
         try {
           NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) {
             if (!Components.isSuccessCode(aStatus)) {
               return self._logError(url, aStatus);
             }
             let source = NetUtil.readInputStreamToString(aStream, aStream.available());
+            source = self._convertToUnicode(source);
             self._onLoadSourceFinished(url, source, null, options);
             aStream.close();
           });
         } catch (ex) {
           return self._logError(url, ex.name);
         }
         break;
 
@@ -1291,28 +1297,50 @@ SourceScripts.prototype = {
           },
           onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) {
             chunks.push(NetUtil.readInputStreamToString(aStream, aCount));
           },
           onStopRequest: function(aRequest, aContext, aStatusCode) {
             if (!Components.isSuccessCode(aStatusCode)) {
               return self._logError(url, aStatusCode);
             }
-            self._onLoadSourceFinished(
-              url, chunks.join(""), channel.contentType, options);
+            let source = self._convertToUnicode(chunks.join(""), channel.contentCharset);
+            self._onLoadSourceFinished(url, source, channel.contentType, options);
           }
         };
 
         channel.loadFlags = channel.LOAD_FROM_CACHE;
         channel.asyncOpen(streamListener, null);
         break;
     }
   },
 
   /**
+   * Convert a given string, encoded in a given character set, to unicode.
+   * @param string aString
+   *        A string.
+   * @param string aCharset
+   *        A character set.
+   * @return string
+   *         A unicode string.
+   */
+  _convertToUnicode: function SS__convertToUnicode(aString, aCharset) {
+    // Decoding primitives.
+    let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+        .createInstance(Ci.nsIScriptableUnicodeConverter);
+
+    try {
+      converter.charset = aCharset || "UTF-8";
+      return converter.ConvertToUnicode(aString);
+    } catch(e) {
+      return aString;
+    }
+  },
+
+  /**
    * Called when a script's source has been loaded.
    *
    * @private
    * @param string aScriptUrl
    *        The URL of the source script.
    * @param string aSourceText
    *        The text of the source script.
    * @param string aContentType
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -28,22 +28,75 @@ let DebuggerView = {
   editor: null,
 
   /**
    * Caches frequently used global view elements.
    */
   cacheView: function DV_cacheView() {
     this._onTogglePanesButtonPressed = this._onTogglePanesButtonPressed.bind(this);
 
+    // Panes and view containers
     this._togglePanesButton = document.getElementById("toggle-panes");
     this._stackframesAndBreakpoints = document.getElementById("stackframes+breakpoints");
     this._stackframes = document.getElementById("stackframes");
     this._breakpoints = document.getElementById("breakpoints");
     this._variables = document.getElementById("variables");
+    this._scripts = document.getElementById("scripts");
     this._globalSearch = document.getElementById("globalsearch");
+    this._globalSearchSplitter = document.getElementById("globalsearch-splitter");
+
+    // Keys
+    this._fileSearchKey = document.getElementById("fileSearchKey");
+    this._lineSearchKey = document.getElementById("lineSearchKey");
+    this._tokenSearchKey = document.getElementById("tokenSearchKey");
+    this._globalSearchKey = document.getElementById("globalSearchKey");
+    this._resumeKey = document.getElementById("resumeKey");
+    this._stepOverKey = document.getElementById("stepOverKey");
+    this._stepInKey = document.getElementById("stepInKey");
+    this._stepOutKey = document.getElementById("stepOutKey");
+
+    // Buttons, textboxes etc.
+    this._resumeButton = document.getElementById("resume");
+    this._stepOverButton = document.getElementById("step-over");
+    this._stepInButton = document.getElementById("step-in");
+    this._stepOutButton = document.getElementById("step-out");
+    this._scriptsSearchbox = document.getElementById("scripts-search");
+    this._globalOperatorLabel = document.getElementById("global-operator-label");
+    this._globalOperatorButton = document.getElementById("global-operator-button");
+    this._tokenOperatorLabel = document.getElementById("token-operator-label");
+    this._tokenOperatorButton = document.getElementById("token-operator-button");
+    this._lineOperatorLabel = document.getElementById("line-operator-label");
+    this._lineOperatorButton = document.getElementById("line-operator-button");
+  },
+
+  /**
+   * Applies the correct key labels and tooltips across global view elements.
+   */
+  initializeKeys: function DV_initializeKeys() {
+    this._resumeButton.setAttribute("tooltiptext",
+      L10N.getFormatStr("pauseButtonTooltip", [LayoutHelpers.prettyKey(this._resumeKey)]));
+    this._stepOverButton.setAttribute("tooltiptext",
+      L10N.getFormatStr("stepOverTooltip", [LayoutHelpers.prettyKey(this._stepOverKey)]));
+    this._stepInButton.setAttribute("tooltiptext",
+      L10N.getFormatStr("stepInTooltip", [LayoutHelpers.prettyKey(this._stepInKey)]));
+    this._stepOutButton.setAttribute("tooltiptext",
+      L10N.getFormatStr("stepOutTooltip", [LayoutHelpers.prettyKey(this._stepOutKey)]));
+
+    this._scriptsSearchbox.setAttribute("placeholder",
+      L10N.getFormatStr("emptyFilterText", [LayoutHelpers.prettyKey(this._fileSearchKey)]));
+    this._globalOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelGlobal", [LayoutHelpers.prettyKey(this._globalSearchKey)]));
+    this._tokenOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelToken", [LayoutHelpers.prettyKey(this._tokenSearchKey)]));
+    this._lineOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelLine", [LayoutHelpers.prettyKey(this._lineSearchKey)]));
+
+    this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
+    this._tokenOperatorButton.setAttribute("label", SEARCH_TOKEN_FLAG);
+    this._lineOperatorButton.setAttribute("label", SEARCH_LINE_FLAG);
   },
 
   /**
    * Initializes UI properties for all the displayed panes.
    */
   initializePanes: function DV_initializePanes() {
     this._togglePanesButton.addEventListener("click", this._onTogglePanesButtonPressed);
 
@@ -87,16 +140,21 @@ let DebuggerView = {
     Prefs.stackframesWidth = this._stackframesAndBreakpoints.getAttribute("width");
     Prefs.variablesWidth = this._variables.getAttribute("width");
 
     this._breakpoints.parentNode.removeChild(this._breakpoints);
     this._stackframes.parentNode.removeChild(this._stackframes);
     this._stackframesAndBreakpoints.parentNode.removeChild(this._stackframesAndBreakpoints);
     this._variables.parentNode.removeChild(this._variables);
     this._globalSearch.parentNode.removeChild(this._globalSearch);
+
+    // Delete all the cached global view elements.
+    for (let i in this) {
+      if (!(this[i] instanceof Function)) delete this[i];
+    }
   },
 
   /**
    * Removes the SourceEditor instance and added breakpoints.
    */
   destroyEditor: function DV_destroyEditor() {
     DebuggerController.Breakpoints.destroy();
     this.editor = null;
@@ -140,20 +198,22 @@ let DebuggerView = {
     if (aAnimatedFlag) {
       this._stackframesAndBreakpoints.setAttribute("animated", "");
     } else {
       this._stackframesAndBreakpoints.removeAttribute("animated");
     }
     if (aVisibleFlag) {
       this._stackframesAndBreakpoints.style.marginLeft = "0";
       this._togglePanesButton.removeAttribute("stackframesAndBreakpointsHidden");
+      this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("collapsePanes"));
     } else {
       let margin = parseInt(this._stackframesAndBreakpoints.getAttribute("width")) + 1;
       this._stackframesAndBreakpoints.style.marginLeft = -margin + "px";
       this._togglePanesButton.setAttribute("stackframesAndBreakpointsHidden", "true");
+      this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("expandPanes"));
     }
     Prefs.stackframesPaneVisible = aVisibleFlag;
   },
 
   /**
    * Sets the variable spane hidden or visible.
    * @param boolean aVisibleFlag
    * @param boolean aAnimatedFlag
@@ -163,33 +223,56 @@ let DebuggerView = {
     if (aAnimatedFlag) {
       this._variables.setAttribute("animated", "");
     } else {
       this._variables.removeAttribute("animated");
     }
     if (aVisibleFlag) {
       this._variables.style.marginRight = "0";
       this._togglePanesButton.removeAttribute("variablesHidden");
+      this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("collapsePanes"));
     } else {
       let margin = parseInt(this._variables.getAttribute("width")) + 1;
       this._variables.style.marginRight = -margin + "px";
       this._togglePanesButton.setAttribute("variablesHidden", "true");
+      this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("expandPanes"));
     }
     Prefs.variablesPaneVisible = aVisibleFlag;
   },
 
   /**
    * The cached global view elements.
    */
   _togglePanesButton: null,
   _stackframesAndBreakpoints: null,
   _stackframes: null,
   _breakpoints: null,
   _variables: null,
-  _globalSearch: null
+  _scripts: null,
+  _globalSearch: null,
+  _globalSearchSplitter: null,
+  _fileSearchKey: null,
+  _lineSearchKey: null,
+  _tokenSearchKey: null,
+  _globalSearchKey: null,
+  _resumeKey: null,
+  _stepOverKey: null,
+  _stepInKey: null,
+  _stepOutKey: null,
+  _resumeButton: null,
+  _stepOverButton: null,
+  _stepInButton: null,
+  _stepOutButton: null,
+  _scriptsSearchbox: null,
+  _globalOperatorLabel: null,
+  _globalOperatorButton: null,
+  _tokenOperatorLabel: null,
+  _tokenOperatorButton: null,
+  _lineOperatorLabel: null,
+  _lineOperatorButton: null
 };
 
 /**
  * A simple way of displaying a "Connect to..." prompt.
  */
 function RemoteDebuggerPrompt() {
 
   /**
@@ -240,31 +323,38 @@ RemoteDebuggerPrompt.prototype = {
  * Functions handling the global search UI.
  */
 function GlobalSearchView() {
   this._onFetchScriptFinished = this._onFetchScriptFinished.bind(this);
   this._onFetchScriptsFinished = this._onFetchScriptsFinished.bind(this);
   this._onLineClick = this._onLineClick.bind(this);
   this._onMatchClick = this._onMatchClick.bind(this);
   this._onResultsScroll = this._onResultsScroll.bind(this);
+  this._onFocusLost = this._onFocusLost.bind(this);
   this._startSearch = this._startSearch.bind(this);
 }
 
 GlobalSearchView.prototype = {
 
   /**
    * Hides or shows the search results container.
    * @param boolean value
    */
   set hidden(value) {
     this._pane.hidden = value;
     this._splitter.hidden = value;
   },
 
   /**
+   * True if the search results container is hidden.
+   * @return boolean
+   */
+  get hidden() this._pane.hidden,
+
+  /**
    * Removes all elements from the search results container, leaving it empty.
    */
   empty: function DVGS_empty() {
     while (this._pane.firstChild) {
       this._pane.removeChild(this._pane.firstChild);
     }
     this._pane.scrollTop = 0;
     this._pane.scrollLeft = 0;
@@ -376,31 +466,31 @@ GlobalSearchView.prototype = {
       return;
     }
 
     // Prepare the results map, containing search details for each script/line.
     let globalResults = new Map();
 
     for (let [url, text] of this._scriptSources) {
       // Check if the search token is not found anywhere in the script source.
-      if (text.toLowerCase().indexOf(lowerCaseToken) === -1) {
+      if (!text.toLowerCase().contains(lowerCaseToken)) {
         continue;
       }
       let lines = text.split("\n");
       let scriptResults = {
         lineResults: [],
         matchCount: 0
       };
 
       for (let i = 0, len = lines.length; i < len; i++) {
         let line = lines[i];
         let lowerCaseLine = line.toLowerCase();
 
         // Search is not case sensitive, and is tied to each line in the source.
-        if (lowerCaseLine.indexOf(lowerCaseToken) === -1) {
+        if (!lowerCaseLine.contains(lowerCaseToken)) {
           continue;
         }
 
         let lineNumber = i;
         let lineContents = [];
 
         lowerCaseLine.split(lowerCaseToken).reduce(function(prev, curr, index, {length}) {
           let unmatched = line.substr(prev.length, curr.length);
@@ -671,16 +761,30 @@ GlobalSearchView.prototype = {
     }
     if (++this._currentlyFocusedMatch >= matches.length) {
       this._currentlyFocusedMatch = 0;
     }
     this._onMatchClick({ target: matches[this._currentlyFocusedMatch] });
   },
 
   /**
+   * Focuses the previously found match in the source editor.
+   */
+  focusPrevMatch: function DVGS_focusPrevMatch() {
+    let matches = this._pane.querySelectorAll(".string[match=true]");
+    if (!matches.length) {
+      return;
+    }
+    if (--this._currentlyFocusedMatch < 0) {
+      this._currentlyFocusedMatch = matches.length - 1;
+    }
+    this._onMatchClick({ target: matches[this._currentlyFocusedMatch] });
+  },
+
+  /**
    * Called when a line in the search results container is clicked.
    */
   _onLineClick: function DVGS__onLineClick(e) {
     let firstMatch = e.target.parentNode.querySelector(".string[match=true]");
     this._onMatchClick({ target: firstMatch });
   },
 
   /**
@@ -704,16 +808,23 @@ GlobalSearchView.prototype = {
     stackframes.updateEditorToLocation(results.scriptUrl, results.lineNumber, 0, 0, 1);
 
     let editor = DebuggerView.editor;
     let offset = editor.getCaretOffset();
     editor.setSelection(offset + range.start, offset + range.start + range.length);
   },
 
   /**
+   * Listener handling the searchbox blur event.
+   */
+  _onFocusLost: function DVGS__onFocusLost(e) {
+    this.hideAndEmpty();
+  },
+
+  /**
    * Listener handling the global search container scroll event.
    */
   _onResultsScroll: function DVGS__onResultsScroll(e) {
     this._expandAllVisibleResults();
   },
 
   /**
    * Expands all the script results that are currently visible.
@@ -785,47 +896,54 @@ GlobalSearchView.prototype = {
    */
   _currentlyFocusedMatch: -1,
 
   /**
    * The cached global search results container.
    */
   _pane: null,
   _splitter: null,
+  _searchbox: null,
 
   /**
    * Initialization function, called when the debugger is initialized.
    */
-  initialize: function DVS_initialize() {
-    this._pane = document.getElementById("globalsearch");
-    this._splitter = document.getElementById("globalsearch-splitter");
+  initialize: function DVGS_initialize() {
+    this._pane = DebuggerView._globalSearch;
+    this._splitter = DebuggerView._globalSearchSplitter;
+    this._searchbox = DebuggerView._scriptsSearchbox;
 
     this._pane.addEventListener("scroll", this._onResultsScroll, false);
+    this._searchbox.addEventListener("blur", this._onFocusLost, false);
   },
 
   /**
    * Destruction function, called when the debugger is shut down.
    */
   destroy: function DVS_destroy() {
     this._pane.removeEventListener("scroll", this._onResultsScroll, false);
+    this._searchbox.removeEventListener("blur", this._onFocusLost, false);
 
     this.hideAndEmpty();
     this._pane = null;
     this._splitter = null;
+    this._searchbox = null;
     this._scriptSources = null;
   }
 };
 
 /**
  * Functions handling the scripts UI.
  */
 function ScriptsView() {
   this._onScriptsChange = this._onScriptsChange.bind(this);
+  this._onScriptsSearchClick = this._onScriptsSearchClick.bind(this);
+  this._onScriptsSearchBlur = this._onScriptsSearchBlur.bind(this);
   this._onScriptsSearch = this._onScriptsSearch.bind(this);
-  this._onScriptsKeyUp = this._onScriptsKeyUp.bind(this);
+  this._onScriptsKeyPress = this._onScriptsKeyPress.bind(this);
 }
 
 ScriptsView.prototype = {
 
   /**
    * Removes all elements from the scripts container, leaving it empty.
    */
   empty: function DVS_empty() {
@@ -1163,16 +1281,20 @@ ScriptsView.prototype = {
     }
 
     this._preferredScript = selectedItem;
     this._preferredScriptUrl = selectedItem.value;
     this._scripts.setAttribute("tooltiptext", selectedItem.value);
     DebuggerController.SourceScripts.showScript(selectedItem.getUserData("sourceScript"));
   },
 
+  _prevSearchedFile: "",
+  _prevSearchedLine: 0,
+  _prevSearchedToken: "",
+
   /**
    * Performs a file search if necessary.
    *
    * @param string aFile
    *        The script filename to search for.
    */
   _performFileSearch: function DVS__performFileSearch(aFile) {
     let scripts = this._scripts;
@@ -1250,127 +1372,179 @@ ScriptsView.prototype = {
       if (offset > -1) {
         editor.setSelection(offset, offset + aToken.length)
       }
     }
     this._prevSearchedToken = aToken;
   },
 
   /**
+   * The focus listener for the scripts search box.
+   */
+  _onScriptsSearchClick: function DVS__onScriptsSearchClick() {
+    this._searchboxPanel.openPopup(this._searchbox);
+  },
+
+  /**
+   * The blur listener for the scripts search box.
+   */
+  _onScriptsSearchBlur: function DVS__onScriptsSearchBlur() {
+    this._searchboxPanel.hidePopup();
+  },
+
+  /**
    * The search listener for the scripts search box.
    */
   _onScriptsSearch: function DVS__onScriptsSearch() {
     // If the webpage has no scripts, searching is redundant.
     if (!this._scripts.itemCount) {
       return;
     }
+    this._searchboxPanel.hidePopup();
+
     let [file, line, token, isGlobal] = this.searchboxInfo;
 
     // If this is a global script search, schedule a search in all the sources,
     // or hide the pane otherwise.
     if (isGlobal) {
       DebuggerView.GlobalSearch.scheduleSearch();
     } else {
       DebuggerView.GlobalSearch.hideAndEmpty();
       this._performFileSearch(file);
       this._performLineSearch(line);
       this._performTokenSearch(token);
     }
   },
 
   /**
-   * The keyup listener for the scripts search box.
+   * The keypress listener for the scripts search box.
    */
-  _onScriptsKeyUp: function DVS__onScriptsKeyUp(e) {
+  _onScriptsKeyPress: function DVS__onScriptsKeyPress(e) {
     if (e.keyCode === e.DOM_VK_ESCAPE) {
       DebuggerView.editor.focus();
       return;
     }
-
-    if (e.keyCode === e.DOM_VK_RETURN || e.keyCode === e.DOM_VK_ENTER) {
-      let token = this.searchboxInfo[2];
-      let isGlobal = this.searchboxInfo[3];
-
-      if (!token.length) {
+    var action;
+
+    if (e.keyCode === e.DOM_VK_DOWN ||
+        e.keyCode === e.DOM_VK_RETURN ||
+        e.keyCode === e.DOM_VK_ENTER) {
+      action = 1;
+    } else if (e.keyCode === e.DOM_VK_UP) {
+      action = 2;
+    }
+
+    if (action) {
+      let [file, line, token, isGlobal] = this.searchboxInfo;
+
+      if (token.length) {
+        e.preventDefault();
+        e.stopPropagation();
+      } else {
         return;
       }
       if (isGlobal) {
-        DebuggerView.GlobalSearch.focusNextMatch();
+        if (DebuggerView.GlobalSearch.hidden) {
+          DebuggerView.GlobalSearch.scheduleSearch();
+        } else {
+          DebuggerView.GlobalSearch[action === 1
+            ? "focusNextMatch"
+            : "focusPrevMatch"]();
+        }
         return;
       }
 
       let editor = DebuggerView.editor;
-      let offset = editor.findNext(true);
+      let offset = editor[action === 1 ? "findNext" : "findPrevious"](true);
       if (offset > -1) {
         editor.setSelection(offset, offset + token.length)
       }
     }
   },
 
   /**
    * Called when the scripts filter key sequence was pressed.
    */
   _onSearch: function DVS__onSearch(aValue = "") {
     this._searchbox.focus();
     this._searchbox.value = aValue;
     DebuggerView.GlobalSearch.hideAndEmpty();
   },
 
   /**
+   * Called when the scripts path filter key sequence was pressed.
+   */
+  _onFileSearch: function DVS__onFileSearch() {
+    this._onSearch();
+    this._searchboxPanel.openPopup(this._searchbox);
+  },
+
+  /**
    * Called when the scripts token filter key sequence was pressed.
    */
   _onLineSearch: function DVS__onLineSearch() {
     this._onSearch(SEARCH_LINE_FLAG);
+    this._searchboxPanel.hidePopup();
   },
 
   /**
    * Called when the scripts token filter key sequence was pressed.
    */
   _onTokenSearch: function DVS__onTokenSearch() {
     this._onSearch(SEARCH_TOKEN_FLAG);
+    this._searchboxPanel.hidePopup();
   },
 
   /**
    * Called when the scripts token filter key sequence was pressed.
    */
   _onGlobalSearch: function DVS__onGlobalSearch() {
     this._onSearch(SEARCH_GLOBAL_FLAG);
+    this._searchboxPanel.hidePopup();
   },
 
   /**
    * The cached scripts container and search box.
    */
   _scripts: null,
   _searchbox: null,
+  _searchboxPanel: null,
 
   /**
    * Initialization function, called when the debugger is initialized.
    */
   initialize: function DVS_initialize() {
-    this._scripts = document.getElementById("scripts");
+    this._scripts = DebuggerView._scripts;
     this._searchbox = document.getElementById("scripts-search");
+    this._searchboxPanel = document.getElementById("scripts-search-panel");
+
     this._scripts.addEventListener("select", this._onScriptsChange, false);
+    this._searchbox.addEventListener("click", this._onScriptsSearchClick, false);
+    this._searchbox.addEventListener("blur", this._onScriptsSearchBlur, false);
     this._searchbox.addEventListener("select", this._onScriptsSearch, false);
     this._searchbox.addEventListener("input", this._onScriptsSearch, false);
-    this._searchbox.addEventListener("keyup", this._onScriptsKeyUp, false);
+    this._searchbox.addEventListener("keypress", this._onScriptsKeyPress, false);
     this.commitScripts();
   },
 
   /**
    * Destruction function, called when the debugger is shut down.
    */
   destroy: function DVS_destroy() {
     this._scripts.removeEventListener("select", this._onScriptsChange, false);
+    this._searchbox.removeEventListener("click", this._onScriptsSearchClick, false);
+    this._searchbox.removeEventListener("blur", this._onScriptsSearchBlur, false);
     this._searchbox.removeEventListener("select", this._onScriptsSearch, false);
     this._searchbox.removeEventListener("input", this._onScriptsSearch, false);
-    this._searchbox.removeEventListener("keyup", this._onScriptsKeyUp, false);
+    this._searchbox.removeEventListener("keypress", this._onScriptsKeyPress, false);
 
     this.empty();
     this._scripts = null;
     this._searchbox = null;
+    this._searchboxPanel = null;
   }
 };
 
 /**
  * Functions handling the html stackframes UI.
  */
 function StackFramesView() {
   this._onFramesScroll = this._onFramesScroll.bind(this);
@@ -1379,36 +1553,37 @@ function StackFramesView() {
   this._onResume = this._onResume.bind(this);
   this._onStepOver = this._onStepOver.bind(this);
   this._onStepIn = this._onStepIn.bind(this);
   this._onStepOut = this._onStepOut.bind(this);
 }
 
 StackFramesView.prototype = {
 
-  /**
-   * Sets the current frames state based on the debugger active thread state.
-   *
-   * @param string aState
-   *        Either "paused" or "attached".
-   */
-   updateState: function DVF_updateState(aState) {
-     let resume = document.getElementById("resume");
-
-     // If we're paused, show a pause label and a resume label on the button.
-     if (aState == "paused") {
-       resume.setAttribute("tooltiptext", L10N.getStr("resumeTooltip"));
-       resume.setAttribute("checked", true);
-     }
-     // If we're attached, do the opposite.
-     else if (aState == "attached") {
-       resume.setAttribute("tooltiptext", L10N.getStr("pauseTooltip"));
-       resume.removeAttribute("checked");
-     }
-   },
+ /**
+  * Sets the current frames state based on the debugger active thread state.
+  *
+  * @param string aState
+  *        Either "paused" or "attached".
+  */
+  updateState: function DVF_updateState(aState) {
+    let resume = DebuggerView._resumeButton;
+    let resumeKey = LayoutHelpers.prettyKey(DebuggerView._resumeKey);
+
+    // If we're paused, show a pause label and a resume label on the button.
+    if (aState == "paused") {
+      resume.setAttribute("tooltiptext", L10N.getFormatStr("resumeButtonTooltip", [resumeKey]));
+      resume.setAttribute("checked", true);
+    }
+    // If we're attached, do the opposite.
+    else if (aState == "attached") {
+      resume.setAttribute("tooltiptext", L10N.getFormatStr("pauseButtonTooltip", [resumeKey]));
+      resume.removeAttribute("checked");
+    }
+  },
 
   /**
    * Removes all elements from the stackframes container, leaving it empty.
    */
   empty: function DVF_empty() {
     while (this._frames.firstChild) {
       this._frames.removeChild(this._frames.firstChild);
     }
@@ -1633,21 +1808,21 @@ StackFramesView.prototype = {
   _frames: null,
 
   /**
    * Initialization function, called when the debugger is initialized.
    */
   initialize: function DVF_initialize() {
     let close = document.getElementById("close");
     let pauseOnExceptions = document.getElementById("pause-exceptions");
-    let resume = document.getElementById("resume");
-    let stepOver = document.getElementById("step-over");
-    let stepIn = document.getElementById("step-in");
-    let stepOut = document.getElementById("step-out");
-    let frames = document.getElementById("stackframes");
+    let resume = DebuggerView._resumeButton;
+    let stepOver = DebuggerView._stepOverButton;
+    let stepIn = DebuggerView._stepInButton;
+    let stepOut = DebuggerView._stepOutButton;
+    let frames = DebuggerView._stackframes;
 
     close.addEventListener("click", this._onCloseButtonClick, false);
     pauseOnExceptions.checked = DebuggerController.StackFrames.pauseOnExceptions;
     pauseOnExceptions.addEventListener("click", this._onPauseExceptionsClick, false);
     resume.addEventListener("click", this._onResume, false);
     stepOver.addEventListener("click", this._onStepOver, false);
     stepIn.addEventListener("click", this._onStepIn, false);
     stepOut.addEventListener("click", this._onStepOut, false);
@@ -1660,21 +1835,21 @@ StackFramesView.prototype = {
   },
 
   /**
    * Destruction function, called when the debugger is shut down.
    */
   destroy: function DVF_destroy() {
     let close = document.getElementById("close");
     let pauseOnExceptions = document.getElementById("pause-exceptions");
-    let resume = document.getElementById("resume");
-    let stepOver = document.getElementById("step-over");
-    let stepIn = document.getElementById("step-in");
-    let stepOut = document.getElementById("step-out");
-    let frames = this._frames;
+    let resume = DebuggerView._resumeButton;
+    let stepOver = DebuggerView._stepOverButton;
+    let stepIn = DebuggerView._stepInButton;
+    let stepOut = DebuggerView._stepOutButton;
+    let frames = DebuggerView._stackframes;
 
     close.removeEventListener("click", this._onCloseButtonClick, false);
     pauseOnExceptions.removeEventListener("click", this._onPauseExceptionsClick, false);
     resume.removeEventListener("click", this._onResume, false);
     stepOver.removeEventListener("click", this._onStepOver, false);
     stepIn.removeEventListener("click", this._onStepIn, false);
     stepOut.removeEventListener("click", this._onStepOut, false);
     frames.removeEventListener("click", this._onFramesClick, false);
@@ -2203,17 +2378,17 @@ BreakpointsView.prototype = {
     commandset.parentNode.removeChild(commandset);
     menupopup.parentNode.removeChild(menupopup);
   },
 
   /**
    * Initialization function, called when the debugger is initialized.
    */
   initialize: function DVB_initialize() {
-    let breakpoints = document.getElementById("breakpoints");
+    let breakpoints = DebuggerView._breakpoints;
     breakpoints.addEventListener("click", this._onBreakpointClick, false);
 
     this._breakpoints = breakpoints;
     this.emptyText();
   },
 
   /**
    * Destruction function, called when the debugger is shut down.
@@ -3309,17 +3484,17 @@ PropertiesView.prototype = {
    * The cached variable properties container.
    */
   _vars: null,
 
   /**
    * Initialization function, called when the debugger is initialized.
    */
   initialize: function DVP_initialize() {
-    this._vars = document.getElementById("variables");
+    this._vars = DebuggerView._variables;
 
     this.emptyText();
     this.createHierarchyStore();
   },
 
   /**
    * Destruction function, called when the debugger is shut down.
    */
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -32,33 +32,33 @@
       <menuitem id="se-cMenu-gotoLine"/>
     </menupopup>
   </popupset>
 
   <commandset id="editMenuCommands"/>
   <commandset id="sourceEditorCommands"/>
   <keyset id="sourceEditorKeys"/>
   <keyset id="scriptSearchKeys">
-    <key key="P" modifiers="access shift"
-         oncommand="DebuggerView.Scripts._onSearch()"/>
-    <key key="G" modifiers="access shift"
+    <key id="fileSearchKey" key="P" modifiers="access shift"
+         oncommand="DebuggerView.Scripts._onFileSearch()"/>
+    <key id="lineSearchKey" key="G" modifiers="access shift"
          oncommand="DebuggerView.Scripts._onLineSearch()"/>
-    <key key="T" modifiers="access shift"
+    <key id="tokenSearchKey" key="T" modifiers="access shift"
          oncommand="DebuggerView.Scripts._onTokenSearch()"/>
-    <key key="F" modifiers="access shift"
+    <key id="globalSearchKey" key="F" modifiers="access shift"
          oncommand="DebuggerView.Scripts._onGlobalSearch()"/>
   </keyset>
   <keyset id="threadStateKeys">
-    <key keycode="VK_F6"
+    <key id="resumeKey" keycode="VK_F6"
          oncommand="DebuggerView.StackFrames._onResume()"/>
-    <key keycode="VK_F7"
+    <key id="stepOverKey" keycode="VK_F7"
          oncommand="DebuggerView.StackFrames._onStepOver()"/>
-    <key keycode="VK_F8"
+    <key id="stepInKey" keycode="VK_F8"
          oncommand="DebuggerView.StackFrames._onStepIn()"/>
-    <key keycode="VK_F8" modifiers="shift"
+    <key id="stepOutKey" keycode="VK_F8" modifiers="shift"
          oncommand="DebuggerView.StackFrames._onStepOut()"/>
   </keyset>
 
   <vbox id="body" flex="1">
     <toolbar id="dbg-toolbar" class="devtools-toolbar">
 #ifdef XP_MACOSX
       <toolbarbutton id="close"
                      tooltiptext="&debuggerUI.closeButton.tooltip;"
@@ -69,46 +69,65 @@
                      tabindex="0"/>
       <hbox id="debugger-controls">
         <toolbarbutton id="resume"
                        class="devtools-toolbarbutton"
                        type="checkbox"
                        tabindex="0"/>
         <toolbarbutton id="step-over"
                        class="devtools-toolbarbutton"
-                       tooltiptext="&debuggerUI.stepOverButton.tooltip;"
                        tabindex="0"/>
         <toolbarbutton id="step-in"
                        class="devtools-toolbarbutton"
-                       tooltiptext="&debuggerUI.stepInButton.tooltip;"
                        tabindex="0"/>
         <toolbarbutton id="step-out"
                        class="devtools-toolbarbutton"
-                       tooltiptext="&debuggerUI.stepOutButton.tooltip;"
                        tabindex="0"/>
       </hbox>
       <menulist id="scripts" class="devtools-menulist"
                 sizetopopup="always"
                 label="&debuggerUI.emptyScriptText;"/>
       <textbox id="scripts-search" type="search"
-               class="devtools-searchinput"
-               emptytext="&debuggerUI.emptyFilterText;"/>
+               class="devtools-searchinput"/>
       <checkbox id="pause-exceptions"
                 type="checkbox"
                 tabindex="0"
                 label="&debuggerUI.pauseExceptions;"/>
       <spacer flex="1"/>
 #ifndef XP_MACOSX
       <toolbarbutton id="close"
                      tooltiptext="&debuggerUI.closeButton.tooltip;"
                      class="devtools-closebutton"/>
 #endif
     </toolbar>
+    <panel id="scripts-search-panel"
+           type="arrow"
+           noautofocus="true"
+           position="before_start">
+      <vbox>
+        <label class="description" value="&debuggerUI.searchPanelTitle;"/>
+        <hbox align="center">
+          <button id="global-operator-button" class="operator"
+                  onclick="DebuggerView.Scripts._onGlobalSearch()"/>
+          <label id="global-operator-label" class="plain operator"/>
+        </hbox>
+        <hbox align="center">
+          <button id="token-operator-button" class="operator"
+                  onclick="DebuggerView.Scripts._onTokenSearch()"/>
+          <label id="token-operator-label" class="plain operator"/>
+        </hbox>
+        <hbox align="center">
+          <button id="line-operator-button" class="operator"
+                  onclick="DebuggerView.Scripts._onLineSearch()"/>
+          <label id="line-operator-label" class="plain operator"/>
+        </hbox>
+      </vbox>
+    </panel>
     <vbox id="dbg-content" flex="1">
-      <vbox id="globalsearch" hidden="true" flex="1"/>
+      <vbox id="globalsearch" hidden="true"/>
       <splitter id="globalsearch-splitter"
                 class="devtools-horizontal-splitter" hidden="true"/>
       <hbox flex="1">
         <vbox id="stackframes+breakpoints">
           <vbox id="stackframes" flex="1"/>
           <splitter class="devtools-horizontal-splitter"/>
           <vbox id="breakpoints"/>
         </vbox>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -51,16 +51,18 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_scripts-sorting.js \
 	browser_dbg_scripts-searching-01.js \
 	browser_dbg_scripts-searching-02.js \
 	browser_dbg_scripts-searching-03.js \
 	browser_dbg_scripts-searching-04.js \
 	browser_dbg_scripts-searching-05.js \
 	browser_dbg_scripts-searching-06.js \
 	browser_dbg_scripts-searching-07.js \
+	browser_dbg_scripts-searching-08.js \
+	browser_dbg_scripts-searching-popup.js \
 	browser_dbg_pause-resume.js \
 	browser_dbg_update-editor-mode.js \
 	$(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \
 	browser_dbg_clean-exit.js \
 	browser_dbg_bug723069_editor-breakpoints.js \
 	browser_dbg_bug723071_editor-breakpoints-pane.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
 	browser_dbg_displayName.js \
--- a/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js
@@ -65,16 +65,18 @@ function test()
       "Should only be getting stack frames while paused.");
 
     is(scripts.itemCount, 2, "Found the expected number of scripts.");
 
     let editor = gDebugger.editor;
 
     isnot(editor.getText().indexOf("debugger"), -1,
           "The correct script was loaded initially.");
+    isnot(editor.getText().indexOf("\u263a"), -1,
+      "Unicode characters are converted correctly.");
 
     contextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
     ok(contextMenu, "source editor context menupopup");
     ok(editor.readOnly, "editor is read only");
 
     editor.focus();
     editor.setSelection(0, 10);
 
--- a/browser/devtools/debugger/test/browser_dbg_menustatus.js
+++ b/browser/devtools/debugger/test/browser_dbg_menustatus.js
@@ -11,38 +11,35 @@ function test() {
   var tab1 = addTab("about:blank", function() {
     var tab2 = addTab("about:blank", function() {
       gBrowser.selectedTab = tab2;
 
       let pane = DebuggerUI.toggleDebugger();
       ok(pane, "toggleDebugger() should return a pane.");
       let frame = pane._frame;
 
-      frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
-        frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
-
+      wait_for_connect_and_resume(function() {
         let cmd = document.getElementById("Tools:Debugger");
         is(cmd.getAttribute("checked"), "true", "<command Tools:Debugger> is checked.");
 
         gBrowser.selectedTab = tab1;
 
         is(cmd.getAttribute("checked"), "false", "<command Tools:Debugger> is unchecked after tab switch.");
 
         gBrowser.selectedTab = tab2;
 
         is(cmd.getAttribute("checked"), "true", "<command Tools:Debugger> is checked.");
 
         let pane = DebuggerUI.toggleDebugger();
 
         is(cmd.getAttribute("checked"), "false", "<command Tools:Debugger> is unchecked once closed.");
-      }, true);
+      });
 
-      frame.addEventListener("Debugger:Unloaded", function dbgUnloaded() {
-        frame.removeEventListener("Debugger:Unloaded", dbgUnloaded, true);
+      window.addEventListener("Debugger:Shutdown", function dbgShutdown() {
+        window.removeEventListener("Debugger:Shutdown", dbgShutdown, true);
           removeTab(tab1);
           removeTab(tab2);
 
           finish();
       }, true);
     });
   });
 }
-
--- a/browser/devtools/debugger/test/browser_dbg_panesize-inner.js
+++ b/browser/devtools/debugger/test/browser_dbg_panesize-inner.js
@@ -15,24 +15,21 @@ function test() {
     let someWidth1 = parseInt(Math.random() * 200) + 100;
     let someWidth2 = parseInt(Math.random() * 200) + 100;
 
     ok(pane, "toggleDebugger() should return a pane.");
 
     is(DebuggerUI.getDebugger(), pane,
       "getDebugger() should return the same pane as toggleDebugger().");
 
-    let frame = pane._frame;
     let content = pane.contentWindow;
     let stackframes;
     let variables;
 
-    frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
-      frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
-
+    wait_for_connect_and_resume(function() {
       ok(content.Prefs.stackframesWidth,
         "The debugger preferences should have a saved stackframesWidth value.");
       ok(content.Prefs.variablesWidth,
         "The debugger preferences should have a saved variablesWidth value.");
 
       stackframes = content.document.getElementById("stackframes+breakpoints");
       variables = content.document.getElementById("variables");
 
@@ -40,21 +37,20 @@ function test() {
         "The stackframes pane width should be the same as the preferred value.");
       is(content.Prefs.variablesWidth, variables.getAttribute("width"),
         "The variables pane width should be the same as the preferred value.");
 
       stackframes.setAttribute("width", someWidth1);
       variables.setAttribute("width", someWidth2);
 
       removeTab(tab1);
-
-    }, true);
+    });
 
-    frame.addEventListener("Debugger:Unloaded", function dbgUnloaded() {
-      frame.removeEventListener("Debugger:Unloaded", dbgUnloaded, true);
+    window.addEventListener("Debugger:Shutdown", function dbgShutdown() {
+      window.removeEventListener("Debugger:Shutdown", dbgShutdown, true);
 
       is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
         "The stackframes pane width should have been saved by now.");
       is(content.Prefs.variablesWidth, variables.getAttribute("width"),
         "The variables pane width should have been saved by now.");
 
       finish();
 
--- a/browser/devtools/debugger/test/browser_dbg_pause-resume.js
+++ b/browser/devtools/debugger/test/browser_dbg_pause-resume.js
@@ -2,45 +2,53 @@
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var gPane = null;
 var gTab = null;
 var gDebugger = null;
+var gView = null;
+var gLH = null;
+var gL10N = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
     gDebugger = gPane.contentWindow;
+    gView = gDebugger.DebuggerView;
+    gLH = gDebugger.LayoutHelpers;
+    gL10N = gDebugger.L10N;
 
     testPause();
   });
 }
 
 function testPause() {
   is(gDebugger.DebuggerController.activeThread.paused, false,
     "Should be running after debug_tab_pane.");
 
   let button = gDebugger.document.getElementById("resume");
-  is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("pauseTooltip"),
+  is(button.getAttribute("tooltiptext"),
+     gL10N.getFormatStr("pauseButtonTooltip", [gLH.prettyKey(gView._resumeKey)]),
     "Button tooltip should be pause when running.");
 
   gDebugger.DebuggerController.activeThread.addOneTimeListener("paused", function() {
     Services.tm.currentThread.dispatch({ run: function() {
 
       let frames = gDebugger.DebuggerView.StackFrames._frames;
       let childNodes = frames.childNodes;
 
       is(gDebugger.DebuggerController.activeThread.paused, true,
         "Should be paused after an interrupt request.");
 
-      is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("resumeTooltip"),
+      is(button.getAttribute("tooltiptext"),
+         gL10N.getFormatStr("resumeButtonTooltip", [gLH.prettyKey(gView._resumeKey)]),
         "Button tooltip should be resume when paused.");
 
       is(frames.querySelectorAll(".dbg-stackframe").length, 0,
         "Should have no frames when paused in the main loop.");
 
       testResume();
     }}, 0);
   });
@@ -53,25 +61,30 @@ function testPause() {
 function testResume() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
     Services.tm.currentThread.dispatch({ run: function() {
 
       is(gDebugger.DebuggerController.activeThread.paused, false,
         "Should be paused after an interrupt request.");
 
       let button = gDebugger.document.getElementById("resume");
-      is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("pauseTooltip"),
+      is(button.getAttribute("tooltiptext"),
+         gL10N.getFormatStr("pauseButtonTooltip", [gLH.prettyKey(gView._resumeKey)]),
         "Button tooltip should be pause when running.");
 
       closeDebuggerAndFinish();
     }}, 0);
   });
 
   EventUtils.sendMouseEvent({ type: "click" },
     gDebugger.document.getElementById("resume"),
     gDebugger);
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
+  gDebugger = null;
+  gView = null;
+  gLH = null;
+  gL10N = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
@@ -6,16 +6,20 @@ var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 var gEditor = null;
 var gScripts = null;
 var gSearchBox = null;
 var gMenulist = null;
 
+/**
+ * Tests basic functionality of scripts filtering (token search and line jump).
+ */
+
 function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
@@ -59,36 +63,41 @@ function testScriptSearching() {
       "The editor didn't jump to the correct line.");
 
     token = "debugger";
     write("#" + token);
     ok(gEditor.getCaretPosition().line == 2 &&
        gEditor.getCaretPosition().col == 44 + token.length,
       "The editor didn't jump to the correct token. (1)");
 
-    EventUtils.sendKey("RETURN");
+    EventUtils.sendKey("DOWN");
     ok(gEditor.getCaretPosition().line == 8 &&
        gEditor.getCaretPosition().col == 2 + token.length,
       "The editor didn't jump to the correct token. (2)");
 
-    EventUtils.sendKey("ENTER");
+    EventUtils.sendKey("DOWN");
     ok(gEditor.getCaretPosition().line == 12 &&
        gEditor.getCaretPosition().col == 8 + token.length,
       "The editor didn't jump to the correct token. (3)");
 
-    EventUtils.sendKey("ENTER");
+    EventUtils.sendKey("RETURN");
     ok(gEditor.getCaretPosition().line == 19 &&
        gEditor.getCaretPosition().col == 4 + token.length,
       "The editor didn't jump to the correct token. (4)");
 
-    EventUtils.sendKey("RETURN");
+    EventUtils.sendKey("ENTER");
     ok(gEditor.getCaretPosition().line == 2 &&
        gEditor.getCaretPosition().col == 44 + token.length,
       "The editor didn't jump to the correct token. (5)");
 
+    EventUtils.sendKey("UP");
+    ok(gEditor.getCaretPosition().line == 19 &&
+       gEditor.getCaretPosition().col == 4 + token.length,
+      "The editor didn't jump to the correct token. (5.1)");
+
 
     token = "debugger;";
     write(":bogus#" + token);
     ok(gEditor.getCaretPosition().line == 8 &&
        gEditor.getCaretPosition().col == 2 + token.length,
       "The editor didn't jump to the correct token. (6)");
 
     write(":13#" + token);
@@ -147,40 +156,45 @@ function testScriptSearching() {
       "The editor didn't jump to the correct line. (13)");
 
     write("#don't#find#me#instead#find#" + token);
     ok(gEditor.getCaretPosition().line == 2 &&
        gEditor.getCaretPosition().col == 44 + token.length,
       "The editor didn't jump to the correct token. (14)");
 
 
-    EventUtils.sendKey("RETURN");
+    EventUtils.sendKey("DOWN");
     ok(gEditor.getCaretPosition().line == 8 &&
        gEditor.getCaretPosition().col == 2 + token.length,
       "The editor didn't jump to the correct token. (15)");
 
-    EventUtils.sendKey("ENTER");
+    EventUtils.sendKey("DOWN");
     ok(gEditor.getCaretPosition().line == 12 &&
        gEditor.getCaretPosition().col == 8 + token.length,
       "The editor didn't jump to the correct token. (16)");
 
     EventUtils.sendKey("RETURN");
     ok(gEditor.getCaretPosition().line == 19 &&
        gEditor.getCaretPosition().col == 4 + token.length,
       "The editor didn't jump to the correct token. (17)");
 
     EventUtils.sendKey("ENTER");
     ok(gEditor.getCaretPosition().line == 2 &&
        gEditor.getCaretPosition().col == 44 + token.length,
       "The editor didn't jump to the correct token. (18)");
 
+    EventUtils.sendKey("UP");
+    ok(gEditor.getCaretPosition().line == 19 &&
+       gEditor.getCaretPosition().col == 4 + token.length,
+      "The editor didn't jump to the correct token. (18.1)");
+
 
     clear();
-    ok(gEditor.getCaretPosition().line == 2 &&
-       gEditor.getCaretPosition().col == 44 + token.length,
+    ok(gEditor.getCaretPosition().line == 19 &&
+       gEditor.getCaretPosition().col == 4 + token.length,
       "The editor didn't remain at the correct token. (19)");
     is(gScripts.visibleItemsCount, 1,
       "Not all the scripts are shown after the search. (20)");
 
     closeDebuggerAndFinish();
   });
 }
 
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js
@@ -1,14 +1,18 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
 
+/**
+ * Tests basic functionality of scripts filtering (file search).
+ */
+
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 var gEditor = null;
 var gScripts = null;
 var gSearchBox = null;
 var gMenulist = null;
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-03.js
@@ -1,14 +1,19 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
 
+/**
+ * Tests basic functionality of global search (lowercase + upper case, expected
+ * UI behavior, number of results found etc.)
+ */
+
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 var gEditor = null;
 var gScripts = null;
 var gSearchView = null;
 var gSearchBox = null;
@@ -317,10 +322,11 @@ function append(text) {
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
   gDebuggee = null;
   gDebugger = null;
   gEditor = null;
   gScripts = null;
+  gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-04.js
@@ -1,14 +1,19 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
 
+/**
+ * Tests if the global search results switch back and forth, and wrap around
+ * when switching between them.
+ */
+
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 var gEditor = null;
 var gScripts = null;
 var gSearchView = null;
 var gSearchBox = null;
@@ -119,17 +124,17 @@ function doFirstJump() {
 
         doSecondJump();
       });
     } else {
       ok(false, "We jumped in a bowl of hot lava (aka WRONG MATCH). That was bad for us.");
     }
   });
   executeSoon(function() {
-    EventUtils.sendKey("ENTER");
+    EventUtils.sendKey("DOWN");
   });
 }
 
 function doSecondJump() {
   window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
     window.removeEventListener(aEvent.type, _onEvent);
     info("Current script url:\n" + aEvent.detail.url + "\n");
     info("Debugger editor text:\n" + gEditor.getText() + "\n");
@@ -146,17 +151,17 @@ function doSecondJump() {
 
         doWrapAroundJump();
       });
     } else {
       ok(false, "We jumped in a bowl of hot lava (aka WRONG MATCH). That was bad for us.");
     }
   });
   executeSoon(function() {
-    EventUtils.sendKey("ENTER");
+    EventUtils.sendKey("RETURN");
   });
 }
 
 function doWrapAroundJump() {
   window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
     window.removeEventListener(aEvent.type, _onEvent);
     info("Current script url:\n" + aEvent.detail.url + "\n");
     info("Debugger editor text:\n" + gEditor.getText() + "\n");
@@ -166,42 +171,69 @@ function doWrapAroundJump() {
       executeSoon(function() {
         info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
         ok(gEditor.getCaretPosition().line == 4 &&
            gEditor.getCaretPosition().col == 6,
           "The editor didn't jump to the correct line. (3)");
         is(gScripts.visibleItemsCount, 2,
           "Not all the correct scripts are shown after the search. (3)");
 
-        testSearchTokenEmpty();
+        doBackwardsWrapAroundJump();
       });
     } else {
       ok(false, "We jumped in a bowl of hot lava (aka WRONG MATCH). That was bad for us.");
     }
   });
   executeSoon(function() {
     EventUtils.sendKey("ENTER");
   });
 }
 
+function doBackwardsWrapAroundJump() {
+  window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
+    window.removeEventListener(aEvent.type, _onEvent);
+    info("Current script url:\n" + aEvent.detail.url + "\n");
+    info("Debugger editor text:\n" + gEditor.getText() + "\n");
+
+    let url = aEvent.detail.url;
+    if (url.indexOf("-02.js") != -1) {
+      executeSoon(function() {
+        info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
+        ok(gEditor.getCaretPosition().line == 5 &&
+           gEditor.getCaretPosition().col == 6,
+          "The editor didn't jump to the correct line. (4)");
+        is(gScripts.visibleItemsCount, 2,
+          "Not all the correct scripts are shown after the search. (4)");
+
+        testSearchTokenEmpty();
+      });
+    } else {
+      ok(false, "We jumped in a bowl of hot lava (aka WRONG MATCH). That was bad for us.");
+    }
+  });
+  executeSoon(function() {
+    EventUtils.sendKey("UP");
+  });
+}
+
 function testSearchTokenEmpty() {
   window.addEventListener("Debugger:GlobalSearch:TokenEmpty", function _onEvent(aEvent) {
     window.removeEventListener(aEvent.type, _onEvent);
     info("Current script url:\n" + gScripts.selected + "\n");
     info("Debugger editor text:\n" + gEditor.getText() + "\n");
 
     let url = gScripts.selected;
-    if (url.indexOf("-01.js") != -1) {
+    if (url.indexOf("-02.js") != -1) {
       executeSoon(function() {
         info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
-        ok(gEditor.getCaretPosition().line == 4 &&
+        ok(gEditor.getCaretPosition().line == 5 &&
            gEditor.getCaretPosition().col == 6,
-          "The editor didn't remain at the correct line. (4)");
+          "The editor didn't remain at the correct line. (5)");
         is(gScripts.visibleItemsCount, 2,
-          "Not all the correct scripts are shown after the search. (4)");
+          "Not all the correct scripts are shown after the search. (5)");
 
         is(gSearchView._pane.childNodes.length, 0,
           "The global search pane shouldn't have any child nodes after clear().");
         is(gSearchView._pane.hidden, true,
           "The global search pane shouldn't be visible after clear().");
         is(gSearchView._splitter.hidden, true,
           "The global search pane splitter shouldn't be visible after clear().");
 
@@ -242,10 +274,11 @@ function append(text) {
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
   gDebuggee = null;
   gDebugger = null;
   gEditor = null;
   gScripts = null;
+  gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-05.js
@@ -1,14 +1,19 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
 
+/**
+ * Tests if the global search results are cleared on location changes, and
+ * the expected UI behaviors are triggered.
+ */
+
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 var gEditor = null;
 var gScripts = null;
 var gSearchView = null;
 var gSearchBox = null;
@@ -161,10 +166,11 @@ function append(text) {
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
   gDebuggee = null;
   gDebugger = null;
   gEditor = null;
   gScripts = null;
+  gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-06.js
@@ -1,14 +1,19 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
 
+/**
+ * Tests if the global search results trigger MatchFound and NoMatchFound events
+ * properly, and triggers the expected UI behavior.
+ */
+
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 var gEditor = null;
 var gScripts = null;
 var gSearchView = null;
 var gSearchBox = null;
@@ -134,10 +139,11 @@ function append(text) {
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
   gDebuggee = null;
   gDebugger = null;
   gEditor = null;
   gScripts = null;
+  gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-07.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-07.js
@@ -1,14 +1,20 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
 
+/**
+ * Tests if the global search results are expanded on scroll or click, and
+ * clicking matches makes the source editor shows the correct script and
+ * makes a selection based on the match.
+ */
+
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 var gEditor = null;
 var gScripts = null;
 var gSearchView = null;
 var gSearchBox = null;
@@ -238,10 +244,11 @@ function append(text) {
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
   gDebuggee = null;
   gDebugger = null;
   gEditor = null;
   gScripts = null;
+  gSearchView = null;
   gSearchBox = null;
 });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-08.js
@@ -0,0 +1,209 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+
+/**
+ * Tests if the global search results are hidden when they're supposed to
+ * (after a focus lost, or when ESCAPE is pressed).
+ */
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+var gEditor = null;
+var gScripts = null;
+var gSearchView = null;
+var gSearchBox = null;
+
+function test()
+{
+  let scriptShown = false;
+  let framesAdded = false;
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+
+    gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
+      framesAdded = true;
+      runTest();
+    });
+
+    gDebuggee.firstCall();
+  });
+
+  window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
+    let url = aEvent.detail.url;
+    if (url.indexOf("-02.js") != -1) {
+      scriptShown = true;
+      window.removeEventListener(aEvent.type, _onEvent);
+      runTest();
+    }
+  });
+
+  function runTest()
+  {
+    if (scriptShown && framesAdded) {
+      Services.tm.currentThread.dispatch({ run: testScriptSearching }, 0);
+    }
+  }
+}
+
+function testScriptSearching() {
+  gDebugger.DebuggerController.activeThread.resume(function() {
+    gEditor = gDebugger.DebuggerView.editor;
+    gScripts = gDebugger.DebuggerView.Scripts;
+    gSearchView = gDebugger.DebuggerView.GlobalSearch;
+    gSearchBox = gScripts._searchbox;
+
+    doSearch();
+  });
+}
+
+function doSearch() {
+  is(gSearchView._pane.hidden, true,
+    "The global search pane shouldn't be visible yet.");
+
+  window.addEventListener("Debugger:GlobalSearch:MatchFound", function _onEvent(aEvent) {
+    window.removeEventListener(aEvent.type, _onEvent);
+    info("Current script url:\n" + gScripts.selected + "\n");
+    info("Debugger editor text:\n" + gEditor.getText() + "\n");
+
+    let url = gScripts.selected;
+    if (url.indexOf("-02.js") != -1) {
+      executeSoon(function() {
+        testFocusLost();
+      });
+    } else {
+      ok(false, "The current script shouldn't have changed after a global search.");
+    }
+  });
+  executeSoon(function() {
+    write("!a");
+  });
+}
+
+function testFocusLost()
+{
+  is(gSearchView._pane.hidden, false,
+    "The global search pane should be visible after a search.");
+
+  window.addEventListener("Debugger:GlobalSearch:ViewCleared", function _onEvent(aEvent) {
+    window.removeEventListener(aEvent.type, _onEvent);
+    info("Current script url:\n" + gScripts.selected + "\n");
+    info("Debugger editor text:\n" + gEditor.getText() + "\n");
+
+    let url = gScripts.selected;
+    if (url.indexOf("-02.js") != -1) {
+      executeSoon(function() {
+        reshowSearch();
+      });
+    } else {
+      ok(false, "The current script shouldn't have changed after the global search stopped.");
+    }
+  });
+  executeSoon(function() {
+    gDebugger.DebuggerView.editor.focus();
+  });
+}
+
+function reshowSearch() {
+  is(gSearchView._pane.hidden, true,
+    "The global search pane shouldn't be visible after the search was stopped.");
+
+  window.addEventListener("Debugger:GlobalSearch:MatchFound", function _onEvent(aEvent) {
+    window.removeEventListener(aEvent.type, _onEvent);
+    info("Current script url:\n" + gScripts.selected + "\n");
+    info("Debugger editor text:\n" + gEditor.getText() + "\n");
+
+    let url = gScripts.selected;
+    if (url.indexOf("-02.js") != -1) {
+      executeSoon(function() {
+        testEscape();
+      });
+    } else {
+      ok(false, "The current script shouldn't have changed after a global re-search.");
+    }
+  });
+  executeSoon(function() {
+    sendEnter();
+  });
+}
+
+function testEscape()
+{
+  is(gSearchView._pane.hidden, false,
+    "The global search pane should be visible after a re-search.");
+
+  window.addEventListener("Debugger:GlobalSearch:ViewCleared", function _onEvent(aEvent) {
+    window.removeEventListener(aEvent.type, _onEvent);
+    info("Current script url:\n" + gScripts.selected + "\n");
+    info("Debugger editor text:\n" + gEditor.getText() + "\n");
+
+    let url = gScripts.selected;
+    if (url.indexOf("-02.js") != -1) {
+      executeSoon(function() {
+        finalCheck();
+      });
+    } else {
+      ok(false, "The current script shouldn't have changed after the global search escaped.");
+    }
+  });
+  executeSoon(function() {
+    sendEscape();
+  });
+}
+
+function finalCheck()
+{
+  is(gSearchView._pane.hidden, true,
+    "The global search pane shouldn't be visible after the search was escaped.");
+
+  closeDebuggerAndFinish();
+}
+
+function clear() {
+  gSearchBox.focus();
+  gSearchBox.value = "";
+}
+
+function write(text) {
+  clear();
+  append(text);
+}
+
+function sendEnter() {
+  gSearchBox.focus();
+  EventUtils.sendKey("ENTER");
+}
+
+function sendEscape() {
+  gSearchBox.focus();
+  EventUtils.sendKey("ESCAPE");
+}
+
+function append(text) {
+  gSearchBox.focus();
+
+  for (let i = 0; i < text.length; i++) {
+    EventUtils.sendChar(text[i]);
+  }
+  info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+  gEditor = null;
+  gScripts = null;
+  gSearchView = null;
+  gSearchBox = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-popup.js
@@ -0,0 +1,62 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+var gScripts = null;
+var gSearchBox = null;
+var gSearchBoxPanel = null;
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+
+    gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
+      runTest();
+    });
+
+    gDebuggee.firstCall();
+  });
+}
+
+function runTest() {
+  gScripts = gDebugger.DebuggerView.Scripts;
+  gSearchBox = gScripts._searchbox;
+  gSearchBoxPanel = gScripts._searchboxPanel;
+
+  focusSearchbox();
+}
+
+function focusSearchbox() {
+  is(gSearchBoxPanel.state, "closed",
+    "The search box panel shouldn't be visible yet.");
+
+  gSearchBoxPanel.addEventListener("popupshown", function _onEvent(aEvent) {
+    gSearchBoxPanel.removeEventListener(aEvent.type, _onEvent);
+    is(gSearchBoxPanel.state, "open",
+      "The search box panel should be visible after searching started.");
+
+    closeDebuggerAndFinish();
+  });
+  EventUtils.sendMouseEvent({ type: "click" }, gSearchBox);
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+  gScripts = null;
+  gSearchBox = null;
+  gSearchBoxPanel = null;
+});
--- a/browser/devtools/debugger/test/test-script-switching-02.js
+++ b/browser/devtools/debugger/test/test-script-switching-02.js
@@ -1,7 +1,7 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function secondCall() {
-  // This comment is useful for browser_dbg_select-line.js.
+  // This comment is useful for browser_dbg_select-line.js. ☺
   eval("debugger;");
 }
--- a/browser/devtools/highlighter/highlighter.jsm
+++ b/browser/devtools/highlighter/highlighter.jsm
@@ -215,20 +215,16 @@ Highlighter.prototype = {
     }
 
     if (oldNode !== this.node) {
       this.updateInfobar();
     }
 
     this.invalidateSize(!!aScroll);
 
-    if (this._highlighting) {
-      this.showOutline();
-    }
-
     if (oldNode !== this.node) {
       this.emitEvent("nodeselected");
     }
   },
 
   /**
    * Notify that a pseudo-class lock was toggled on the highlighted element
    *
@@ -258,16 +254,17 @@ Highlighter.prototype = {
       rect = LayoutHelpers.getDirtyRect(this.node);
     }
 
     this.highlightRectangle(rect);
 
     this.moveInfobar();
 
     if (this._highlighting) {
+      this.showOutline();
       this.emitEvent("highlighting");
     }
   },
 
   /**
    * Returns the selected node.
    *
    * @returns node
--- a/browser/devtools/highlighter/inspector.jsm
+++ b/browser/devtools/highlighter/inspector.jsm
@@ -13,16 +13,17 @@ var EXPORTED_SYMBOLS = ["InspectorUI"];
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/TreePanel.jsm");
 Cu.import("resource:///modules/devtools/MarkupView.jsm");
 Cu.import("resource:///modules/highlighter.jsm");
 Cu.import("resource:///modules/devtools/LayoutView.jsm");
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 
 // Inspector notifications dispatched through the nsIObserverService.
 const INSPECTOR_NOTIFICATIONS = {
   // Fires once the Inspector completes the initialization and opens up on
   // screen.
   OPENED: "inspector-opened",
 
   // Fires once the Inspector is closed.
@@ -62,17 +63,17 @@ const LAYOUT_CHANGE_TIMER = 250;
  * closing the inspector or by user switching the tab.  This should
  * only be destroyed when user closes the inspector.
  */
 function Inspector(aIUI)
 {
   this._IUI = aIUI;
   this._winID = aIUI.winID;
   this._browser = aIUI.browser;
-  this._listeners = {};
+  this._eventEmitter = new EventEmitter();
 
   this._browser.addEventListener("resize", this, true);
 
   this._markupButton = this._IUI.chromeDoc.getElementById("inspector-treepanel-toolbutton");
 
   if (Services.prefs.getBoolPref("devtools.inspector.htmlPanelOpen")) {
     this.openMarkup();
   } else {
@@ -142,17 +143,17 @@ Inspector.prototype = {
    * Called by the InspectorUI when the inspector is being destroyed.
    */
   _destroy: function Inspector__destroy()
   {
     this._cancelLayoutChange();
     this._destroyMarkup();
     this._browser.removeEventListener("resize", this, true);
     delete this._IUI;
-    delete this._listeners;
+    delete this._eventEmitter;
   },
 
   /**
    * Event handler for DOM events.
    *
    * @param DOMEvent aEvent
    */
   handleEvent: function Inspector_handleEvent(aEvent)
@@ -279,17 +280,17 @@ Inspector.prototype = {
   {
     this._markupFrame.removeEventListener("load", this._boundMarkupFrameLoad, true);
     delete this._boundMarkupFrameLoad;
 
     this._markupSplitter.removeAttribute("hidden");
     this._markupBox.removeAttribute("hidden");
 
     this.markup = new MarkupView(this, this._markupFrame);
-    this._emit("markuploaded");
+    this.emit("markuploaded");
   },
 
   _destroyMarkup: function Inspector__destroyMarkup()
   {
     if (this._boundMarkupFrameLoad) {
       this._markupFrame.removeEventListener("load", this._boundMarkupFrameLoad, true);
       delete this._boundMarkupFrameLoad;
     }
@@ -343,90 +344,65 @@ Inspector.prototype = {
     if (this._markupOpen && !this._boundMarkupFrameLoad) {
       this._markupSplitter.removeAttribute("hidden");
       this._markupBox.removeAttribute("hidden");
     }
     this._browser.addEventListener("resize", this, true);
     delete this._frozen;
   },
 
-  /// Event stuff.  Would like to refactor this eventually.
-  /// Emulates the jetpack event source, which has a nice API.
+  /// Forward the events related calls to the event emitter.
 
   /**
    * Connect a listener to this object.
    *
    * @param string aEvent
    *        The event name to which we're connecting.
    * @param function aListener
    *        Called when the event is fired.
    */
   on: function Inspector_on(aEvent, aListener)
   {
-    if (!(aEvent in this._listeners)) {
-      this._listeners[aEvent] = [];
-    }
-    this._listeners[aEvent].push(aListener);
+    this._eventEmitter.on(aEvent, aListener);
   },
 
   /**
    * Listen for the next time an event is fired.
    *
    * @param string aEvent
    *        The event name to which we're connecting.
    * @param function aListener
    *        Called when the event is fired.  Will be called at most one time.
    */
   once: function Inspector_once(aEvent, aListener)
   {
-    let handler = function() {
-      this.removeListener(aEvent, handler);
-      aListener();
-    }.bind(this);
-    this.on(aEvent, handler);
+    this._eventEmitter.once(aEvent, aListener);
   },
 
   /**
    * Remove a previously-registered event listener.  Works for events
    * registered with either on or once.
    *
    * @param string aEvent
    *        The event name whose listener we're disconnecting.
    * @param function aListener
    *        The listener to remove.
    */
-  removeListener: function Inspector_removeListener(aEvent, aListener)
+  off: function Inspector_removeListener(aEvent, aListener)
   {
-    this._listeners[aEvent] = this._listeners[aEvent].filter(function(l) aListener != l);
+    this._eventEmitter.off(aEvent, aListener);
   },
 
   /**
    * Emit an event on the inspector.  All arguments to this method will
    * be sent to listner functions.
    */
-  _emit: function Inspector__emit(aEvent)
+  emit: function Inspector_emit()
   {
-    if (!(aEvent in this._listeners))
-      return;
-
-    let originalListeners = this._listeners[aEvent];
-    for (let listener of this._listeners[aEvent]) {
-      // If the inspector was destroyed during event emission, stop
-      // emitting.
-      if (!this._listeners) {
-        break;
-      }
-
-      // If listeners were removed during emission, make sure the
-      // event handler we're going to fire wasn't removed.
-      if (originalListeners === this._listeners[aEvent] ||
-          this._listeners[aEvent].some(function(l) l === listener)) {
-        listener.apply(null, arguments);
-      }
-    }
+    this._eventEmitter.emit.apply(this._eventEmitter, arguments);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////
 //// InspectorUI
 
 /**
  * Main controller class for the Inspector.
@@ -867,23 +843,23 @@ InspectorUI.prototype = {
    */
   startInspecting: function IUI_startInspecting()
   {
     this.inspectCommand.setAttribute("checked", "true");
 
     this.inspecting = true;
     this.highlighter.unlock();
     this._notifySelected();
-    this._currentInspector._emit("unlocked");
+    this._currentInspector.emit("unlocked");
   },
 
   _notifySelected: function IUI__notifySelected(aFrom)
   {
     this._currentInspector._cancelLayoutChange();
-    this._currentInspector._emit("select", aFrom);
+    this._currentInspector.emit("select", aFrom);
   },
 
   /**
    * Stop inspecting webpage, detach page listeners, disable highlighter
    * event listeners.
    * @param aPreventScroll
    *        Prevent scroll in the HTML tree?
    */
@@ -903,17 +879,17 @@ InspectorUI.prototype = {
     if (this.highlighter.getNode()) {
       this.select(this.highlighter.getNode(), true, !aPreventScroll);
     } else {
       this.select(null, true, true);
     }
 
     this.highlighter.lock();
     this._notifySelected();
-    this._currentInspector._emit("locked");
+    this._currentInspector.emit("locked");
   },
 
   /**
    * Select an object in the inspector.
    * @param aNode
    *        node to inspect
    * @param forceUpdate
    *        force an update?
@@ -988,17 +964,17 @@ InspectorUI.prototype = {
    *        The tool that triggered the update (if any), that tool's
    *        onChanged will not be called.
    */
   nodeChanged: function IUI_nodeChanged(aUpdater)
   {
     this.highlighter.updateInfobar();
     this.highlighter.invalidateSize();
     this.breadcrumbs.updateSelectors();
-    this._currentInspector._emit("change", aUpdater);
+    this._currentInspector.emit("change", aUpdater);
   },
 
   /////////////////////////////////////////////////////////////////////////
   //// Event Handling
 
   highlighterReady: function IUI_highlighterReady()
   {
     let self = this;
@@ -1816,18 +1792,18 @@ InspectorStyleSidebar.prototype = {
    * @param aTool object
    *        The tool object we're loading.
    */
   _showContent: function ISS__showContent(aTool)
   {
     // If the current tool is already loaded, notify that we're
     // showing this sidebar.
     if (aTool.loaded) {
-      this._inspector._emit("sidebaractivated", aTool.id);
-      this._inspector._emit("sidebaractivated-" + aTool.id);
+      this._inspector.emit("sidebaractivated", aTool.id);
+      this._inspector.emit("sidebaractivated-" + aTool.id);
       return;
     }
 
     // If we're already loading, we're done.
     if (aTool.onLoad) {
       return;
     }
 
@@ -1836,24 +1812,24 @@ InspectorStyleSidebar.prototype = {
       if (evt.target.location != aTool.registration.contentURL) {
         return;
       }
       aTool.frame.removeEventListener("load", aTool.onLoad, true);
       delete aTool.onLoad;
       aTool.loaded = true;
       aTool.context = aTool.registration.load(this._inspector, aTool.frame);
 
-      this._inspector._emit("sidebaractivated", aTool.id);
+      this._inspector.emit("sidebaractivated", aTool.id);
 
       // Send an event specific to the activation of this panel.  For
       // this initial event, include a "createpanel" argument
       // to let panels watch sidebaractivated to refresh themselves
       // but ignore the one immediately after their load.
       // I don't really like this, we should find a better solution.
-      this._inspector._emit("sidebaractivated-" + aTool.id, "createpanel");
+      this._inspector.emit("sidebaractivated-" + aTool.id, "createpanel");
     }.bind(this);
     aTool.frame.addEventListener("load", aTool.onLoad, true);
     aTool.frame.setAttribute("src", aTool.registration.contentURL);
   },
 
   /**
    * For testing purposes, mostly - return the tool-provided context
    * for a given tool.  Will only work after the tool has been loaded
--- a/browser/devtools/layoutview/LayoutView.jsm
+++ b/browser/devtools/layoutview/LayoutView.jsm
@@ -118,18 +118,18 @@ LayoutView.prototype = {
                   value: undefined},
     };
   },
 
   /**
    * Destroy the nodes. Remove listeners.
    */
   destroy: function LV_destroy() {
-    this.inspector.removeListener("select", this.onSelect);
-    this.inspector.removeListener("unlocked", this.onUnlock);
+    this.inspector.off("select", this.onSelect);
+    this.inspector.off("unlocked", this.onUnlock);
     this.browser.removeEventListener("MozAfterPaint", this.update, true);
     this.iframe.removeEventListener("keypress", this.bound_handleKeypress, true);
     this.inspector.chromeWindow.removeEventListener("message", this.onMessage, true);
     this.close();
     this.iframe = null;
     this.view.parentNode.removeChild(this.view);
   },
 
--- a/browser/devtools/markupview/MarkupView.jsm
+++ b/browser/devtools/markupview/MarkupView.jsm
@@ -326,17 +326,17 @@ MarkupView.prototype = {
         continue;
       }
       if (mutation.type === "attributes" || mutation.type === "characterData") {
         container.update();
       } else if (mutation.type === "childList") {
         this._updateChildren(container);
       }
     }
-    this._inspector._emit("markupmutation");
+    this._inspector.emit("markupmutation");
   },
 
   /**
    * Make sure the given node's parents are expanded and the
    * node is scrolled on to screen.
    */
   showNode: function MT_showNode(aNode)
   {
@@ -474,17 +474,17 @@ MarkupView.prototype = {
     delete this.undo;
 
     this._frame.addEventListener("focus", this._boundFocus, false);
     delete this._boundFocus;
 
     this._frame.removeEventListener("keydown", this._boundKeyDown, true);
     delete this._boundKeyDown;
 
-    this._inspector.removeListener("select", this._boundSelect);
+    this._inspector.off("select", this._boundSelect);
     delete this._boundSelect;
 
     delete this._elt;
 
     delete this._containers;
     this._observer.disconnect();
     delete this._observer;
   }
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -18,71 +18,30 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource:///modules/PropertyPanel.jsm");
 Cu.import("resource:///modules/source-editor.jsm");
+Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource://gre/modules/jsdebugger.jsm");
 
-
 const SCRATCHPAD_CONTEXT_CONTENT = 1;
 const SCRATCHPAD_CONTEXT_BROWSER = 2;
 const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties";
 const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
 const PREF_RECENT_FILES_MAX = "devtools.scratchpad.recentFilesMax";
 const BUTTON_POSITION_SAVE = 0;
 const BUTTON_POSITION_CANCEL = 1;
 const BUTTON_POSITION_DONT_SAVE = 2;
 const BUTTON_POSITION_REVERT=0;
 
-let keysbundle = Services.strings.createBundle("chrome://global-platform/locale/platformKeys.properties");
-
-
-function SP_Pretty_Key(aElemKey) {
-
-  let elemString = "";
-  let elemMod = aElemKey.getAttribute("modifiers");
-
-  if (elemMod.match("accel")) {
-    if (navigator.platform.indexOf("Mac") !== -1) {
-      // XXX bug 779642 Use "Cmd-" literal vs cloverleaf meta-key until
-      // Orion adds variable height lines
-      // elemString += keysbundle.GetStringFromName("VK_META_CMD") +
-      //               keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
-      elemString += "Cmd-";
-    } else {
-      elemString += keysbundle.GetStringFromName("VK_CONTROL") +
-                    keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
-    }
-  }
-
-  if (elemMod.match("shift")) {
-    elemString += keysbundle.GetStringFromName("VK_SHIFT") +
-                  keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-  if (elemMod.match("alt")) {
-    elemString += keysbundle.GetStringFromName("VK_ALT") +
-                  keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-  if (elemMod.match("ctrl")) {
-    elemString += keysbundle.GetStringFromName("VK_CONTROL") +
-                  keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-  if (elemMod.match("meta")) {
-    elemString += keysbundle.GetStringFromName("VK_META") +
-                  keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-
-  return elemString + aElemKey.getAttribute("key").toUpperCase();
-}
-
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
 var Scratchpad = {
   _initialWindowTitle: document.title,
 
   /**
    * The script execution context. This tells Scratchpad in which context the
@@ -263,16 +222,17 @@ var Scratchpad = {
     if (!this._contentSandbox ||
         this.browserWindow != this._previousBrowserWindow ||
         this._previousBrowser != this.gBrowser.selectedBrowser ||
         this._previousLocation != this.gBrowser.contentWindow.location.href) {
       let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
       this._contentSandbox = new Cu.Sandbox(contentWindow,
         { sandboxPrototype: contentWindow, wantXrays: false, 
           sandboxName: 'scratchpad-content'});
+      this._contentSandbox.__SCRATCHPAD__ = this;
 
       this._previousBrowserWindow = this.browserWindow;
       this._previousBrowser = this.gBrowser.selectedBrowser;
       this._previousLocation = contentWindow.location.href;
     }
 
     return this._contentSandbox;
   },
@@ -297,16 +257,17 @@ var Scratchpad = {
       return;
     }
 
     if (!this._chromeSandbox ||
         this.browserWindow != this._previousBrowserWindow) {
       this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
         { sandboxPrototype: this.browserWindow, wantXrays: false, 
           sandboxName: 'scratchpad-chrome'});
+      this._chromeSandbox.__SCRATCHPAD__ = this;
       addDebuggerToGlobal(this._chromeSandbox);
 
       this._previousBrowserWindow = this.browserWindow;
     }
 
     return this._chromeSandbox;
   },
 
@@ -446,16 +407,44 @@ var Scratchpad = {
       this.deselect();
       this.openPropertyPanel(selection, result);
     } else {
       this.writeAsErrorComment(error);
     }
   },
 
   /**
+   * Reload the current page and execute the entire editor content when
+   * the page finishes loading. Note that this operation should be available
+   * only in the content context.
+   */
+  reloadAndRun: function SP_reloadAndRun()
+  {
+    if (this.executionContext !== SCRATCHPAD_CONTEXT_CONTENT) {
+      Cu.reportError(this.strings.
+          GetStringFromName("scratchpadContext.invalid"));
+      return;
+    }
+
+    let browser = this.gBrowser.selectedBrowser;
+
+    this._reloadAndRunEvent = function onLoad(evt) {
+      if (evt.target !== browser.contentDocument) {
+        return;
+      }
+
+      browser.removeEventListener("load", this._reloadAndRunEvent, true);
+      this.run();
+    }.bind(this);
+
+    browser.addEventListener("load", this._reloadAndRunEvent, true);
+    browser.contentWindow.location.reload();
+  },
+
+  /**
    * Execute the selected text (if any) or the entire editor content in the
    * current context. The evaluation result is inserted into the editor after
    * the selected text, or at the end of the editor content if there is no
    * selected text.
    */
   display: function SP_display()
   {
     let [selectedText, error, result] = this.execute();
@@ -474,19 +463,19 @@ var Scratchpad = {
    *        The Object to write out as a string
    */
   writeAsComment: function SP_writeAsComment(aValue)
   {
     let selection = this.getSelectionRange();
     let insertionPoint = selection.start != selection.end ?
                          selection.end : // after selected text
                          this.editor.getCharCount(); // after text end
-                         
+
     let newComment = "\n/*\n" + aValue + "\n*/";
-    
+
     this.setText(newComment, insertionPoint, insertionPoint);
 
     // Select the new comment.
     this.selectRange(insertionPoint, insertionPoint + newComment.length);
   },
 
   /**
    * Write out an error at the current insertion point as a block comment
@@ -505,17 +494,17 @@ var Scratchpad = {
       }
       else {
         stack = "@" + aError.fileName;
       }
     }
     else if (aError.lineNumber) {
       stack = "@" + aError.lineNumber;
     }
-    
+
     let newComment = "Exception: " + ( aError.message || aError) + ( stack == "" ? stack : "\n" + stack.replace(/\n$/, "") );
 
     this.writeAsComment(newComment);
   },
 
   /**
    * Open the Property Panel to inspect the given object.
    *
@@ -926,17 +915,16 @@ var Scratchpad = {
   /**
    * Restore content from saved version of current file.
    *
    * @param function aCallback
    *        Optional function you want to call when file is saved
    */
   revertFile: function SP_revertFile(aCallback)
   {
-    
     let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
     file.initWithPath(this.filename);
 
     if (!file.exists()) {
       return;
     }
 
     this.importFromFile(file, false, function(aStatus, aContent) {
@@ -1014,34 +1002,39 @@ var Scratchpad = {
   setContentContext: function SP_setContentContext()
   {
     if (this.executionContext == SCRATCHPAD_CONTEXT_CONTENT) {
       return;
     }
 
     let content = document.getElementById("sp-menu-content");
     document.getElementById("sp-menu-browser").removeAttribute("checked");
+    document.getElementById("sp-cmd-reloadAndRun").removeAttribute("disabled");
     content.setAttribute("checked", true);
     this.executionContext = SCRATCHPAD_CONTEXT_CONTENT;
     this.notificationBox.removeAllNotifications(false);
     this.resetContext();
   },
 
   /**
    * Set the current execution context to be the most recent chrome window.
    */
   setBrowserContext: function SP_setBrowserContext()
   {
     if (this.executionContext == SCRATCHPAD_CONTEXT_BROWSER) {
       return;
     }
 
     let browser = document.getElementById("sp-menu-browser");
+    let reloadAndRun = document.getElementById("sp-cmd-reloadAndRun");
+
     document.getElementById("sp-menu-content").removeAttribute("checked");
+    reloadAndRun.setAttribute("disabled", true);
     browser.setAttribute("checked", true);
+
     this.executionContext = SCRATCHPAD_CONTEXT_BROWSER;
     this.notificationBox.appendNotification(
       this.strings.GetStringFromName("browserContext.notification"),
       SCRATCHPAD_CONTEXT_BROWSER,
       null,
       this.notificationBox.PRIORITY_WARNING_HIGH,
       null);
     this.resetContext();
@@ -1092,19 +1085,19 @@ var Scratchpad = {
       chromeContextCommand.removeAttribute("disabled");
       errorConsoleCommand.removeAttribute("disabled");
     }
 
     let state = null;
 
     let initialText = this.strings.formatStringFromName(
       "scratchpadIntro1",
-      [SP_Pretty_Key(document.getElementById("sp-key-run")),
-       SP_Pretty_Key(document.getElementById("sp-key-inspect")),
-       SP_Pretty_Key(document.getElementById("sp-key-display"))],
+      [LayoutHelpers.prettyKey(document.getElementById("sp-key-run")),
+       LayoutHelpers.prettyKey(document.getElementById("sp-key-inspect")),
+       LayoutHelpers.prettyKey(document.getElementById("sp-key-display"))],
       3);
 
     if ("arguments" in window &&
          window.arguments[0] instanceof Ci.nsIDialogParamBlock) {
       state = JSON.parse(window.arguments[0].GetString(0));
       this.setState(state);
       initialText = state.text;
     }
@@ -1208,16 +1201,18 @@ var Scratchpad = {
    */
   onUnload: function SP_onUnload(aEvent)
   {
     if (aEvent.target != document) {
       return;
     }
 
     this.resetContext();
+    this.gBrowser.selectedBrowser.removeEventListener("load",
+        this._reloadAndRunEvent, true);
     this.editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED,
                                     this._onDirtyChanged);
     PreferenceObserver.uninit();
 
     this.editor.destroy();
     this.editor = null;
     this.initialized = false;
   },
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -40,16 +40,17 @@
  -->
 
   <command id="sp-cmd-close" oncommand="Scratchpad.close();"/>
   <command id="sp-cmd-run" oncommand="Scratchpad.run();"/>
   <command id="sp-cmd-inspect" oncommand="Scratchpad.inspect();"/>
   <command id="sp-cmd-display" oncommand="Scratchpad.display();"/>
   <command id="sp-cmd-contentContext" oncommand="Scratchpad.setContentContext();"/>
   <command id="sp-cmd-browserContext" oncommand="Scratchpad.setBrowserContext();" disabled="true"/>
+  <command id="sp-cmd-reloadAndRun" oncommand="Scratchpad.reloadAndRun();"/>
   <command id="sp-cmd-resetContext" oncommand="Scratchpad.resetContext();"/>
   <command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/>
   <command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/>
   <command id="sp-cmd-documentationLink" oncommand="Scratchpad.openDocumentationPage();"/>
 </commandset>
 
 <keyset id="sourceEditorKeys"/>
 
@@ -85,16 +86,20 @@
   <key id="sp-key-inspect"
        key="&inspect.key;"
        command="sp-cmd-inspect"
        modifiers="accel"/>
   <key id="sp-key-display"
        key="&display.key;"
        command="sp-cmd-display"
        modifiers="accel"/>
+  <key id="sp-key-reloadAndRun"
+       key="&reloadAndRun.key;"
+       command="sp-cmd-reloadAndRun"
+       modifiers="accel,shift"/>
   <key id="sp-key-errorConsole"
        key="&errorConsoleCmd.commandkey;"
        command="sp-cmd-errorConsole"
        modifiers="accel,shift"/>
   <key id="sp-key-webConsole"
        key="&webConsoleCmd.commandkey;"
        command="sp-cmd-webConsole"
        modifiers="accel,shift"/>
@@ -189,16 +194,21 @@
                 key="sp-key-inspect"
                 command="sp-cmd-inspect"/>
       <menuitem id="sp-text-display"
                 label="&display.label;"
                 accesskey="&display.accesskey;"
                 key="sp-key-display"
                 command="sp-cmd-display"/>
       <menuseparator/>
+      <menuitem id="sp-text-reloadAndRun"
+                label="&reloadAndRun.label;"
+                key="sp-key-reloadAndRun"
+                accesskey="&reloadAndRun.accesskey;"
+                command="sp-cmd-reloadAndRun"/>
       <menuitem id="sp-text-resetContext"
                 label="&resetContext2.label;"
                 accesskey="&resetContext2.accesskey;"
                 command="sp-cmd-resetContext"/>
     </menupopup>
   </menu>
 
   <menu id="sp-environment-menu"
--- a/browser/devtools/scratchpad/test/Makefile.in
+++ b/browser/devtools/scratchpad/test/Makefile.in
@@ -29,11 +29,12 @@ MOCHITEST_BROWSER_FILES = \
 		browser_scratchpad_bug684546_reset_undo.js \
 		browser_scratchpad_bug690552_display_outputs_errors.js \
 		browser_scratchpad_bug650345_find_ui.js \
 		browser_scratchpad_bug714942_goto_line_ui.js \
 		browser_scratchpad_bug_650760_help_key.js \
 		browser_scratchpad_bug_651942_recent_files.js \
 		browser_scratchpad_bug756681_display_non_error_exceptions.js \
 		browser_scratchpad_bug_751744_revert_to_saved.js \
+		browser_scratchpad_bug740948_reload_and_run.js \
 		head.js \
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug740948_reload_and_run.js
@@ -0,0 +1,73 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
+let EDITOR_TEXT = [
+  "var evt = new CustomEvent('foo', { bubbles: true });",
+  "document.body.innerHTML = 'Modified text';",
+  "window.dispatchEvent(evt);"
+].join("\n");
+
+function test()
+{
+  waitForExplicitFinish();
+  Services.prefs.setBoolPref(DEVTOOLS_CHROME_ENABLED, true);
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+    openScratchpad(runTests);
+  }, true);
+
+  content.location = "data:text/html,Scratchpad test for bug 740948";
+}
+
+function runTests()
+{
+  let sp = gScratchpadWindow.Scratchpad;
+  ok(sp, "Scratchpad object exists in new window");
+
+  // Test that Reload And Run command is enabled in the content
+  // context and disabled in the browser context.
+
+  let reloadAndRun = gScratchpadWindow.document.
+    getElementById("sp-cmd-reloadAndRun");
+  ok(reloadAndRun, "Reload And Run command exists");
+  ok(!reloadAndRun.hasAttribute("disabled"),
+      "Reload And Run command is enabled");
+
+  sp.setBrowserContext();
+  ok(reloadAndRun.hasAttribute("disabled"),
+      "Reload And Run command is disabled in the browser context.");
+
+  // Switch back to the content context and run our predefined
+  // code. This code modifies the body of our document and dispatches
+  // a custom event 'foo'. We listen to that event and check the
+  // body to make sure that the page has been reloaded and Scratchpad
+  // code has been executed.
+
+  sp.setContentContext();
+  sp.setText(EDITOR_TEXT);
+
+  let browser = gBrowser.selectedBrowser;
+
+  browser.addEventListener("DOMWindowCreated", function onWindowCreated() {
+    browser.removeEventListener("DOMWindowCreated", onWindowCreated, true);
+
+    browser.contentWindow.addEventListener("foo", function onFoo() {
+      browser.contentWindow.removeEventListener("foo", onFoo, true);
+
+      is(browser.contentWindow.document.body.innerHTML, "Modified text",
+        "After reloading, HTML is different.");
+
+      Services.prefs.clearUserPref(DEVTOOLS_CHROME_ENABLED);
+      finish();
+    }, true);
+  }, true);
+
+  ok(browser.contentWindow.document.body.innerHTML !== "Modified text",
+      "Before reloading, HTML is intact.");
+  sp.reloadAndRun();
+}
+
--- a/browser/devtools/scratchpad/test/browser_scratchpad_contexts.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_contexts.js
@@ -36,16 +36,24 @@ function runTests()
      "content menuitem is checked");
 
   isnot(chromeMenu.getAttribute("checked"), "true",
      "chrome menuitem is not checked");
 
   ok(!notificationBox.currentNotification,
      "there is no notification in content context");
 
+  let dsp = sp.contentSandbox.__SCRATCHPAD__;
+
+  ok(sp.contentSandbox.__SCRATCHPAD__,
+      "there is a variable named __SCRATCHPAD__");
+
+  ok(sp.contentSandbox.__SCRATCHPAD__.editor,
+      "scratchpad is actually an instance of Scratchpad");
+
   sp.setText("window.foobarBug636725 = 'aloha';");
 
   ok(!content.wrappedJSObject.foobarBug636725,
      "no content.foobarBug636725");
 
   sp.run();
 
   is(content.wrappedJSObject.foobarBug636725, "aloha",
@@ -57,16 +65,22 @@ function runTests()
      "executionContext is chrome");
 
   is(chromeMenu.getAttribute("checked"), "true",
      "chrome menuitem is checked");
 
   isnot(contentMenu.getAttribute("checked"), "true",
      "content menuitem is not checked");
 
+  ok(sp.chromeSandbox.__SCRATCHPAD__,
+    "there is a variable named __SCRATCHPAD__");
+
+  ok(sp.chromeSandbox.__SCRATCHPAD__.editor,
+      "scratchpad is actually an instance of Scratchpad");
+
   ok(notificationBox.currentNotification,
      "there is a notification in browser context");
 
   sp.setText("2'", 31, 33);
 
   ok(sp.getText(), "window.foobarBug636725 = 'aloha2';",
      "setText() worked");
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/EventEmitter.jsm
@@ -0,0 +1,80 @@
+var EXPORTED_SYMBOLS = ["EventEmitter"];
+
+function EventEmitter() {
+}
+
+EventEmitter.prototype = {
+  /**
+   * Connect a listener.
+   *
+   * @param string aEvent
+   *        The event name to which we're connecting.
+   * @param function aListener
+   *        Called when the event is fired.
+   */
+  on: function EventEmitter_on(aEvent, aListener) {
+    if (!this._eventEmitterListeners)
+      this._eventEmitterListeners = new Map();
+    if (!this._eventEmitterListeners.has(aEvent)) {
+      this._eventEmitterListeners.set(aEvent, []);
+    }
+    this._eventEmitterListeners.get(aEvent).push(aListener);
+  },
+
+  /**
+   * Listen for the next time an event is fired.
+   *
+   * @param string aEvent
+   *        The event name to which we're connecting.
+   * @param function aListener
+   *        Called when the event is fired.  Will be called at most one time.
+   */
+  once: function EventEmitter_once(aEvent, aListener) {
+    let handler = function() {
+      this.off(aEvent, handler);
+      aListener();
+    }.bind(this);
+    this.on(aEvent, handler);
+  },
+
+  /**
+   * Remove a previously-registered event listener.  Works for events
+   * registered with either on or once.
+   *
+   * @param string aEvent
+   *        The event name whose listener we're disconnecting.
+   * @param function aListener
+   *        The listener to remove.
+   */
+  off: function EventEmitter_off(aEvent, aListener) {
+    if (!this._eventEmitterListeners)
+      return;
+    let listeners = this._eventEmitterListeners.get(aEvent);
+    this._eventEmitterListeners.set(aEvent, listeners.filter(function(l) aListener != l));
+  },
+
+  /**
+   * Emit an event.  All arguments to this method will
+   * be sent to listner functions.
+   */
+  emit: function EventEmitter_emit(aEvent) {
+    if (!this._eventEmitterListeners || !this._eventEmitterListeners.has(aEvent))
+      return;
+
+    let originalListeners = this._eventEmitterListeners.get(aEvent);
+    for (let listener of this._eventEmitterListeners.get(aEvent)) {
+      // If the object was destroyed during event emission, stop
+      // emitting.
+      if (!this._eventEmitterListeners) {
+        break;
+      }
+
+      // If listeners were removed during emission, make sure the
+      // event handler we're going to fire wasn't removed.
+      if (originalListeners === this._eventEmitterListeners.get(aEvent) ||
+          this._eventEmitterListeners.get(aEvent).some(function(l) l === listener)) {
+        listener.apply(null, arguments);
+      }
+    }
+  },
+}
--- a/browser/devtools/shared/LayoutHelpers.jsm
+++ b/browser/devtools/shared/LayoutHelpers.jsm
@@ -3,16 +3,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+  "resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "PlatformKeys", function() {
+  return Services.strings.createBundle(
+    "chrome://global-platform/locale/platformKeys.properties");
+});
+
 var EXPORTED_SYMBOLS = ["LayoutHelpers"];
 
 LayoutHelpers = {
 
   /**
    * Compute the position and the dimensions for the visible portion
    * of a node, relativalely to the root window.
    *
@@ -305,9 +315,65 @@ LayoutHelpers = {
                       !(aNode.compareDocumentPosition(aNode.ownerDocument.documentElement) &
                       aNode.DOCUMENT_POSITION_DISCONNECTED));
       return connected;
     } catch (e) {
       // "can't access dead object" error
       return false;
     }
   },
+
+  /**
+   * Prettifies the modifier keys for an element.
+   *
+   * @param Node aElemKey
+   *        The key element to get the modifiers from.
+   * @return string
+   *         A prettified and properly separated modifier keys string.
+   */
+  prettyKey: function LH_prettyKey(aElemKey)
+  {
+    let elemString = "";
+    let elemMod = aElemKey.getAttribute("modifiers");
+
+    if (elemMod.match("accel")) {
+      if (Services.appinfo.OS == "Darwin") {
+        // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
+        // Orion adds variable height lines.
+        // elemString += PlatformKeys.GetStringFromName("VK_META") +
+        //               PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+        elemString += "Cmd-";
+      } else {
+        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
+                      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+      }
+    }
+    if (elemMod.match("access")) {
+      if (Services.appinfo.OS == "Darwin") {
+        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
+                      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+      } else {
+        elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+                      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+      }
+    }
+    if (elemMod.match("shift")) {
+      elemString += PlatformKeys.GetStringFromName("VK_SHIFT") +
+                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("alt")) {
+      elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("ctrl")) {
+      elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
+                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("meta")) {
+      elemString += PlatformKeys.GetStringFromName("VK_META") +
+                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+
+    return elemString +
+      (aElemKey.getAttribute("keycode").replace(/^.*VK_/, "") ||
+       aElemKey.getAttribute("key")).toUpperCase();
+  }
 };
--- a/browser/devtools/shared/test/Makefile.in
+++ b/browser/devtools/shared/test/Makefile.in
@@ -17,16 +17,17 @@ MOCHITEST_BROWSER_FILES = \
   browser_browser_basic.js \
   browser_promise_basic.js \
   browser_require_basic.js \
   browser_templater_basic.js \
   browser_toolbar_basic.js \
   browser_toolbar_tooltip.js \
   browser_toolbar_webconsole_errors_count.js \
   browser_layoutHelpers.js \
+  browser_eventemitter_basic.js \
   head.js \
   helpers.js \
   leakhunt.js \
   $(NULL)
 
 MOCHITEST_BROWSER_FILES += \
   browser_templater_basic.html \
   browser_toolbar_basic.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/test/browser_eventemitter_basic.js
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+function test() {
+  Cu.import("resource:///modules/devtools/EventEmitter.jsm", this);
+  let emitter = new EventEmitter();
+  ok(emitter, "We have an event emitter");
+
+  emitter.on("next", next);
+  emitter.emit("next", "abc", "def");
+
+  let beenHere1 = false;
+  function next(eventName, str1, str2) {
+    is(eventName, "next", "Got event");
+    is(str1, "abc", "Argument 1 is correct");
+    is(str2, "def", "Argument 2 is correct");
+
+    ok(!beenHere1, "first time in next callback");
+    beenHere1 = true;
+
+    emitter.off("next", next);
+
+    emitter.emit("next");
+
+    emitter.once("onlyonce", onlyOnce);
+
+    emitter.emit("onlyonce");
+    emitter.emit("onlyonce");
+  }
+
+  let beenHere2 = false;
+  function onlyOnce() {
+    ok(!beenHere2, "\"once\" listner has been called once");
+    beenHere2 = true;
+    emitter.emit("onlyonce");
+
+    killItWhileEmitting();
+  }
+
+  function killItWhileEmitting() {
+    function c1() {
+      ok(true, "c1 called");
+    }
+    function c2() {
+      ok(true, "c2 called");
+      emitter.off("tick", c3);
+    }
+    function c3() {
+      ok(false, "c3 should not be called");
+    }
+    function c4() {
+      ok(true, "c4 called");
+    }
+
+    emitter.on("tick", c1);
+    emitter.on("tick", c2);
+    emitter.on("tick", c3);
+    emitter.on("tick", c4);
+
+    emitter.emit("tick");
+
+    delete emitter;
+    finish();
+  }
+}
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -141,19 +141,19 @@ RuleViewTool.prototype = {
     }
 
     if (this.inspector.locked && this.inspector.isPanelVisible("ruleview")) {
       this.view.nodeChanged();
     }
   },
 
   destroy: function RVT_destroy() {
-    this.inspector.removeListener("select", this._onSelect);
-    this.inspector.removeListener("change", this._onChange);
-    this.inspector.removeListener("sidebaractivated-ruleview", this._onChange);
+    this.inspector.off("select", this._onSelect);
+    this.inspector.off("change", this._onChange);
+    this.inspector.off("sidebaractivated-ruleview", this._onChange);
     this.view.element.removeEventListener("CssRuleViewChanged",
                                           this._changeHandler);
     this.view.element.removeEventListener("CssRuleViewCSSLinkClicked",
                                           this._cssLinkHandler);
     this.doc.documentElement.removeChild(this.view.element);
 
     this.view.destroy();
 
@@ -209,19 +209,19 @@ ComputedViewTool.prototype = {
     if (this.inspector.locked && this.inspector.isPanelVisible("computedview")) {
       this.cssLogic.highlight(this.inspector.selection);
       this.view.refreshPanel();
     }
   },
 
   destroy: function CVT_destroy(aContext)
   {
-    this.inspector.removeListener("select", this._onSelect);
-    this.inspector.removeListener("change", this._onChange);
-    this.inspector.removeListener("sidebaractivated-computedview", this._onChange);
+    this.inspector.off("select", this._onSelect);
+    this.inspector.off("change", this._onChange);
+    this.inspector.off("sidebaractivated-computedview", this._onChange);
     this.view.destroy();
     delete this.view;
 
     delete this.cssLogic;
     delete this.cssHtmlTree;
     delete this.iframe;
     delete this.window;
     delete this.document;
--- a/browser/devtools/webconsole/HUDService-content.js
+++ b/browser/devtools/webconsole/HUDService-content.js
@@ -642,18 +642,18 @@ function JSTermHelper(aJSTerm)
 
   /**
    * Opens a help window in MDN.
    */
   aJSTerm.sandbox.help = function JSTH_help()
   {
     aJSTerm.helperEvaluated = true;
     aJSTerm.window.open(
-        "https://developer.mozilla.org/AppLinks/WebConsoleHelp?locale=" +
-        aJSTerm.window.navigator.language, "help", "");
+        "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers",
+        "help", "");
   };
 
   /**
    * Inspects the passed aObject. This is done by opening the PropertyPanel.
    *
    * @param object aObject
    *        Object to inspect.
    */
--- a/browser/extensions/pdfjs/LICENSE
+++ b/browser/extensions/pdfjs/LICENSE
@@ -1,34 +1,178 @@
 
-    Copyright (c) 2011 Mozilla Foundation
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
 
-    Contributors: Andreas Gal <gal@mozilla.com>
-                  Chris G Jones <cjones@mozilla.com>
-                  Shaon Barman <shaon.barman@gmail.com>
-                  Vivien Nicolas <21@vingtetun.org>
-                  Justin D'Arcangelo <justindarc@gmail.com>
-                  Yury Delendik
-                  Kalervo Kujala
-                  Adil Allawi <@ironymark>
-                  Jakob Miland <saebekassebil@gmail.com>
-                  Artur Adib <aadib@mozilla.com>
-                  Brendan Dahl <bdahl@mozilla.com>
-                  David Quintana <gigaherz@gmail.com>
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
 
-    Permission is hereby granted, free of charge, to any person obtaining a
-    copy of this software and associated documentation files (the "Software"),
-    to deal in the Software without restriction, including without limitation
-    the rights to use, copy, modify, merge, publish, distribute, sublicense,
-    and/or sell copies of the Software, and to permit persons to whom the
-    Software is furnished to do so, subject to the following conditions:
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
 
-    The above copyright notice and this permission notice shall be included in
-    all copies or substantial portions of the Software.
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
 
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-    DEALINGS IN THE SOFTWARE.
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
 
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,4 +1,4 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 0.4.11
+Current extension version is: 0.5.22
 
--- a/browser/extensions/pdfjs/components/PdfStreamConverter.js
+++ b/browser/extensions/pdfjs/components/PdfStreamConverter.js
@@ -1,10 +1,24 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 'use strict';
 
 var EXPORTED_SYMBOLS = ['PdfStreamConverter'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
@@ -13,16 +27,17 @@ const Cu = Components.utils;
 const MOZ_CENTRAL = true;
 const PDFJS_EVENT_ID = 'pdf.js.message';
 const PDF_CONTENT_TYPE = 'application/pdf';
 const PREF_PREFIX = 'pdfjs';
 const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
 const MAX_DATABASE_LENGTH = 4096;
 const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
 const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}';
+const METRO_ID = '{99bceaaa-e3c6-48c1-b981-ef9b46b67d60}';
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/NetUtil.jsm');
 
 
 let appInfo = Cc['@mozilla.org/xre/app-info;1']
                   .getService(Ci.nsIXULAppInfo);
@@ -31,17 +46,18 @@ let Svc = {};
 XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
                                    '@mozilla.org/mime;1',
                                    'nsIMIMEService');
 
 if (appInfo.ID === FIREFOX_ID) {
   privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
                           .getService(Ci.nsIPrivateBrowsingService);
   inPrivateBrowsing = privateBrowsing.privateBrowsingEnabled;
-} else if (appInfo.ID === SEAMONKEY_ID) {
+} else if (appInfo.ID === SEAMONKEY_ID ||
+           appInfo.ID === METRO_ID) {
   privateBrowsing = null;
   inPrivateBrowsing = false;
 }
 
 function getBoolPref(pref, def) {
   try {
     return Services.prefs.getBoolPref(pref);
   } catch (ex) {
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -1,8 +1,23 @@
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 var EXPORTED_SYMBOLS = ["PdfJs"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cm = Components.manager;
 const Cu = Components.utils;
 
--- a/browser/extensions/pdfjs/content/web/debugger.js
+++ b/browser/extensions/pdfjs/content/web/debugger.js
@@ -1,10 +1,24 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 'use strict';
 
 var FontInspector = (function FontInspectorClosure() {
   var fonts;
   var panelWidth = 300;
   var active = false;
   var fontAttribute = 'data-font-name';
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -1,8 +1,23 @@
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 * {
   padding: 0;
   margin: 0;
 }
 
 html {
   height: 100%;
 }
@@ -24,46 +39,38 @@ select {
   display: none;
 }
 [hidden] {
   display: none !important;
 }
 
 #viewerContainer:-webkit-full-screen {
   top: 0px;
-  padding-top: 6px;
-  padding-bottom: 24px;
-  background-color: #404040;
-  background-image: url(images/texture.png);
-  width: 100%;
-  height: 100%;
-  overflow: auto;
-}
-
-:-webkit-full-screen #viewer {
-  margin: 0pt;
-  padding: 0pt;
-  height: 100%;
-  width: 100%;
-  overflow: hidden;
-}
-
-:-webkit-full-screen .page {
-  margin: 0px auto;
-  margin-bottom: 10px;
-}
-
-#viewerContainer:-moz-full-screen {
+  border-top: 5px solid transparent;
   background-color: #404040;
   background-image: url(images/texture.png);
   width: 100%;
   height: 100%;
   overflow: hidden;
 }
 
+#viewerContainer:-moz-full-screen {
+  top: 0px;
+  border-top: 5px solid transparent;
+  background-color: #404040;
+  background-image: url(images/texture.png);
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+
+:-webkit-full-screen .page:last-child {
+  margin-bottom: 40px;
+}
+
 :-moz-full-screen .page:last-child {
   margin-bottom: 40px;
 }
 
 #viewerContainer:full-screen {
   top: 0px;
   background-color: #404040;
   background-image: url(images/texture.png);
@@ -755,29 +762,27 @@ html[dir='rtl'] .toolbarButton.pageDown:
   line-height: 14px;
   text-align: left;
   -webkit-user-select:none;
   -moz-user-select:none;
   cursor: default;
 }
 
 #thumbnailView {
-  position: fixed;
+  position: absolute;
   width: 120px;
-  top: 33px;
+  top: 0;
   bottom: 0;
   padding: 10px 40px 0;
   overflow: auto;
 }
 
 .thumbnail {
   margin-bottom: 15px;
   float: left;
-  width: 114px;
-  height: 142px;
 }
 
 .thumbnail:not([data-loaded]) {
   border: 1px dashed rgba(255, 255, 255, 0.5);
 }
 
 .thumbnailImage {
   -moz-transition-duration: 150ms;
@@ -820,19 +825,19 @@ a:focus > .thumbnail > .thumbnailSelecti
   background-clip: padding-box;
   box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
               0 0 1px hsla(0,0%,100%,.1) inset,
               0 0 1px hsla(0,0%,0%,.2);
   color: hsla(0,0%,100%,1);
 }
 
 #outlineView {
-  position: fixed;
+  position: absolute;
   width: 192px;
-  top: 33px;
+  top: 0;
   bottom: 0;
   padding: 4px 4px 0;
   overflow: auto;
   -webkit-user-select:none;
   -moz-user-select:none;
 }
 
 .outlineItem > .outlineItems {
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -1,36 +1,79 @@
 <!DOCTYPE html>
+<!--
+Copyright 2012 Mozilla Foundation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
 <html dir="ltr">
   <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
     <title>PDF.js viewer</title>
 
 <!-- This snippet is used in firefox extension, see Makefile -->
 <base href="resource://pdf.js/web/" />
 <script type="text/javascript" src="l10n.js"></script>
 <script type="text/javascript" id="PDFJS_SCRIPT_TAG">
 <!--
 // pdf.js is inlined here because resource:// urls won't work
 // for loading workers.
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 var PDFJS = {};
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
   PDFJS.build =
-'cb05144';
+'3120edc';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 'use strict';
 
 var globalScope = (typeof window === 'undefined') ? this : window;
 
 var isWorker = (typeof window == 'undefined');
 
 var ERRORS = 0, WARNINGS = 1, INFOS = 5;
@@ -584,20 +627,16 @@ var PDFDocument = (function PDFDocumentC
       return this.catalog.getPage(n);
     }
   };
 
   return PDFDocument;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 // Use only for debugging purposes. This should not be used in any code that is
 // in mozilla master.
 function log(msg) {
   if (console && console.log)
     console.log(msg);
   else if (print)
     print(msg);
@@ -1222,18 +1261,16 @@ var StatTimer = (function StatTimerClosu
         out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
       }
       return out;
     }
   };
   return StatTimer;
 })();
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 
 /**
  * This is the main entry point for loading a PDF and interacting with it.
  * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
  * is used, which means it must follow the same origin rules that any XHR does
  * e.g. No cross domain requests without CORS.
  *
  * @param {string|TypedAray|object} source Can be an url to where a PDF is
@@ -1535,23 +1572,29 @@ var PDFPageProxy = (function PDFPageProx
       );
     },
     /**
      * For internal use only.
      */
     ensureFonts: function PDFPageProxy_ensureFonts(fonts, callback) {
       this.stats.time('Font Loading');
       // Convert the font names to the corresponding font obj.
+      var fontObjs = [];
       for (var i = 0, ii = fonts.length; i < ii; i++) {
-        fonts[i] = this.objs.objs[fonts[i]].data;
+        var obj = this.objs.objs[fonts[i]].data;
+        if (obj.error) {
+          warn('Error during font loading: ' + obj.error);
+          continue;
+        }
+        fontObjs.push(obj);
       }
 
       // Load all the fonts
       FontLoader.bind(
-        fonts,
+        fontObjs,
         function pageEnsureFontsFontObjs(fontObjs) {
           this.stats.timeEnd('Font Loading');
 
           callback.call(this);
         }.bind(this)
       );
     },
     /**
@@ -1783,17 +1826,22 @@ var WorkerTransport = (function WorkerTr
             if (file) {
               // Rewrap the ArrayBuffer in a stream.
               var fontFileDict = new Dict();
               file = new Stream(file, 0, file.length, fontFileDict);
             }
 
             // At this point, only the font object is created but the font is
             // not yet attached to the DOM. This is done in `FontLoader.bind`.
-            var font = new Font(name, file, properties);
+            var font;
+            try {
+              font = new Font(name, file, properties);
+            } catch (e) {
+              font = new ErrorFont(e);
+            }
             this.objs.resolve(id, font);
             break;
           default:
             error('Got unkown object type ' + type);
         }
       }, this);
 
       messageHandler.on('DocProgress', function transportDocProgress(data) {
@@ -1875,20 +1923,16 @@ var WorkerTransport = (function WorkerTr
       this.messageHandler.send('GetAnnotationsRequest',
         { pageIndex: pageIndex });
     }
   };
   return WorkerTransport;
 
 })();
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 // <canvas> contexts store most of the state we need natively.
 // However, PDF needs a bit more state, which we store here.
 
 var TextRenderingMode = {
   FILL: 0,
   STROKE: 1,
   FILL_STROKE: 2,
@@ -3177,20 +3221,16 @@ function checkPutBinaryImageDataCompatib
         ctx.putImageData(tmpImgData, 0, 0);
       };
   }
 }
 if (!isWorker) {
   checkPutBinaryImageDataCompatibility();
 }
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var Name = (function NameClosure() {
   function Name(name) {
     this.name = name;
   }
 
   Name.prototype = {};
 
@@ -4009,20 +4049,16 @@ var PDFObjects = (function PDFObjectsClo
       // create a *resolved* promise which shouldn't be the case!
       this.ensureObj(objId).data = data;
     }
   };
   return PDFObjects;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var PDFFunction = (function PDFFunctionClosure() {
   var CONSTRUCT_SAMPLED = 0;
   var CONSTRUCT_INTERPOLATED = 2;
   var CONSTRUCT_STICHED = 3;
   var CONSTRUCT_POSTSCRIPT = 4;
 
   return {
@@ -4888,20 +4924,16 @@ var PostScriptLexer = (function PostScri
         error('Invalid floating point number: ' + value);
       return value;
     }
   };
   return PostScriptLexer;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var ISOAdobeCharset = [
   '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
   'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
   'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
   'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
   'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
   'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
@@ -4994,20 +5026,16 @@ var ExpertSubsetCharset = [
   'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
   'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
   'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
   'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
   'periodinferior', 'commainferior'
 ];
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var CIDToUnicodeMaps = {
   'Adobe-Japan1': [[32, 160], {f: 12, c: 33}, [45, 8209], {f: 46, c: 46}, 165,
     {f: 2, c: 93}, [95, 818], [96, 768], {f: 27, c: 97}, 166, 125, [732, 771],
     [700, 8217], 92, [699, 8216], 124, [126, 8764], {f: 3, c: 161}, 8260, 402,
     0, 164, 8220, 171, {f: 2, c: 8249}, {f: 2, c: 64257}, [8210, 8211], 0, 0,
     [183, 8729], 0, 8226, 8218, 8222, 8221, 187, 0, 0, 191, {f: 2, c: 769},
     [175, 772], {f: 3, c: 774}, 778, [184, 807], 779, 808, 780, [822, 8212],
@@ -11928,20 +11956,16 @@ var CIDToUnicodeMaps = {
     {f: 5, c: 18212}, {f: 82, c: 18218}, {f: 16, c: 18301}, {f: 441, c: 18318},
     {f: 50, c: 18760}, {f: 2, c: 18811}, {f: 4, c: 18814}, 18820,
     {f: 20, c: 18823}, {f: 3, c: 18844}, {f: 22, c: 18848}, {f: 703, c: 18872},
     {f: 39, c: 19576}, {f: 111, c: 19620}, {f: 148, c: 19738},
     {f: 7, c: 19887}]
 };
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var ColorSpace = (function ColorSpaceClosure() {
   // Constructor should define this.numComps, this.defaultColor, this.name
   function ColorSpace() {
     error('should not call ColorSpace constructor');
   }
 
   ColorSpace.prototype = {
@@ -12468,20 +12492,16 @@ var LabCS = (function LabCSClosure() {
         return true;
       else
         return false;
     }
   };
   return LabCS;
 })();
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var ARCFourCipher = (function ARCFourCipherClosure() {
   function ARCFourCipher(key) {
     this.a = 0;
     this.b = 0;
     var s = new Uint8Array(256);
     var i, j = 0, tmp, keyLength = key.length;
     for (i = 0; i < 256; ++i)
@@ -13119,20 +13139,16 @@ var CipherTransformFactory = (function C
       return new CipherTransform(cipherConstructor, cipherConstructor);
     }
   };
 
   return CipherTransformFactory;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var PartialEvaluator = (function PartialEvaluatorClosure() {
   function PartialEvaluator(xref, handler, uniquePrefix) {
     this.state = new EvalState();
     this.stateStack = [];
 
     this.xref = xref;
     this.handler = handler;
@@ -13695,18 +13711,23 @@ var PartialEvaluator = (function Partial
 
         var cidToGidMap = dict.get('CIDToGIDMap');
         if (isStream(cidToGidMap))
           properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
       }
 
       var flags = properties.flags;
       var differences = [];
-      var baseEncoding = !!(flags & FontFlags.Symbolic) ?
-                         Encodings.symbolsEncoding : Encodings.StandardEncoding;
+      var baseEncoding = Encodings.StandardEncoding;
+      // The Symbolic attribute can be misused for regular fonts
+      // Heuristic: we have to check if the font is a standard one also
+      if (!!(flags & FontFlags.Symbolic)) {
+        baseEncoding = !properties.file ? Encodings.symbolsEncoding :
+                                          Encodings.MacRomanEncoding;
+      }
       var hasEncoding = dict.has('Encoding');
       if (hasEncoding) {
         var encoding = dict.get('Encoding');
         if (isDict(encoding)) {
           var baseName = encoding.get('BaseEncoding');
           if (baseName)
             baseEncoding = Encodings[baseName.name];
           else
@@ -14108,20 +14129,16 @@ var EvalState = (function EvalStateClosu
     this.strokeColorSpace = null;
   }
   EvalState.prototype = {
   };
   return EvalState;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 /**
  * Maximum time to wait for a font to be loaded by font-face rules.
  */
 var kMaxWaitForFontFace = 1000;
 
 // Unicode Private Use Area
 var kCmapGlyphOffset = 0xE000;
@@ -14514,82 +14531,90 @@ function mapPrivateUseChars(code) {
     case 0xF6D9: // copyrightserif
       return 0x00A9; // copyright
     default:
       return code;
   }
 }
 
 var FontLoader = {
-  listeningForFontLoad: false,
+  loadingContext: {
+    requests: [],
+    nextRequestId: 0
+  },
 
   bind: function fontLoaderBind(fonts, callback) {
-    function checkFontsLoaded() {
-      for (var i = 0, ii = fonts.length; i < ii; i++) {
-        var fontObj = fonts[i];
-        if (fontObj.loading) {
-          return false;
-        }
-      }
-
-      document.documentElement.removeEventListener(
-        'pdfjsFontLoad', checkFontsLoaded, false);
-
-      // Use timeout to fix chrome intermittent failures on font loading.
-      setTimeout(callback, 0);
-      return true;
-    }
-
-    var rules = [], names = [], fontsToLoad = [];
-    var fontCreateTimer = 0;
-
+    assert(!isWorker, 'bind() shall be called from main thread');
+
+    var rules = [], fontsToLoad = [];
     for (var i = 0, ii = fonts.length; i < ii; i++) {
       var font = fonts[i];
 
       // Add the font to the DOM only once or skip if the font
       // is already loaded.
       if (font.attached || font.loading == false) {
         continue;
       }
       font.attached = true;
 
-      fontsToLoad.push(font);
-
       var str = '';
       var data = font.data;
       if (data) {
         var length = data.length;
         for (var j = 0; j < length; j++)
           str += String.fromCharCode(data[j]);
 
         var rule = font.bindDOM(str);
         if (rule) {
           rules.push(rule);
-          names.push(font.loadedName);
-        }
-      }
-    }
-
-    this.listeningForFontLoad = false;
-    if (!isWorker && rules.length) {
-      FontLoader.prepareFontLoadEvent(rules, names, fontsToLoad);
-    }
-
-    if (!checkFontsLoaded()) {
-      document.documentElement.addEventListener(
-        'pdfjsFontLoad', checkFontsLoaded, false);
+          fontsToLoad.push(font);
+        }
+      }
+    }
+
+    var request = FontLoader.queueLoadingCallback(callback);
+    if (rules.length > 0) {
+      FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request);
+    } else {
+      request.complete();
     }
   },
+
+  queueLoadingCallback: function FontLoader_queueLoadingCallback(callback) {
+    function LoadLoader_completeRequest() {
+      assert(!request.end, 'completeRequest() cannot be called twice');
+      request.end = Date.now();
+
+      // sending all completed requests in order how they were queued
+      while (context.requests.length > 0 && context.requests[0].end) {
+        var otherRequest = context.requests.shift();
+        setTimeout(otherRequest.callback, 0);
+      }
+    }
+
+    var context = FontLoader.loadingContext;
+    var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);
+    var request = {
+      id: requestId,
+      complete: LoadLoader_completeRequest,
+      callback: callback,
+      started: Date.now()
+    };
+    context.requests.push(request);
+    return request;
+  },
+
   // Set things up so that at least one pdfjsFontLoad event is
-  // dispatched when all the @font-face |rules| for |names| have been
+  // dispatched when all the @font-face |rules| for |fonts| have been
   // loaded in a subdocument.  It's expected that the load of |rules|
   // has already started in this (outer) document, so that they should
   // be ordered before the load in the subdocument.
-  prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules, names,
-                                                                fonts) {
+  prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules,
+                                                                fonts,
+                                                                request) {
       /** Hack begin */
       // There's no event when a font has finished downloading so the
       // following code is a dirty hack to 'guess' when a font is
       // ready.  This code will be obsoleted by Mozilla bug 471915.
       //
       // The only reliable way to know if a font is loaded in Gecko
       // (at the moment) is document.onload in a document with
       // a @font-face rule defined in a "static" stylesheet.  We use a
@@ -14603,16 +14628,30 @@ var FontLoader = {
       // outer document, then create the iframe.  Unless something
       // goes really wonkily, we expect the @font-face for the outer
       // document to be processed before the inner.  That's still
       // fragile, but seems to work in practice.
       //
       // The postMessage() hackery was added to work around chrome bug
       // 82402.
 
+      var requestId = request.id;
+      // Validate the requestId parameter -- the value used to construct HTML.
+      if (!/^[\w\-]+$/.test(requestId)) {
+        error('Invalid request id: ' + requestId);
+
+        // Normally the error-function throws. But if a malicious code
+        // intercepts the function call then the return is needed.
+        return;
+      }
+
+      var names = [];
+      for (var i = 0, ii = fonts.length; i < ii; i++)
+        names.push(fonts[i].loadedName);
+
       // Validate the names parameter -- the values can used to construct HTML.
       if (!/^\w+$/.test(names.join(''))) {
         error('Invalid font name(s): ' + names.join());
 
         // Normally the error-function throws. But if a malicious code
         // intercepts the function call then the return is needed.
         return;
       }
@@ -14624,49 +14663,45 @@ var FontLoader = {
                        'position: absolute; top: 0px; left: 0px;');
       var html = '';
       for (var i = 0, ii = names.length; i < ii; ++i) {
         html += '<span style="font-family:' + names[i] + '">Hi</span>';
       }
       div.innerHTML = html;
       document.body.appendChild(div);
 
-      if (!this.listeningForFontLoad) {
-        window.addEventListener(
-          'message',
-          function fontLoaderMessage(e) {
-            var fontNames = JSON.parse(e.data);
-            for (var i = 0, ii = fonts.length; i < ii; ++i) {
-              var font = fonts[i];
-              font.loading = false;
-            }
-            var evt = document.createEvent('Events');
-            evt.initEvent('pdfjsFontLoad', true, false);
-            document.documentElement.dispatchEvent(evt);
-          },
-          false);
-        this.listeningForFontLoad = true;
-      }
+      window.addEventListener(
+        'message',
+        function fontLoaderMessage(e) {
+          if (e.data !== requestId)
+            return;
+          for (var i = 0, ii = fonts.length; i < ii; ++i) {
+            var font = fonts[i];
+            font.loading = false;
+          }
+          request.complete();
+          // cleanup
+          document.body.removeChild(frame);
+          window.removeEventListener('message', fontLoaderMessage, false);
+        },
+        false);
 
       // XXX we should have a time-out here too, and maybe fire
       // pdfjsFontLoadFailed?
       var src = '<!DOCTYPE HTML><html><head><meta charset="utf-8">';
       src += '<style type="text/css">';
       for (var i = 0, ii = rules.length; i < ii; ++i) {
         src += rules[i];
       }
       src += '</style>';
       src += '<script type="application/javascript">';
-      var fontNamesArray = '';
-      for (var i = 0, ii = names.length; i < ii; ++i) {
-        fontNamesArray += '"' + names[i] + '", ';
-      }
-      src += '  var fontNames=[' + fontNamesArray + '];\n';
       src += '  window.onload = function fontLoaderOnload() {\n';
-      src += '    parent.postMessage(JSON.stringify(fontNames), "*");\n';
+      src += '    parent.postMessage("' + requestId + '", "*");\n';
+      // Chrome stuck on loading (see chrome issue 145227) - resetting url
+      src += '    window.location = "about:blank";\n';
       src += '  }';
       // Hack so the end script tag isn't counted if this is inline JS.
       src += '</scr' + 'ipt></head><body>';
       for (var i = 0, ii = names.length; i < ii; ++i) {
         src += '<p style="font-family:\'' + names[i] + '\'">Hi</p>';
       }
       src += '</body></html>';
       var frame = document.createElement('iframe');
@@ -15671,23 +15706,29 @@ var Font = (function FontClosure() {
 
       this.encoding = properties.baseEncoding;
       this.noUnicodeAdaptation = true;
       this.loadedName = fontName.split('-')[0];
       this.loading = false;
       return;
     }
 
+    // Some fonts might use wrong font types for Type1C or CIDFontType0C
+    var subtype = properties.subtype;
+    if (subtype == 'Type1C' && (type != 'Type1' && type != 'MMType1'))
+      type = 'Type1';
+    if (subtype == 'CIDFontType0C' && type != 'CIDFontType0')
+      type = 'CIDFontType0';
+
     var data;
     switch (type) {
       case 'Type1':
       case 'CIDFontType0':
         this.mimetype = 'font/opentype';
 
-        var subtype = properties.subtype;
         var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ?
           new CFFFont(file, properties) : new Type1Font(name, file, properties);
 
         // Wrap the CFF data inside an OTF font file
         data = this.convert(name, cff, properties);
         break;
 
       case 'TrueType':
@@ -17032,16 +17073,17 @@ var Font = (function FontClosure() {
       if (properties.subtype == 'CIDFontType0C') {
         var toFontChar = [];
         for (var i = 0; i < charstrings.length; ++i) {
           var charstring = charstrings[i];
           toFontChar[charstring.code] = charstring.unicode;
         }
         this.toFontChar = toFontChar;
       }
+      var unitsPerEm = properties.unitsPerEm || 1000; // defaulting to 1000
 
       var fields = {
         // PostScript Font Program
         'CFF ': font.data,
 
         // OS/2 and Windows Specific metrics
         'OS/2': stringToArray(createOS2Table(properties, charstrings)),
 
@@ -17052,17 +17094,17 @@ var Font = (function FontClosure() {
         // Font header
         'head': (function fontFieldsHead() {
           return stringToArray(
               '\x00\x01\x00\x00' + // Version number
               '\x00\x00\x10\x00' + // fontRevision
               '\x00\x00\x00\x00' + // checksumAdjustement
               '\x5F\x0F\x3C\xF5' + // magicNumber
               '\x00\x00' + // Flags
-              '\x03\xE8' + // unitsPerEM (defaulting to 1000)
+              safeString16(unitsPerEm) + // unitsPerEM
               '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date
               '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date
               '\x00\x00' + // xMin
               safeString16(properties.descent) + // yMin
               '\x0F\xFF' + // xMax
               safeString16(properties.ascent) + // yMax
               string16(properties.italicAngle ? 2 : 0) + // macStyle
               '\x00\x11' + // lowestRecPPEM
@@ -17403,16 +17445,30 @@ var Font = (function FontClosure() {
       // Enter the translated string into the cache
       return (charsCache[chars] = glyphs);
     }
   };
 
   return Font;
 })();
 
+var ErrorFont = (function ErrorFontClosure() {
+  function ErrorFont(error) {
+    this.error = error;
+  }
+
+  ErrorFont.prototype = {
+    charsToGlyphs: function ErrorFont_charsToGlyphs() {
+      return [];
+    }
+  };
+
+  return ErrorFont;
+})();
+
 var CallothersubrCmd = (function CallothersubrCmdClosure() {
   function CallothersubrCmd(index) {
     this.index = index;
   }
 
   return CallothersubrCmd;
 })();
 
@@ -18507,16 +18563,29 @@ var CFFParser = (function CFFParserClosu
 
       this.parsePrivateDict(cff.topDict);
 
       cff.isCIDFont = topDict.hasName('ROS');
 
       var charStringOffset = topDict.getByName('CharStrings');
       cff.charStrings = this.parseCharStrings(charStringOffset);
 
+      var fontMatrix = topDict.getByName('FontMatrix');
+      if (fontMatrix) {
+        // estimating unitsPerEM for the font
+        properties.unitsPerEm = 1 / fontMatrix[0];
+      }
+
+      var fontBBox = topDict.getByName('FontBBox');
+      if (fontBBox) {
+        // adjusting ascent/descent
+        properties.ascent = fontBBox[3];
+        properties.descent = fontBBox[1];
+      }
+
       var charset, encoding;
       if (cff.isCIDFont) {
         var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj;
         for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) {
           var dictRaw = fdArrayIndex.get(i);
           var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw),
                                          cff.strings);
           this.parsePrivateDict(fontDict);
@@ -18580,17 +18649,17 @@ var CFFParser = (function CFFParserClosu
       var pos = 0;
 
       function parseOperand() {
         var value = dict[pos++];
         if (value === 30) {
           return parseFloatOperand(pos);
         } else if (value === 28) {
           value = dict[pos++];
-          value = (value << 8) | dict[pos++];
+          value = ((value << 24) | (dict[pos++] << 16)) >> 16;
           return value;
         } else if (value === 29) {
           value = dict[pos++];
           value = (value << 8) | dict[pos++];
           value = (value << 8) | dict[pos++];
           value = (value << 8) | dict[pos++];
           return value;
         } else if (value >= 32 && value <= 246) {
@@ -19609,20 +19678,16 @@ var CFFCompiler = (function CFFCompilerC
       }
       return data;
     }
   };
   return CFFCompiler;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var GlyphsUnicode = {
   A: 0x0041,
   AE: 0x00C6,
   AEacute: 0x01FC,
   AEmacron: 0x01E2,
   AEsmall: 0xF7E6,
   Aacute: 0x00C1,
@@ -23822,20 +23887,16 @@ var GlyphsUnicode = {
   zretroflexhook: 0x0290,
   zstroke: 0x01B6,
   zuhiragana: 0x305A,
   zukatakana: 0x30BA,
   '.notdef': 0x0000
 };
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var PDFImage = (function PDFImageClosure() {
   /**
    * Decode the image in the main thread if it supported. Resovles the promise
    * when the image data is ready.
    */
   function handleImageData(handler, xref, res, image, promise) {
     if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) {
@@ -23921,17 +23982,22 @@ var PDFImage = (function PDFImageClosure
         this.decodeCoefficients[j] = dmax - dmin;
         this.decodeAddends[j] = max * dmin;
       }
     }
 
     if (smask) {
       this.smask = new PDFImage(xref, res, smask, false);
     } else if (mask) {
-      this.mask = new PDFImage(xref, res, mask, false);
+      if (isStream(mask)) {
+        this.mask = new PDFImage(xref, res, mask, false);
+      } else {
+        // Color key mask (just an array).
+        this.mask = mask;
+      }
     }
   }
   /**
    * Handles processing of image data and calls the callback with an argument
    * of a PDFImage when the image is ready to be used.
    */
   PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
                                                      res, image, inline) {
@@ -23953,21 +24019,25 @@ var PDFImage = (function PDFImageClosure
     var smask = image.dict.get('SMask');
     var mask = image.dict.get('Mask');
 
     if (smask) {
       handleImageData(handler, xref, res, smask, smaskPromise);
       maskPromise.resolve(null);
     } else {
       smaskPromise.resolve(null);
-      if (mask && isStream(mask)) {
-        handleImageData(handler, xref, res, mask, maskPromise);
-      } else if (mask) {
-        TODO('handle color key masking');
-        maskPromise.resolve(null);
+      if (mask) {
+        if (isStream(mask)) {
+          handleImageData(handler, xref, res, mask, maskPromise);
+        } else if (isArray(mask)) {
+          maskPromise.resolve(mask);
+        } else {
+          warn('Unsupported mask format.');
+          maskPromise.resolve(null);
+        }
       } else {
         maskPromise.resolve(null);
       }
     }
   };
 
   /**
    * Resize an image using the nearest neighbor algorithm.  Currently only
@@ -24103,43 +24173,65 @@ var PDFImage = (function PDFImageClosure
           }
           output[i] = value;
           buf = buf & ((1 << remainingBits) - 1);
           bits = remainingBits;
         }
       }
       return output;
     },
-    getOpacity: function PDFImage_getOpacity(width, height) {
+    getOpacity: function PDFImage_getOpacity(width, height, image) {
       var smask = this.smask;
       var mask = this.mask;
       var originalWidth = this.width;
       var originalHeight = this.height;
       var buf;
 
       if (smask) {
         var sw = smask.width;
         var sh = smask.height;
         buf = new Uint8Array(sw * sh);
         smask.fillGrayBuffer(buf);
         if (sw != width || sh != height)
           buf = PDFImage.resize(buf, smask.bpc, 1, sw, sh, width, height);
       } else if (mask) {
-        var sw = mask.width;
-        var sh = mask.height;
-        buf = new Uint8Array(sw * sh);
-        mask.numComps = 1;
-        mask.fillGrayBuffer(buf);
-
-        // Need to invert values in buffer
-        for (var i = 0, ii = sw * sh; i < ii; ++i)
-          buf[i] = 255 - buf[i];
-
-        if (sw != width || sh != height)
-          buf = PDFImage.resize(buf, mask.bpc, 1, sw, sh, width, height);
+        if (mask instanceof PDFImage) {
+          var sw = mask.width;
+          var sh = mask.height;
+          buf = new Uint8Array(sw * sh);
+          mask.numComps = 1;
+          mask.fillGrayBuffer(buf);
+
+          // Need to invert values in buffer
+          for (var i = 0, ii = sw * sh; i < ii; ++i)
+            buf[i] = 255 - buf[i];
+
+          if (sw != width || sh != height)
+            buf = PDFImage.resize(buf, mask.bpc, 1, sw, sh, width, height);
+        } else if (isArray(mask)) {
+          // Color key mask: if any of the compontents are outside the range
+          // then they should be painted.
+          buf = new Uint8Array(width * height);
+          var numComps = this.numComps;
+          for (var i = 0, ii = width * height; i < ii; ++i) {
+            var opacity = 0;
+            var imageOffset = i * numComps;
+            for (var j = 0; j < numComps; ++j) {
+              var color = image[imageOffset + j];
+              var maskOffset = j * 2;
+              if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
+                opacity = 255;
+                break;
+              }
+            }
+            buf[i] = opacity;
+          }
+        } else {
+          error('Unknown mask format.');
+        }
       } else {
         buf = new Uint8Array(width * height);
         for (var i = 0, ii = width * height; i < ii; ++i)
           buf[i] = 255;
       }
       return buf;
     },
     applyStencilMask: function PDFImage_applyStencilMask(buffer,
@@ -24181,17 +24273,17 @@ var PDFImage = (function PDFImageClosure
                          height / originalHeight);
 
       var comps = this.colorSpace.getRgbBuffer(
         this.getComponents(imgArray), bpc);
       if (originalWidth != width || originalHeight != height)
         comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
                                 originalHeight, width, height);
       var compsPos = 0;
-      var opacity = this.getOpacity(width, height);
+      var opacity = this.getOpacity(width, height, imgArray);
       var opacityPos = 0;
       var length = width * actualHeight * 4;
 
       for (var i = 0; i < length; i += 4) {
         buffer[i] = comps[compsPos++];
         buffer[i + 1] = comps[compsPos++];
         buffer[i + 2] = comps[compsPos++];
         buffer[i + 3] = opacity[opacityPos++];
@@ -24229,20 +24321,16 @@ function loadJpegStream(id, imageData, o
   var img = new Image();
   img.onload = (function loadJpegStream_onloadClosure() {
     objs.resolve(id, img);
   });
   img.src = 'data:image/jpeg;base64,' + window.btoa(imageData);
 }
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 // The Metrics object contains glyph widths (in glyph space units).
 // As per PDF spec, for most fonts (Type 3 being an exception) a glyph
 // space unit corresponds to 1/1000th of text space unit.
 var Metrics = {
   'Courier': 600,
   'Courier-Bold': 600,
   'Courier-BoldOblique': 600,
@@ -27177,20 +27265,16 @@ var Metrics = {
     'a188': 873,
     'a189': 927,
     'a190': 970,
     'a191': 918
   }
 };
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var EOF = {};
 
 function isEOF(v) {
   return v == EOF;
 }
 
 var Parser = (function ParserClosure() {
@@ -27835,20 +27919,16 @@ var Linearization = (function Linearizat
       return this.getInt('P');
     }
   };
 
   return Linearization;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var PatternType = {
   AXIAL: 2,
   RADIAL: 3
 };
 
 var Pattern = (function PatternClosure() {
   // Constructor should define this.getPattern
@@ -28042,18 +28122,19 @@ var TilingPattern = (function TilingPatt
 
   function TilingPattern(IR, color, ctx, objs) {
     var operatorList = IR[2];
     this.matrix = IR[3];
     var bbox = IR[4];
     var xstep = IR[5];
     var ystep = IR[6];
     var paintType = IR[7];
-
-    TODO('TilingType');
+    var tilingType = IR[8];
+
+    TODO('TilingType: ' + tilingType);
 
     this.curMatrix = ctx.mozCurrentTransform;
     this.invMatrix = ctx.mozCurrentTransformInverse;
     this.ctx = ctx;
     this.type = 'Pattern';
 
     var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
 
@@ -28116,19 +28197,21 @@ var TilingPattern = (function TilingPatt
   }
 
   TilingPattern.getIR = function TilingPattern_getIR(operatorList, dict, args) {
     var matrix = dict.get('Matrix');
     var bbox = dict.get('BBox');
     var xstep = dict.get('XStep');
     var ystep = dict.get('YStep');
     var paintType = dict.get('PaintType');
+    var tilingType = dict.get('TilingType');
 
     return [
-      'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep, paintType
+      'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
+      paintType, tilingType
     ];
   };
 
   TilingPattern.prototype = {
     getPattern: function TilingPattern_getPattern() {
       var matrix = this.matrix;
       var curMatrix = this.curMatrix;
       var ctx = this.ctx;
@@ -28145,20 +28228,16 @@ var TilingPattern = (function TilingPatt
       return ctx.createPattern(this.canvas, 'repeat');
     }
   };
 
   return TilingPattern;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 var Stream = (function StreamClosure() {
   function Stream(arrayBuffer, start, length, dict) {
     this.bytes = new Uint8Array(arrayBuffer);
     this.start = start || 0;
     this.pos = this.start;
     this.end = (start + length) || this.bytes.length;
     this.dict = dict;
@@ -30484,20 +30563,16 @@ var LZWStream = (function LZWStreamClosu
 
     this.bufferLength = currentBufferLength;
   };
 
   return LZWStream;
 })();
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
 
 function MessageHandler(name, comObj) {
   this.name = name;
   this.comObj = comObj;
   this.callbackIndex = 1;
   var callbacks = this.callbacks = {};
   var ah = this.actionHandler = {};
 
@@ -30797,935 +30872,16 @@ if (typeof window === 'undefined') {
     }
   });
 
   var handler = new MessageHandler('worker_processor', this);
   WorkerMessageHandler.setup(handler);
 }
 
 
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-// - The JPEG specification can be found in the ITU CCITT Recommendation T.81
-//   (www.w3.org/Graphics/JPEG/itu-t81.pdf)
-// - The JFIF specification can be found in the JPEG File Interchange Format
-//   (www.w3.org/Graphics/JPEG/jfif3.pdf)
-// - The Adobe Application-Specific JPEG markers in the Supporting the DCT Filters
-//   in PostScript Level 2, Technical Note #5116
-//   (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf)
-
-var JpegImage = (function jpegImage() {
-  "use strict";
-  var dctZigZag = new Int32Array([
-     0,
-     1,  8,
-    16,  9,  2,
-     3, 10, 17, 24,
-    32, 25, 18, 11, 4,
-     5, 12, 19, 26, 33, 40,
-    48, 41, 34, 27, 20, 13,  6,
-     7, 14, 21, 28, 35, 42, 49, 56,
-    57, 50, 43, 36, 29, 22, 15,
-    23, 30, 37, 44, 51, 58,
-    59, 52, 45, 38, 31,
-    39, 46, 53, 60,
-    61, 54, 47,
-    55, 62,
-    63
-  ]);
-
-  var dctCos1  =  4017   // cos(pi/16)
-  var dctSin1  =   799   // sin(pi/16)
-  var dctCos3  =  3406   // cos(3*pi/16)
-  var dctSin3  =  2276   // sin(3*pi/16)
-  var dctCos6  =  1567   // cos(6*pi/16)
-  var dctSin6  =  3784   // sin(6*pi/16)
-  var dctSqrt2 =  5793   // sqrt(2)
-  var dctSqrt1d2 = 2896  // sqrt(2) / 2
-
-  function constructor() {
-  }
-
-  function buildHuffmanTable(codeLengths, values) {
-    var k = 0, code = [], i, j, length = 16;
-    while (length > 0 && !codeLengths[length - 1])
-      length--;
-    code.push({children: [], index: 0});
-    var p = code[0], q;
-    for (i = 0; i < length; i++) {
-      for (j = 0; j < codeLengths[i]; j++) {
-        p = code.pop();
-        p.children[p.index] = values[k];
-        while (p.index > 0) {
-          p = code.pop();
-        }
-        p.index++;
-        code.push(p);
-        while (code.length <= i) {
-          code.push(q = {children: [], index: 0});
-          p.children[p.index] = q.children;
-          p = q;
-        }
-        k++;
-      }
-      if (i + 1 < length) {
-        // p here points to last code
-        code.push(q = {children: [], index: 0});
-        p.children[p.index] = q.children;
-        p = q;
-      }
-    }
-    return code[0].children;
-  }
-
-  function decodeScan(data, offset,
-                      frame, components, resetInterval,
-                      spectralStart, spectralEnd,
-                      successivePrev, successive) {
-    var precision = frame.precision;
-    var samplesPerLine = frame.samplesPerLine;
-    var scanLines = frame.scanLines;
-    var mcusPerLine = frame.mcusPerLine;
-    var progressive = frame.progressive;
-    var maxH = frame.maxH, maxV = frame.maxV;
-
-    var startOffset = offset, bitsData = 0, bitsCount = 0;
-    function readBit() {
-      if (bitsCount > 0) {
-        bitsCount--;
-        return (bitsData >> bitsCount) & 1;
-      }
-      bitsData = data[offset++];
-      if (bitsData == 0xFF) {
-        var nextByte = data[offset++];
-        if (nextByte) {
-          throw "unexpected marker: " + ((bitsData << 8) | nextByte).toString(16);
-        }
-        // unstuff 0
-      }
-      bitsCount = 7;
-      return bitsData >>> 7;
-    }
-    function decodeHuffman(tree) {
-      var node = tree, bit;
-      while ((bit = readBit()) !== null) {
-        node = node[bit];
-        if (typeof node === 'number')
-          return node;
-        if (typeof node !== 'object')
-          throw "invalid huffman sequence";
-      }
-      return null;
-    }
-    function receive(length) {
-      var n = 0;
-      while (length > 0) {
-        var bit = readBit();
-        if (bit === null) return;
-        n = (n << 1) | bit;
-        length--;
-      }
-      return n;
-    }
-    function receiveAndExtend(length) {
-      var n = receive(length);
-      if (n >= 1 << (length - 1))
-        return n;
-      return n + (-1 << length) + 1;
-    }
-    function decodeBaseline(component, zz) {
-      var t = decodeHuffman(component.huffmanTableDC);
-      var diff = t === 0 ? 0 : receiveAndExtend(t);
-      zz[0]= (component.pred += diff);
-      var k = 1;
-      while (k < 64) {
-        var rs = decodeHuffman(component.huffmanTableAC);
-        var s = rs & 15, r = rs >> 4;
-        if (s === 0) {
-          if (r < 15)
-            break;
-          k += 16;
-          continue;
-        }
-        k += r;
-        var z = dctZigZag[k];
-        zz[z] = receiveAndExtend(s);
-        k++;
-      }
-    }
-    function decodeDCFirst(component, zz) {
-      var t = decodeHuffman(component.huffmanTableDC);
-      var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
-      zz[0] = (component.pred += diff);
-    }
-    function decodeDCSuccessive(component, zz) {
-      zz[0] |= readBit() << successive;
-    }
-    var eobrun = 0;
-    function decodeACFirst(component, zz) {
-      if (eobrun > 0) {
-        eobrun--;
-        return;
-      }
-      var k = spectralStart, e = spectralEnd;
-      while (k <= e) {
-        var rs = decodeHuffman(component.huffmanTableAC);
-        var s = rs & 15, r = rs >> 4;
-        if (s === 0) {
-          if (r < 15) {
-            eobrun = receive(r) + (1 << r) - 1;
-            break;
-          }
-          k += 16;
-          continue;
-        }
-        k += r;
-        var z = dctZigZag[k];
-        zz[z] = receiveAndExtend(s) * (1 << successive);
-        k++;
-      }
-    }
-    var successiveACState = 0, successiveACNextValue;
-    function decodeACSuccessive(component, zz) {
-      var k = spectralStart, e = spectralEnd, r = 0;
-      while (k <= e) {
-        var z = dctZigZag[k];
-        switch (successiveACState) {
-        case 0: // initial state
-          var rs = decodeHuffman(component.huffmanTableAC);
-          var s = rs & 15, r = rs >> 4;
-          if (s === 0) {
-            if (r < 15) {
-              eobrun = receive(r) + (1 << r);
-              successiveACState = 4;
-            } else {
-              r = 16;
-              successiveACState = 1;
-            }
-          } else {
-            if (s !== 1)
-              throw "invalid ACn encoding";
-            successiveACNextValue = receiveAndExtend(s);
-            successiveACState = r ? 2 : 3;
-          }
-          continue;
-        case 1: // skipping r zero items
-        case 2:
-          if (zz[z])
-            zz[z] += (readBit() << successive);
-          else {
-            r--;
-            if (r === 0)
-              successiveACState = successiveACState == 2 ? 3 : 0;
-          }
-          break;
-        case 3: // set value for a zero item
-          if (zz[z])
-            zz[z] += (readBit() << successive);
-          else {
-            zz[z] = successiveACNextValue << successive;
-            successiveACState = 0;
-          }
-          break;
-        case 4: // eob
-          if (zz[z])
-            zz[z] += (readBit() << successive);
-          break;
-        }
-        k++;
-      }
-      if (successiveACState === 4) {
-        eobrun--;
-        if (eobrun === 0)
-          successiveACState = 0;
-      }
-    }
-    function decodeMcu(component, decode, mcu, row, col) {
-      var mcuRow = (mcu / mcusPerLine) | 0;
-      var mcuCol = mcu % mcusPerLine;
-      var blockRow = mcuRow * component.v + row;
-      var blockCol = mcuCol * component.h + col;
-      decode(component, component.blocks[blockRow][blockCol]);
-    }
-    function decodeBlock(component, decode, mcu) {
-      var blockRow = (mcu / component.blocksPerLine) | 0;
-      var blockCol = mcu % component.blocksPerLine;
-      decode(component, component.blocks[blockRow][blockCol]);
-    }
-
-    var componentsLength = components.length;
-    var component, i, j, k, n;
-    var decodeFn;
-    if (progressive) {
-      if (spectralStart === 0)
-        decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
-      else
-        decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
-    } else {
-      decodeFn = decodeBaseline;
-    }
-
-    var mcu = 0, marker;
-    var mcuExpected;
-    if (componentsLength == 1) {
-      mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
-    } else {
-      mcuExpected = mcusPerLine * frame.mcusPerColumn;
-    }
-    if (!resetInterval) resetInterval = mcuExpected;
-
-    var h, v;
-    while (mcu < mcuExpected) {
-      // reset interval stuff
-      for (i = 0; i < componentsLength; i++)
-        components[i].pred = 0;
-      eobrun = 0;
-
-      if (componentsLength == 1) {
-        component = components[0];
-        for (n = 0; n < resetInterval; n++) {
-          decodeBlock(component, decodeFn, mcu);
-          mcu++;
-        }
-      } else {
-        for (n = 0; n < resetInterval; n++) {
-          for (i = 0; i < componentsLength; i++) {
-            component = components[i];
-            h = component.h;
-            v = component.v;
-            for (j = 0; j < v; j++) {
-              for (k = 0; k < h; k++) {
-                decodeMcu(component, decodeFn, mcu, j, k);
-              }
-            }
-          }
-          mcu++;
-        }
-      }
-
-      // find marker
-      bitsCount = 0;
-      marker = (data[offset] << 8) | data[offset + 1];
-      if (marker <= 0xFF00) {
-        throw "marker was not found";
-      }
-
-      if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
-        offset += 2;
-      }
-      else
-        break;
-    }
-
-    return offset - startOffset;
-  }
-
-  function buildComponentData(frame, component) {
-    var lines = [];
-    var blocksPerLine = component.blocksPerLine;
-    var blocksPerColumn = component.blocksPerColumn;
-    var samplesPerLine = blocksPerLine << 3;
-    var R = new Int32Array(64), r = new Uint8Array(64);
-
-    // A port of poppler's IDCT method which in turn is taken from:
-    //   Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
-    //   "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
-    //   IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
-    //   988-991.
-    function quantizeAndInverse(zz, dataOut, dataIn) {
-      var qt = component.quantizationTable;
-      var v0, v1, v2, v3, v4, v5, v6, v7, t;
-      var p = dataIn;
-      var i;
-
-      // dequant
-      for (i = 0; i < 64; i++)
-        p[i] = zz[i] * qt[i];
-
-      // inverse DCT on rows
-      for (i = 0; i < 8; ++i) {
-        var row = 8 * i;
-
-        // check for all-zero AC coefficients
-        if (p[1 + row] == 0 && p[2 + row] == 0 && p[3 + row] == 0 &&
-            p[4 + row] == 0 && p[5 + row] == 0 && p[6 + row] == 0 &&
-            p[7 + row] == 0) {
-          t = (dctSqrt2 * p[0 + row] + 512) >> 10;
-          p[0 + row] = t;
-          p[1 + row] = t;
-          p[2 + row] = t;
-          p[3 + row] = t;
-          p[4 + row] = t;
-          p[5 + row] = t;
-          p[6 + row] = t;
-          p[7 + row] = t;
-          continue;
-        }
-
-        // stage 4
-        v0 = (dctSqrt2 * p[0 + row] + 128) >> 8;
-        v1 = (dctSqrt2 * p[4 + row] + 128) >> 8;
-        v2 = p[2 + row];
-        v3 = p[6 + row];
-        v4 = (dctSqrt1d2 * (p[1 + row] - p[7 + row]) + 128) >> 8;
-        v7 = (dctSqrt1d2 * (p[1 + row] + p[7 + row]) + 128) >> 8;
-        v5 = p[3 + row] << 4;
-        v6 = p[5 + row] << 4;
-
-        // stage 3
-        t = (v0 - v1+ 1) >> 1;
-        v0 = (v0 + v1 + 1) >> 1;
-        v1 = t;
-        t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
-        v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
-        v3 = t;
-        t = (v4 - v6 + 1) >> 1;
-        v4 = (v4 + v6 + 1) >> 1;
-        v6 = t;
-        t = (v7 + v5 + 1) >> 1;
-        v5 = (v7 - v5 + 1) >> 1;
-        v7 = t;
-
-        // stage 2
-        t = (v0 - v3 + 1) >> 1;
-        v0 = (v0 + v3 + 1) >> 1;
-        v3 = t;
-        t = (v1 - v2 + 1) >> 1;
-        v1 = (v1 + v2 + 1) >> 1;
-        v2 = t;
-        t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
-        v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
-        v7 = t;
-        t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
-        v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
-        v6 = t;
-
-        // stage 1
-        p[0 + row] = v0 + v7;
-        p[7 + row] = v0 - v7;
-        p[1 + row] = v1 + v6;
-        p[6 + row] = v1 - v6;
-        p[2 + row] = v2 + v5;
-        p[5 + row] = v2 - v5;
-        p[3 + row] = v3 + v4;
-        p[4 + row] = v3 - v4;
-      }
-
-      // inverse DCT on columns
-      for (i = 0; i < 8; ++i) {
-        var col = i;
-
-        // check for all-zero AC coefficients
-        if (p[1*8 + col] == 0 && p[2*8 + col] == 0 && p[3*8 + col] == 0 &&
-            p[4*8 + col] == 0 && p[5*8 + col] == 0 && p[6*8 + col] == 0 &&
-            p[7*8 + col] == 0) {
-          t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14;
-          p[0*8 + col] = t;
-          p[1*8 + col] = t;
-          p[2*8 + col] = t;
-          p[3*8 + col] = t;
-          p[4*8 + col] = t;
-          p[5*8 + col] = t;
-          p[6*8 + col] = t;
-          p[7*8 + col] = t;
-          continue;
-        }
-
-        // stage 4
-        v0 = (dctSqrt2 * p[0*8 + col] + 2048) >> 12;
-        v1 = (dctSqrt2 * p[4*8 + col] + 2048) >> 12;
-        v2 = p[2*8 + col];
-        v3 = p[6*8 + col];
-        v4 = (dctSqrt1d2 * (p[1*8 + col] - p[7*8 + col]) + 2048) >> 12;
-        v7 = (dctSqrt1d2 * (p[1*8 + col] + p[7*8 + col]) + 2048) >> 12;
-        v5 = p[3*8 + col];
-        v6 = p[5*8 + col];
-
-        // stage 3
-        t = (v0 - v1 + 1) >> 1;
-        v0 = (v0 + v1 + 1) >> 1;
-        v1 = t;
-        t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
-        v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
-        v3 = t;
-        t = (v4 - v6 + 1) >> 1;
-        v4 = (v4 + v6 + 1) >> 1;
-        v6 = t;
-        t = (v7 + v5 + 1) >> 1;
-        v5 = (v7 - v5 + 1) >> 1;
-        v7 = t;
-
-        // stage 2
-        t = (v0 - v3 + 1) >> 1;
-        v0 = (v0 + v3 + 1) >> 1;
-        v3 = t;
-        t = (v1 - v2 + 1) >> 1;
-        v1 = (v1 + v2 + 1) >> 1;
-        v2 = t;
-        t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
-        v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
-        v7 = t;
-        t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
-        v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
-        v6 = t;
-
-        // stage 1
-        p[0*8 + col] = v0 + v7;
-        p[7*8 + col] = v0 - v7;
-        p[1*8 + col] = v1 + v6;
-        p[6*8 + col] = v1 - v6;
-        p[2*8 + col] = v2 + v5;
-        p[5*8 + col] = v2 - v5;
-        p[3*8 + col] = v3 + v4;
-        p[4*8 + col] = v3 - v4;
-      }
-
-      // convert to 8-bit integers
-      for (i = 0; i < 64; ++i) {
-        var sample = 128 + ((p[i] + 8) >> 4);
-        dataOut[i] = sample < 0 ? 0 : sample > 0xFF ? 0xFF : sample;
-      }
-    }
-
-    var i, j;
-    for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
-      var scanLine = blockRow << 3;
-      for (i = 0; i < 8; i++)
-        lines.push(new Uint8Array(samplesPerLine));
-      for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
-        quantizeAndInverse(component.blocks[blockRow][blockCol], r, R);
-
-        var offset = 0, sample = blockCol << 3;
-        for (j = 0; j < 8; j++) {
-          var line = lines[scanLine + j];
-          for (i = 0; i < 8; i++)
-            line[sample + i] = r[offset++];
-        }
-      }
-    }
-    return lines;
-  }
-
-  constructor.prototype = {
-    load: function load(path) {
-      var xhr = new XMLHttpRequest();
-      xhr.open("GET", path, true);
-      xhr.responseType = "arraybuffer";
-      xhr.onload = (function() {
-        // TODO catch parse error
-        var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
-        this.parse(data);
-        if (this.onload)
-          this.onload();
-      }).bind(this);
-      xhr.send(null);
-    },
-    parse: function parse(data) {
-      var offset = 0, length = data.length;
-      function readUint16() {
-        var value = (data[offset] << 8) | data[offset + 1];
-        offset += 2;
-        return value;
-      }
-      function readDataBlock() {
-        var length = readUint16();
-        var array = data.subarray(offset, offset + length - 2);
-        offset += array.length;
-        return array;
-      }
-      function prepareComponents(frame) {
-        var maxH = 0, maxV = 0;
-        var component, componentId;
-        for (componentId in frame.components) {
-          if (frame.components.hasOwnProperty(componentId)) {
-            component = frame.components[componentId];
-            if (maxH < component.h) maxH = component.h;
-            if (maxV < component.v) maxV = component.v;
-          }
-        }
-        var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / maxH);
-        var mcusPerColumn = Math.ceil(frame.scanLines / 8 / maxV);
-        for (componentId in frame.components) {
-          if (frame.components.hasOwnProperty(componentId)) {
-            component = frame.components[componentId];
-            var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / maxH);
-            var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines  / 8) * component.v / maxV);
-            var blocksPerLineForMcu = mcusPerLine * component.h;
-            var blocksPerColumnForMcu = mcusPerColumn * component.v;
-            var blocks = [];
-            for (var i = 0; i < blocksPerColumnForMcu; i++) {
-              var row = [];
-              for (var j = 0; j < blocksPerLineForMcu; j++)
-                row.push(new Int32Array(64));
-              blocks.push(row);
-            }
-            component.blocksPerLine = blocksPerLine;
-            component.blocksPerColumn = blocksPerColumn;
-            component.blocks = blocks;
-          }
-        }
-        frame.maxH = maxH;
-        frame.maxV = maxV;
-        frame.mcusPerLine = mcusPerLine;
-        frame.mcusPerColumn = mcusPerColumn;
-      }
-      var jfif = null;
-      var adobe = null;
-      var pixels = null;
-      var frame, resetInterval;
-      var quantizationTables = [], frames = [];
-      var huffmanTablesAC = [], huffmanTablesDC = [];
-      var fileMarker = readUint16();
-      if (fileMarker != 0xFFD8) { // SOI (Start of Image)
-        throw "SOI not found";
-      }
-
-      fileMarker = readUint16();
-      while (fileMarker != 0xFFD9) { // EOI (End of image)
-        var i, j, l;
-        switch(fileMarker) {
-          case 0xFFE0: // APP0 (Application Specific)
-          case 0xFFE1: // APP1
-          case 0xFFE2: // APP2
-          case 0xFFE3: // APP3
-          case 0xFFE4: // APP4
-          case 0xFFE5: // APP5
-          case 0xFFE6: // APP6
-          case 0xFFE7: // APP7
-          case 0xFFE8: // APP8
-          case 0xFFE9: // APP9
-          case 0xFFEA: // APP10
-          case 0xFFEB: // APP11
-          case 0xFFEC: // APP12
-          case 0xFFED: // APP13
-          case 0xFFEE: // APP14
-          case 0xFFEF: // APP15
-          case 0xFFFE: // COM (Comment)
-            var appData = readDataBlock();
-
-            if (fileMarker === 0xFFE0) {
-              if (appData[0] === 0x4A && appData[1] === 0x46 && appData[2] === 0x49 &&
-                appData[3] === 0x46 && appData[4] === 0) { // 'JFIF\x00'
-                jfif = {
-                  version: { major: appData[5], minor: appData[6] },
-                  densityUnits: appData[7],
-                  xDensity: (appData[8] << 8) | appData[9],
-                  yDensity: (appData[10] << 8) | appData[11],
-                  thumbWidth: appData[12],
-                  thumbHeight: appData[13],
-                  thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13])
-                };
-              }
-            }
-            // TODO APP1 - Exif
-            if (fileMarker === 0xFFEE) {
-              if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6F &&
-                appData[3] === 0x62 && appData[4] === 0x65 && appData[5] === 0) { // 'Adobe\x00'
-                adobe = {
-                  version: appData[6],
-                  flags0: (appData[7] << 8) | appData[8],
-                  flags1: (appData[9] << 8) | appData[10],
-                  transformCode: appData[11]
-                };
-              }
-            }
-            break;
-
-          case 0xFFDB: // DQT (Define Quantization Tables)
-            var quantizationTableCount = Math.floor((readUint16() - 2) / 65);
-            for (i = 0; i < quantizationTableCount; i++) {
-              var quantizationTableSpec = data[offset++];
-              var tableData = new Int32Array(64);
-              if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
-                for (j = 0; j < 64; j++) {
-                  var z = dctZigZag[j];
-                  tableData[z] = data[offset++];
-                }
-              } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
-                for (j = 0; j < 64; j++) {
-                  var z = dctZigZag[j];
-                  tableData[z] = readUint16();
-                }
-              } else
-                throw "DQT: invalid table spec";
-              quantizationTables[quantizationTableSpec & 15] = tableData;
-            }
-            break;
-
-          case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
-          case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
-            readUint16(); // skip data length
-            frame = {};
-            frame.progressive = (fileMarker === 0xFFC2);
-            frame.precision = data[offset++];
-            frame.scanLines = readUint16();
-            frame.samplesPerLine = readUint16();
-            frame.components = {};
-            frame.componentsOrder = [];
-            var componentsCount = data[offset++], componentId;
-            var maxH = 0, maxV = 0;
-            for (i = 0; i < componentsCount; i++) {
-              componentId = data[offset];
-              var h = data[offset + 1] >> 4;
-              var v = data[offset + 1] & 15;
-              var qId = data[offset + 2];
-              frame.componentsOrder.push(componentId);
-              frame.components[componentId] = {
-                h: h,
-                v: v,
-                quantizationTable: quantizationTables[qId]
-              };
-              offset += 3;
-            }
-            prepareComponents(frame);
-            frames.push(frame);
-            break;
-
-          case 0xFFC4: // DHT (Define Huffman Tables)
-            var huffmanLength = readUint16();
-            for (i = 2; i < huffmanLength;) {
-              var huffmanTableSpec = data[offset++];
-              var codeLengths = new Uint8Array(16);
-              var codeLengthSum = 0;
-              for (j = 0; j < 16; j++, offset++)
-                codeLengthSum += (codeLengths[j] = data[offset]);
-              var huffmanValues = new Uint8Array(codeLengthSum);
-              for (j = 0; j < codeLengthSum; j++, offset++)
-                huffmanValues[j] = data[offset];
-              i += 17 + codeLengthSum;
-
-              ((huffmanTableSpec >> 4) === 0 ? 
-                huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
-                buildHuffmanTable(codeLengths, huffmanValues);
-            }
-            break;
-
-          case 0xFFDD: // DRI (Define Restart Interval)
-            readUint16(); // skip data length
-            resetInterval = readUint16();
-            break;
-
-          case 0xFFDA: // SOS (Start of Scan)
-            var scanLength = readUint16();
-            var selectorsCount = data[offset++];
-            var components = [], component;
-            for (i = 0; i < selectorsCount; i++) {
-              component = frame.components[data[offset++]];
-              var tableSpec = data[offset++];
-              component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
-              component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
-              components.push(component);
-            }
-            var spectralStart = data[offset++];
-            var spectralEnd = data[offset++];
-            var successiveApproximation = data[offset++];
-            var processed = decodeScan(data, offset,
-              frame, components, resetInterval,
-              spectralStart, spectralEnd,
-              successiveApproximation >> 4, successiveApproximation & 15);
-            offset += processed;
-            break;
-          default:
-            throw "unknown JPEG marker " + fileMarker.toString(16);
-        }
-        fileMarker = readUint16();
-      }
-      if (frames.length != 1)
-        throw "only single frame JPEGs supported";
-
-      this.width = frame.samplesPerLine;
-      this.height = frame.scanLines;
-      this.jfif = jfif;
-      this.adobe = adobe;
-      this.components = [];
-      for (var i = 0; i < frame.componentsOrder.length; i++) {
-        var component = frame.components[frame.componentsOrder[i]];
-        this.components.push({
-          lines: buildComponentData(frame, component),
-          scaleX: component.h / frame.maxH,
-          scaleY: component.v / frame.maxV
-        });
-      }
-    },
-    getData: function getData(width, height) {
-      function clampTo8bit(a) {
-        return a < 0 ? 0 : a > 255 ? 255 : a;
-      }