KEMBAR78
Implementing New Web | PDF
IMPLEMENTING NEW WEBAPIS
   Gregor Wagner (gwagner@mozilla.com)
    Julian Viereck (jviereck@mozilla.com)
DISCALIMER

• No    API designing/standadization here

• Talk   about making the implementation happen!

• 55”   not enough to get you going

• Reach    out to us and do “hands-on” hacking
OUTLINE
• General   Introduction

• How    To Implement New API

  • JS

  • C++

• Make    your work land

• Q&A
GENERAL INTRODUCTION
GENERAL INTRODUCTION
• Build   on two previous presentations

  • JS: David Dahl’s “From Web Developer to Firefox
      Hacker” [1]

  • C++:    Bobby Holley’s “Hacking Gecko” [2]

  •   [1]: http://people.mozilla.com/~ddahl/pages/HackingFirefox/
      template.html

  •   [2]: http://people.mozilla.com/~bholley/hacking-gecko-
      fosdem2012/hacking-gecko.html
GENERAL INTRODUCTION
• Need   to build Firefox

• Run   build:

  • Linux/Windows:      objdir/dist/bin/firefox

  • OSX:
       objdir/dist/AppName.app/Contents/
   MacOS/firefox

  • options:     -ProfileManager, -no-remote
GENERAL INTRODUCTION
GENERAL INTRODUCTION
• Don’t   get lost in the details

• Ask   for an implementation outline

• There    is documentation, overview

• Über-Weapon:      Ask for help

  • IRC:   https://wiki.mozilla.org/IRC, #developers

  • Mailing list:
   https://lists.mozilla.org/listinfo, dev-webapi
FRIENDLY PEOPLE TO
    PING ON IRC
khuey (Kyle Huey)
ehsan (Ehsan Akhgari)
bholley (Bobby Holley)
jdm (Josh Matthews)
dholbert (Daniel Holbert)
Ms2ger (???)
GENERAL INTRODUCTION
• whenever    you do communication

 • try   to be precise

 • give   reasoning to your arguments

 • get
     only short answer - don’t take it wrong,
  people are really busy

 • dump     whatever you have (crashback/patch...)
GENERAL INTRODUCTION

• don’t   be afraid to ping people

• might    get hint to ping someone else

• tell   people you're new to hacking JS/Gecko

• look/ask    for bugs that do similar things you try
 to solve
HTTPS://MXR.MOZILLA.ORG/
FIREFOX OS WEBAPI

 Wifi     Browser          Battery
                  Telephony
 Settings                     Idle
                Power
Contacts                 Bluetooth
        Vibrator   Webapps
           many more to come....

    https://wiki.mozilla.org/WebAPI/
INTERFACE + IMPLEMENTATION
IT ALL STARTS WITH AN INTERFACE
         XPIDL VS. WEBIDL
XPIDL VS. WEBIDL

[scriptable, builtinclass,
                                                            interface EventTarget {
uuid(5a8294df-ffe4-48e5-803f-f57bebc29289)]
                                                             void addEventListener(DOMString type,
interface nsIDOMScreen : nsIDOMEventTarget
                                                                         EventListener? listener,
{                                                                        optional boolean capture = false,
  readonly attribute long top;                                           optional boolean? wantsUntrusted = null);
  readonly attribute DOMString mozOrientation;               void removeEventListener(DOMString type,
  [implicit_jscontext]                                                    EventListener? listener,
  attribute jsval      onmozorientationchange;                            optional boolean capture = false);
                                                             boolean dispatchEvent(Event event);
  boolean mozLockOrientation(in DOMString orientation);     };
  void mozUnlockOrientation();
};




          https://developer.mozilla.org/en-US/docs/XPIDL   https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings
MAPPING JS VS C++

• Read    other APIs

• Interfaces   are defined in dom/interfaces

• Implementations      mostly in dom/*, content/*

• c++   implementations use common inheritance

• JS   implementations use manifest file
TIME TO FILE A BUG
Bugzilla: DOM:Device Interfaces
HOW TO IMPLEMENT JS
WHY IN JS?
• Prototyping

• Lower   entry point

• WebDevs    know JS

 • Also
      better for
  understanding!
INTERFACE EXAMPLE



For example dom/interfaces/helloworld/nsIHelloWorld.idl

[scriptable, uuid(da0f7040-388b-11e1-b86c-0800200c9444)]
interface nsIDOMHelloWorld : nsISupports
{
  void sayHello(in DOMString aName);
};




https://bugzilla.mozilla.org/show_bug.cgi?id=674720
HELLOWORLD.MANIFEST

For example dom/helloworld/HelloWorld.manifest


component {f5181640-89e8-11e1-b0c4-0800200c9444} HelloWorld.js
contract @mozilla.org/helloWorld;1 {f5181640-89e8-11e1-b0c4-0800200c9444}
category JavaScript-navigator-property mozHelloWorld @mozilla.org/helloWorld;1
HELLOWORLD.JS
For example dom/helloworld/HelloWorld.js
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");

function HelloWorld() {}

HelloWorld.prototype = {

  init: function init(aWindow) {},



                                                      Text
  sayHello: function sayHello(aName) {
    dump("Hello " + aName + "n");
  },

  classID : Components.ID("{d88af7e0-a45f-11e1-b3dd-0800200c9444}"),
  QueryInterface : XPCOMUtils.generateQI([Components.interfaces.nsIDOMHelloWorld]),

  classInfo : XPCOMUtils.generateCI({classID: Components.ID("{d88af7e0-a45f-11e1-b3dd-0800200c9444}"),
                                     contractID: "@mozilla.org/helloWorld;1",
                                     classDescription: "HelloWorld",
                                     interfaces: [Components.interfaces.nsIDOMHelloWorld,
Ci.nsIDOMGlobalPropertyInitializer],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT})
}

const NSGetFactory = XPCOMUtils.generateNSGetFactory([HelloWorld]);
BOILERPLATE

• Makefiles

• Manifest

• Packaging

• Module   Loading

• Access   Permission
EXPOSEDPROPS


let foo = new Foo();

Foo.prototype = {
  __exposedProps__: {
                        name: 'rw'
    }
}
FIREFOX OS PROCESS MODEL
• Parent
       - Child            • Nested process
 Processes                 structure not possible
                           (yet)
• Only   one parent
                          • Parent   is trusted
• Browser is in parent,
 content pages are        • Child
                               can be
 children                  compromised

                          • Securitycritical code
                           has to run in parent
SYSTEM MESSAGE MANAGER
• Use   for child-parent
     communication

• Child:
childProcessMessageManager.sendAsyncMessage("message-name", {"foo": 2});
var response = sendSyncMessage("message-name", {"foo": 1});




  Parent:
•receiveMessage: function(aMessage) {
     switch (aMessage.name) {
       [...]
       parentProcessMessageManager.sendAsynMessage(“return-message-name”, [...])
     }
 }
DOMREQUESTS

var pending = navigator.mozApps.install(manifestUrl);
pending.onsuccess = function () {
  // Save the App object that is returned
  var appRecord = this.result;
  alert('Installation successful!')
};
pending.onerror = function () {
  // Display the name of the error
  alert('Install failed, error: ' + this.error.name);
};
PERMISSIONS
HOW TO IMPLEMENT C++
MAPPING JS/C++
• IDL   files → JS & C++

• JS: ctx.lineWidth
 C++: ctx::GetLineWidth(float *width)

• Need   to implement C++ class for interface

• NS_IMETHODIMP:      returns NS_<status>

• Expose
      object:
 nsDOMClassInfo.cpp/nsDOMClassInfoClasses.h
INTERFACES
                     Attribute

           canvas.mozPrintCallback =

Callback    function(obj) {              PrintState
              var ctx = obj.context;
              ctx.fillRect(0, 0, 100, 100);
              obj.done();
            };
INTERFACES                                                               Taken from
                                                                        bug #745025

       te    [scriptable, uuid(a7062fca-41c6-4520-b777-3bb30fd77273)]
             interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
     bu

             {
  tri


               [...]
At




               // A Mozilla-only callback that is called during the printing process.
               attribute nsIPrintCallback mozPrintCallback;
             };
       k
     ac




             [scriptable, function, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a66)]
  llb




             interface nsIPrintCallback : nsISupports
Ca




             {
               void render(in nsIDOMMozCanvasPrintState ctx);
             };
        te
      ta




             [scriptable, builtinclass, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a67)]
    tS




             interface nsIDOMMozCanvasPrintState : nsISupports
  in




             {
Pr




               // A canvas rendering context.
               readonly attribute nsISupports context;

               // To be called when rendering to the context is done.
               void done();
             };
class nsHTMLCanvasPrintState : public nsIDOMMozCanvasPrintState
{
public:
  nsHTMLCanvasPrintState(nsHTMLCanvasElement* aCanvas,
                         nsICanvasRenderingContextInternal* aContext,
                         nsITimerCallback* aCallback)
    : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
      mContext(aContext), mCallback(aCallback)
  {
  }

    NS_IMETHOD GetContext(nsISupports** aContext)
    {
      NS_ADDREF(*aContext = mContext);
      return NS_OK;
    }

    NS_IMETHOD Done()
    {
      [...]                                                    Taken from
      return NS_OK;
    }
                                                              bug #745025


    [...]
}
MEMORY MANAGEMENT
• C++   doesn’t have a garbage collector :(

• In   Gecko: Reference counting & cycle collector

• Reference    counting:

  • nsCOMPtr     (for interfaces), nsREFPtr

   • use   getter_AddRefs

   • NS_IF_ADDREF     & NS_IF_RELEASE
MEMORY MANAGEMENT


• Reference   counting doesn’t work always

• Make   use of Gecko’s cycle collector

• Better   cycle then maybe leak
DEBUGGING

• Make     sure to have a debug build

• Enable    logging (example)

• Watch    for assertion in logs

• Insert   printfs

• There    is documentation how to use debugger
OVERVIEW OF SOME TREES


• Frame   Tree:     Frames on page

• Content   Tree:   Content going with frames

• View   Tree:      Connecting views
MAKE YOUR WORK LAND
TESTS TESTS TESTS
DIFFERENT TYPE OF TESTS
• Reftests

• Crashtests

• XPCShell     Tests

• Mochitests

• JS   tests

• Compiled     code tests :-(

• Marionette     tests
MOCHITEST

•/path/to/objdir $ TEST_PATH=dom/
 contacts/tests make mochitest-plain

•/path/to/objdir $ TEST_PATH=dom/
                 Text
 contacts/tests/test_contacts.html
 make mochitest-plain
TIME FOR REVIEW
• Makesure the patch is   • Whenuploading a new
formatted according to    version:
the guidelines:
                           • address
                                  *all* review
 •8   lines of context      comments

 • correctcommitter        • obsolete   the old
  info (name + email)       patch

 • correct
        checking           • run   tests again
  message
REVIEW
• Make     sure your patch is clean

• Patch    should be green on try-push

• WIP:    State what’s working/what not/what’s next

• Review    might take some time (~1 week?)

• If   longer, ping person, switch review person

• Except    r-, don’t worry!
Q&A
THINGS TO HACK ON


• Implement   vw/vh/vmin/vmax

• "dirname"   DOM attribute on form controls

• Implement   FileSaver

Implementing New Web

  • 1.
    IMPLEMENTING NEW WEBAPIS Gregor Wagner (gwagner@mozilla.com) Julian Viereck (jviereck@mozilla.com)
  • 2.
    DISCALIMER • No API designing/standadization here • Talk about making the implementation happen! • 55” not enough to get you going • Reach out to us and do “hands-on” hacking
  • 3.
    OUTLINE • General Introduction • How To Implement New API • JS • C++ • Make your work land • Q&A
  • 4.
  • 5.
    GENERAL INTRODUCTION • Build on two previous presentations • JS: David Dahl’s “From Web Developer to Firefox Hacker” [1] • C++: Bobby Holley’s “Hacking Gecko” [2] • [1]: http://people.mozilla.com/~ddahl/pages/HackingFirefox/ template.html • [2]: http://people.mozilla.com/~bholley/hacking-gecko- fosdem2012/hacking-gecko.html
  • 6.
    GENERAL INTRODUCTION • Need to build Firefox • Run build: • Linux/Windows: objdir/dist/bin/firefox • OSX: objdir/dist/AppName.app/Contents/ MacOS/firefox • options: -ProfileManager, -no-remote
  • 7.
  • 8.
    GENERAL INTRODUCTION • Don’t get lost in the details • Ask for an implementation outline • There is documentation, overview • Über-Weapon: Ask for help • IRC: https://wiki.mozilla.org/IRC, #developers • Mailing list: https://lists.mozilla.org/listinfo, dev-webapi
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
    GENERAL INTRODUCTION • whenever you do communication • try to be precise • give reasoning to your arguments • get only short answer - don’t take it wrong, people are really busy • dump whatever you have (crashback/patch...)
  • 17.
    GENERAL INTRODUCTION • don’t be afraid to ping people • might get hint to ping someone else • tell people you're new to hacking JS/Gecko • look/ask for bugs that do similar things you try to solve
  • 18.
  • 19.
    FIREFOX OS WEBAPI Wifi Browser Battery Telephony Settings Idle Power Contacts Bluetooth Vibrator Webapps many more to come.... https://wiki.mozilla.org/WebAPI/
  • 20.
  • 21.
    IT ALL STARTSWITH AN INTERFACE XPIDL VS. WEBIDL
  • 22.
    XPIDL VS. WEBIDL [scriptable,builtinclass, interface EventTarget { uuid(5a8294df-ffe4-48e5-803f-f57bebc29289)] void addEventListener(DOMString type, interface nsIDOMScreen : nsIDOMEventTarget EventListener? listener, { optional boolean capture = false, readonly attribute long top; optional boolean? wantsUntrusted = null); readonly attribute DOMString mozOrientation; void removeEventListener(DOMString type, [implicit_jscontext] EventListener? listener, attribute jsval onmozorientationchange; optional boolean capture = false); boolean dispatchEvent(Event event); boolean mozLockOrientation(in DOMString orientation); }; void mozUnlockOrientation(); }; https://developer.mozilla.org/en-US/docs/XPIDL https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings
  • 23.
    MAPPING JS VSC++ • Read other APIs • Interfaces are defined in dom/interfaces • Implementations mostly in dom/*, content/* • c++ implementations use common inheritance • JS implementations use manifest file
  • 24.
    TIME TO FILEA BUG Bugzilla: DOM:Device Interfaces
  • 25.
  • 26.
    WHY IN JS? •Prototyping • Lower entry point • WebDevs know JS • Also better for understanding!
  • 27.
    INTERFACE EXAMPLE For exampledom/interfaces/helloworld/nsIHelloWorld.idl [scriptable, uuid(da0f7040-388b-11e1-b86c-0800200c9444)] interface nsIDOMHelloWorld : nsISupports { void sayHello(in DOMString aName); }; https://bugzilla.mozilla.org/show_bug.cgi?id=674720
  • 28.
    HELLOWORLD.MANIFEST For example dom/helloworld/HelloWorld.manifest component{f5181640-89e8-11e1-b0c4-0800200c9444} HelloWorld.js contract @mozilla.org/helloWorld;1 {f5181640-89e8-11e1-b0c4-0800200c9444} category JavaScript-navigator-property mozHelloWorld @mozilla.org/helloWorld;1
  • 29.
    HELLOWORLD.JS For example dom/helloworld/HelloWorld.js constCc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); function HelloWorld() {} HelloWorld.prototype = { init: function init(aWindow) {}, Text sayHello: function sayHello(aName) { dump("Hello " + aName + "n"); }, classID : Components.ID("{d88af7e0-a45f-11e1-b3dd-0800200c9444}"), QueryInterface : XPCOMUtils.generateQI([Components.interfaces.nsIDOMHelloWorld]), classInfo : XPCOMUtils.generateCI({classID: Components.ID("{d88af7e0-a45f-11e1-b3dd-0800200c9444}"), contractID: "@mozilla.org/helloWorld;1", classDescription: "HelloWorld", interfaces: [Components.interfaces.nsIDOMHelloWorld, Ci.nsIDOMGlobalPropertyInitializer], flags: Ci.nsIClassInfo.DOM_OBJECT}) } const NSGetFactory = XPCOMUtils.generateNSGetFactory([HelloWorld]);
  • 30.
    BOILERPLATE • Makefiles • Manifest •Packaging • Module Loading • Access Permission
  • 31.
    EXPOSEDPROPS let foo =new Foo(); Foo.prototype = { __exposedProps__: { name: 'rw' } }
  • 32.
    FIREFOX OS PROCESSMODEL • Parent - Child • Nested process Processes structure not possible (yet) • Only one parent • Parent is trusted • Browser is in parent, content pages are • Child can be children compromised • Securitycritical code has to run in parent
  • 33.
    SYSTEM MESSAGE MANAGER •Use for child-parent communication • Child: childProcessMessageManager.sendAsyncMessage("message-name", {"foo": 2}); var response = sendSyncMessage("message-name", {"foo": 1}); Parent: •receiveMessage: function(aMessage) { switch (aMessage.name) { [...] parentProcessMessageManager.sendAsynMessage(“return-message-name”, [...]) } }
  • 34.
    DOMREQUESTS var pending =navigator.mozApps.install(manifestUrl); pending.onsuccess = function () {   // Save the App object that is returned   var appRecord = this.result;   alert('Installation successful!') }; pending.onerror = function () {   // Display the name of the error   alert('Install failed, error: ' + this.error.name); };
  • 35.
  • 36.
  • 37.
    MAPPING JS/C++ • IDL files → JS & C++ • JS: ctx.lineWidth C++: ctx::GetLineWidth(float *width) • Need to implement C++ class for interface • NS_IMETHODIMP: returns NS_<status> • Expose object: nsDOMClassInfo.cpp/nsDOMClassInfoClasses.h
  • 38.
    INTERFACES Attribute canvas.mozPrintCallback = Callback function(obj) { PrintState var ctx = obj.context; ctx.fillRect(0, 0, 100, 100); obj.done(); };
  • 39.
    INTERFACES Taken from bug #745025 te [scriptable, uuid(a7062fca-41c6-4520-b777-3bb30fd77273)] interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement bu { tri [...] At // A Mozilla-only callback that is called during the printing process. attribute nsIPrintCallback mozPrintCallback; }; k ac [scriptable, function, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a66)] llb interface nsIPrintCallback : nsISupports Ca { void render(in nsIDOMMozCanvasPrintState ctx); }; te ta [scriptable, builtinclass, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a67)] tS interface nsIDOMMozCanvasPrintState : nsISupports in { Pr // A canvas rendering context. readonly attribute nsISupports context; // To be called when rendering to the context is done. void done(); };
  • 40.
    class nsHTMLCanvasPrintState :public nsIDOMMozCanvasPrintState { public: nsHTMLCanvasPrintState(nsHTMLCanvasElement* aCanvas, nsICanvasRenderingContextInternal* aContext, nsITimerCallback* aCallback) : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas), mContext(aContext), mCallback(aCallback) { } NS_IMETHOD GetContext(nsISupports** aContext) { NS_ADDREF(*aContext = mContext); return NS_OK; } NS_IMETHOD Done() { [...] Taken from return NS_OK; } bug #745025 [...] }
  • 41.
    MEMORY MANAGEMENT • C++ doesn’t have a garbage collector :( • In Gecko: Reference counting & cycle collector • Reference counting: • nsCOMPtr (for interfaces), nsREFPtr • use getter_AddRefs • NS_IF_ADDREF & NS_IF_RELEASE
  • 42.
    MEMORY MANAGEMENT • Reference counting doesn’t work always • Make use of Gecko’s cycle collector • Better cycle then maybe leak
  • 43.
    DEBUGGING • Make sure to have a debug build • Enable logging (example) • Watch for assertion in logs • Insert printfs • There is documentation how to use debugger
  • 44.
    OVERVIEW OF SOMETREES • Frame Tree: Frames on page • Content Tree: Content going with frames • View Tree: Connecting views
  • 45.
  • 46.
  • 47.
    DIFFERENT TYPE OFTESTS • Reftests • Crashtests • XPCShell Tests • Mochitests • JS tests • Compiled code tests :-( • Marionette tests
  • 48.
    MOCHITEST •/path/to/objdir $ TEST_PATH=dom/ contacts/tests make mochitest-plain •/path/to/objdir $ TEST_PATH=dom/ Text contacts/tests/test_contacts.html make mochitest-plain
  • 49.
    TIME FOR REVIEW •Makesure the patch is • Whenuploading a new formatted according to version: the guidelines: • address *all* review •8 lines of context comments • correctcommitter • obsolete the old info (name + email) patch • correct checking • run tests again message
  • 50.
    REVIEW • Make sure your patch is clean • Patch should be green on try-push • WIP: State what’s working/what not/what’s next • Review might take some time (~1 week?) • If longer, ping person, switch review person • Except r-, don’t worry!
  • 51.
  • 52.
    THINGS TO HACKON • Implement vw/vh/vmin/vmax • "dirname" DOM attribute on form controls • Implement FileSaver